Automatically deploy rust applications to Dokku using Travis CI
Lately I’ve been playing around with the idea of having a small Dokku instance so I can deploy my side projects to. Having such an infrastructure is rather cheap (5$/month in DigitalOcean) and pretty easy to set up.
From past experience, I know I need my side projects to be automatically deployed, because I don’t make changes in them quite often and when I do, I don’t want to start thinking “How the hell am I deploying this? 🤔”
I started looking around for guides on how to automatically deploy to Dokku and found this great article on how to do that using Travis CI. A lot of what I eventually did is based on that article.
I wrote this post so I don’t forget how to set it up for future projects and to share the knowledge with others.
Prerequisites
This guide assumes you have a:
- GitHub account
- Travis CI account (free for public GitHub repos)
- Travis CLI tool installed
- Dokku server you can access to using ssh
Preparing SSH keys for deployment
First, on your local machine:
ssh-keygen -t rsa -b 4096 -f dokku-deploy.key
This should create both a private key named dokku-deploy.key
and a public key named dokku-deploy.key.pub
.
Copy the public key to your Dokku host by:
scp ./dokku-deploy.key.pub root@dokku-host.com:/tmp/.
Add this key as an SSH key to Dokku so you can deploy using that key and then remove it. On your Dokku host:
dokku ssh-keys:add travis /tmp/dokku-deploy.key.pub
rm /tmp/dokku-deploy.key.pub
We will use the private key later on. In the meanwhile, it’s worth mentioning that the private key should never be shared with anyone!
Setting up the Dokku app
The first step is creating the Dokku app. On your Dokku host:
dokku apps:create rust-dokku-deploy
Then, you’ll need to add a rust buildpack. Buildpacks tell Dokku how it should turn your app from a code base to an actual running container. In the case of rust, it needs to install rustup
, rustc
and cargo
and then compile your code.
I’ll be using this buildpack:
dokku buildpacks:add rust-dokku-deploy https://github.com/emk/heroku-buildpack-rust
That’s it! You now have a Dokku app ready to have some code pushed into.
Preparing your repository to be deployed
Encrypt the private key
Travis logs are open and so you don’t want sensitive information (such as the private key) to appear there. Luckily, Travis allows encrypting sensitive information to be used later on in your build.
First, let’s make a .travis
directory and copy the keys we created earlier into it:
mkdir .travis
cp /path/to/dokku-deploy.key .travis/.
In order to not mistakenly add the private key to your repository, let’s add it to .gitignore
:
echo ".travis/*.key" >> .gitignore
Then, you need to log in to Travis CLI, in order to encrypt the key. On your local machine, navigate to your project folder and then:
travis login
This will for your GitHub credentials. After a successful login, you can encrypt the key and add it to your .travis.yml
(this action will create .travis.yml
if it doesn’t already exist):
travis encrypt-file .travis/dokku-deploy.key --add
This will do the following:
- Create a
dokku-deploy.key.enc
file in your repository root - Add a
before_install
section to your.travis.yml
file.
Then, you need to move the newly created file to .travis
directory:
mv dokku-deploy.key.enc .travis/.
Adding deployment files to the repository
The first file we will add is deploy.sh
. This is script that will be in charge of deploying the code to Dokku. I’m creating this file in .travis
folder for convenience:
As you might notice, I’m using two environment variables in the script (DOKKU_HOST
and DOKKU_APP
) since I prefer hiding these values. In order to do that, I use Travis’s encryption feature once more:
travis encrypt DOKKU_HOST=dokku-host.com --add
travis encrypt DOKKU_APP=rust-dokku-deploy --add
This will add an env
section to your .travis.yml
file, with a global
section nested under it, with the two encrypted variables in that section.
In order to run deploy.sh
on every merge to master
you need to do two things:
Add another line to the before_install
section to make deploy.sh
executable:
chmod +x .travis/deploy.sh
Add an after_success
section to run the script after the build succeeded:
after_success:
- |
if [ "$TRAVIS_BRANCH" == "master" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ]; then
bash .travis/deploy.sh;
fi;
I wanted my application to be deployed only when there’s a push to master
(either directly or by merging a PR), and this is the reason for the if
clause.
So eventually, your .travis.yml
file should be similar to this:
For the buildpack to know how to compile and run your rust application, you need to add two more files to your repository root:
Procfile tells the buildpack how to run your application. You can read more about it here: http://dokku.viewdocs.io/dokku/deployment/methods/dockerfiles/#procfiles-and-multiple-processes
rust-toolchain tells the buildpack which rust version it should use in order to compile your app.
That’s it! It might seem a bit complicated at first glance but I believe it’s worth the effort. From now on, I don’t need to think about how to deploy my app to Dokku, it happens automatically!
Originally posted on Medium.