Статьи

Docker для разработчиков Java: развертывание на Docker

Эта статья является частью нашего курса Академии под названием Docker Tutorial для разработчиков Java .

В этом курсе мы предлагаем серию руководств, чтобы вы могли разрабатывать свои собственные приложения на основе Docker. Мы охватываем широкий спектр тем, от Docker через командную строку, до разработки, тестирования, развертывания и непрерывной интеграции. С нашими простыми учебными пособиями вы сможете запустить и запустить собственные проекты за минимальное время. Проверьте это здесь !

1. Введение

Многие компании использовали виртуализацию на основе контейнеров для развертывания приложений (в том числе на основе JVM) в производственном режиме до появления Docker на горизонте. Однако, в первую очередь из-за Docker , практика развертывания с использованием контейнеров в наши дни стала основной.

В этом разделе руководства мы рассмотрим некоторые из наиболее популярных механизмов оркестровки и управления кластерами (включая несколько облачных предложений), которые изначально поддерживают развертывание и жизненный цикл контейнерных приложений.

Темы, о которых мы поговорим, стоят нескольких книг (по крайней мере!), Поэтому цель этой части — служить введением. Если вы испытываете особый интерес к любому из них, в открытом доступе есть огромное количество ресурсов.

2. Контейнеры как единицы развертывания

В наши дни контейнеры (в частности, контейнеры Docker ) стали стандартизированными единицами развертывания программного обеспечения. Они упакованы со всем, что может понадобиться приложениям: кодом (или двоичным кодом), средой выполнения, системными инструментами и библиотеками, как вы это называете.

Управление и организация развертываний на основе контейнеров — довольно актуальная тема, и, как мы увидим через мгновение, каждое имеющееся решение предлагает ее с самого начала.

3. Оркестровка с использованием Kubernetes

В редких случаях вы еще не слышали об этом, Kubernetes — это система с открытым исходным кодом для автоматизации развертывания, масштабирования и управления контейнерными приложениями. Это один из самых интересных, инновационных и активно развивающихся проектов в сообществе открытого кода. Возможно, если вы или ваша компания ищете решение для контейнерной оркестровки, Kubernetes является де-факто выбором в наши дни.

Kubernetes может сделать для вас много вещей, но в этой части руководства мы увидим, как легко развернуть наш контейнер приложений Spring Boot , включая MySQL , с использованием лишь минимального подмножества функций Kubernetes .

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

Предполагая, что вы установили minikube в выбранной вами операционной системе, давайте перейдем к следующему шагу и развернем на нем пару контейнеров Docker .

1
$ minikube start

Когда Minikube запущен, мы можем сразу же начать развертывание MySQL , придерживаясь той же версии 8.0.2 которую мы использовали в этом руководстве.

1
$ kubectl run mysql --image=mysql:8.0.2 --env='MYSQL_ROOT_PASSWORD=p$ssw0rd' --env='MYSQL_DATABASE=my_app_db' --env='MYSQL_ROOT_HOST=%' --port=3306

Это займет некоторое время, и в конце вы сможете увидеть, что MySQL контейнер (или, точнее, Kubernetes pod) запущен и работает:

1
2
3
$ kubectl get pod
NAME                       READY     STATUS    RESTARTS   AGE
mysql-5d4dbfcd58-6fmck     1/1       Running   0          22m

Отлично, теперь нам нужно перестроить образ Docker нашего приложения Spring Boot, которое мы разработали ранее , используя настройки Docker развернутого кластера Kubernetes (в качестве альтернативы, мы могли бы использовать частный реестр).

1
2
3
4
5
6
$ eval $(minikube docker-env)
$ docker image build \
  --build-arg BUILD_VERSION=0.0.1-SNAPSHOT \
  -f Dockerfile.build \
  -t jcg/spring-boot-webapp:latest \
  -t jcg/spring-boot-webapp:0.0.1-SNAPSHOT .

По завершении этого шага у нас есть образ Docker, доступный для развертывания в Kubernetes, и мы можем запустить его как еще один модуль.

1
$ kubectl run spring-boot-webapp --image=jcg/spring-boot-webapp:latest --env='DB_HOST=mysql.default.svc.cluster.local' --port=19900 --image-pull-policy=Never

Давайте проверим, что у нас есть два модуля:

