Docker: Swarm mode, Compose и scaling

Автор: | 11/03/2017

Быстрый пример запуска и управления сервисами в Docker Swarm.

Имеется две VM в Azure.

Master setup

Подключаемся к Мастеру:

[simterm]

$ ssh [email protected]
...
setevoy@jm-sw-arseny-test-1-master:~$

[/simterm]

Устанавливаем Docker:

[simterm]

$ sudo curl https://get.docker.com/ | sudo bash

[/simterm]

Добавляем пользователя в группу docker:

[simterm]

$ sudo usermod -aG docker setevoy

[/simterm]

Перелогиниваемся, поверяем:

[simterm]

$ docker info
Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 17.03.0-ce
...

[/simterm]

Инициализируем Swarm-менеджер:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker swarm init
Swarm initialized: current node (w4md2hvsyj8sqez8gutv4m8dz) is now a manager.

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

    docker swarm join \
    --token SWMTKN-1-259al7lgdwymdbr3ciyfixphxtxngwbwxhcsfwn7eceh8rg9se-bgrklm5tm0aqrw71l592x1bpu \
    172.16.1.4:2377

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

[/simterm]

Тут Docker:

  • переключает текущую нодув редим swarm mode;
  • создаёт ферму с именем default.
  • устанавливает текущую ноду как управляющий менеджер для всей фермы;
  • задаёт ноде имя хоста;
  • настраивает менеджер на прослушиваение порта 2377;
  • устанавливает ноде режим Active, что бы она могла принимать задачи от планирощика;
  • создаёт самоподписанный roto CA для фермы;
  • создаёт токены для воркеров и других менеджер-нод;
  • создаёт overlay-сеть с именем ingress для маппинга портов сервисов.

Проверяем порт 2377 – на него Swarm-master будет принимать запросы от нод:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ sudo netstat -anp | grep 2377
tcp        0      0 127.0.0.1:37066         127.0.0.1:2377          ESTABLISHED 5417/dockerd    
tcp6       0      0 :::2377                 :::*                    LISTEN      5417/dockerd    
tcp6       0      0 127.0.0.1:2377          127.0.0.1:37066         ESTABLISHED 5417/dockerd    

[/simterm]

Node

Про ноды – читать тут>>>.

Подготавливаем, как и мастер:

[simterm]

16:29:59 [setevoy@setevoy-arch-work ~]  $ ssh [email protected]
setevoy@jm-sw-arseny-test-1-node:~$ sudo curl https://get.docker.com/ | sudo bash
setevoy@jm-sw-arseny-test-1-node:~$ sudo usermod -aG docker your-user

[/simterm]

На мастере – вызываем join-token worker, что бы получить ключ авторизации:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker swarm join-token worker
To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-3q5vffsb4b8c168q9m7x93z8cmbcrccpknx69nc87c8c3u0xn9-dksfajolcnqrccapmb2bp6qlf \
    172.16.1.4:2377

[/simterm]

На ноде – выполняем подключение:

[simterm]

setevoy@jm-sw-arseny-test-1-node:~$ docker swarm join \
>     --token SWMTKN-1-3q5vffsb4b8c168q9m7x93z8cmbcrccpknx69nc87c8c3u0xn9-dksfajolcnqrccapmb2bp6qlf \
>     172.16.1.4:2377
This node joined a swarm as a worker.

[/simterm]

С помощью node – проверяем машины в ферме:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ls
ID                           HOSTNAME                    STATUS  AVAILABILITY  MANAGER STATUS
96xrngmjobhuatin7qbwib1j3    jm-sw-arseny-test-1-node    Ready   Active        
q35n6wiqw8fnsvxhzskb2uavp *  jm-sw-arseny-test-1-master  Ready   Active        Leader

[/simterm]

