Docker Tutorial Part 2: Orchestration with Kamal

This document will cover how to orchestrate docker deployments using Kamal. We will build on our previous tutorial Docker Tutorial Part 1: Application Deployment with Docker. This tutorial expects you already know how to “dockerize” your application.

Like Part 1, the instructions here are generally applicable to any application, since everything lives in the docker image.

We will begin where we left off, with a slice containing the default syminet marketplace install of Flask, already dockerized to run from a container.

The majority of this tutorial was distilled from the instructions here: Kamal - Installation ↗

Install Kamal

Kamal is written in the Ruby programming language, and we will be installing Kamal using the Ruby packaging system, gem.

First, change to the directory with your application:

cd /home/flask_app

Make your application directory a git repository

Kamal uses the source control versioning system git to keep track of your code repository. If your application is not already a git repository, we will need to make it one with the following commands:

Install git:

apt install git

Initialize your application directory to be a git repository:

git init

…configure git to have your email address:

git config --global user.email "you@example.com"

Add everything in your application directory to git (note the dot “.” at the end!):

git add .

Commit everything into the directory:

git commit -a

Install dependencies for ruby packages

We need to install a few additional packages for the gem command:

apt -y install ruby-dev make gcc;

Then you can install Kamal:

gem install kamal

Once complete, you are ready to start using Kamal! Read on.

Configure Kamal

Install a target server slice

The slice we are installing Kamal on is your deploy slice: It is where Kamal lives, automating the installation and updates of your application on other servers (slices):

  1. Create -> Slice with Debian Stable.

  2. Make sure you have SSH access to it using your keys.

Create deploy.yml

Make sure you are in your application directory and run the following:

kamal init

You should now have a configuration file for Kamal in config/deploy.yml. First, make a backup copy of it so you can reference it later for all of the commented options:

cp config/deploy.yml config/deploy.bak

Since we have a backup, we can now safely overwrite deploy.yml with the test below. Be sure to fill in the following details with your own information:

TARGET_SLICE_IP_1

IPv4 Address of the target server slice you just created.

YOUR_REGISTRY_USERNAME

Your username at your registry server.

# Name of your application. Used to uniquely configure containers.
service: flaskr

# Name of the container image.
image: my_group/my_project/flaskr

# Deploy to these servers.
servers:
  web:
    hosts:
      - TARGET_SLICE_IP_1
      #- TARGET_SLICE_IP_2
      #- etc. ...

proxy:
  ssl: false
  #  host: app.example.com
  # Proxy connects to your container on port 80 by default.
  #app_port: 80
  healthcheck:
    interval: 3
    path: /
    timeout: 3
  # Credentials for your image host.
registry:
  # Specify the registry server, if you're not using Docker Hub
  server: registry.gitlab.com
  username: YOUR_REGISTRY_USERNAME

  # Always use an access token rather than real password (pulled from .kamal/secrets).
  password:
    - KAMAL_REGISTRY_PASSWORD

builder:
  arch: amd64

Export KAMAL_REGISTRY_PASSWORD

There is one other value in the file, KAMAL_REGISTRY_PASSWORD. For this, you want to export your registry passord into your shell environment where Kamal can pick it up each time it is run. This is to prevent your password being inadvertently checked out by git and explosing it to the world:

export KAMAL_REGISTRY_PASSWORD="my_registry_password"

You might want to add this line to the end of your $HOME/.bashrc file, so that it is automatically assigned every time you login.

Deploy with Kamal

If all is correct, you should be able to deploy to your target server like so:

kamal setup

This should automatically connect to your target server and install docker if required, pull your application from the registry and start it. Full details of all steps are here. You should be able to bring up your application using plain http on port 80, using the IP directly:

http://TARGET_SLICE_IP_1

Further testing

Some things you can do to test further:

Try changing some of the text in your application and commit your changes to git:

git commit -a

Then run kamal setup again and reload on your target server to see the changes have propagated there.

Also you can use the Syminet Cloud Panel to do a Rebuild. Make sure your SSH keys are reinstalled and working, and redeploy with kamal setup again.

Try adding a few more servers and see your changes propagate across all of them.