1
2
3
4
$ kubectl get pod
NAME                                  READY     STATUS    RESTARTS   AGE
mysql-5d4dbfcd58-6fmck                1/1       Running   0          33m
spring-boot-webapp-5ff8456bf5-gf5qv   1/1       Running   0          31m

И последнее, но не менее важное: мы должны представить развертывание нашего приложения Spring Boot как сервис Kubernetes, чтобы сделать его доступным:

1
$ kubectl expose deployment spring-boot-webapp --type=NodePort

И быстро проверьте, что это перечислено среди других услуг:

1
2
3
4
$ kubectl.exe get service
NAME               TYPE      CLUSTER-IP          EXTERNAL-IP PORT(S     AGE
kubernetes         ClusterIP 10.96.0.1           443/TCP                4d
spring-boot-webapp NodePort  10.109.108.87       19900:30253/TCP        40s

И это в основном то, что за несколько простых шагов мы запустили и запустили наши контейнеры Docker , которыми все управляет Kubernetes . Давайте удостоверимся, что приложение фактически проходит все проверки работоспособности:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
$ curl $(minikube service spring-boot-webapp --url)/application/health
{
    "status":"UP",
    "details": {
        "diskSpace": {
            "status":"UP",
            "details": {
                "total":17293533184,
                "free":14476333056,
                "threshold":10485760
            }
        },
        "db": {
            "status":"UP",
            "details": {
                "database":"MySQL",
                "hello":1
            }
        }
    }
}

И это действительно так! Чтобы завершить нашу дискуссию о Kubernetes , стоит упомянуть, что Docker уже включает раннюю встроенную интеграцию с Kubernetes на некоторых пограничных каналах .

4. Оркестровка с использованием Apache Mesos

Apache Mesos , возможно, является одной из самых старых используемых сред управления ресурсами и кластерами. Он эффективно отводит ресурсы (ЦП, память, хранилище) от физического или виртуального оборудования, позволяя создавать и эксплуатировать отказоустойчивые и эластичные распределенные системы. Одна из его сильных сторон — исключительный уровень расширяемости и поддержки развертываний приложений в контейнерах, однако он также известен как довольно сложный и сложный в эксплуатации.

Архитектурно Apache Mesos состоит из master который управляет agents (работает на каждом узле кластера), и frameworks (которые выполняют tasks на этих агентах). Мастер позволяет детально распределять ресурсы (ЦП, ОЗУ и т. Д.) В разных средах, resource offers им resource offers . Ограничив себя только необходимыми компонентами, давайте посмотрим, как кластер Apache Mesos можно определить с помощью спецификации docker-compose .

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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
version: "3"
 
services:
  zookeeper:
    image: zookeeper
    networks:
      - mesos-network
    environment:
      ZOO_TICK_TIME: 2000
      ZOO_INIT_LIMIT: 10
      ZOO_SYNC_LIMIT: 5
      ZOO_MAX_CLIENT_CNXNS: 128
      ZOO_PORT: 2181
      ZOO_MY_ID: 1
 
  mesos-master:
    image: mesosphere/mesos-master:1.3.2
    networks:
      - mesos-network
    ports:
      - "5050:5050"
    environment:
      MESOS_ZK: zk://zookeeper:2181/mesos
      MESOS_QUORUM: 1
      MESOS_CLUSTER: docker-compose
      MESOS_REGISTRY: replicated_log
    volumes:
      - /var/run/docker.sock:/run/docker.sock
    depends_on:
      - zookeeper
 
  mesos-slave:
    image: mesosphere/mesos-slave:1.3.2
    privileged: true
    networks:
      - mesos-network
    ports:
      - "5051:5051"
    links:
      - zookeeper
      - mesos-master
    environment:
      - MESOS_CONTAINERIZERS=docker
      - MESOS_ISOLATOR=cgroups/cpu, cgroups/mem
      - MESOS_LOG_DIR=var/log
      - MESOS_MASTER=zk://zookeeper:2181/mesos
      - MESOS_PORT=5051
      - MESOS_EXECUTOR_REGISTRATION_TIMEOUT=5mins
      - MESOS_EXECUTOR_SHUTDOWN_GRACE_PERIOD=90secs
      - MESOS_DOCKER_STOP_TIMEOUT=90secs
      - MESOS_RESOURCES=cpus:2;mem:2080;disk:5600;ports(*):[19000-19999]
      - MESOS_WORK_DIR=/var/lib/mesos
      - MESOS_SYSTEMD_ENABLE_SUPPORT=false
    volumes:
      - /var/run/docker.sock:/run/docker.sock
    dns:
      - mesos-dns
    depends_on:
      - mesos-master
      - mesos-dns
 
  marathon:
    image: mesosphere/marathon:v1.5.6
    networks:
      - mesos-network
    environment:
      - MARATHON_ZK=zk://zookeeper:2181/marathon
      - MARATHON_MASTER=zk://zookeeper:2181/mesos
    ports:
      - "8080:8080"
    depends_on:
      - mesos-master
 
  mesos-dns:
    image: mesosphere/mesos-dns:v0.6.0
    command: [ "/usr/bin/mesos-dns", "-v=2", "-config=/config.json" ]
    ports:
      - 53:53/udp
      - 8123:8123
    volumes:
      - ./config.json:/config.json
      - /tmp
    links:
      - zookeeper
    dns:
      - 8.8.8.8
      - 8.8.4.4
    networks:
      - mesos-network
 
networks:
    mesos-network:
       driver: bridge

Как мы видим, там довольно много движущихся частей, кроме Apache MesosApache Zookeeper ). В основе этого лежит платформа Marathon , платформа оркестровки контейнеров. Marathon предоставляет прекрасный веб-интерфейс, а также REST (ful) API для управления развертыванием приложений и использует собственный формат спецификаций на основе JSON . Следуя нашему стеку приложений Spring Boot , давайте рассмотрим пример дескриптора развертывания MySQL (который хранится в файле mysql.json ):

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
{
  "id": "/jcg/mysql",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "mysql:8.0.2",
      "network": "BRIDGE",
      "portMappings": [
        {
          "containerPort": 3306,
          "servicePort": 3306,
          "hostPort": 0,
          "protocol": "tcp"
        }
      ],
      "parameters": [
        {
          "key": "hostname",
          "value": "mysql"
        }
      ]
    }
  },
  "env": {
    "MYSQL_ROOT_PASSWORD": "p$ssw0rd",
    "MYSQL_DATABASE": "my_app_db",
    "MYSQL_ROOT_HOST": "%"
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 500,
  "healthChecks": [
    {
      "protocol": "COMMAND",
      "command": { "value": "ss -ltn src :3306 | grep 3306" },
      "gracePeriodSeconds": 10,
      "intervalSeconds": 10,
      "timeoutSeconds": 5,
      "maxConsecutiveFailures": 2
    }
  ]
}

