Docker + Docker Compose – запуск контейнеров для вебразработки
Новогодние каникулы были потрачены на изучение системы контейнерной виртуализации Docker и применение полученных навыков для организации окружения своих проектов. Краткая выжимка из того что понял и пока не забыл, небольшие инструкции по применению, часто используемые команды, а также много ссылок на другие источники и варианты использования. (Статья будет добавляться и исправляться по мере прозрения)
Docker был создан в 2013 году для собственных нужд компании dotCloud (Paas платформа). За пять лет своего существования Docker стал одним из самых популярных стартапов в виду своей полезности и удобности как для разработки так и для использования в продакшене. На текущий момент начиная работу над серьёзным проектом в команде, вам почти наверника предложат развернуть окружения для него именно в докере.
Нужно ли изучать докер?
2017 год для Docker Inc выдался не особо удачным ввиду внутрикомандных разногласий и судя по блогам создателей - в компании есть небольшие проблемы с определением курса её дальнейшего развития (об этом можно почитать на хабре в статье с громким названием - Докер мертв). Тем не менее Docker остается популярен, в большинстве вакансий уровня выше junior, знание докера чаще может является хоть и не основным, но желательным требованием. К тому же многих устраивает текущий инструментарий и менять его нет смысла (список аналогичных Докеру систем).
У докера есть ряд преимуществ и особенностей который обычно выделяют в следующий список:
- Быстрое развертывание и загрузка боевого окружения;
- Масштабируемость - локальная машина разработчика или кластер с системой оркестрации и балансировкой нагрузки;
- Модульность - отдельные контейнеры или микросервисная архитектура вашего приложения;
- и другие достоинство можно посмотреть здесь.
Иными словами для разработчика докер хорош тем, что вам не надо настраивать сервер и каждый раз устанавливать разные компоненты, долго их конфигурировать, да ещё пытаться создать окружение, которое будет похоже на боевое, да ещё и ставить разные компонеты в отдельности для каждого проекта захламляя основную ОС и создавая конфликты между установленными пакетами. С Docker, вы просто заполняете конфигурационный файл и командой в консоли запускаете "виртуалку" с вашим проектом. После чего, текущую конфигурацию можно будет также развернуть на собственном сервере или на облачных платформах типа Amazon Web Server. Либо эту же конфигурацию запустить на другом проекте и Docker будет переиспользовать контейнеры, которые у него уже есть.
Docker - установка
Для каждой системы установка докера несколько отличается. Инструкции для разных ОС на официальном сайте:
Официально докер не поддерживает Windows 7, но с помощью Docker Toolbox установить можно, хотя и будет использоваться VirtualBox. Также подробнее остановимся на установке Docker в Linux, а именно в дистрибутив Debian. Кроме того помимо Docker, установим Docker Compose для того чтобы управлять докер контейнерами.
Установка Docker и Docker Compose на Debian 9
1 - Установим необходимые компоненты
1 2 3 4 5 6 |
$ sudo apt-get install \ apt-transport-https \ ca-certificates \ curl \ gnupg2 \ software-properties-common |
2 - Добавим репозиторий откуда будем скачивать пакеты докера, предварительно добавим ключ для этого репозитория. Итак, ключ -
1 |
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - |
3 - А теперь и сам репозиторий:
1 2 3 4 |
$ sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \ $(lsb_release -cs) \ stable" |
4 - Обновим список репозиториев -
1 |
$ sudo apt-get update |
5 - И вот, мы уже ставим Docker -
1 |
$ sudo apt-get install docker-ce |
Проверяем откликается ли, только что установленный Docker, запросив у него информацию о версии -
1 |
$ sudo docker --version |
В консоль должна быть выведена текущая версия Docker. Если команда docker не найдена, значит на каком-то из этапов у вас была ошибка. Ищите эту ошибку в консоле и гуглите решение помог так помог.
Устанавливаем Docker Compose
Официальная документация - Install Docker Compose и официальный гитхаб репозиторий - Compose.
Качаем файлы Docker Compose (предварительно откройте гитхаб Docker-Compose и посмотрите какая версия последняя, на текущий момент это 1.18.0 вставляем версию в ссылку после "/download/") -
1 |
sudo curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose |
Затем раздаём права
1 |
sudo chmod +x /usr/local/bin/docker-compose |
Проверяем работоспособность -
1 |
docker-compose --version |
Все команды докер композ для командной строки можно посмотреть здесь. Если возникли проблемы с этим способом установки Docker-Compose, в официальной документации есть альтернативный способ установки с помощью Pip.
<del>Забавно, когда я впервые знакомился с Docker и Docker Compose у меня была уйма ошибок (собственно по этому и затеял написание инструкции установки, которая не особо то в итоге отличается от мануала), но при написании статьи в чистой тестовой Debian всё прошло как по маслу, даже поделиться нечем </del>
Во время экспериментов ошибок поддобавилось, о них чуть ниже.
Docker - возможные проблемы
- Ошибка 1396 при создания пользователя:
Docker mysql ERROR 1396 (HY000): Operation CREATE USER failed for 'root'@'%'
Конфигурация mysql не верна. Вероятно вы задали директиву "MYSQL_USER" равную "root", а это стандартное имя пользователя MySQL и при попытки создать вторую учетную запись с одинаковым именем вываливается эта ошибка. Используйте логин отличный от "root".
- Ошибка инициализации базы данных без пароля для root пользователя:
error: database is uninitialized and password option is not specified
mysql exited with code 1
По идеи из перевода ошибки ясно, что пароль отсутствует, причем в терминале далее мы видим просьбу установить одну из директив для решения этой проблемы. Директивы установка значений которых может решить эту проблему -
- MYSQL_ROOT_PASSWORD - задать пароль для root пользователя;
- MYSQL_ALLOW_EMPTY_PASSWORD - разрешить разворачивать MySQL без пароля;
- MYSQL_RANDOM_ROOT_PASSWORD - рандомный пароль.
Добавьте, директиву "MYSQL_ROOT_PASSWORD" с вашим паролем в docker-compose.yml и перезапустите Docker (пример файла "docker-compose.yml" с этой директивой чуть ниже).
Docker - конфигурирование отдельного проекта
Для начала определимся из каких компонентов будет состоять окружение. В качестве простого примера поднимем вебсервер LEMP (Linux - Engine-X/nginx - MySQL - PHP). Создадим папку проекта, в которой будут конфигурационные файлы и папка с исходными кодом проекта. Настройки будем хранить в папке проекта с названием "docker". Общая структура следующая:
- /docker/ - папка с настройками контейнеров:
- /nginx/nginx.conf - папка с файлом настройки сервера nginx;
- /php-fpm/Dockerfile - папка с файлом сборки контейнера с PHP;
- /db_data/ - папка с данными из БД;
- /www/ - папка с кодом проекта;
- /docker-compose.yml - конфигурация Docker Compose.
1. Создаём конфигурационные файлы
В проекте создаём конфигурационный файл docker-compose.yml
1 2 3 4 5 6 7 8 9 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 |
version: "3.1" services: mysql: image: mysql:8.0 container_name: atlogex-mysql working_dir: /application volumes: - ./db_data:/application environment: - MYSQL_ROOT_PASSWORD=112233 - MYSQL_DATABASE=db - MYSQL_USER=atlogex - MYSQL_PASSWORD=123456 ports: - "8082:3306" webserver: image: nginx:alpine container_name: atlogex-webserver working_dir: /apl volumes: - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/nginx.conf/ ports: - "80:80" php-fpm: build: docker/php-fpm container_name: atlogex-php-fpm working_dir: /apl volumes: - ./www:/var/apl - ./docker/php-fpm/php-ini-overrides.ini:/etc/php/7.1/fpm/conf.d/99-overrides.ini |
Разбираем по порядку.
version - версия конфигурации, с течением времени Compose модифицирует команды, поэтому нужно указывать версию которой будут соответствовать команды в вашем конфигурационном файле. Подробнее о различиях в версиях конфигурации Compose.
services - контейнеры и их настройки для вашего приложения.
Например контейнер с БД:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
mysql: image: mysql:8.0 container_name: atlogex-mysql working_dir: /application volumes: - ./db_data:/application environment: - MYSQL_ROOT_PASSWORD=112233 - MYSQL_DATABASE=db - MYSQL_USER=atlogex - MYSQL_PASSWORD=123456 ports: - "8082:3306" |
image - образ который будет скачен из докеровского репозитория и использован для того чтобы развернуть текущий контейнер;
container_name - произвольное имя контейнера;
working_dir - директория внутри контейнера где будут размещаться данные
volumes - директория для данных, отсюда будут перекидываться данные в докер контейнер и докер контейнер будет сюда же сохранять данные.
enviroments - настройки контейнера;
posrts - порты для связи контейнера и вашей операционной системы.
Другие возможные настройки для контейнеров можно просмотреть в официальной документации.
Подробнее о директиве volumes - указанные в ней параметры осуществляют, так называемое, монтирование директории из хост системы в виртуальную (либо монтирование директории из одного контейнера в другой).
Монтирование директории (сквозная директория) из вашей операционной системы в контейнер позволяет, например, сохранять MySQL данные, которые не должны оставаться в контейнере (в соответствии с основным подходом - контейнер это неизменяемая во время работы сущность), а также подгружать в контейнер файлы проекта, например файлы сайта, которые можно будет править и изменения тут же будут применены в контейнеры (подход только для разработки, для продакшена файлы проекта должны быть скопированы в контейнер).
Настройки контейнера webserver
В качестве вебсервера мы используем nginx, с прокси запросами к php-fpm для php скриптов. Для настройки nginx с помощью директивы volume cмантируем в контейнер конфигурационный файл nginx (todo: конфиг nginx лучше копировать, по сути изменять на лету его бесполезно), который лежит в папке с конфигурацией докер контейнеров "./docker/nginx/nginx.conf". Конфигурация nginx -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
server { listen 80 default; server_name yoursite.lcl www.yoursite.lcl; client_max_body_size 108M; access_log /var/log/nginx/application.access.log; root /var/apl/; index index.php; location / { index index.php index.html index.htm; } location ~ \.php$ { fastcgi_pass php-fpm:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PHP_VALUE "error_log=/var/log/nginx/application_php_errors.log"; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; include fastcgi_params; } } |
2. Собираем контейнеры
Некоторые контейнеры требуют предварительной сборки. В нашем примере предварительной сборки требует контейнер "php-fpm", обратите внимание на команду build в секции параметров этого контейнера в конфигурации docker-compose.yml. Контейнер собирается уже из Docker файла (файл с названием Dockerfile), который можно положить в отдельную папку с конфигурациями контейнеров, в этом проекте это путь "./docker/php-fpm/Dockerfile".
Чтобы создать PHP образ с необходимыми библиотеками, можно воспользоваться документацией или автогенератором конфигураций. Содержимое файла для контейнера с PHP 7 будет следующие -
1 2 3 4 5 6 7 8 |
FROM phpdockerio/php71-fpm:latest WORKDIR "/application" # Install selected extensions and other stuff RUN apt-get update \ && apt-get -y --no-install-recommends install php7.1-mysql \ && apt-get -y install git \ && apt-get clean; rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /usr/share/doc/* |
Команда для сборки -
docker-compose build
3. Запускаем Docker
После того как необходимые контейнеры собраны, можно запустить докер.
docker-compose up
Если что-то пошло не так, остановить Docker можно командой - "docker-compose down", перезапустить - "docker-compose restart".
Если вы изменяли настройки в контейнерах которые предварительно нужно собирать, то такие контейнеры нужно пересобрать, команда для пересборки проекта на лету (минуя ввод команд остановки, пересборки и запуска) -
docker-compose up -d --force-recreate --build
Директива "-d" запустит докер в фоновом режиме не блокируя консоль после старта.
Также если у вас много контейнеров порой приходиться ждать пока они все перезагрузится, если использовать общую команду для перезапуска контейнеров -
docker-compose restart
Чтобы ускорить процесс можно добавить конкретный контейнер, который нужно перезагрузить, например при конфигурировании nginx, перезагружать только контейнер webserver
docker-compose restart webserver
4. Проверяем работоспособность
Для того чтобы проверить какие контейнеры запущены в данный момент и как к ним можно достучаться используйте команду
docker-compose ps
Вывод будет примерно таким -
1 2 3 4 5 |
Name Command State Ports ---------------------------------------------------------------------------------- atlogex-mysql docker-entrypoint.sh mysqld Up 0.0.0.0:8082->3306/tcp atlogex-php-fpm /bin/sh -c /usr/bin/php-fpm Up 9000/tcp atlogex-webserver nginx -g daemon off; Up 0.0.0.0:80->80/tcp |
Из этого листинга мы видим, что nginx и соответственно сайт будут доступны на стандартном 80 порту (нет смысла добавлять порт 80 к адресу сайта или ip адресу в адресной строке, т.к. порт 80 используется по умолчанию), а MySQL на 8082 порту.
Проверим работоспособность сайта, он должен открыться по следующим адресам:
- 0.0.0.0
- 127.0.0.1
Для того чтобы сайт открывался по ЧПУ адресу, нужно отредактировать файл /etc/hosts (Linux - "/etc/hosts", Windows - "C:\Windows\System32\drivers\etc\hosts") добавив строку:
127.0.0.1 yoursite.lcl
Запущенные контейнеры | Работащий nginx | Работающий сайт |
MySQL будет доступна по адресу 127.0.0.1:8082 , но просто из браузера посмотреть её нельзя, нужно либо подключиться к этому адресу с помощью программ для редактирования БД, например Workbench, либо поставить в докер контейнер PhpMyAdmin или залить PhpMyAdmin в отдельную папку в директории проекта.
Файлы данной конфигурации можно посмотреть в репозитории - https://github.com/Atlogex/axdocker-lemp
Docker - конфигурирование сервера под несколько проектов/сайтов (только для разработки)
В первую очередь мне понравился Docker за то, что на пользовательской Linux системе, можно отделить компоненты разработки от системы и друг от друга (на момент знакомства с Docker у меня не было проекта вписывающегося в основную парадигму Docker). Например, не ставить LAMP или Apache в систему, а сделать несколько серверов в отдельных каталогах и потом в эти каталоги складывать проекты которые будут работать в готовом окружении, которое можно запускать когда понадобиться (видимо сказывается опыт разработки под Windows и желание засунуть в Linux свой вариант Опенсервера и для таких как я наверняка уже есть отдельный котёл или, если вы поклонник Данте, круг). Этот вариант наверняка противоречит философии контейнеризации, да и врядли кто-то соберется использовать такой вариант в проде, но тем не менее, предупреждение - дальнейшая инструкция только для разработки, не стоит применять эти конфиги в боевом окружении.
Для начала определимся со структурой каталогов, например будем использовать что-то подобное:
- conf - конфигурационные файлы контейнеров;
- nginx
- nginx.cong
- php-fpm
- Dockerfile - докер файл для сборки php-fpm
- nginx
- db_data - файлы базы данных;
- projects - сайты и веб приложения
- docker-compose.yml
Примерная структура сервера для нескольких проектов
Конфигурация docker-compose.yml
Конфигурация nginx с автоопределением директорий проектов и использования названия директорий как урл (подробнее здесь) -
1 2 3 4 5 6 7 8 9 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 |
server { listen 80 default; #server_name yii1.lcl; server_name _; # конфиг применим для любого сайта set $sathost $host; # В sathost будет лежать имя сайта. Так же должна называться директрия с сайтом # убираем www if ( $host ~ ^(www\.)?(.+)$ ) { set $sathost $2; } root /var/apl/$sathost; # корень сайта определяем автоматически client_max_body_size 108M; access_log /var/log/nginx/application.access.log; index index.php; if (!-e $request_filename) { rewrite ^.*$ /index.php last; } location ~ \.php$ { fastcgi_pass php-fpm:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PHP_VALUE "error_log=/var/log/nginx/application_php_errors.log"; fastcgi_buffers 16 16k; fastcgi_buffer_size 32k; include fastcgi_params; } } |
Помимо этого, сайты нужно будет не забыть добавить в hosts файл вашей системы, для того чтобы они были доступны по именам, а не IP адресу.
Полезные материалы и ссылки:
- Исходники примера на github - https://github.com/Atlogex/axdocker-lemp
- Что такое Docker и зачем он нужен - https://habrahabr.ru/post/343572/
- Интерактивное обучение - http://training.play-with-docker.com
- Автогенерация конфигов для PHP проектов - https://phpdocker.io/generator
- Docker + Ansimble + Docker Swarn: cвой облачный хостинг - https://habrahabr.ru/post/261415/
- 12 факторов: методолгия построения микросервисных приложений - https://12factor.net/ru/