Kamal 2 finally brings the most requested feature to reality and allows people to run multiple applications simultaneously on a single server. Here’s how.
The Kamal way
Kamal is an application-centric deploy tool rather than a small PaaS. And this hasn’t changed with the new version 2. But what does it even mean?
Let’s look at a typical config/deploy.yml
to run a generic application:
# config/deploy.yml
service: [APP_NAME]
image: [DOCKER_REGISTRY]/[APP_NAME]
servers:
web:
- 165.22.71.211
job:
hosts:
- 165.22.71.211
cmd: bin/jobs
proxy:
ssl: true
host: [APP_DOMAIN]
registry:
username: [DOCKER_REGISTRY]
# Always use an access token rather than real password when possible.
password:
- KAMAL_REGISTRY_PASSWORD
env:
...
As you can notice the configuration describes only one particular service. And this hasn’t changed. Applications still have their own configuration. The only thing that changed is the possibility to share their servers.
Kamal Proxy
Kamal 2 adds support for multiple apps with the new Kamal Proxy. The new proxy registers new deployments for services and handles their gapless switchover.
The only thing Kamal Proxy needs to know is the host
(domain) of the service so it can route the traffic to the service web containers. This is done with the following Kamal configuration:
# config/deploy.yml
...
proxy:
ssl: true
host: [APP_DOMAIN]
The extra ssl
option let’s us also request automatic SSL/TLS certificates via Let’s Encrypt.
There will only be one instance of Kamal Proxy running on a given server, installed by the first deployed application.
Multiple apps
Let’s say we want to deploy three different application on the same server for a local dealership. The main app, API server, and their marketing website. Then we need three different configurations, one for each app.
The main app will run on app.dealership.com
:
# dealership/config/deploy.yml
service: dealership
image: [DOCKER_REGISTRY]/dealership
servers:
web:
- 165.22.71.211
job:
hosts:
- 165.22.71.211
cmd: bin/jobs
proxy:
ssl: true
host: app.dealership.com
registry:
...
env:
...
The API service will run on api.dealership.com
:
# dealership-api/config/deploy.yml
service: api
image: [DOCKER_REGISTRY]/dealership-api
servers:
web:
- 165.22.71.211
proxy:
ssl: true
host: api.dealership.com
registry:
...
env:
...
And the marketing website will be accesible from the main domain as well as www.dealership.com
:
# marketing/config/deploy.yml
service: marketing
image: [DOCKER_REGISTRY]/dealership-web
servers:
web:
- 165.22.71.211
proxy:
ssl: true
host: "dealership.com,www.dealership.com"
registry:
...
env:
...
Kamal cannot do redirects right now, so the auto redirect from www to non-www variant has to be done on the application side. Also any accessory that needs to expose an HTTP endpoint should actually be another app like these three.
To deploy them we would run kamal setup
for each. The first one will install Docker, set up the kamal
network, and make sure kamal-proxy
is running. The other two would safely skip these steps and deploy to existing proxy.
dealeship$ kamal setup
dealeship-api$ kamal setup
marketing$ kamal setup
Debugging
If we want to check what apps should Kamal Proxy be running, we can do so on the server with kamal-proxy list
:
$ ssh [USER]@[SERVER]
# docker exec kamal-proxy kamal-proxy list
Service Host Target State TLS
dealership dealearship.com cde2433e86d6:80 running yes
dealership-api api.dealearship.com 82361b53174f:80 running yes
...
We’ll get what hosts and revisions are running for each deployed service as well as their status.
This is not exposed directly to Kamal but we can fix it with an alias:
# config/deploy.yml
...
aliases:
...
apps: server exec docker exec kamal-proxy kamal-proxy list
Now running kamal apps
gives us a nice rundown of what’s running which is pretty sweet.