Теперь, чтобы запустить MySQL- контейнер, нам просто нужно отправить этот дескриптор в Marathon , используя его REST (ful) API (при условии, что наш Apache Mesos запущен и работает), например:

1
2
3
4
5
6
7
8
9
$ curl -X POST http://localhost:8080/v2/apps -d @mysql.json -H "Content-type: application/json"
 
{
  "id":"/jcg/mysql",
  "container":{
     
  },
  
}

Выглядит хорошо, давайте сделаем то же самое для приложения Spring Boot , начиная с дескриптора развертывания Marathon и spring-webapp.json файле spring-webapp.json .

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
{
  "id": "/jcg/spring-webapp",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "jcg/spring-boot-webapp:latest",
      "network": "BRIDGE",
      "portMappings": [
        {
          "containerPort": 19900,
          "servicePort": 19900,
          "hostPort": 19900
        }
      ],
      "parameters": [
        { "key": "hostname", "value": "spring-webapp" }
      ]
    }
  },
  "env": {
    "DB_HOST": "172.17.0.2"
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 512,
  "healthChecks": [
    {
      "protocol": "COMMAND",
      "command": { "value": "nc -z localhost 19900" },
      "gracePeriodSeconds": 25,
      "intervalSeconds": 10,
      "timeoutSeconds": 5,
      "maxConsecutiveFailures": 3
    }
  ]
}

Следующим шагом будет отправить его на Марафон :

1
2
3
4
5
6
7
8
9
$ curl -X POST http://localhost:8080/v2/apps -d @spring-webapp.json -H "Content-type: application/json"
 
{
  "id":"/jcg/spring-webapp",
  "container":{
     
  },
  
}

И мы эффективно сделали! Как только развертывание будет завершено, мы сможем увидеть наш стек приложений в рабочем состоянии, используя, например, веб-интерфейс Marathon , доступный по адресу http: // localjost: 8080 / ui / .

