Deploying to Dokku

Jeff Lindsay created Dokku, the smallest PaaS implementation you've ever seen. It is powered by Docker and written in less than 100 lines of Bash code. I wanted to play with ever since it was released. This weekend I finally did and successfully deployed my application to Dokku running on an Digital Ocean droplet. In this post I share how you can do this as well. Of course I used to wercker to automate everything.

Prerequisites

First of all, to use dokku with wercker (as described here) you need:

Add app to wercker

Fork the getting-started-nodejs sample application and clone it on a local machine.

$ git clone git@github.com:pjvds/getting-started-nodejs.git
Cloning into 'getting-started-nodejs'...
remote: Counting objects: 24, done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 24 (delta 5), reused 17 (delta 1)
Receiving objects: 100% (24/24), done.
Resolving deltas: 100% (5/5), done.
Checking connectivity... done

With the wercker cli installed add the project to wercker using the wercker create command (you can use the default options with any questions it will ask you).

$ cd getting-started-nodejs
$ wercker create

The wercker command should finish with something that looks like:

Triggering build
A new build has been created

Done.
-------------

You are all set up to for using wercker. You can trigger new builds by
committing and pushing your latest changes.

Happy coding!

Generate an SSH key

Run wercker open to open the newly added project on wercker. You should see a successfull build that was triggered during the project creation via the wercker cli. Go to the settings tab and scroll down to 'Key management'. Click the generate new key pair button and enter a meaningful name, I named it "DOKKU".

add ssh key

Create a Dokku Droplet

Now that we have an application in place and have generated an SSH key that will be used in deployment pipeline, it is time to get a dokku environment. Although you can run dokku virtually on every place that runs Linux, we'll use Digital Ocean to get the environment up and running within a minute.

After logging in to Digital Ocean, create a new droplet. Enter the details of your liking. The important part is to pick Dokku on Ubuntu 13.04 in the applications tab.

dokku droplet

Get the ip

After the droplet is created, you'll see a small dashboard with the details of that droplet. Next, replace the public SSH key in the dokku setup with the one from wercker. You can find it in the settings tab of your project. Copy the public key from the key management section and replace the existing key. Next, copy the ip address from the dokku setup(you can find the ip address of it in the left top corner), we'll use it later. You can now click 'Finish setup'.

configure dokku

Create a deploy target

Go to the settings tab of the project on wercker, click on add deploy target and choose custom deploy target. Let's name it production and add two environment variables by clicking the add new variable button. The first one is the server host name: name it SERVER_HOSTNAME and set the value to the ip address of your newly created digital ocean droplet. Add another with the name DOKKU and choose SSH Key pair as a type. Now select the previously created ssh key from the dropdown and hit ok.

Don't forget to save the deploy target by clicking the save button!

Add the wercker.yml

We're ready for the last step which is setting up our deployment pipeline using the wercker.yml file. All we need to do now is tell wercker which steps to perform during a deploy. Create a file called wercker.yml in the root of your repository with the following content:

box: wercker/nodejs
build:
  steps:
    - npm-install
    - npm-test
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:getting-started-nodejs
    - 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

Add the file to the git repository and push it.

$ git add wercker.yml
$ git commit -m 'wercker.yml added'
$ git push origin master

Deploy

Go to your project on wercker and open the latest build, wait until it is finished (and green). You can now click the Deploy to button and select the deploy target we created earlier. A new deploy will be queued and you'll be redirected to it. Wait untill the deploy is finished and enjoy your first successfull deploy to a Digital Ocean droplet running dokku!

Append two slices in Go

Go ships with a buildin function append that can append elements to the end of a slice and returns the updated slice. Here is an example:

data := []int{ 1,2,3 }
data = append(data, 4)

fmt.Println(data)

This will print the following:

[1 2 3 4]

Now I was browsing to some Go code and found something like this:

data := []int{ 1,2,3 }
next := []int{ 4,5,6 }

for _ , v := range next {
    data = append(data, v)
}

This is not a very good way to append a slice to another slice. Actually it is bad and here is why. The append function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated.

The important part here is that it will allocate a new underlying array everytime there is insufficient capacity. Because the code above only appends a single value at the time, the runtime does not know what to expect, otherwise that it should grow to make room for an single extra value. The whole idea behind slices is to prevent unnecessary allocations.

An easy way to fix this is to pass all the data that needs to be appended at once. This way the runtime has all the information needed to grow only once, if needed.

data := []int{ 1,2,3 }
next := []int{ 4,5,6 }

data = append(data, next...)

Notice the suffix ... added to next. This is Go's way of telling to a variadict that we want to pass multiple arguments instead of a single value. If we remove the ... we will receive an compile error that next an invalid type to append to data. This makes sense because we can't append an []int value to an []int, only int values are allowed.

I guess that the programmer used an for loop to resolve this compile error instead of passing multiple arguments at once.

Tune your biological clock with Redshift

I recently started using Redshift and now I question myself how I ever looked into that bright illuminated screen all the time?

Redshift adjusts the color temperature your screen based on the position of the sun. When there is no sun because it is too early or too late it tries to match the color temperature of the lamps there room.

The thing that surprised me is that not only it alleviates the strain on my eyes, but that the slow transition of color temperature make me more aware of the time of the day. When my screen is pretty bright - normal color temperature - I know it is time to lunch. I know it is almost time to get ready for my trip to home when everything starts to look warm. Also the deep red tone during the evening gets makes me aware that I am hacking at night, rather than the I am just hacking. It is hard to explain this, but when I talked to one of my colleagues today, that was his experience as well.

It makes you better aware of time without the explicit numbers a clock offers. And a clock jumps from time to time. We have all been there where you look at the clock, and the next time you look a few hours past. I guess that Redshift is some sort of clock that you can't miss. Maybe that is the reason that is can also help you sleep better.

A pleasant surprise from a tool that I thought would just save my eyes.

Although Redshift works on Linux and Windows, I think people that want to try this on Windows or Mac OS are better of with f.lux.