Статьи

Docker Services, стек и распределенный пакет приложений

Первый релиз Кандидат в Docker 1.12 был объявлен более двух недель назад . В этом выпуске запланировано несколько новых функций.

В этом блоге будет показано, как создать пакет распределенных приложений из Docker Compose и развернуть его как стек Docker в режиме Docker Swarm. Большое спасибо @friism, чтобы помочь мне понять эти концепции.

Давайте сначала посмотрим на функции:

  • Встроенная оркестровка . Типичное приложение определяется с помощью файла Docker Compose. Это определение состоит из нескольких контейнеров и развернуто на нескольких хостах. Это позволяет избежать единой точки отказа (SPOF) и обеспечивает устойчивость вашего приложения. Множество структур оркестровки, таких как Docker Swarm, Kubernetes и Mesos, позволяют вам управлять этими приложениями. Однако это очень важная характеристика приложения, теперь в Docker Engine встроена оркестровка. Подробнее об этой теме в более позднем блоге.
  • Сервис : реплицированный, распределенный сервис с балансировкой нагрузки может быть легко создан с помощью команды docker service create . Предоставляется «желаемое состояние» приложения, такое как запуск 3 контейнеров Couchbase, а самовосстанавливающийся механизм Docker гарантирует, что в кластере работает много контейнеров. Если контейнер выходит из строя, запускается другой контейнер. Если узел выходит из строя, контейнеры на этом узле запускаются на другом узле. Подробнее об этом позже.
  • Безопасность с нулевой конфигурацией : Docker 1.12 поставляется с взаимно аутентифицированным TLS, обеспечивая аутентификацию, авторизацию и шифрование для связи каждого узла, участвующего в рое, из коробки. Подробнее об этом позже.
  • Стек Docker и пакет распределенных приложений. Пакет распределенных приложений, или DAB, представляет собой формат многоадресного распространяемого образа. Читайте дальше для более подробной информации.

Пока что вы можете взять Dockerfile и создать из него образ, используя команду docker build . Контейнер можно запустить с помощью команды docker run . Несколько контейнеров можно легко запустить, дав эту команду несколько раз. Или вы также можете использовать файл Docker Compose и масштабировать ваши контейнеры с помощью команды docker-compose scale .

докер-жизненный цикл

Изображение — это переносимый формат для одного контейнера. Распределенный пакет приложений , или DAB, — это новая концепция, представленная в Docker 1.12, представляющая собой переносимый формат для нескольких контейнеров. Каждый пакет может быть развернут как стек во время выполнения.

докер-стека жизненным циклом

Узнайте больше о DAB на docker.com/dab .

Для простоты можно привести аналогию:

Dockerfile -> Изображение -> Контейнер

Docker Compose -> Комплект распределенных приложений -> Стек Docker

Давайте используем файл Docker Compose, создадим из него DAB и развернем его как стек Docker.

Важно отметить, что это экспериментальная функция в 1.12-RC2.

Создать распределенный пакет приложений из Docker Compose

Docker Compose CLI добавляет новую команду bundle . Более подробную информацию можно найти:

01
02
03
04
05
06
07
08
09
10
11
docker-compose bundle --help
Generate a Docker bundle from the Compose file.
  
Local images will be pushed to a Docker registry, and remote images
will be pulled to fetch an image digest.
  
Usage: bundle [options]
  
Options:
    -o, --output PATH          Path to write the bundle file to.
                               Defaults to ".dsb".

Теперь давайте возьмем определение Docker Compose и создадим из него DAB. Вот наше определение Docker Compose:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
version: "2"
services:
  db:
    container_name: "db"
    image: arungupta/oreilly-couchbase:latest
    ports:
      - 8091:8091
      - 8092:8092
      - 8093:8093
      - 11210:11210
  web:
    image: arungupta/oreilly-wildfly:latest
    depends_on:
      - db
    environment:
      - COUCHBASE_URI=db
    ports:
      - 8080:8080

