В этом руководстве используются файлы 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. Покажу на скриншотах:
Создание пользовательского образа 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
нужен для указания, из какого из них создавать образ. В конце ставится символ .
, которым текущему каталогу задается контекст сборки:
Для Dockerfile.prod1 и Dockerfile.prod2 процесс повторяется, каждому образу присваивается свой тег-имя и меняется файл для поиска -f
:
Выводим список только что созданных образов и подтверждаем их командой 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
Для создания контейнеров из образов Dockerfile.prod1 и Dockerfile.prod2 процесс повторяется, в команде CLI каждому контейнеру обязательно дается уникальное имя и указывается образ, из которого он создается:
Выводим список только что созданных контейнеров и подтверждаем их командой 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 w16adv_dev_cont и клонировали в него репозиторий GitHub. Командой exit выходим из первого контейнера и подтверждаем то же для второго и третьего:
Создание сети 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:
Создание сети Production
Для второго и третьего контейнеров w16adv_prod1_cont и w16adv_prod2_cont создадим сеть Production:
docker network create Production
Подключаем к ней контейнеры:
docker network connect <network_name> <container_name>
Подтверждаем подключения сети командой docker container inspect 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 взаимодействуют друг с другом.
Читайте также:
- Как отслеживать среду выполнения Docker с помощью Prometheus и Grafana
- Автоматизация и масштабирование инфраструктуры приложений с Docker Swarm и AWS
- 10 ключевых команд Docker в арсенал фронтенд-разработчиков
Читайте нас в Telegram, VK и Дзен
Перевод статьи Brandi McCall: Docker Containers and Networking