Получить детали о ноде – inspect:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node inspect 96xrngmjobhuatin7qbwib1j3
[
    {
        "ID": "96xrngmjobhuatin7qbwib1j3",
        "Version": {
            "Index": 15
        },
        "CreatedAt": "2017-03-10T16:12:34.463028369Z",
        "UpdatedAt": "2017-03-10T16:12:34.616122003Z",
        "Spec": {
            "Role": "worker",
            "Availability": "active"
        },
        "Description": {
            "Hostname": "jm-sw-arseny-test-1-node",
            "Platform": {
                "Architecture": "x86_64",
                "OS": "linux"
            },
...

[/simterm]

Добавление сервиса

Читать тут>>>.

Для запуска любого сервиса – достаточно выполнить service create, например:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service create --name lb_nginx nginx
tigighh2xhv1etvcgtkjkweq8

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ls
ID            NAME      MODE        REPLICAS  IMAGE
tigighh2xhv1  lb_nginx  replicated  1/1       nginx:latest

[/simterm]

Состояние нод:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps
ID            NAME        IMAGE         NODE                        DESIRED STATE  CURRENT STATE           ERROR  PORTS
q0ephywt8ek6  lb_nginx.1  nginx:latest  jm-sw-arseny-test-1-master  Running        Running 27 seconds ago

[/simterm]

Сервис запущен на одной ноде.

Для того, что бы Swarm замасштабировал сервис на другие ноды – используем service scale:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service scale tigighh2xhv1=2
tigighh2xhv1 scaled to 2

[/simterm]

Где tigighh2xhv1 – ID из результатов docker service ls.

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ls
ID            NAME      MODE        REPLICAS  IMAGE
tigighh2xhv1  lb_nginx  replicated  2/2       nginx:latest

[/simterm]

Проверяем на второй ноде. Находим ID ноды:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ls
ID                           HOSTNAME                    STATUS  AVAILABILITY  MANAGER STATUS
96xrngmjobhuatin7qbwib1j3    jm-sw-arseny-test-1-node    Ready   Active        
q35n6wiqw8fnsvxhzskb2uavp *  jm-sw-arseny-test-1-master  Ready   Active        Leader

[/simterm]

Проверяем процессы на ней:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps 96xrngmjobhuatin7qbwib1j3
ID            NAME        IMAGE         NODE                      DESIRED STATE  CURRENT STATE               ERROR  PORTS
1z7sblrovq51  lb_nginx.2  nginx:latest  jm-sw-arseny-test-1-node  Running        Running about a minute ago

[/simterm]

И он же – на мастере:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps q35n6wiqw8fnsvxhzskb2uavp
ID            NAME        IMAGE         NODE                        DESIRED STATE  CURRENT STATE          ERROR  PORTS
q0ephywt8ek6  lb_nginx.1  nginx:latest  jm-sw-arseny-test-1-master  Running        Running 5 minutes ago

[/simterm]

Настройки нод

Сейчас контейнер с NGINX не принимает никаких соединений – порты закрыты.

Что бы открыть порты во время создания сервиса – используем опцию --publish:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service create --name lb_nginx_80 --publish 80:80 --replicas 2 nginx 
ht0vp3go1cm5yip2gl7g7dcc7

[/simterm]

--replicas 2 – запустить сервис сразу на обеих нодах.

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ curl localhost
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
...

[/simterm]

Сервисы на нодах:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ls
ID                           HOSTNAME                    STATUS  AVAILABILITY  MANAGER STATUS
96xrngmjobhuatin7qbwib1j3    jm-sw-arseny-test-1-node    Ready   Active        
q35n6wiqw8fnsvxhzskb2uavp *  jm-sw-arseny-test-1-master  Ready   Active        Leader

[/simterm]
[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps q35n6wiqw8fnsvxhzskb2uavp
ID            NAME           IMAGE         NODE                        DESIRED STATE  CURRENT STATE           ERROR  PORTS
q0ephywt8ek6  lb_nginx.1     nginx:latest  jm-sw-arseny-test-1-master  Running        Running 11 minutes ago         
n7wr3fpgtx2v  lb_nginx_80.2  nginx:latest  jm-sw-arseny-test-1-master  Running        Running 52 seconds ago

[/simterm]
[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps q35n6wiqw8fnsvxhzskb2uavp
ID            NAME           IMAGE         NODE                        DESIRED STATE  CURRENT STATE               ERROR  PORTS
q0ephywt8ek6  lb_nginx.1     nginx:latest  jm-sw-arseny-test-1-master  Running        Running 11 minutes ago             
n7wr3fpgtx2v  lb_nginx_80.2  nginx:latest  jm-sw-arseny-test-1-master  Running        Running about a minute ago

[/simterm]
И останавливаем первый запущенный сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service rm tigighh2xhv1
tigighh2xhv1

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ls
ID            NAME         MODE        REPLICAS  IMAGE
ht0vp3go1cm5  lb_nginx_80  replicated  2/2       nginx:latest

[/simterm]

Масшабирование с Docker Compose

Устанавливаем Docker Compose:

[simterm]

root@jm-sw-arseny-test-1-master:~# curl -L https://github.com/docker/compose/releases/download/1.11.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
root@jm-sw-arseny-test-1-master:~# chmod +x /usr/local/bin/docker-compose
root@jm-sw-arseny-test-1-master:~# /usr/local/bin/docker-compose -v
docker-compose version 1.11.2, build dfed245

[/simterm]

Создадим простой compose-файл:

version: '3'
services:
  web:
    image: "nginx"
    ports:
     - "80:80"

Обратите внимание на версию:

version: ‘3’

Потребуется для docker stack deploy ниже.

Запускаем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker-compose up -d
WARNING: The Docker Engine you're using is running in swarm mode.

Compose does not use swarm mode to deploy services to multiple nodes in a swarm. All containers will be scheduled on the current node.

To deploy your application across the swarm, use `docker stack deploy`.

Starting setevoy_web_1

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker-compose ps
    Name              Command          State              Ports            
--------------------------------------------------------------------------
setevoy_web_1   nginx -g daemon off;   Up      443/tcp, 0.0.0.0:80->80/tcp

[/simterm]

На нодах Swarm-а – сервисы не запущены:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps q35n6wiqw8fnsvxhzskb2uavp
ID  NAME  IMAGE  NODE  DESIRED STATE  CURRENT STATE  ERROR  PORTS
setevoy@jm-sw-arseny-test-1-master:~$ docker node ps 96xrngmjobhuatin7qbwib1j3
ID  NAME  IMAGE  NODE  DESIRED STATE  CURRENT STATE  ERROR  PORTS

[/simterm]

Стопаем compose:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker-compose down
Stopping setevoy_web_1 ... done
Removing setevoy_web_1 ... done
Removing network setevoy_default

[/simterm]

С помощью docker stack deploy – деплоим сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker stack deploy -c docker-compose.yml lb_nginx
Creating network lb_nginx_default
Creating service lb_nginx_web

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker stack services lb_nginx
ID            NAME          MODE        REPLICAS  IMAGE
wpe7whxqnods  lb_nginx_web  replicated  1/1       nginx:latest

[/simterm]

Обратите внимание, что REPLICAS 1/1, сервис запущен только на мастере:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps q35n6wiqw8fnsvxhzskb2uavp
ID            NAME            IMAGE         NODE                        DESIRED STATE  CURRENT STATE           ERROR  PORTS
ksthn3r0yu3v  lb_nginx_web.1  nginx:latest  jm-sw-arseny-test-1-master  Running        Running 28 seconds ago

[/simterm]

Но на второй ноде – ничего:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ps 96xrngmjobhuatin7qbwib1j3
ID  NAME  IMAGE  NODE  DESIRED STATE  CURRENT STATE  ERROR  PORTS

[/simterm]

Скейлим сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service scale lb_nginx_web=2
lb_nginx_web scaled to 2

[/simterm]

Проверяем ноды:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ps lb_nginx_web
ID            NAME            IMAGE         NODE                        DESIRED STATE  CURRENT STATE               ERROR  PORTS
ksthn3r0yu3v  lb_nginx_web.1  nginx:latest  jm-sw-arseny-test-1-master  Running        Running 2 minutes ago              
tj0dmku1r8di  lb_nginx_web.2  nginx:latest  jm-sw-arseny-test-1-node    Running        Running about a minute ago

[/simterm]

Последнее, что стоит показать – использование мастер-ноды в роли только менеджера, без запуска сервисов на нём.

Сейчас обе ноды могут запускать новые контейнеры.

Добавим ещё одну ноду, и переведём Мастер в режим только менеджера.

Заводим ещё одну машину:

Сетапим её:

[simterm]

$ ssh [email protected]
...
setevoy@jm-sw-arseny-test-2-node:~$ sudo curl https://get.docker.com/ | sudo bash
...
setevoy@jm-sw-arseny-test-2-node:~$ sudo usermod -aG docker setevoy

[/simterm]

На местере получаем токен:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker swarm join-token worker
To add a worker to this swarm, run the following command:                                                                                                                                                                                     
                                                                                                                                                                                                                                              
    docker swarm join \                                                                                                                                                                                                                       
    --token SWMTKN-1-3q5vffsb4b8c168q9m7x93z8cmbcrccpknx69nc87c8c3u0xn9-dksfajolcnqrccapmb2bp6qlf \                                                                                                                                           
    172.16.1.4:2377

[/simterm]

На новой ноде – подключаемся:

[simterm]

setevoy@jm-sw-arseny-test-2-node:~$ docker swarm join --token SWMTKN-1-3q5vffsb4b8c168q9m7x93z8cmbcrccpknx69nc87c8c3u0xn9-dksfajolcnqrccapmb2bp6qlf 172.16.1.4:2377
This node joined a swarm as a worker.

[/simterm]

На мастере проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ls
ID                           HOSTNAME                    STATUS  AVAILABILITY  MANAGER STATUS
96xrngmjobhuatin7qbwib1j3    jm-sw-arseny-test-1-node    Ready   Active        
q35n6wiqw8fnsvxhzskb2uavp *  jm-sw-arseny-test-1-master  Ready   Active        Leader
zdz4mni0bndah9aq0phdazibb    jm-sw-arseny-test-2-node    Ready   Active

[/simterm]

Стопаем сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ls
ID            NAME          MODE        REPLICAS  IMAGE
wpe7whxqnods  lb_nginx_web  replicated  4/4       nginx:latest

[/simterm]
[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service rm lb_nginx_web
lb_nginx_web

[/simterm]

Устанавливаем для мастера availability drain:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node update --help

Usage:  docker node update [OPTIONS] NODE

Update a node

Options:
      --availability string   Availability of the node (active/pause/drain)
      --help                  Print usage
      --label-add list        Add or update a node label (key=value) (default [])
      --label-rm list         Remove a node label if exists (default [])
      --role string           Role of the node (worker/manager)

[/simterm]
[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node update --availability drain q35n6wiqw8fnsvxhzskb2uavp
q35n6wiqw8fnsvxhzskb2uavp

[/simterm]

Проверяем (колонка AVAILABILITY):

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker node ls
ID                           HOSTNAME                    STATUS  AVAILABILITY  MANAGER STATUS
96xrngmjobhuatin7qbwib1j3    jm-sw-arseny-test-1-node    Ready   Active        
q35n6wiqw8fnsvxhzskb2uavp *  jm-sw-arseny-test-1-master  Ready   Drain         Leader
zdz4mni0bndah9aq0phdazibb    jm-sw-arseny-test-2-node    Ready   Active

[/simterm]

Запускаем сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker stack deploy -c docker-compose.yml lb_nginx
Creating service lb_nginx_web

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ls
ID            NAME          MODE        REPLICAS  IMAGE
y64pm6gpjwhn  lb_nginx_web  replicated  1/1       nginx:latest

[/simterm]
[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ps lb_nginx_web
ID            NAME            IMAGE         NODE                      DESIRED STATE  CURRENT STATE               ERROR  PORTS
l8eb99wz4nzo  lb_nginx_web.1  nginx:latest  jm-sw-arseny-test-1-node  Running        Running about a minute ago

[/simterm]

Запущен только на ноде1. Масштабируем севрис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service scale lb_nginx_web=2
lb_nginx_web scaled to 2

[/simterm]

Проверяем:

[simterm]

$ docker service ps lb_nginx_web
ID            NAME            IMAGE         NODE                      DESIRED STATE  CURRENT STATE            ERROR  PORTS
l8eb99wz4nzo  lb_nginx_web.1  nginx:latest  jm-sw-arseny-test-1-node  Running        Running 2 minutes ago           
ieh41le96ix1  lb_nginx_web.2  nginx:latest  jm-sw-arseny-test-2-node  Running        Preparing 2 seconds ago

[/simterm]

Другой способ запускать сервисы сразу на нескольких нодах – указать желаемое кол-во репликаций в compose-файле.

Стопаем сервис:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service rm lb_nginx_web
lb_nginx_web

[/simterm]

Редактируем docker-compose.yml, и добавляем replicas:

version: '3'
services:
  web:
    image: "nginx"
    ports:
     - "80:80"
    deploy:
      mode: replicated
      replicas: 2

Запускаем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker stack deploy -c docker-compose.yml lb_nginx
Creating service lb_nginx_web

[/simterm]

Проверяем:

[simterm]

setevoy@jm-sw-arseny-test-1-master:~$ docker service ps lb_nginx_web
ID            NAME            IMAGE         NODE                      DESIRED STATE  CURRENT STATE          ERROR  PORTS
xgctl5unz6ce  lb_nginx_web.1  nginx:latest  jm-sw-arseny-test-2-node  Running        Running 2 seconds ago         
vv0eka00whg0  lb_nginx_web.2  nginx:latest  jm-sw-arseny-test-1-node  Running        Running 3 seconds ago

[/simterm]

Собственно, на этом всё.

P.S. Docker Swarm и авторизация в приватных репозиториях. Добавьте –with-registry-auth :

setevoy@jm-sw-arseny-test-1-master:~$ docker stack deploy -c docker-compose.yml jm-website --with-registry-auth 

Updating service jm-website_web_preview (id: ozkh2himygik03jj0e6xxgxnx)
Updating service jm-website_transform (id: f19hyqrsdw762rp2c901ls7g3)
Updating service jm-website_transform_preview (id: s0uuw1zhurhq2j3lcn4mc5boz)
Updating service jm-website_web (id: omkkmp3or5hfdd51np3sm7xw1)

Почитать по Swarm

Swarm mode key concepts

How nodes work

How services work

Administer and maintain a swarm of Docker Engines

Introduction to Docker Swarm Mode and Multi-Host Networking

По Compose

Compose file version 3 reference

Docker compose v3 example