Service deployment with Docker

The goal of this document is to describe the recommended way of deploying a service to with Docker. With this procedure, the service is automatically deployed and updated on lund. For this documentation we assume that the service is simple enough to fit in one Docker container and that the service is accessible through HTTP.

NOTE: Please make sure to follow the process for new services. Setting up a Docker container or VM is just the technical part but in order to make the FSFE's technical infrastructure clear and maintainable, we need proper communication and documentation.

General Idea

We have one server that hosts our containers. We have a Continuous Integration system, Drone, that builds images and run containers locally on the server. Drone listens for commits in a git server, each commit triggers the creation of a Ansible containers that will build the container and run it. We have a HTTP reverse proxy container that watches container creation and create virtual host dynamically to route the HTTP traffic to the containers.

Here are the necessary steps to use the CI to deploy a service:

1. Build a Dockerfile recipe that builds a Docker image for the service.

2. Create a Ansible playbook that will build and run the container.

3. Create a Drone file that will run the Ansible playbook so the Docker container is deployed on lund.

4. Configure Drone to listen for git commits on the git server.

5.Add a SSH_KEY secret on Drone so it can access to the server.

6. Commit


The Dockerfile that builds the service should have 4 main items:

1. Selection of the base image with a FROM statement.

2. List of the ports that will be exposed so Docker knows what ports are used in the container. Use the EXPOSE statement

3. The actual build of the service. Install the service dependencies and the service itself

4. A CMD statement so the service is run automatically when the container starts.

An example Dockerfile is provided below:

# Base image selection
FROM debian:9

# List of ports that will be exposed to the outside world

# Installing the services and dependencies
RUN [ "apt-get", "-q", "update" ]
RUN [ "apt-get", "-qy", "--force-yes", "upgrade" ]
RUN [ "apt-get", "-qy", "--force-yes", "dist-upgrade" ]
RUN [ "apt-get", "install", "--no-install-recommends", "-qy", "--force-yes", \
      "ca-certificates", \
      "perl", \
      "git", \
      "uuid-dev", \
      "sqlite3", \
      "build-essential", \
      "cpanminus" ]
RUN [ "apt-get", "clean" ]
RUN [ "rm", "-rf", "/var/lib/apt/lists/*", "/tmp/*", "/var/tmp/*" ]
RUN ["cpanm", "--notest", "DBI", "DBD::SQLite", "Mojolicious", "UUID" ]
RUN adduser --quiet --disabled-password --shell /bin/bash --home /home/perlscript --gecos "User" perlscript
USER perlscript
WORKDIR /home/perlscript
RUN git clone
WORKDIR /home/perlscript/mailman-reconfirm

# CMD to run the service on container start
CMD perl daemon -l

Here is the Dockerfile reference.

Ansible playbook

Next, we need to create an Ansible playbook. The playbook is responsible for building the image with the Dockerfile and running the container.

To run the container, there are mandatory options:

An example is provided below:

- hosts:
  remote_user: root

    - name: build image mailman reconfirm
      command: docker build -t mailman-reconfirm

    - name: run the container
        name: mailman-reconfirm
        image: mailman-reconfirm
        state: started
        restart: yes
        restart_policy: always
          - 3000
            - "/srv/mailman-reconfirm/data:/home/perlscript/mailman-reconfirm/data/:rw"

Here is the Ansible docker reference.

Drone configuration

Drone is the Continuous Integration and Continuous Delivery software we use. We need to tell Drone to build the image and run the container.

Add this file to your project and call it .drone.yml:

    image: williamyeh/ansible:debian8
    secrets: [ ssh_key ]
      - mkdir /root/.ssh && echo "$SSH_KEY" > /root/.ssh/id_rsa && chmod 0600 /root/.ssh/id_rsa
      - ssh-keyscan -H >> ~/.ssh/known_hosts
      - ansible-playbook playbook.yml -i
       branch: master

This will create a Ansible Docker container that will build connect locally to with SSH and run the Ansible playbook.

Next, got to and use your FSFE login. Click on the hamburger menu in the upper right corner and select "Repositories". Then activate the CI for your repository.

One last think is to add the lund server ssh key secret. Connect to lund as root and run the following commands:

cd ~
./drone secret add --image=williamyeh/ansible:debian8 --repository <repository path> --name SSH_KEY --value @/root/.ssh/id_rsa

Here <repository path> must be something like <your git username>/<your repository name>.

If that does not work, please make sure the DRONE_* env variables are set correctly. You do so by typing env | grep DRONE_. Please make sure that the DRONE_TOKEN belongs to a user that is owner of the repository.


You can do a test commit to see if it deploys the container correctly.

git commit --allow-empty -m 'Trigger build'

TechDocs/TechnicalProcesses/DockerDeployment (last edited 2018-05-17 10:24:44 by max.mehl)