Серия вебинаров: создание контейнерных приложений

Вступление

В последнем руководстве, How для установки и настройки Docker, мы исследовали один метод преобразования https: // www .digitalocean.com / community / tutorials / how-to-install-and-configure-docker # step-2-% E2% 80% 94-launching-Containers [Контейнеры Docker] в https://www.digitalocean.com/ community / tutorials / how-to-install-and-configure-docker # step-4-% E2% 80% 94-building-images [изображения Docker]. Хотя метод, который мы использовали, работал, он не всегда является оптимальным способом построения изображений.

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

Https://docs.docker.com/engine/reference/builder/[Dockerfile] отвечает этим требованиям, предоставляя декларативный и последовательный способ построения образов Docker.

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

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

В этом руководстве вы будете использовать пример веб-приложения на основе Node.js и MongoDB для создания образа Docker из файла Docker. создаст пользовательскую сеть, которая позволит вашим контейнерам Docker взаимодействовать, и вы будете использовать Docker Compose для запуска и масштабирования приложения в контейнере.

Предпосылки

Чтобы следовать этому уроку, вам понадобится:

Шаг 1 - Создание образа с помощью Dockerfile

Начните с перехода в свой домашний каталог, а затем используйте Git, чтобы клонировать образец веб-приложения этого руководства из его official репозитория. на GitHub.

cd ~
git clone https://github.com/janakiramm/todo-app.git

Это скопирует пример приложения в новый каталог с именем + todo-app +.

Переключитесь на + todo-app + и используйте + ls + для просмотра содержимого каталога.

cd todo-app
ls

Новый каталог содержит две подкаталоги и два файла:

  • + app + - каталог, в котором хранится исходный код примера приложения

  • + compose + - каталог, в котором хранится файл конфигурации Docker Compose

  • + Dockerfile + - файл, содержащий инструкции для построения образа Docker

  • + README.md + - файл, содержащий резюме из одного предложения примера приложения

Запуск + cat Dockerfile + показывает нам следующее:

~ / TODO-приложение / Dockerfile

FROM node:slim
LABEL maintainer = "[email protected]"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY ./app/ ./
RUN npm install
CMD ["node", "app.js"]

Давайте посмотрим на содержимое этого файла более подробно:

  • + FROM + указывает базовое изображение, из которого вы строите пользовательское изображение. В этом примере изображение основано на + node: slim +, public Node.js image, который содержит только минимальные пакеты, необходимые для запуска `+ node + `.

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

  • + RUN + выполняет команды внутри контейнера. Это включает в себя такие задачи, как создание каталогов и инициализация контейнера с помощью основных команд Linux. Первая команда + RUN + в этом файле используется для создания каталога + / usr / src / app +, который содержит исходный код.

  • + WORKDIR + определяет каталог, в котором выполняются все команды. Обычно это каталог, в который копируется код.

  • + COPY + копирует файлы с хост-машины в образ контейнера. В этом случае вы копируете весь каталог + app + в образ.

  • Вторая команда + RUN + выполняет + npm install +, чтобы установить зависимости приложения, как определено в + package.json +.

  • + CMD + запускает процесс, который будет поддерживать работу контейнера. В этом примере вы выполните + node + с параметром + app.js +.

Теперь пришло время создать образ из + Dockerfile. Используйте переключатель + -t +, чтобы пометить изображение именем пользователя в реестре, именем изображения и необязательным тегом.

docker build -t /todo-web .

Вывод подтверждает, что изображение + успешно построено + и помечено соответствующим образом.

Output from docker build -tSending build context to Docker daemon  8.238MB
Step 1/7 : FROM node:slim
---> 286b1e0e7d3f
Step 2/7 : LABEL maintainer = "[email protected]"
---> Using cache
---> ab0e049cf6f8
Step 3/7 : RUN mkdir -p /usr/src/app
---> Using cache
---> 897176832f4d
Step 4/7 : WORKDIR /usr/src/app
---> Using cache
---> 3670f0147bed
Step 5/7 : COPY ./app/ ./
---> Using cache
---> e28c7c1be1a0
Step 6/7 : RUN npm install
---> Using cache
---> 7ce5b1d0aa65
Step 7/7 : CMD node app.js
---> Using cache
---> 2cef2238de24
2cef2238de24
/todo-web:latest

