Continuous Deployment with Dokku (Full Guide)

So you have a fancy new Cloud@Cost [DigitalOcean/Linode] Server, and you want to do something interesting/useful with it. You’ve heard of this cool new tool called docker, but you’re not sure if it’s that useful for you, you mostly play with web development. You’re a big fan of Heroku however, and wouldn’t it be cool if you could do all your prototyping and development in a Heroku-like environment using Docker? Dokku to the rescue.

Ubuntu Version

First thing’s first, lets check what version of Ubuntu we have installed, we want to live on the bleeding edge (LTS) so why not upgrade to the newest version of Ubuntu.

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=13.10
DISTRIB_CODENAME=saucy
DISTRIB_DESCRIPTION="Ubuntu 13.10"

Well that’s no fun. Lets upgrade to 14.04, the new hotness.

$ sudo apt-get update
$ sudo apt-get install update-manager-core
$ sudo nano /etc/update-manager/release-upgrades

Now change normal to lts in opened text file

Prompt=lts

Before we get started, lets poke a hole in our firewall, just for fun. (Mostly because our upgrade is going to occur over SSH, and the installer will open up an additional ssh port as a backup)

iptables -I INPUT -p tcp --dport 1022 -j ACCEPT

Now use one of the following commands to upgrade:

Option1:

$ sudo apt-get update
$ sudo do-release-upgrade -d

Option2:

$ sudo apt-get dist-upgrade -d

Now you can wait for an un-godly amount of time.

Configuring Ubuntu

Its no fun entering passwords all the time, so lets log into our brand new Ubuntu 14.04 machine with a fancy SSH key.

First lets create a new SSH key, just follow the default instructions.

$ ssh-keygen

Now we can see the result in our ~/.ssh folder.

$ ls ~/.ssh/
-rw-------. 1 root root 1675 Jul 27 15:01 id_rsa
-rw-r--r--. 1 root root  406 Jul 27 15:01 id_rsa.pub

Now lets copy our public key over to the Cloud@Cost machine To copy the public key to the machine you want to SSH and fix permissions (you will be prompted for the root password):

$ ssh root@{server ip address} 'mkdir -p /root/.ssh'
$ scp /root/.ssh/id_rsa.pub root@{server ip address}:/root/.ssh/authorized_keys
$ ssh root@{server ip address} 'chmod  700 /root/.ssh'
$ ssh root@{server ip address} 'chmod  600 /root/.ssh/*'

You should now be able to ssh directly from to Cloud@Cost server without providing a password:

$ ssh root@{server ip address}

Dokku for everyone!

Now that we’ve finished with the baby steps, lets get into the meat of the matter. Docker/Dokku!

It starts off simple enough, just run the following command on your Cloud@Cost server.

$ wget -qO- https://raw.github.com/progrium/dokku/v0.2.3/bootstrap.sh | sudo DOKKU_TAG=v0.2.3 bash

Now that Dokku is installed, we have to tell it what domain it’s hosted on. Basically we’ll be accessing our applications on unique subdomains (*.mydomain.com), eg. mygreatapp.thesparktree.com or helloworld.thesparktree.com.

$ echo "thesparktree.com" >> /home/dokku/VHOST

Finally, we need to make sure that we can push code and create apps on our Dokku service. We’ll need to add our ssh key to the Dokku user, and specify a short descriptor for our key (eg. dokkukey). On our host machine, run the following:

$ cat ~/.ssh/id_rsa.pub | ssh root@{server ip address} "sudo sshcommand acl-add dokku {key name/descriptor}"

Plugins

The best part about being a developer is being able to steal reuse other developers code. Dokku has a pretty vibrant plugin ecosystem, and we’ll install a few of my favorite plugins below. You can see the full list of plugins here

All plugins live in the same folder.

$ cd /var/lib/dokku/plugins
$ git clone https://github.com/petercip/dokku-pg-plugin.git postgresql
# the following repo only works with postgres 9.1 - https://github.com/jeffutter/dokku-postgresql-plugin postgresql
$ git clone https://github.com/cedricziel/dokku-deployment-keys.git /var/lib/dokku/plugins/deployment-keys
...other plugins here...
$ dokku plugins-install

Deploy an app

Now that Dokku is all setup, we can push our web app to Dokku. Make sure you don’t have any spaces in your {dokku remote name} or {application name}.

$ cd node-js-sample
$ git remote add {dokku remote name} dokku@{server ip address}:{application name}
$ git push {dokku remote name} master

You can now see your application’s url by typing:

$ dokku url {application name}

Lets start up the postgresql container.

$ dokku postgresql:create {application name}
$ dokku postgresql:link {application name} {application name}

Setting Environmental variables.

You have your app running pushed to Dokku, but it’s not working (of course its not, when has something ever worked the first time). Lets set some of the required environmental variables that your app needs to work properly.