Этот Compose файл запускает WildFly и сервер Couchbase. Приложение Java EE предварительно развернуто на сервере WildFly, который подключается к серверу Couchbase и позволяет выполнять операции CRUD с использованием REST API.

Источник этого файла: github.com/arun-gupta/oreilly-docker-book/blob/master/hello-javaee/docker-compose.yml .

Создайте пакет приложений с ним:

1
2
3
4
docker-compose bundle
WARNING: Unsupported key 'depends_on' in services.web - ignoring
WARNING: Unsupported key 'container_name' in services.db - ignoring
Wrote bundle to hellojavaee.dsb

depends_on только создает зависимость между двумя сервисами и заставляет их запускаться в определенном порядке. Это только обеспечивает запуск контейнера Docker, но запуск приложения в контейнере может занять больше времени. Так что этот атрибут только частично решает проблему. container_name дает конкретное имя для контейнера. Опора на конкретное имя контейнера является жесткой связью и не позволяет масштабировать контейнер. Таким образом, оба предупреждения можно пока игнорировать.

Эта команда создает файл, используя имя проекта Compose, которое является именем каталога. В нашем случае hellojavaee.dsb файл hellojavaee.dsb . Это расширение файла было переименовано в .dab в RC3.

Сгенерированный пакет приложений выглядит так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
  "services": {
    "db": {
      "Image": "arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c",
      "Networks": [
        "default"
      ],
      "Ports": [
        {
          "Port": 8091,
          "Protocol": "tcp"
        },
        {
          "Port": 8092,
          "Protocol": "tcp"
        },
        {
          "Port": 8093,
          "Protocol": "tcp"
        },
        {
          "Port": 11210,
          "Protocol": "tcp"
        }
      ]
    },
    "web": {
      "Env": [
        "COUCHBASE_URI=db"
      ],
      "Image": "arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914",
      "Networks": [
        "default"
      ],
      "Ports": [
        {
          "Port": 8080,
          "Protocol": "tcp"
        }
      ]
    }
  },
  "version": "0.1"
}

Этот файл содержит полное описание услуг, включенных в приложение. Я не совсем уверен, является ли Distributed Application Bundle наиболее подходящим именем, обсудите это в # 24250 . Было бы здорово, если бы здесь могли поддерживаться другие форматы контейнеров, такие как Rkt или даже виртуальные машины. Но на данный момент Docker — единственный поддерживаемый формат.

Инициализировать Swarm Mode в Docker

Как упоминалось выше, «желаемое состояние» теперь поддерживается Docker Swarm. И это уже запечено в Docker Engine.

Концепции Docker Swarm также развивались и могут быть прочитаны в ключевых концепциях режима Swarm . Более подробный блог об этом будет позже.

Но для этого блога добавлена ​​новая команда docker swarm :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
docker swarm --help
  
Usage:    docker swarm COMMAND
  
Manage Docker Swarm
  
Options:
      --help   Print usage
  
Commands:
  init        Initialize a Swarm
  join        Join a Swarm as a node and/or manager
  update      Update the Swarm
  leave       Leave a Swarm
  inspect     Inspect the Swarm
  
Run 'docker swarm COMMAND --help' for more information on a command.

Инициализируйте узел Swarm (как рабочий) в Docker Engine:

1
2
docker swarm init
Swarm initialized: current node (ek9p1k8r8ox7iiua5c247skci) is now a manager.