Мы можем проверить, что образ создан, запустив команду + docker images +.

docker images

Здесь мы можем увидеть размер изображения вместе с временем, прошедшим с момента его создания.

Output from docker imagesREPOSITORY                                       TAG                 IMAGE ID            CREATED             SIZE
/todo-web                                   latest              81f5f605d1ca        9 minutes ago       236MB

Поскольку нам также нужен контейнер MongoDB для запуска примера веб-приложения, давайте перенесем его на нашу машину.

docker pull mongo:latest

Вывод сообщает точно, какое изображение было извлечено вместе со статусом загрузки.

Output from docker pulllatest: Pulling from library/mongo
Digest: sha256:18b239b996e0d10f4ce2b0f64db6f410c17ad337e2cecb6210a3dcf2f732ed82
Status: Downloaded newer image for mongo:latest

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

Шаг 2 - Создание сети для связи контейнеров

Если бы мы запускали контейнеры веб-приложения и базы данных независимо через команду + docker run +, они не смогли бы найти друг друга.

Чтобы понять почему, просмотрите содержимое файла конфигурации базы данных веб-приложения.

cat app/db.js

После импорта Mongoose - библиотеки объектного моделирования MongoDB для Node.js - и определения нового https://www.digitalocean.com/community/tutorials/understanding-sql-and-nosql -databases-and-different-database-models [схема базы данных], веб-приложение пытается подключиться к базе данных по имени хоста + db +, которого еще нет.

~ / TODO-приложение / приложение / db.js

var mongoose = require( 'mongoose' );
var Schema   = mongoose.Schema;

var Todo = new Schema({
   user_id    : String,
   content    : String,
   updated_at : Date
});

mongoose.model( 'Todo', Todo );

mongoose.connect( 'mongodb:///express-todo' );

Чтобы контейнеры, принадлежащие одному и тому же приложению, обнаруживали друг друга, нам нужно запустить их в одной сети.

Docker предоставляет возможность создавать собственные сети в дополнение к default сетей, созданных во время установки.

Вы можете проверить свои доступные в настоящее время сети с помощью следующей команды:

docker network ls

Каждая сеть, созданная Docker, основана на driver. В следующем выводе мы видим, что сеть с именем + bridge + основана на драйвере + bridge +. Область + local + `указывает, что сеть доступна только на этом хосте.

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
5029df19d0cf
367330960d5c        host                host                local
f280c1593b89        none                null                local

Теперь мы создадим пользовательскую сеть с именем + todo_net + для нашего приложения, а затем запустим контейнеры в этой сети.

docker network create todo_net

Вывод сообщает нам хэш сети, которая была создана.

Output from docker network createC09f199809ccb9928dd9a93408612bb99ae08bb5a65833fefd6db2181bfe17ac

Теперь снова перечислите доступные сети.

docker network ls

Здесь мы видим, что + todo_net + готов к использованию.

Output from docker network lsNETWORK ID          NAME                DRIVER              SCOPE
c51377a045ff        bridge              bridge              local
2e4106b07544        host                host                local
7a8b4801a712        none                null                local

Используя команду + docker run +, мы теперь можем обращаться к этой сети с помощью переключателя + - network +. Давайте запустим веб-контейнеры и контейнеры базы данных с конкретными именами хостов. Это гарантирует, что контейнеры могут соединяться друг с другом через эти имена хостов.

Сначала запустите контейнер базы данных MongoDB.

docker run -d \
--name=db \
--hostname=db \
--network=todo_net \
mongo

При более внимательном рассмотрении этой команды мы видим:

  • Переключатель + -d + запускает контейнер в режиме detached.

  • Переключатели + - name + и + - hostname + назначают контейнеру определенное пользователем имя. Переключатель + - hostname + также добавляет запись в службу DNS, управляемую Docker. Это помогает в разрешении контейнера по имени хоста.

  • Переключатель + - network + указывает Docker Engine запускать контейнер в пользовательской сети вместо мостовой сети по умолчанию.

Когда мы видим длинную строку в качестве результата команды + docker run +, мы можем предположить, что контейнер успешно запущен. Но это не может гарантировать, что контейнер действительно работает.

Output docker runaa56250f2421c5112cf8e383b68faefea91cd4b6da846cbc56cf3a0f04ff4295

Убедитесь, что контейнер + db + запущен и работает с командой + docker logs +.

docker logs db

Это печатает журналы контейнера в + stdout. Последняя строка журнала указывает, что MongoDB готов и + ожидает подключения +.

Output from docker logs2017-12-10T02:55:08.284+0000 I CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=db
. . . .
2017-12-10T02:55:08.366+0000 I NETWORK  [initandlisten]  on port 27017

Теперь давайте запустим веб-контейнер и проверим его. На этот раз мы также включаем + - publish = 3000: 3000 +, который публикует порт хоста + 3000 + в порт контейнера + 3000+.

docker run -d \
--name=web \
--publish=3000:3000 \
--hostname=web \
--network=todo_net \
/todo-web

Вы получите длинную строку в качестве вывода, как и раньше.

Давайте также проверим, что этот контейнер запущен и работает.

docker logs web

Вывод подтверждает, что Express - инфраструктура Node.js, на которой основано наше тестовое приложение, - "+ прослушивает порт 3000+".

Output from docker logsExpress server listening on port 3000

Убедитесь, что веб-контейнер может общаться с контейнером db с помощью команды + ping +. Мы делаем это, выполняя команду + docker exec + в интерактивном (+ -i +) режиме, подключенном к псевдо-TTY (+ -t +).

docker exec -it web ping db

Команда производит стандартный вывод + ping + и сообщает нам, что два контейнера могут связываться друг с другом.

Output from docker exec -it web ping dbPING db (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: icmp_seq=0 ttl=64 time=0.210 ms
64 bytes from 172.18.0.2: icmp_seq=1 ttl=64 time=0.095 ms
...

Нажмите + CTRL + C +, чтобы остановить команду + ping +.

Наконец, откройте пример приложения, указав в веб-браузере + http: // your_server_ip: 3000 +. Вы увидите веб-страницу с меткой, которая гласит * Пример контейнера *, а также текстовое поле, которое принимает задачу todo в качестве входных данных.

Чтобы избежать конфликтов имен, вы можете теперь остановить контейнеры и очистить ресурсы с помощью команд + docker rm + и + docker network remove +.

docker rm -f db
docker rm -f web
docker network remove todo_net

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

Шаг 3 - Развертывание мультиконтейнерного приложения

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

Docker Compose - это платформа, доступная разработчикам для работы с мультиконтейнерными приложениями. Как и Dockefile, это декларативный механизм для определения всего стека. Теперь мы преобразуем наше приложение Node.js и MongoDB в приложение на основе Docker Compose.

Начните с установки Docker Compose.

sudo apt-get install -y docker-compose

Давайте рассмотрим файл + docker-compose.yaml +, расположенный в каталоге + compose + примера веб-приложения.

cat compose/docker-compose.yaml

Файл + docker-compose.yaml + объединяет все. Он определяет контейнер MongoDB в блоке + db: +, веб-контейнер Node.js в блоке + web: + и пользовательскую сеть в блоке + networks: +.

Обратите внимание, что с помощью директивы + build: ../.+ мы указываем Compose на + Dockerfile + в каталоге + app +. Это даст команду Compose создать изображение перед запуском веб-контейнера.

~ / TODO-приложение / создавать / докер-compose.yml

version: '2'
services:
 db:
   image: mongo:latest
   container_name: db
   networks:
     - todonet
 web:
   build: ../.
   networks:
     - todonet
   ports:
    - "3000"
networks:
 todonet:
   driver: bridge

Теперь перейдите в каталог + composer и запустите приложение с помощью команды` + docker-compose up`. Как и в случае + docker run +, переключатель + -d + запускает контейнер в отдельном режиме.

cd compose
docker-compose up -d

Вывод сообщает, что Docker Compose создал сеть с именем + compose_todonet + и запустил в ней оба контейнера.

Output from docker-compose up -dCreating network "compose_todonet" with driver "bridge"
Creating db
Creating compose_web_1

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

docker ps

Мы видим, что веб-приложение выставлено на хост-порт + 32782 +.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
6700761c0a1e        compose_web         "node app.js"            2 minutes ago       Up 2 minutes        0.0.0.0:->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   2 minutes ago       Up 2 minutes        27017/tcp                 db

Проверьте это, перейдя в веб-браузер к + http: // your_server_ip: 32782 +. Это вызовет веб-приложение так же, как вы видели его в конце ссылки: # step-2-% E2% 80% 94-создание-сеть-на-ссылку-контейнеры [Шаг 2].

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

Шаг 4 - Управление и масштабирование приложения

Docker Compose позволяет легко масштабировать веб-приложения без сохранения состояния. Мы можем запустить 10 экземпляров нашего контейнера + web + с помощью одной команды.

docker-compose scale web=10

Вывод позволяет нам наблюдать за созданием и запуском экземпляров в реальном времени.

Output from docker-compose scaleCreating and starting compose_web_2 ... done
Creating and starting compose_web_3 ... done
Creating and starting compose_web_4 ... done
Creating and starting compose_web_5 ... done
Creating and starting compose_web_6 ... done
Creating and starting compose_web_7 ... done
Creating and starting compose_web_8 ... done
Creating and starting compose_web_9 ... done
Creating and starting compose_web_10 ... done

Убедитесь, что веб-приложение масштабировано до 10 экземпляров, запустив + docker ps +.

docker ps

Обратите внимание, что Docker назначил случайный порт для показа каждого контейнера + web + на хосте. Любой из этих портов может быть использован для доступа к приложению.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                     NAMES
cec405db568d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_9
56adb12640bb        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_10
4a1005d1356a        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_7
869077de9cb1        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_8
eef86c56d16f        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_4
26dbce7f6dab        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_5
0b3abd8eee84        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_3
8f867f60d11d        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_6
36b817c6110b        compose_web         "node app.js"            About a minute ago   Up About a minute   0.0.0.0:->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            7 minutes ago        Up 7 minutes        0.0.0.0:->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   7 minutes ago        Up 7 minutes        27017/tcp                 db

Вы также можете масштабировать веб-контейнер той же командой.

docker-compose scale web=2

На этот раз мы видим, как лишние экземпляры удаляются в режиме реального времени.

Output from docker-composeStopping and removing compose_web_3 ... done
Stopping and removing compose_web_4 ... done
Stopping and removing compose_web_5 ... done
Stopping and removing compose_web_6 ... done
Stopping and removing compose_web_7 ... done
Stopping and removing compose_web_8 ... done
Stopping and removing compose_web_9 ... done
Stopping and removing compose_web_10 ... done

Наконец, перепроверьте экземпляры.

docker ps

Вывод подтверждает, что осталось только два экземпляра.

Output from docker psCONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                     NAMES
36b817c6110b        compose_web         "node app.js"            3 minutes ago       Up 3 minutes        0.0.0.0:32787->3000/tcp   compose_web_2
6700761c0a1e        compose_web         "node app.js"            9 minutes ago       Up 9 minutes        0.0.0.0:32782->3000/tcp   compose_web_1
ad7656ef5db7        mongo:latest        "docker-entrypoint..."   9 minutes ago       Up 9 minutes        27017/tcp                 db

Теперь вы можете остановить приложение и, как и раньше, вы также можете очистить ресурсы, чтобы избежать конфликтов имен.

docker-compose stop
docker-compose rm -f
docker network remove compose_todonet

Заключение

Это руководство познакомило вас с Dockerfiles и Docker Compose. Мы начали с Dockerfile в качестве декларативного механизма для создания образов, а затем изучили основы работы с сетями Docker. Наконец, мы масштабировали и управляли мультиконтейнерными приложениями с помощью Docker Compose.

Чтобы расширить вашу новую настройку, вы можете добавить Nginx обратный прокси, работающий внутри другого контейнера направлять запросы в один из доступных контейнеров веб-приложений. Или вы можете воспользоваться DigitalOcean’s Block Storage и https://www.digitalocean.com/ сообщества / учебные пособия / введение в digitalocean-балансировки нагрузки [Load Balancers], чтобы обеспечить долговечность и масштабируемость для контейнерных приложений.

Related