Deploy with Docker stack

Create your docker-compose file.

Ensure it’s stating a version of at least 3.

version: '3'
services:
  app:
    image: php:7
    environment:
      DB_HOST: db
      DB_USER: root
      DB_PASS: root
      DB_NAME: test
    ports:
      - 8000:80
    networks:
      - devnet
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

  db:
    image: mysql:latest
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test
    networks:
      - devnet
    deploy:
      replicas: 1
      update_config:
        parallelism: 2
        delay: 10s
      restart_policy:
        condition: on-failure

networks:
  devnet:
    driver: overlay

Initiate swarm

You can only deploy to a swarm. So when you’re not on a swarm yet, initiate a swarm.

$ docker swarm init

Swarm initialized: current node (12345abcd) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token long-token-1234-abdc 192.168.1.2:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Deploy the stack

$ docker stack deploy -c docker-compose.yml dev
Creating network dev_devnet
Creating service dev_app
Creating service dev_db

Check the status of your stack

To check the status of the services in your stack, issue the command docker stack ps <stackname>.

$ docker stack ps dev
ID                  NAME                IMAGE               NODE                    DESIRED STATE       CURRENT STATE              ERROR               PORTS
smfn5wlsf9iy        dev_db.1            mysql:latest        linuxkit-025000000001   Running             Running 33 seconds ago
q6zade4sjes3        dev_app.1           php:7               linuxkit-025000000001   Running             Preparing 37 seconds ago

Check services in your stack

$ docker stack services dev
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
085u7la8kgso        dev_app             replicated          1/1                 php:7-apache        *:8000->80/tcp
ogwbs8ge3a7x        dev_db              replicated          1/1                 mysql:latest

Get more detailed info of a service with docker service ps

$ docker service ps apibot-test_app
ID                  NAME                IMAGE                                            NODE                DESIRED STATE       CURRENT STATE           ERROR                              PORTS
rd7lpji8noqx        apibot-test_app.1   registry.gitlab.com/pauledenburg/apibot:latest                       Running             Pending 4 minutes ago   "no suitable node (2 nodes not…"

Get the full errormessage. Because, by default, it’s truncated. No prob, just use the --no-trunc flag

$ docker service ps apibot-test_app --no-trunc
ID                          NAME                IMAGE                                            NODE                DESIRED STATE       CURRENT STATE           ERROR                                                      PORTS
rd7lpji8noqxftr6c4dozzg8d   apibot-test_app.1   registry.gitlab.com/pauledenburg/apibot:latest                       Running             Pending 4 minutes ago   "no suitable node (2 nodes not available for new tasks)"

Services use containers too

The services use containers too. This knowledge can help if you need to debug and want to execute a command on one of the containers.

$ docker ps
CONTAINER ID        IMAGE                                                COMMAND                  CREATED             STATUS              PORTS               NAMES
24501897f39a        php:7-apache                                         "docker-php-entrypoi…"   2 hours ago         Up 2 hours          80/tcp              dev_app.1.sct5wyx3hcix3rvtac9eaek6i
168f471918a6        mysql:latest                                         "docker-entrypoint.s…"   2 hours ago         Up 2 hours          3306/tcp            dev_db.1.smfn5wlsf9iyndvqq0j4cyz7j

Pro-tip
The containers have really long names. I prefer to use a little helperscript to make executing commands on containers easier.

#!/usr/bin/env bash

search=$1
shift 1
command="$@"

CONTAINER=$(docker ps -q --filter="name=_$search")
CONTAINER_NAME=$(docker ps --filter="name=_$search" | rev | awk '{print $1}' | sed -n '1!p' | rev)

printf "[executing on container $CONTAINER_NAME]\n\n"
docker exec -it $CONTAINER bash -lc "$command"

Now when I want to execute a command on a container with ‘app’ in the name, I use that as the first argument. So the command becomes ./dev <part_of_container_name> <command_to_execute_on_container>

$ ./dev app php -v
[executing on dev_app.1.sct5wyx3hcix3rvtac9eaek6i]

PHP 7.2.2 (cli) (built: Feb  6 2018 22:13:41) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

Update the stack

If there are changes to the images, you can update your stack by simply running the deploy again.

$ docker stack deploy -c docker-compose.yml dev
Updating service dev_db (id: ogwbs8ge3a7xv4l2icr4nd4x6)
Updating service dev_app (id: 085u7la8kgso48obt948de2dp)

Getting the logs for a service

To debug your stack, you can use docker service logs to see what happens on the service.

# see what services are in the stack
$ docker stack services dev
ID                  NAME                MODE                REPLICAS            IMAGE               PORTS
085u7la8kgso        dev_app             replicated          1/1                 php:7-apache        *:8000->80/tcp
ogwbs8ge3a7x        dev_db              replicated          1/1                 mysql:latest

# get the logs for one of them
$ docker service logs dev_db
dev_db.1.smfn5wlsf9iy@linuxkit-025000000001    | Initializing database
dev_db.1.smfn5wlsf9iy@linuxkit-025000000001    | 2018-02-14T13:56:16.....
...

Remove the stack

To remove your stack, use the rm flag.

$ docker stack rm dev
Removing service dev_app
Removing service dev_db
Removing network dev_devnet
0 Shares
>