Приложения марафона

Любопытный читатель может задаться вопросом, как мы связали эти два приложения Marathon , Spring Boot и MySQL , вместе. В этом конкретном случае мы использовали возможности Apache Mesos для обнаружения служб и распределения нагрузки, выполняемые Mesos-DNS . Чтобы проиллюстрировать их в действии, мы можем запросить IP-адрес экземпляра MySQL по его имени mysql-jcg.marathon.mesos .

1
2
3
4
5
6
7
$ curl http://localhost:8123/v1/hosts/mysql-jcg.marathon.mesos
[
  {
   "host": "mysql-jcg.marathon.mesos.",
   "ip": "172.17.0.2"
  }
]

Как обычно, давайте подтвердим, что приложение Spring Boot запущено и работает, отправив HTTP-запрос на конечную точку работоспособности:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
$ curl http://localhost:19900/application/health
 
{
    "details": {
        "db": {
            "details": {
                "database": "MySQL",
                "hello": 1
            },
            "status": "UP"
        },
        "diskSpace": {
            "details": {
                "free": 44011802624,
                "threshold": 10485760,
                "total": 49536962560
            },
            "status": "UP"
        }
    },
    "status": "UP"
}

5. Оркестровка с использованием Docker Swarm

Прошло некоторое время с тех пор, как Docker имеет встроенные в движок функции управления кластером и его оркестровки. Этот оркестровочный слой раньше назывался Docker Swarm, но позже превратился, по сути, в специальный режим ( режим роя ) для запуска Docker Engine .

Если вы делаете большие ставки на Docker и предпочитаете не искать ничего другого, запуск Docker Engine в режиме роя может быть хорошим вариантом для оркестра. С ним довольно легко начать.

1
$ docker swarm init

Концептуально, существует довольно много различий, которые вводит режим роя, помимо просто изменений в самом Docker Engine . Прежде всего, вы должны начать думать с точки зрения услуг, а не контейнеров. Предположения о том, что все выполняется внутри одного хоста Docker, больше не будут точными, поскольку рой очень хотел бы состоять из множества хостов Docker, распределенных по сети.

При запуске Docker Engine в режиме роя мы можем развернуть полный стек приложений (сервисов), используя уже знакомую спецификацию docker-compose . Однако существует только одно ограничение: формат файла docker-compose должен быть версии 3 (or above) чтобы быть совместимым между Docker Compose и режимом роя Docker Engine .

Чтобы увидеть режим роя в действии, давайте немного переделаем наш стек приложений Spring Boot в соответствии с форматом файла docker-compose версии 3.3 .

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
version: '3.3'
 
services:
  mysql:
    image: mysql:8.0.2
    environment:
      - MYSQL_ROOT_PASSWORD=p$$ssw0rd
      - MYSQL_DATABASE=my_app_db
      - MYSQL_ROOT_HOST=%
    healthcheck:
      test: ["CMD-SHELL", "ss -ltn src :3306 | grep 3306"]
      interval: 10s
      timeout: 5s
      retries: 3
    networks:
      - my-app-network
 
  java-app:
    image: jcg/spring-boot-webapp:latest
    environment:
      - DB_HOST=mysql
    ports:
      - 19900:19900
    depends_on:
      - mysql
    healthcheck:
      test: ["CMD-SHELL", "nc -z localhost 19900"]
      interval: 10s
      timeout: 5s
      retries: 3
    networks:
      - my-app-network
 
networks:
    my-app-network:
       driver: overlay

Честно говоря, нам не нужно было делать много изменений. Специально для поддержки режима роя существует специальное семейство команд, которое было введено в инструментальные средства docker stack : docker stack . Мы не говорили о них во второй части этого урока , но сейчас самое время это сделать.

С помощью команды deploy и спецификации docker-compose мы могли бы инициировать развертывание стека приложений в кластере swarm.

1
$ docker stack deploy --compose-file docker-compose.yml springboot-webapp

Чтобы увидеть состояние развертываний, а также всех развернутых сервисов, мы могли бы использовать команду services , как в примере ниже (вывод был немного сокращен):

1
2
3
4
$ docker stack services  springboot-webapp
NAME                        IMAGE                         REPLICAS PORTS
springboot-webapp_java-app  jcg/spring-boot-webapp:latest 1/1      *:19900->19900/tcp
springboot-webapp_mysql     mysql:8.0.2                   1/1  