Более подробную информацию об этом узле можно найти с помощью команды docker swarm inspect .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
docker swarm inspect
[
    {
        "ID": "1rcvu7m9mv2c8hiaijr7an9zk",
        "Version": {
            "Index": 1895
        },
        "CreatedAt": "2016-07-01T23:52:38.074748177Z",
        "UpdatedAt": "2016-07-02T04:54:32.79093117Z",
        "Spec": {
            "Name": "default",
            "AcceptancePolicy": {
                "Policies": [
                    {
                        "Role": "worker",
                        "Autoaccept": true
                    },
                    {
                        "Role": "manager",
                        "Autoaccept": false
                    }
                ]
            },
            "Orchestration": {
                "TaskHistoryRetentionLimit": 10
            },
            "Raft": {
                "SnapshotInterval": 10000,
                "LogEntriesForSlowFollowers": 500,
                "HeartbeatTick": 1,
                "ElectionTick": 3
            },
            "Dispatcher": {
                "HeartbeatPeriod": 5000000000
            },
            "CAConfig": {
                "NodeCertExpiry": 7776000000000000
            }
        }
    }
]

Вывод показывает, что узел является только работником, а не менеджером. Это может быть хорошо, если кластер имеет один узел. Но в многоузловом кластере должен быть хотя бы менеджер.

Развертывание стека докеров

Создайте стек с помощью команды docker deploy :

1
2
3
4
5
docker deploy -f hellojavaee.dsb hellojavaee
Loading bundle from hellojavaee.dsb
Creating network hellojavaee_default
Creating service hellojavaee_db
Creating service hellojavaee_web

Использование команды, безусловно, может быть упрощено, как описано в # 24249 .

Смотрите список услуг:

1
2
3
4
docker service ls
ID            NAME             REPLICAS  IMAGE                                                                                                COMMAND
2g8kmrimztes  hellojavaee_web  1/1       arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914   
46xhlb15cc60  hellojavaee_db   1/1       arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c

Вывод показывает, что запущены две службы, WildFly и Couchbase. Сервисы — это также новая концепция, представленная в Docker 1.12. Есть то, что дает вам «желаемое состояние», и Docker Engine работает, чтобы дать вам это.

docker ps показывает список запущенных контейнеров:

1
2
3
CONTAINER ID        IMAGE                                                                                                 COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
622756277f40        arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c   "/entrypoint.sh /opt/"   3 seconds ago       Up 1 seconds        8091-8093/tcp, 11207/tcp, 11210-11211/tcp, 18091-18092/tcp   hellojavaee_db.1.19enwdt6i5m853m5675tx3z29
abf8703ed713        arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914     "/opt/jboss/wildfly/b"   3 seconds ago       Up 1 seconds        8080/tcp                                                     hellojavaee_web.1.70piloz6j4zt06co8htzisgyl

Контейнер WildFly запускается до запуска и запуска контейнера Couchbase. Это означает, что приложение Java EE пытается подключиться к серверу Couchbase и терпит неудачу. Таким образом, приложение никогда не загружается успешно.

Докер Сервис

Docker Service поддерживает «желаемое состояние» приложения. В нашем случае желаемое состояние — убедиться, что запущен один и только один контейнер для службы. Если мы удалим контейнер, а не службу, то служба автоматически запустит контейнер снова.

Удалить контейнер как:

1
docker rm -f abf8703ed713

Обратите внимание, вы должны -f поскольку контейнер уже запущен. Механизмы самовосстановления Docker 1.12 включаются и автоматически перезапускают контейнер. Теперь, если вы снова перечислите контейнеры

1
2
3
CONTAINER ID        IMAGE                                                                                                 COMMAND                  CREATED             STATUS                  PORTS                                                        NAMES
db483ac27e41        arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914     "/opt/jboss/wildfly/b"   1 seconds ago       Up Less than a second   8080/tcp                                                     hellojavaee_web.1.ddvwdmojjysf46d4n3x4g8uv4
622756277f40        arungupta/oreilly-couchbase@sha256:f150fcb9fca5392075c96f1baffc7f893858ba763f3c05cf0908ef2613cbf34c   "/entrypoint.sh /opt/"   26 seconds ago      Up 25 seconds           8091-8093/tcp, 11207/tcp, 11210-11211/tcp, 18091-18092/tcp   hellojavaee_db.1.19enwdt6i5m853m5675tx3z29