$ dokku config <app> # display the config vars for an app
$ dokku config:get <app> KEY 3 display a config value for an app
$ dokku config:set <app> KEY1=VALUE1 [KEY2=VALUE2 ...] # set one or more config vars
$ dokku config:unset <app> KEY1 [KEY2 ...] # unset one or more config vars

so we could do something like:

$ dokku config:set {application name} NODE_ENV=development

Adding SSL

But wait, something’s wrong. Where’s that green lock in the corner of your browser… without it, how are you going to stop the hackers and the NSA from breaking into your Twitter clone? Don’t worry, I got you covered.

Since this is just a web server for testing applications, lets assume you can get away with a simple SSL cert. Possibly even one that expires yearly. Check out StartSSL for a free SSL certificate.

This SSL guide has some good instructions under the SSL section. At the end of the process you should have the following files:

secure.key - The unencrypted version of your private key (be very careful no one else has access to this file!)
secure.key.secure - The encrypted version of your private key (does not need to be copied to server)
server.csr - Your new certificate (bundle)

If you had any intermediate certificates, you should just concatenate them to the server.csr file to create a certificate bundle. Now copy the secure.key and server.csr to the /home/dokku/{application name}/tls folder on your cloud@cost server. Create the tls folder if it doesn’t exist. Rename the secure.key file to server.key and rename the server.csr to server.crt

$ ls -al
-rw-r--r-- 1 dokku  dokku  7241 Jun 15 12:58 server.crt
-rw-r--r-- 1 dokku  dokku  1676 Jun 15 12:58 server.key

Redeployment of the application will be needed to apply TLS configuration. Once it is redeployed, the application will be accessible by https:// (redirection fromhttps:// is applied as well).

Continuous Deployment.

So you’ve gotten through this wonderful guide, and you’re thinking.. Its a sunday night, and I still have some time to kill. That’s great. Let’s finish up by setting up continuous deployment for our application using Wercker. Wercker is a SAAS similar to CircleCI, TravisCI and Jenkins. The nice thing about Wercker is that it has free accounts with the limitation that only one build can occur at a time.

There’s no need to walk you through creating an account with Wercker. Wercker is based around a werker.yml file that you add to your project root. Here’s what mine looks like.

box: wercker/nodejs
# Build definition
build:
  # The steps that will be executed on build
  steps:
    # A step that executes `npm install` command
    - npm-install
    # A step that executes `npm test` command
    - npm-test
    # A custom script step, name value is used in the UI
    # and the code value contains the command that get executed
    - script:
      name: echo nodejs information
        code: |
          echo "node version $(node -v) running"
          echo "npm version $(npm -v) running"
deploy:
  steps:
    - add-to-known_hosts:
        hostname: $SERVER_HOSTNAME
    - add-ssh-key:
        keyname: DOKKU
    - script:
        name: Initialize new repository
        code: |
          rm -rf .git
          git init
          git config --global user.name "wercker"
          git config --global user.email "pleasemailus@wercker.com"
          git remote add dokku dokku@$SERVER_HOSTNAME:build
    - script:
        name: Add everything to the repository
        code: |
          git add .
          git commit -m "Result of deploy $WERCKER_GIT_COMMIT"
    - script:
        name: Push to dokku
        code: |
          git push dokku master -f

The wercker.yml file is broken up into two parts, the build and deploy sections. This wercker.yml file is for a node application. Once the build finishes, and the tests pass, the application deploys to our Dokku server, automatically.

I’m going to assume that you’ve already connected your bitbucket/github account, and added your project. Lets jump straight into the configuration. First lets got to the settings tab, and add a new SSH key. Wercker will generate the private key pair for us, we just have to name the key, and copy the public key that they give us.

Ssh Keys

We can then add the key to our Dokku server by modifying the authorized_keys file or using sudo sshcommand acl-add dokku {key name/descriptor}

Then, we should add a new Deploy Target to our Wercker project, pointing to our Cloud@Cost server. Select Custom deploy from the dropdown.

Custom Deploy Target

Create a new environmental variable called SERVER_HOSTNAME and specify your dokku server hostname or ipaddress.

Env Variable

Create one more environmental variable called DOKKU and point it to the SSH keypair you created earlier

Env Variable Populated

Make sure you hit the Save button, otherwise Wercker will ignore your configuration changes.

Now make a test commit to your master branch, and push it to github/bitbucket. Your commit should automatically deploy via Wercker to your Dokku box.

Fin.

Jason Kulatunga

Devops & Infrastructure guy @Gusto (ex-Adobe). I write about, and play with, all sorts of new tech. All opinions are my own.

San Francisco, CA blog.thesparktree.com

Subscribe to Sparktree

Get the latest posts delivered right to your inbox.

or subscribe via RSS with Feedly!