Круто, похоже, что наше приложение Spring Boot запущено и работает, давайте подтвердим это, отправив HTTP-запрос на конечную точку работоспособности:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
$ curl http://localhost:19900/application/health
 
{
    "details": {
        "db": {
            "details": {
                "database": "MySQL",
                "hello": 1
            },
            "status": "UP"
        },
        "diskSpace": {
            "details": {
                "free": 3606978560,
                "threshold": 10485760,
                "total": 19195224064
            },
            "status": "UP"
        }
    },
    "status": "UP"
}

Это выглядит именно то, что мы ожидали. В заключение следует отметить, что Docker Engine в режиме роя представляет интересный вариант, но стоит отметить, что он не так популярен, как Kubernetes или Apache Mesos .

6. Контейнеры в облаке

Каждый крупный игрок в облачном пространстве спешит на рынок со своими собственными управляемыми предложениями, которые намереваются поддержать развертывание и оркестровку контейнеров, чтобы вы могли просто уронить один из них и волшебство случилось. Давайте быстро взглянем на них.

6.1. Amazon Эластичный Контейнерный Сервис

Amazon Elastic Container Service (или просто Amazon ECS ) — это масштабируемая, быстрая служба управления контейнерами, которая позволяет легко запускать, останавливать и управлять контейнерами Docker в кластере. Как вы можете ожидать, Amazon ECS прекрасно интегрируется со многими другими облачными предложениями из портфолио Amazon Web Services , включая:

  • Управление идентификацией и доступом AWS
  • Amazon EC2 с автоматическим масштабированием
  • Упругая балансировка нагрузки
  • Amazon Elastic Container Registry
  • AWS CloudFormation

Amazon ECS — это региональная служба, которая упрощает запуск контейнеров приложений с высокой степенью доступности в нескольких зонах доступности в регионе.

6.2. Google Kubernetes Engine

Google Kubernetes Engine (ранее известный как Google Container Engine) — это управляемая среда для развертывания контейнерных приложений. Он привносит уникальный опыт Google и последние инновации в продуктивности разработчиков, эффективности использования ресурсов, автоматизированных операциях и гибкости открытого исходного кода для ускорения выхода на рынок.

Google очень долго выполнял производственные рабочие нагрузки в контейнерах и включил лучшее из того, что они узнали, в Kubernetes , ведущего в отрасли оркестратора контейнеров с открытым исходным кодом, который работает с Kubernetes Engine . Он предлагает (но не ограничивается) следующие отличительные особенности:

  • Управление идентификацией и доступом
  • Гибридная сеть
  • Безопасность и соответствие
  • Интегрированная регистрация и мониторинг
  • Авто Масштаб
  • Автообновление
  • Авто Ремонт
  • Пределы ресурса
  • Поддержка приложений с отслеживанием состояния
  • Поддержка изображений Docker
  • Полностью управляемый
  • ОС, созданная для контейнеров
  • Реестр частных контейнеров
  • Быстрая согласованная сборка
  • Портативность открытого исходного кода

6.3. Служба контейнеров Azure

Служба контейнеров Azure (AKS) управляет размещенной средой Kubernetes , обеспечивая быстрое и простое развертывание и управление контейнеризованными приложениями без опыта управления контейнерами. Он также устраняет бремя текущих операций и обслуживания за счет предоставления, обновления и масштабирования ресурсов по требованию без необходимости переводить приложения в автономный режим.

Как управляемая служба Kubernetes , контейнерная служба Azure предоставляет:

  • Автоматизированные обновления и исправления версии Kubernetes
  • Простое масштабирование кластера
  • Самовосстанавливающееся управление самолетом (мастера)
  • Платите только за работающие узлы пула агентов

7. Выводы

В этом разделе руководства мы рассмотрели ряд ведущих решений для управления кластерами и их оркестровки, которые предлагают всестороннюю поддержку развертывания приложений в контейнерах. В целом, Kubernetes играет ведущую роль, однако у каждого варианта есть свои плюсы и минусы.

8. Что дальше

В следующей, заключительной части урока мы поговорим об очень важном предмете практики непрерывной интеграции и о том, как Docker вписывается в картину.

Полный набор файлов конфигурации и спецификации доступен для скачивания .