Traditionally, one problem that occurs during a deployment process is that your site or application might suffer some downtime, especially if a request is made to it while an important file is being overwritten, or some parts of the site are still running out of date code.
A service such a DeployHQ helps to minimise this by only uploading files that have changed since the last deployment, however this can be completely mitigated by using zero-downtime, or atomic deployments.
How does it work?
When you first run an atomic deployment to your server, DeployHQ will prepare two directories within your deployment path:
And one symlink:
The current symlink points to a folder within the releases directory, named as the timestamp of when you ran the associated deployment.
When you run a deployment, your changed files will be uploaded to that directory. Once this process has finished, the current symlink will be switched to that release. This is where your live app will be run from.
The current symlink will therefore look like so:
current -> releases/20190123120000
This will also happen in exactly the same way during any subsequent deployments. Each time you run a new deployment, DeployHQ will copy the previous release folder to a new one, then upload the changed files to the new release folder. Because the symlink doesn't get switched until after files are transferred, your site will continue to run in its previous state, pointed to the previous release.
Additionally, if the deployment fails at any point before that time, the site will stay pointed to the last release, completely unaffected.
Setting up an atomic deployment
To start using Atomic deployments, you'll need to have access to a server which supports SSH access, with the ability to run POSIX operations (for both copying, and symlinking to release directories).
If you need to test this, login to your server via your terminal, and run the following command:
$ cp --help
If help documentation is outputted to your terminal, you'll be able to get set up.
Adding an atomic server
Just configure a new SSH/SFTP server as normal, but then also enable the option for Zero-downtime deployments at the same time:
Once you've added your server, you'll need to run a full deployment, so that the correct directories are prepared and a full copy of your site is uploaded to it.
After that, only your changes will be uploaded but onto a new, full copy of the last release on every subsequent deployment.
Using the shared directory
The shared directory within an atomic deployment structure is very useful for storing files that you want to persist across releases, and that aren't kept within the repository. For example, you might have an uploads directory that stores user's images when they add a photo when logged into your app, or a series of configuration files.
During each deployment, DeployHQ will automatically symlink everything from the shared folder directly to the latest release, with the structure matching exactly. As part of this process, we check that the same folder doesn't exist in the repository. If it does, we'll drop down a directory and keep doing so until find a subdirectory or file that isn't kept in the repository.
Therefore, it's advisable to confirm that anything you want kept in shared doesn't exist in the repository as well.
Once you've set up a folder or file in shared, all future deployments will symlink it to the latest release, and it'll look like so:
## Path in shared /your-deployment-path/shared/config/database.yml ## Symlinked to latest release: /your-deployment-path/releases/20190417144000/config/database.yml
A couple of other aspects of the atomic deployment process that are useful to know:
- DeployHQ will only keep 3 releases (the current, and 2 previous ones) on your server, and automatically tidy up older releases during the deployment process.
- At present, atomic deployments are only supported on SSH servers, when you first add a new server to your project.
As always, if you have any questions about this feature, or any other aspect of DeployHQ, please don't hesitate to ask .