Running multiple services on Dokku
Dokku makes it very easy to deploy and run simpler web apps.
Recently, I had to deploy a slightly more complex web app with multiple non-web worker services talking to each other. It’s surprisingly simple to get make this work.
Services talking to each other¶
The web app itself is built using Django, so Dokku deploys it using the Python buildpack.
Let’s call this service W for web worker.
There is also Postgres, Redis, a Celery beat and Celery worker processes. I consider these services to be part of a simple web app since they are straightforward to set up using Dokku.
In the more complex setup, I have to run two additional services, service A and B using Go.
So W -> A -> B where W is exposed to the Internet using Dokku with NGINX.
Polyglot web app
Luckily, Dokku supports multiple buildpacks. Dokku just needs some markers that say it’s a Python and Go project.
Having initialized Dokku using Python, I can simply add Go:
$ dokku buildpacks:add facebook https://github.com/heroku/heroku-buildpack-go
$ dokku buildpacks:list facebook
-----> facebook buildpack urls https://github.com/heroku/heroku-buildpack-python https://github.com/heroku/heroku-buildpack-go Connection to server closed.
Services A and B run different Go executables compiled from the same code base. Dokku knows how to build a project with go.mod file by compiling all the main.go binaries.
In order to override the binary names a file bin/go-post-compile can be added with the following contents:
#!/bin/bash set -e go build -o bin/a servicea/main/main.go go build -o bin/b serviceb/main/main.go
The Procfile looks something like this:
release: python manage.py migrate web: gunicorn config.wsgi:application --workers=2 worker: celery -A config.celery_app worker --loglevel=info beat: celery -A config.celery_app beat --loglevel=info b: bin/a a: bin/b
Great! This is how to deploy multiple Processes using different tech stacks with Dokku. Let’s make them talk to each other.
It’s trivial with Dokku to have a web app responding to requests with many other side car processes communicating through Redis or Postgres.
My service A is talking to service B via a HTTP API. Service A needs SERVICE_B_URL.
Dokku creator Jose Diaz-Gonzalez suggests to attach a separate network. Let’s assume our app is called facebook.
$ dokku network:create my-network
$ dokku network:set facebook attach-post-deploy my-network
After a restart service A is able to talk to service B on the host facebook.a because of the process name defined in Procfile.
Service B listens on port 8090 so the full SERVICE_B_URL would be facebook.a:8090.
Update the configuration:
$ dokku config:set facebook SERVICE_B_URL=facebook.a:8090
A can now talk to B!