We recently had to move a rails app from heroku+postgres to our own servers, since heroku free is now enforcing nap times (but I don’t wanna nap!). We don’t want to have to manage the rails dependencies ourselves, as they can be a pita. Docker to the rescue!
We need to run 2 containers for this, a postgres container for data storage and the actual rails app. We need to persist our postgres data so we mount a local dir into the postgres container and then link from the app container to the postgres container.
##RoR docker container As recommended by the rails docker page we build our own Dockerfile based on their onbuild Dockerfile.
The onbuild Dockerfile builds in some weird places, so it’s customised a bit to build in the more traditional (from docker perspective) /app folder as a mount point.
We use the normal rails server at this point but can easily be replaced with unicorn or whatever. Now we can build the docker image (and push to docker hub if wanted).
And there we have it, we have a rails app working on docker connecting to another docker container which is running postgres.
##Import postgres backup Nah that’s not it don’t worry. You’re probably sat there thinking that’s no good, what about the years of data we’ve already got in the heroku db? What about proxying from http[s] to the rails app? Don’t worry I got you covered.
If you’re using heroku’s postgres you should be able to make a backup of the current db and then download it, we can then transfer that to the docker host and import to our postgres db.
Now we can download the backup we’ve just made. When downloaded it’ll have a name like 46213451-51f0-490a-311d-22c24ea1e4f5, we rename it to magicapp-dump.dump and then upload it to a temporary directory on the docker host /var/www/vhosts/magicapp/tmp in our case.
Now you’ve got your data restored to your new postgres container!
You’ll probably see something like WARNING: errors ignored on restore: 20 these are normally todo with the dump attempting to drop tables that don’t yet exist.
##http proxy container So we’ve now got an app running with a db with our restored data in, time for some http[s] proxy magic. We’re not using one of the docker special images for this, but a rather awesome image from jwilder called nginx-proxy.
One of the beauties about docker is it it’s easy to see what the user has done to the image before we use it, just by looking at the Dockerfile. One of the things that’s great about this docker image is that it can handle most of your proxying without fuss, you don’t need new containers for each url you wish to proxy. We want to proxy both http as well as https traffic (the rails app will redirect to https for us) we need to tell it where our ssl certificates are, and to forward the appropriate ports, but other than that it’s fairly simple to get running.
When we’re using this we actually need to start our rails app with a few more env vars that the proxy container uses to channel.
So now we have a running RoR container, a running Postgres container with data restored from heroku and finally an nginx proxy to forward traffic from normal http/s ports to our app.
##systemd configuration Whilst docker is happy to run on boot, our container’s won’t boot or restart by themselves. These are a basic set of systemd files to get all 3 containers to run. Simply put them in /etc/systemd/system/ and then run sudo systemctl enable docker-nginx-proxy.service etc to enable them and get them to start on boot/restart on error etc.
Note that we don’t pass the -d flag in the run commands, we don’t want to background the running, as this would cause systemd to continuously restart.