Это показывает, что новый контейнер был запущен.

Проверьте сервис WildFly:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
docker service inspect hellojavaee_web
[
    {
        "ID": "54otfi6dc9bis7z6gc6ubynwc",
        "Version": {
            "Index": 328
        },
        "CreatedAt": "2016-07-02T01:36:35.735767569Z",
        "UpdatedAt": "2016-07-02T01:36:35.739240775Z",
        "Spec": {
            "Name": "hellojavaee_web",
            "Labels": {
                "com.docker.stack.namespace": "hellojavaee"
            },
            "TaskTemplate": {
                "ContainerSpec": {
                    "Image": "arungupta/oreilly-wildfly@sha256:d567ade7bb82ba8f15a85df0c6d692d85c15ec5a78d8826dfba92756babcb914",
                    "Env": [
                        "COUCHBASE_URI=db"
                    ]
                }
            },
            "Mode": {
                "Replicated": {
                    "Replicas": 1
                }
            },
            "Networks": [
                {
                    "Target": "epw57lz7txtfchmbf6u0cimis",
                    "Aliases": [
                        "web"
                    ]
                }
            ],
            "EndpointSpec": {
                "Mode": "vip",
                "Ports": [
                    {
                        "Protocol": "tcp",
                        "TargetPort": 8080
                    }
                ]
            }
        },
        "Endpoint": {
            "Spec": {},
            "Ports": [
                {
                    "Protocol": "tcp",
                    "TargetPort": 8080,
                    "PublishedPort": 30004
                }
            ],
            "VirtualIPs": [
                {
                    "NetworkID": "9lpz688ir3pzexubkcb828ikg",
                    "Addr": "10.255.0.5/16"
                },
                {
                    "NetworkID": "epw57lz7txtfchmbf6u0cimis",
                    "Addr": "10.0.0.4/24"
                }
            ]
        }
    }
]

Swarm назначает случайный порт службе или может быть обновлен вручную с помощью команды docker service update . В нашем случае порт 8080 контейнера сопоставлен с портом 30004 на хосте.

Проверьте приложение

Убедитесь, что приложение успешно развернуто:

1
2
curl http://localhost:30004/books/resources/book
[{"books":0}]

Добавить новую книгу в приложение:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
curl -v \
&qt; -H "Content-Type: application/json" \
&qt; -X POST -d '{
&qt;   "isbn": "978-1-4919-1889-0",
&qt;   "name": "Minecraft Modding with Forge",
&qt;   "cost": 29.99
&qt; }' \
&qt; http://localhost:30004/books/resources/book
*   Trying ::1...
* Connected to localhost (::1) port 30004 (#0)
&qt; POST /books/resources/book HTTP/1.1
&qt; Host: localhost:30004
&qt; User-Agent: curl/7.43.0
&qt; Accept: */*
&qt; Content-Type: application/json
&qt; Content-Length: 92
&qt;
* upload completely sent off: 92 out of 92 bytes
<HTTP/1.1 200 OK
<Connection: keep-alive
<X-Powered-By: Undertow/1
<Server: WildFly/10
<Content-Type: application/octet-stream
<Content-Length: 88
<Date: Sat, 02 Jul 2016 01:39:49 GMT
<
* Connection #0 to host localhost left intact

Проверьте книги еще раз:

1
2
curl http://localhost:30004/books/resources/book
[{"books":{"name":"Minecraft Modding with Forge","cost":29.99,"id":"1","isbn":"978-1-4919-1889-0"}}, {"books":1}]

Узнайте больше об этом приложении Java EE на github.com/arun-gupta/oreilly-docker-book/tree/master/hello-javaee .

В этом блоге показано, как создать пакет распределенных приложений из Docker Compose и развернуть его как стек Docker в режиме Docker Swarm.