I would like to add a system to automatically pull down new versions of my app and update automatically, but I’m not sure where to even start on that. My app is self-hostable and thus this sort of thing would reduce the administrative workload for hosters.
From an operational risk management perspective I would look into the direction of container images.
I should add that I once implemented something like this for another technology stack.
It was a nightmare!
People will ignore installation details, prerequisites, etc. and still blame you for all issues coming from their mistakes.
Take a look at the way Gitlab deploys. Every week we have an upgrade window, and many weeks our on-premise install gets a patch or minor (and occasionally major) upgrade. They have a lot of different ways to install, and our sysfolk just run a script to update. There’s a lot of documentation around this project, and it has a lot of real-world experience that is freely shared. Naturally, as an open/paid dual-license project, there’s a lot going on in the code that only makes sense to other projects that need the “freemium” experience. If that’s you, then you may find a lot of good information by digging through their various repos. This one in particular is what they use to “build the deploy packages”: GitLab.org / omnibus-gitlab · GitLab
Walter
I would echo @ChrisJ on looking at using containerization.
In this regard, you can look at what Discourse does. Though their upgrade process is probably tightly coupled to their customized container approach.
For something simpler, you could emulate how capistrano
does blue-green deploys, where you have the following folder structure:
application/shared
application/current -> application/releases/2020601123454435
application/releases/2020601123454435
application/releases/2020602235466446
Then the upgrade process does the following:
- Download the update and verify signature
- Unpack it into a releases directory
- Symlink any “shared” files into the new release directory (these are usually include custom configs and shared directories between releases like
log
orstorage
) - Run
rails db:migrate
,rails assets:precompile
- Attempt booting the new release of the app, and if it succeeds you replace the
current
symlink with the latest release. - If it fails you can log an error by for example writing to a
UpgradeNotices
table or sending an email that the upgrade failed.
Alright, I ended up implementing a container based approach using docker-compose and Watchtower, which will fetch the latest version every 30 minutes and pull the container and restart if there’s a new version:
https://containrrr.dev/watchtower
If anyone’s interested, here’s the relevant files:
For static sites, there is Kamal Skiff.
Is there a specific environment or set of environments (e.g., development, staging, production) where you want the auto-update feature to be implemented?