Контейнеры Docker и их связывание в сети

В этом руководстве используются файлы Dockerfile с репозиториями GitHub внутри, из этих Dockerfile собираются пользовательские образы и контейнеры. Научимся создавать и использовать в каталоге несколько файлов Dockerfile, создавать из них образы, а из образов  —  контейнеры и связывать контейнеры в сети.

Потребуется

  • Учетная запись Docker Hub.
  • Docker, установленный на локальном компьютере или IDE.
  • Учетная запись GitHub с репозиториями.
  • Базовые знания о Docker и Dockerfile.
  • Основные команды Linux.
  • IDE, например VS Code.

Цели

  • Создать три файла Dockerfile, автоматически подключаемых к Github, причем каждый к своему репозиторию.
  • Создать из трех Dockerfile три пользовательских образа Docker, а из каждого образа  —  по контейнеру.
  • Подтвердить доступ к репозиторию GitHub в каждом контейнере.
  • Один контейнер поместить в сеть Development, два других  —  в сеть Production.
  • Проверить, что контейнер сети Development не взаимодействует с другими контейнерами, а контейнеры сети Production взаимодействуют друг с другом.

Создание трех Dockerfile, автоматически подключаемых к Github

Сначала командой mkdir создаем в CLI каталог для Dockerfile и клонов репозитория GitHub, затем командой cd переходим в этот каталог:

Dockerfile создается прямо в командной строке с помощью vim или nano. Я предпочитаю VS Code. Подробнее о содержимом и параметрах Dockerfile  —  в официальной документации Docker Hub. Наша задача  —  создать три разных Dockerfile, каждый со своим репозиторием GitHub внутри. Затем создать образы и контейнеры Docker, связать один контейнер в сеть Development, а два  —  в сеть Production.

Создаем три Dockerfile  —  Dockerfile.dev, Dockerfile.prod1 и Dockerfile.prod2:

Командой ls выводим три файла текущего рабочего каталога:

В Vim, Nano или другом редакторе открываем файл Dockerfile.dev и начинаем его с официального образа Ubuntu последней версии FROM ubuntu:latest.

Для каждого Dockerfile добавляется репозиторий GitHub, к которому имеется доступ из контейнера. При запуске Ubuntu или любой другой ОС сначала командой RUN apt-get update обновляют пакеты, затем с помощью apt-get install -y git устанавливают Git для запуска команд Git внутри контейнера.

Получается пока такой Dockerile.dev:

FROM ubuntu:latest

RUN apt-get update && apt-get install -y git

Следующей командой в Dockerfile.dev клонируется нужный репозиторий GitHub внутри контейнера. В GitHub копируем URL-адрес репозитория, для первого контейнера возьму свой репозиторий Python:

В Dockerfile.dev запускаем RUN git clone <repo_URL> /repo. Этим /repo указывается, что при создании образа Docker появляется новый каталог repo, в который и отправляется клон репозитория GitHub.

Получился такой Dockerfile.dev:

FROM ubuntu:latest 

RUN apt-get update && apt-get install -y git

RUN git clone <repo_URL> /<new_directory_name>

Вот снимок экрана:

Мы просто клонируем репозиторий в контейнер, поэтому CMD в Dockerfile не нужен.

Повторим процесс создания Dockerfile для Dockerfile.prod1 и Dockerfile.prod2, понадобятся два дополнительных репозитория GitHub. Покажу на скриншотах:

Dockerfile.prod1
Dockerfile.prod2

Создание пользовательского образа Docker из Dockerfile

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

*Если у вас несколько проектов с несколькими Dockerfile, убедитесь, что находитесь в правильном каталоге с только что созданными Dockerfile:

Создаем пользовательский образ из Dockerfile.dev этой командой:

docker build -t <image_name> -f Dockerfile.dev .

-t  —  это необязательный тег для именования образа. -f  —  это сокращение от find. Оно применяется, когда имеется несколько Dockerfile или у Dockerfile иное имя, нежели Dockerfile. В этом случае в одном каталоге несколько файлов Dockerfile. -f нужен для указания, из какого из них создавать образ. В конце ставится символ ., которым текущему каталогу задается контекст сборки:

Сборка образа Docker для Dockerfile.dev

Для Dockerfile.prod1 и Dockerfile.prod2 процесс повторяется, каждому образу присваивается свой тег-имя и меняется файл для поиска -f:

Сборка образа Docker для Dockerfile.prod1
Сборка Docker для Dockerfile.prod2

Выводим список только что созданных образов и подтверждаем их командой docker images:

Создание контейнера из каждого пользовательского образа

Создадим из каждого образа по контейнеру:

docker run -dt --name <container_name> <image_name>

Разберем эту команду:

docker run нужно для создания и запуска нового контейнера.

-d  —  сокращение от detach. В Docker им указывается на запуск контейнера в фоновом режиме и вывод идентификатора контейнера.

t  —  это TTY, которым выделяется псевдо-TTY для продолжения работы контейнера.

--name <container_name>  —  необязательное присвоение имени контейнера. Если его не присвоить, в Docker контейнеру автоматически присваивается случайное имя.

<image_name>  —  образ, из которого собирается контейнер.

Создаем первый контейнер с образом Dockerfile.dev, его имя может быть другим:

