Это пример взаимодействия между несколькими контейнерами Docker. В данном случае используется популярная технологическая стэк LNMP (Nginx + PHP + MySQL).
В этом примере я использую Docker Compose, что делает конфигурацию более компактной. Конечно, можно использовать команды docker
, но процесс будет сложнее.
В файле docker-compose.yml
определены три сервиса: nginx
, php
и mysql
.
services:
nginx:
image: "${DOCKER_USER}/lnmp-nginx:v1.2"
build:
context: .
dockerfile: Dockerfile.nginx
...
php:
image: "${DOCKER_USER}/lnmp-php:v1.2"
build:
context: .
dockerfile: Dockerfile.php
...
mysql:
image: mysql:5.7
...
Здесь mysql
сервис использует образ mysql:5.7
. А образы для nginx
и php
имеют более сложное значение. Это указывает на использование образа с таким названием, а если такого образа нет, то он будет автоматически собран с помощью команд в секции build
. В одиночной среде наличие image
не обязательно, достаточно указать только build
. Однако при использовании Swarm требуется одинаковый образ для всех узлов, поэтому указание image
позволяет собирать его локально и пушить в реестр, чтобы затем автоматически скачать нужные образы при запуске.
Имена образов могут содержать переменные окружения:
image: "${DOCKER_USER}/lnmp-nginx:v1.2"
Переменная ${DOCKER_USER}
заменяется значением переменной окружения DOCKER_USER
. Эта переменная может быть установлена либо в Shell через export
, либо в специальном файле .env
, который поддерживает Docker Compose.
DOCKER_USER=twang2218
Каждый раз при выполнении команд Docker Compose этот файл .env
автоматически загружается, что удобно для настройки файла compose. Здесь определена одна переменная окружения DOCKER_USER
, но можно добавить больше переменных одной на строку.
Дополнительно можно явно указывать файлы переменных окружения. Подробности см. в официальной документации Docker Compose.
Образ mysql
сервиса использует официальный Docker образ.
mysql:
image: mysql:5.7
...
environment:
TZ: 'Asia/Shanghai'
MYSQL_ROOT_PASSWORD: Passw0rd
command: ['mysqld', '--character-set-server=utf8']
...
В этом примере MySQL база данных инициализируется паролем Passw0rd
, а также устанавливается часовой пояс через переменную окружения TZ
.
Также переопределён командный вызов контейнера, добавив параметр --character-set-server=utf8
, который устанавливает дефолтное кодировочное пространство.
Официальный образ Nginx удовлетворяет большинство требований, однако нам необходимы конфигурационные файлы сайта и директория со страницами сайта.
FROM nginx:1.11
ENV TZ=Asia/Shanghai
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY ./site /usr/share/nginx/html
Настройка образа очень проста: устанавливаем часовой пояс и копируем конфигурационные файлы и директорию сайтов в соответствующие места.
Образ php
сервиса отличается тем, что официальные образы PHP не предоставляют плагины для подключения к MySQL. Поэтому здесь показывается как создать свой собственный образ на основе официального, добавив необходимые плагины.
См. соответствующий файл Dockerfile.php:
FROM php:7-fpm
ENV TZ=Asia/Shanghai
COPY sources.list /etc/apt/sources.list
RUN set -xe \
&& echo "Building dependencies" \
&& buildDeps=" \
build-essential \
php5-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmcrypt-dev \
libpng12-dev \
" \
&& echo "Runtime dependencies" \
&& runtimeDeps=" \
libfreetype6 \
libjpeg62-turbo \
libmcrypt4 \
libpng12-0 \
" \
&& echo "Installing PHP and building components" \
&& apt-get update \
&& apt-get install -y ${runtimeDeps} ${buildDeps} --no-install-recommends \
&& echo "Compiling PHP extensions" \
&& docker-php-ext-install iconv mcrypt mysqli pdo pdo_mysql zip \
&& docker-php-ext-configure gd \
--with-freetype-dir=/usr/include/ \
--with-jpeg-dir=/usr/include/ \
&& docker-php-ext-install gd \
&& echo "Cleaning up" \
&& apt-get purge -y --auto-remove \
-o APT::AutoRemove::RecommendsImportant=false \
-o APT::AutoRemove::SuggestsImportant=false \
$buildDeps \
&& rm -rf /var/cache/apt/* \
&& rm -rf /var/lib/apt/lists/*
COPY ./php.conf /usr/local/etc/php/conf.d/php.conf
COPY ./site /usr/share/nginx/html
Первая часть просто указывает базовый образ php:7-fpm
, устанавливает часовой пояс и заменяет источники пакетов на китайский источник, чтобы избежать проблем с блокировками доступа к интернету. Далее следует длинная команда RUN
, которая выполняет установку и сборку PHP расширений.
Новички Docker часто путают Dockerfile
с shell скриптами и используют много команд RUN
, каждая из которых представляет отдельную команду. Это неверный подход, так как приводит к увеличению размера образа. Каждая команда в Dockerfile
должна быть направлена на изменение текущего слоя, следуя лучшим практикам, чтобы минимизировать количество слоёв и очистить лишние файлы после завершения сборки.
Цель этого слоя — установка и сборка PHP расширений, поэтому в конце происходит удаление всех временных файлов, кроме необходимых библиотек и расширений.
В конце Dockerfile
копируются конфигурационные файлы и директория сайта в соответствующие места.
В этом примере демонстрируется использование пользовательских сетей и взаимодействие между сервисами по имени сервиса.
В конце файла docker-compose.yml
определяются два пользовательских сети: frontend
и backend
.
networks:
frontend:
backend:
Пользовательские сети могут иметь множество настроек, таких как тип драйвера сети и диапазон адресов. Но здесь они остаются пустыми, что означает использование стандартных настроек: bridge
для одиночной машины и overlay
для Swarm.
Для каждого сервиса в разделе services
указывается, какие сети он использует.
services:
nginx:
...
networks:
- frontend
php:
...
networks:
- frontend
- backend
mysql:
...
networks:
- backend
В этом примере:
nginx
подключается к сети frontend
;mysql
подключается к сети backend
;php
подключается к обоим сетям.Контейнеры, подключённые к одной сети, могут взаимодействовать друг с другом, тогда как контейнеры из разных сетей будут изолированы.В этом примере nginx
может взаимодействовать с php
, а php
— с mysql
, потому что они находятся в одной сети. nginx
и mysql
же находятся в разных сетях, поэтому они не могут взаимодействовать, обеспечивая изоляцию.
Контейнеры, находящиеся в одной сети, могут обращаться друг к другу по имени сервиса. Например, в файле ./site/index.php
используется имя сервиса mysql
для подключения к серверу базы данных.
<?php
// Установление соединения
$conn = mysqli_connect("mysql", "root", $_ENV["MYSQL_PASSWORD"]);
...
?>
В этой части кода пароль для базы данных берётся из переменной окружения $_ENV["MYSQL_PASSWORD"]
, что позволяет передавать актуальные значения пароля при запуске контейнера. В данном примере пароль передаётся через переменную окружения в файле docker-compose.yml
.
версия: '2'
сервисы:
...
php:
...
окружение:
MYSQL_PASSWORD: Passw0rd
...
Чтобы узнать больше о пользовательских сетях Docker, можно обратиться к официальной документации: https://docs.docker.com/engine/userguide/networking/dockernetworks/#/user-defined-networks
Для получения информации о том, как использовать пользовательские сети в Docker Compose, рекомендуется ознакомиться с этой частью документации: https://docs.docker.com/compose/networking/
В этих трёх сервисах, nginx
и php
являются бессостоятельными службами, они не требуют локального хранения данных. Однако, mysql
является базой данных, которая нуждается в хранении динамических данных. В контейнерах Docker все состояние должно быть вынесено за пределы хранимых данных, поэтому все динамические данные должны быть сохранены через использование томов.
тома:
mysql-data:
В конфигурационном файле docker-compose.yml
, есть глобальная секция тома
, где мы определяем названные тома. Здесь мы определили том mysql-data
. Можно указывать дополнительные параметры для тома, такие как драйвер тома или его конфигурацию, но здесь используются значения по умолчанию. Это значит, что используется простой локальный драйвер тома local
, и созданный названный том может находиться в директории /var/lib/docker/volumes
.
В разделе конфигурации сервиса mysql
, также присутствует секция тома
, где указывается, какие тома должны быть смонтированы в контейнер при запуске. Мы используем ранее определенный названный том mysql-data
, который монтируется в папку /var/lib/mysql
внутри контейнера.
mysql:
образ: mysql:5.7
тома:
- mysql-data:/var/lib/mysql
...
Порядок запуска сервисов иногда имеет значение. Compose позволяет контролировать порядок запуска до некоторой степени. Например, в этом примере, я использовал зависимость depends_on
для настройки.
сервисы:
nginx:
...
зависит_от:
- php
php:
...
зависит_от:
- mysql
mysql:
...
Здесь nginx
зависит от php
сервиса, а php
сервис зависит от mysql
. При выполнении команды docker-compose up -d
, сервисы будут запущены в порядке зависимости: mysql
-> php
-> nginx
.
Необходимо отметить, что этот контроль над порядком запуска ограничен. Он не гарантирует, что следующий сервис будет запущен только после того, как завершится подготовка всех необходимых ему сервисов. Вместо этого он начинает запуск следующего сервиса сразу после старта текущего. Поэтому, даже если порядок запуска указан правильно, это может привести к ошибкам, вызванным тем, что один сервис запускается раньше, чем другой сервис, на котором он зависит, готов к работе.
Если требуется более строгое управление зависимостями между сервисами, следует использовать скрипты типа entrypoint.sh
, чтобы обеспечить ожидание готовности зависимых сервисов перед запуском основного сервиса. Также можно использовать параметр restart: always
, чтобы обеспечить повторную попытку запуска сервиса, если он был остановлен из-за ошибки.
docker-compose up -d
Если во время сборки заметили, что загрузка образов происходит очень медленно или вообще не удается, возможно, проблема связана с блокировкой доступа. Вам потребуется настроить акселератор, подробнее можно прочитать в моих записях FAQ.
Если были внесены изменения в конфигурационные файлы, возможно, потребуется явное перестроение, которое можно выполнить с помощью команды docker-compose build
.
docker-compose ps
docker-compose logs
Сервер nginx
будет слушать порт 80,
Docker for Mac
, то можно обращаться к нему по адресу http://localhost
Docker Toolbox
, то следует использовать адрес виртуальной машины, такой как http://192.168.99.100. Адрес можно найти с помощью команды docker-machine ip default
.Если после обращения видите сообщение «Успешное соединение с сервером MySQL», значит база данных подключена корректно.
docker-compose down
В одиночной среде использования контейнеров часто удобно использовать привязку к каталогам хоста. Это полезно при разработке. Но при развертывании приложений в кластере, привязка к каталогам хоста становится крайне неудобной.
В кластерной среде, Swarm может распределить контейнеры на любую машину. Если одна машина выйдет из строя, контейнеры могут быть переназначены на другую машину, чтобы гарантировать продолжение работы сервиса. В таких условиях, использование привязки к каталогам хоста требует наличия и синхронизации содержимого каталогов на всех машинах. Это не лучший подход.Поэтому для удобства развертывания в кластерной среде лучше всего помещать код приложения и конфигурационные файлы прямо в образ. Как в данном примере, мы видим, что в образах nginx
и php
службы включены файлы конфигурации и код приложения.
Файл Dockerfile
для сервиса nginx
...
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY ./site /usr/share/nginx/html
Файл Dockerfile
для сервиса php
...
COPY ./php.conf /usr/local/etc/php/conf.d/php.conf
COPY ./site /usr/share/nginx/html
Docker Swarm существует в двух поколениях. Первое поколение представляет собой раннюю попытку Docker команды по организации кластеров, работающее в виде контейнера, известное как Docker Swarm; второе поколение — это версия начиная с 1.12
, основанная на SwarmKit
и интегрированная в docker
, называемая Docker Swarm Mode.
Первое поколение Swarm (https://docs.docker.com/swarm/) было первой попыткой Docker команды по организации кластеров, работавшей в виде контейнера, требовала внешнего ключ-значения хранилища (например, etcd, consul, zookeeper) и необходимости вручную настраивать overlay
сети. Её конфигурация была проще, чем Kubernetes, но всё же сложнее, чем последующее поколение.
В этом примере предоставлен скрипт run1.sh
, который помогает создать кластер первого поколения Swarm, запустить сервисы и масштабировать их.
На машине с установленным docker-machine
и VirtualBox (например, с Docker Toolbox для Mac/Windows), можно использовать скрипт run1.sh
для создания кластера:
./run1.sh create
./run1.sh up
./run1.sh scale 3 5
Первый параметр указывает количество контейнеров nginx
, второй — количество контейнеров php
.
Сервер nginx
будет слушать порт OnClickListener. Используйте команду docker ps
, чтобы получить информацию о конкретном узле кластера, где работает nginx
, и его IP-адрес.
$ eval $(./run1.sh env)
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d85a2c26dd7d twang2218/lnmp-php:v1.2 "php-fpm" 9 минут назад Up 9 минут 9000/tcp node1/dockerlnmp_php_5
c81e169c164d twang2218/lnmp-php:v1.2 "php-fpm" 9 минут назад Up 9 минут 9000/tcp node1/dockerlnmp_php_2
b43de77c9340 twang2218/lnmp-php:v1.2 "php-fpm" 9 минут назад Up 9 минут 9000/tcp master/dockerlnmp_php_4
fdcb718b6183 twang2218/lnmp-php:v1.2 "php-fpm" 9 минут назад Up 9 минут 9000/tcp node3/dockerlnmp_php_3
764b10b17dc4 twang2218/lnmp-nginx:v1.2 "nginx -g 'daemon off" 9 минут назад Up 9 минут 192.168.99.104:80->80/tcp, 443/tcp master/dockerlnmp_nginx_3
e92b34f998bf twang2218/lnmp-nginx:v1.2 "nginx -g 'daemon off" 9 минут назад Up 9 минут 192.168.99.106:80->80/tcp, 443/tcp node2/dockerlnmp_nginx_2
077ee73c8148 twang2218/lnmp-nginx:v1.2 "nginx -g 'daemon off" 22 минут назад Up 22 минут 192.168.99.105:80->80/tcp, 443/tcp node3/dockerlnmp_nginx_1
1931249a66c1 e8920543aee8 "php-fpm" 22 минут назад Up 22 минут 9000/tcp node2/dockerlnmp_php_1
cf71bca309dd mysql:5.7 "docker-entrypoint.sh" 22 минут назад Up 22 минут 3306/tcp node1/dockerlnmp_mysql_1
В таком случае, можно использовать http://192.168.99.104, http://192.168.99.105, http://192.168.99.106 для доступа к сервисам.
./run1.sh down
./run1.sh remove
Второе поколение Swarm (https://docs.docker.com/engine/swarm/), или Docker Swarm Mode, было введено с версии 1.12 и представляет собой встроенную систему управления кластерами Docker. Она значительно отличается от первого поколения Swarm и существенно упрощает процесс создания кластера. Внутренний дистрибутивный базовый набор данных заменил необходимость настройки внешних ключ-значения хранилищ; внутренняя нагрузочная балансировка уровня ядра заменила необходимость настройки внешней нагрузочной балансировки; и внутренняя граница нагрузочной балансировки заменила необходимость настройки внешней границы нагрузочной балансировки.
Как и в примере с первым поколением Swarm, для удобства объяснения здесь представлен скрипт run2.sh
, который поможет создать кластер, запустить сервисы и масштабировать их.
На машине с установленным docker-machine
и VirtualBox (например, с Docker Toolbox для Mac/Windows), можно использовать скрипт run2.sh
для создания кластера:
./run2.sh create
Использование облачных сервисов, таких как DigitalOcean, AWS, не требует использования VirtualBox, однако необходимо предварительно настроить соответствующие переменные окружения для docker-machine
.
./run2.sh up
./run2.sh scale 10 5
Первый параметр указывает количество контейнеров nginx
, второй — количество контейнеров php
.
Можно использовать стандартные команды для выбора всех сервисов и их состояния:
docker service ls
Мы также можем использовать следующие команды для вывода состояния каждого контейнера, связанного с каждым сервисом:
docker container ls --all
``````bash
$ ./run2.sh ps
+ docker service ps -f desired-state=running nginx
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
87xr5oa577hl9amelznpy7s7z nginx.1 twang2218/lnmp-nginx:v1.2 node2 Running Running 3 hours ago
7dwmc22qaftz0xrvijij9dnuw nginx.2 twang2218/lnmp-nginx:v1.2 node3 Running Running 22 minutes ago
00rus0xed3y851pcwkbybop80 nginx.3 twang2218/lnmp-nginx:v1.2 manager Running Running 22 minutes ago
5ypct2dnfu6ducnokdlk82dne nginx.4 twang2218/lnmp-nginx:v1.2 manager Running Running 22 minutes ago
7qshykjq8cqju0zt6yb9dkktq nginx.5 twang2218/lnmp-nginx:v1.2 node2 Running Running 22 minutes ago
e2cux4vj2femrb3wc33cvm70n nginx.6 twang2218/lnmp-nginx:v1.2 node1 Running Running 22 minutes ago
9uwbn5tm49k7vxesucym4plct nginx.7 twang2218/lnmp-nginx:v1.2 node1 Running Running 22 minutes ago
6d8v5asrqwnz03hvm2jh96rq3 nginx.8 twang2218/lnmp-nginx:v1.2 node1 Running Running 22 minutes ago
eh44qdsiv7wq8jbwh2sr30ada nginx.9 twang2218/lnmp-nginx:v1.2 node3 Running Running 22 minutes ago
51l7nirwtv4gxnzbhkx6juvko nginx.10 twang2218/lnmp-nginx:v1.2 node2 Running Running 22 minutes ago
+ docker service ps -f desired-state=running php
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
4o3pqdva92vjdbfygdn0agp32 php.1 twang2218/lnmp-php:v1.2 manager Running Running 3 hours ago
bf3d6g4rr8cax4wucu9lixgmh php.2 twang2218/lnmp-php:v1.2 node3 Running Running 22 minutes ago
9xq9ozbpea7evllttvyxk7qtf php.3 twang2218/lnmp-php:v1.2 manager Running Running 22 minutes ago
8umths3p8rqib0max6b6wiszv php.4 twang2218/lnmp-php:v1.2 node2 Running Running 22 minutes ago
0fxe0i1n2sp9nlvfgu4xlc0fx php.5 twang2218/lnmp-php:v1.2 node1 Running Running 22 minutes ago
+ docker service ps -f desired-state=running mysql
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR
3ozjwfgwfcq89mu7tqzi1hqeu mysql.1 mysql:5.7 node3 Running Running 3 hours ago
Сервис nginx
будет прослушивать порт 80. Поскольку второе поколение Swarm имеет сетевую маршрутизацию (Routing Mesh) и балансировку нагрузки, все узлы в кластере будут прослушивать порт 80, будь то менеджеры или рабочие ноды, даже если нет контейнеров nginx
, запущенных на этих нодах. Когда какой-либо узел получает запрос на порт 80, он автоматически перенаправляет его на нужный контейнер через overlay-сети. Поэтому доступ к любому узлу по порту 80 должен показывать работу сервиса.
Используйте следующую команду для получения списка всех узлов. Адрес любого из этих узлов должен отображать страницу приложения:
$ ./run2.sh nodes
manager http://192.168.99.101
node1 http://192.168.99.103
node2 http://192.168.99.102
node3 http://192.168.99.104
./run2.sh down
./run2.sh remove
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )