.NET web apps on DigitalOcean
I wanted to take some time and document my latest web app setup that I use for my trading tracking site.
The site itself is a simple .net web app which allows you to track your trading and portfolio performance, the source code is public and can be found here: https://github.com/laimis/stock-analysis
The site itself was used by a few people to track their portfolios, so I treat it like a production system as far as its operations are concerned. I recently shut down the public access so that I can focus on my trading and adding features that I need (vs what others need ;) ). It is a critical tool in my own trading today.
I used to run it on AWS and have shared my setup as to how I did it: ASP.NET Core apps on AWS, Github actions for publishing to ECR, and Pushing live updates from ECR to EC2.
To be honest, if I had to deploy it on AWS again, I would go via a much simpler route now by using AWS App Runner and not maintain my own EC2 instance but that’s all behind me now since I decided to move to DigitalOcean.
Current setup
I really like the setup I have now on DigitalOcean. They offer “App” hosting where you basically can deploy any dockerized app (and more) and you will automatically get a DNS name to access the site, CDN in front of it (looks like it’s powered by Cloudflare), and API that you can trigger deployments as part of your CI flow.
Here is what I have:
This app points to a docker image that’s hosted on DigitalOcean’s container registry:
To deploy, I use Github’s workflow action:
Here is the full action code:
on:
push:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
name: Create Release
jobs:
build:
name: Create Release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@main
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
- name: Login to DigitalOcean
run: doctl registry login
- name: Build, tag, and push image to DigitalOcean
id: build-image
env:
ECR_REGISTRY: registry.digitalocean.com/nightingale-trading/web
run: |
IMAGE_TAG=$(echo "${GITHUB_REF}" | cut -d "/" -f3)
# rename it to latest, that's what I use right now
IMAGE_TAG=latest
echo "building $ECR_REGISTRY:${IMAGE_TAG}"
docker build -t $ECR_REGISTRY:${IMAGE_TAG} .
docker image ls
echo "pushing $ECR_REGISTRY:${IMAGE_TAG}"
docker push registry.digitalocean.com/nightingale-trading/web:latest
echo "::set-output name=image::$ECR_REPOSITORY:${IMAGE_TAG}"
- name: Create Deployment
run: doctl apps create-deployment ${{ secrets.DO_APP_ID }}
- name: Kick off garbage collection
run: doctl registry garbage-collection start -f
- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
body: |
See releases tags for full set of changes
draft: false
prerelease: false
I just love the simplicity of it all. DigitalOcean has a doctl utility that you can install in your action and then use that utility to call their APIs.
As you can see, the utility gets installed first, and then after logging into DO’s registry, we build the docker image, push the image, and create an app deployment via doct apps create-deployment
I also ping garbage collection in there to keep my registry neat and tidy. Whenever I create a new release, I delete untagged manifests so this garbage collection step cleans them up. Again, this might be too specific for my setup and you can ignore it. The key flow is: create an image, push to the container, create app deployment, and you are done.
Note on DigitalOcean experience
Thus far I am very happy. I have been on them since around March of 2022 and the experience have been great. I did have a few prod level issues where I had to reach out to the support and their support is simply amazing. A small fish like me can get immediate attention. I was talking to a real and capable person right away and my issues were addressed promptly. I couldn’t be more happy about that.
The cost of the setup is a bit cheaper than what I had on Amazon too, so I am not complaining at all.
So far as good!