docker run -dt --name w16adv_dev_cont w16adv_dev
Контейнер 1: w16adv_dev_cont

Для создания контейнеров из образов Dockerfile.prod1 и Dockerfile.prod2 процесс повторяется, в команде CLI каждому контейнеру обязательно дается уникальное имя и указывается образ, из которого он создается:

Контейнер 2: w16_adv_prod1_cont
Контейнер 3: w16_adv_prod2_cont

Выводим список только что созданных контейнеров и подтверждаем их командой docker container ls:

Подтверждение доступа к репозиторию GitHub в каждом контейнере

Пока что мы создали три разных контейнера Docker из трех разных Dockerfile, каждый с уникальным репозиторием GitHub.

Доступ к репозиторию внутри каждого контейнера подтверждается командой docker exec с флагами -it для открытия интерактивного терминала, конечным bash открывается одноименная оболочка для работы в контейнере:

docker container exec -it <container_name> bash

Получаем поступ к репозиторию в первом контейнере w16adv_dev_cont:

docker container exec -it w16adv_dev_cont bash

И оказываемся внутри контейнера в корневом каталоге:

Командой ls выводим файловую систему внутри контейнера, в которой должен быть каталог repo  —  он появляется в каждом созданном ранее Dockefile:

Переходим в этот каталог командой cd repo и с помощью ls выводим список файлов репозитория GitHub:

Контейнер 1: подтверждение репозитория GitHub

Этим подтверждается: мы оказались в контейнере 1 w16adv_dev_cont и клонировали в него репозиторий GitHub. Командой exit выходим из первого контейнера и подтверждаем то же для второго и третьего:

Контейнер 2: подтверждение репозитория GitHub
Контейнер 3: подтверждение репозитория GitHub

Создание сети Development

Чтобы контейнеры взаимодействовали, они связываются в сеть. Наша задача  —  изолировать контейнер w16adv_dev_cont от двух других w16adv_prod1_cont и w16adv_prod2_cont, которые бы взаимодействовали друг с другом. Поместим первый контейнер в сеть Development.

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

Запускаем docker network inspect bridge и видим, что три контейнера автоматически присвоены этой сети, то есть все они взаимодействуют друг с другом:

Чтобы изолировать контейнер w16adv_dev_cont, поместим его в собственную сеть Development, создаваемую командой docker network create:

docker network create <network_name>

Подключаем его к этой сети командой docker network connect, вместо имени контейнера сгодится идентификатор, а вместо идентификатора сети  —  ее имя:

docker network connect <network_name> <container_name>

Подтверждаем подключение к Development командой docker network inspect Development:

Контейнер 1: подключение к сети Development

Создание сети Production

Для второго и третьего контейнеров w16adv_prod1_cont и w16adv_prod2_cont создадим сеть Production:

docker network create Production

Подключаем к ней контейнеры:

docker network connect <network_name> <container_name>

Подтверждаем подключения сети командой docker container inspect Production:

Контейнеры 2 и 3: подключение к сети Production

Проверяем, что сети Development и Production не взаимодействуют

Один контейнер Development и два Production находятся в разных сетях и не должны взаимодействовать. При выполнении команды docker network inspect контейнерам присваивается IPv4-адрес. Чтобы подтвердить отсутствие взаимодействия контейнеров Production с контейнером Development, зайдем в последний командой docker container exec -it и пропингуем первые, просто используя имя контейнера.

Проверка 1. Development не взаимодействует с Production

Входим в Development-контейнер w16adv_dev_cont:

docker exec -it <container_name> bash

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

apt-get install -y iputils-ping

Пропинговываем второй Production-контейнер w16adv_prod1_cont:

ping <container_name>

Подключиться не получится:

Командой Exit выходим из контейнера Development.

Проверка 2. Production не взаимодействует с Development

Входим во второй Production-контейнер w16adv_prod1_cont:

docker exec -it <container_name> bash

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

apt-get install -y iputils-ping

Пропинговываем Development-контейнер w16adv_dev_cont, и снова подключиться не получится:

Командой Exit выходим из контейнера.

Проверка 3. Production взаимодействует с Production

Production-контейнеры w16adv_prod1_cont и w16adv_prod2_cont находятся в одной сети, поэтому пропинговываются друг другом.

Входим в Production-контейнер w16adv_prod2_cont:

docker exec -it <container_name> bash

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

apt-get install -y iputils-ping

Пропинговываем другой Production-контейнер w16adv_prod1_cont, здесь все проходит успешно, проверка останавливается командой control c:

Вот и все. Мы создали три файла Dockerfile с прямым подключением каждого к своему репозиторию GitHub. Из Dockerfile сделали три пользовательских образа Docker, а из каждого образа  —  по одному контейнеру. Изолировали один контейнер в сети Development и поместили два в Production. Затем проверили, что сеть Development изолирована и контейнеры Production взаимодействуют друг с другом.

Читайте также:

Читайте нас в TelegramVK и Дзен


Перевод статьи Brandi McCall: Docker Containers and Networking

Предыдущая статьяКак овладеть наукой о геопространственных данных в 2023 году
Следующая статьяПлохие модели машинного обучения? Но их можно откалибровать