Содержание
По работе потребовалось ставить на конвейер разработку модулей под разные CMS для команды разработчиков. Имея опыт работы с Docker, было решено конфигурировать среду разработки модуля для CMS в Docker.
При наличии достаточного пространства на диске, организованная среда на docker контейнерах имеет ряд преимуществ:
Файловая структура:
.docker
- директория с конфигами для организации среды разработкиmysql
php
webserver
(не apache чтобы в дальнейшем можно было заменить на любой другой web сервер)cms
- директория с исходниками CMSsrc
- директория с исходниками плагина (если нужно).gitignore
чтобы не коммитить в удаленный репозиторийСначала сконфигурируем каждый сервис/контейнер по отдельности, а потом запишем это в docker-compose.yml
.
docker-compose.yml
Нужна отладка и тесты на phpunit, значит нужен xdebug и composer.
Создаем файл .docker/php/Dockerfile
и записываем в него конфигурацию образа на основе официального образа docker php:
plaintextFROM php:7.3-fpm RUN apt update && apt install -y libzip-dev zip mc nano # установка модулей php из репозитория ОС RUN docker-php-ext-install pdo_mysql zip # установка модулей php из репозитория pecl RUN pecl install xdebug && docker-php-ext-enable xdebug # установка composer RUN cd ~ \ && curl -sS https://getcomposer.org/installer -o composer-setup.php \ && php composer-setup.php --install-dir=/usr/local/bin --filename=composer # запуск PHP-FPM CMD ["php-fpm"]
Внутрь контейнера с PHP будем прокидывать следущие файлы:
.docker/php/php.ini
(документация про файл конфигурации php и про директивы php.ini):ini[PHP] user_ini.filename = "php.ini" error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT log_errors = On error_log = /var/www/html/php_errors.log
.docker/php/xdebug.ini
(документация xdebug по настройкам):inixdebug.remote_handler = dbgp xdebug.log=/var/www/html/xdebug.log xdebug.client_host = 172.18.0.1 xdebug.client_port = 9003 xdebug.mode=coverage,debug xdebug.start_with_request = yes
.docker/php/entrypoint.sh
:bash#!/bin/bash # устанавливаем нужные библиотеки, если надо composer install # запускаем вечный цикл, чтобы контейнер не упал while true; do sleep 10; done;
.docker/php/entrypoint.sh
будет запускаться каждый раз при старте контейнера!За основу возьмем официальный Docker образ Apache2 от Canonical (Ubuntu) и внутри образа установим модуль для работы веб-сервера по FastCGI. Запишем все это в конфиг образа .docker/webserver/Dockerfile
:
plaintextFROM ubuntu/apache2:latest RUN apt update && apt install -y libapache2-mod-fcgid nano mc
Запускать веб-сервер будем в отдельном скрипте .docker/webserver/entrypoint.sh
, имхо удобнее, там несколько команд на запуск:
bash#!/bin/bash # включаем нужные модули a2enmod proxy a2enmod proxy_fcgi a2enmod rewrite # тестируем конфиги apachectl configtest # запускаем демона apache2 service apache2 start # стартуем вечный цикл while true; do sleep 10; done;
Сделаем конфиг .docker/webserver/host.conf
для нашего виртуального хоста:
plaintext<VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html <FilesMatch \.php$> # по дефолту PHP-FPM работает на 9000 порту # имя хоста php берем из имени сервиса, # которое присвоили контейнеру с php в docker-compose-dev.yml SetHandler "proxy:fcgi://php:9000" </FilesMatch> ErrorLog /var/www/html/error.log CustomLog /var/www/html/access.log combined </VirtualHost>
Теперь нам необходим сам конфиг .docker/webserver/apache2.conf
. Оригинальный конфиг apache2 в контейнере можно просмотреть так:
bash# запускаем контейнер в фоне $ docker run -d ubuntu/apache2 # смотрим список запущенных контейнеров $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 2464a3b528d2 ubuntu/apache2 "apache2-foreground" 25 seconds ago Up 23 seconds 80/tcp heuristic_lederberg # заходим в терминал в контейнере $ docker exec -it 2464a3b528d2 /bin/bash # просматрвиаем файл конфига $ cat /etc/apache2/apache2.conf # здесь будет вывод файла конфига # закрываем сессию терминала в контейнере (выходим из контейнера) $ exit # останавливаем контейнер $ docker stop 2464a3b528d2
Копируем то что в файле конфига, и заменяем некоторые настройки на это:
plaintext# ip адрес сервера ServerName 172.18.0.1 # разрешение на децентрализованную конфигурацию (.htaccess) в диреткории /var/www/ <Directory /var/www/> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> # название файла с децентрализованным конфигом AccessFileName .htaccess
ServerName
должен совпадать с IP адресом подсети создаваемой для композиции контейнеров в docket-compose.yml
В простом варианте достаточно взять Docker образ MySQL и заюзать переменные из раздела Environment Variables
типа MYSQL_ROOT_PASSWORD
, MYSQL_USER
и MYSQL_PASSWORD
.
Однако, у меня это не заработало в момент когда появилась вторая композиция контейнеров, то есть была одна запущенная композиция контейнеров с MySQL и все работало, но при попытке поднять вторую композицию контейнеров с использованием MySQL начались проблемы, что-то вроде такого:
plaintextLost connection to MySQL server at 'reading initial communication packet', system error: 104 # или Can't open and lock privilege tables: Table 'mysql.user' doesn't exist # или Can't open the mysql.plugin table. Please run mysql_upgrade to create it
И да, я не пытался поднять второй инстанс одной и той же композиции контейнеров, нет.
В одном случае могла успешно работать композиция контейнеров 1, но не работала 2-ая композиция, но после docker system prune -a
, магичеким образом переставала работаться 1-ая композиция, а 2-ая работала.
Для этого нужно 2 файла.
.docker/mysql/entrypoint.sh
:
bash#!/bin/bash # инициализировать mysql без root пароля # в первый запуск сработает, во второй нет, потому что хранилище уже инициализировано mysqld --initialize-insecure # запустить демона mysql в фоне mysqld --user=root --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --default-authentication-plugin=mysql_native_password --daemonize # зайти в mysql от root но без пароля и передать на выполнение содержимое файла # в первый запуск сработает, во второй не сможет зайти без пароля mysql -u root < /usr/bin/init.sql # запустить вечный цикл while true; do sleep 10; done;
.docker/mysql/init.sql
для MySQL 5.7:
sqlALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; GRANT ALL ON *.* to 'root'@'%' IDENTIFIED BY 'root'; FLUSH PRIVILEGES; CREATE DATABASE IF NOT EXISTS db_name; USE db_name;
.docker/mysql/init.sql
для MySQL 8.0:
sqlCREATE USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY 'root'; GRANT ALL PRIVILEGES ON *.* TO 'root'@'%'; FLUSH PRIVILEGES; CREATE DATABASE IF NOT EXISTS db_name; USE db_name;
'root'@'%'
позволяет указать что root
пользователь может заходить с любого хоста. localhost
будет доступен только в контейнере с MySQL, но к сервису MySQL в композиции контейнеров, будут обращаться другие контейнеры не по localhost
, а по имени сервиса MySQL, например 'root'@'mysql'
.А здесь ничего дополнительно конфигурировать не будем, просто возьмем Docker образ phpMyAdmin, прокинем порт контейнера на хост машину, и укажем доступы к сервису mysql прямо в docker-compose.yml
, и все будет работать :)
Сделаем docker-compose.yml
(документация):
ymlversion: '3.0' services: mysql: image: mysql:5.7 container_name: cms-mysql-dev restart: unless-stopped volumes: # хранилище mysql прокинем на хост машину - ./docker-data/mysql/data:/var/lib/mysql - ./.docker/mysql/init.sql:/usr/bin/init.sql - ./.docker/mysql/entrypoint.sh:/usr/bin/entrypoint.sh command: /bin/bash -c "/usr/bin/entrypoint.sh" networks: - app-network php: build: context: ./.docker/php container_name: cms-php-dev restart: unless-stopped depends_on: - mysql volumes: # монтируем файлы cms (и плагина) внутрь контейнера networks: - app-network webserver: build: context: ./.docker/webserver container_name: cms-webserver-dev restart: unless-stopped depends_on: - php ports: - "5011:80" volumes: - ./.docker/webserver/host.conf:/etc/apache2/sites-available/000-default.conf - ./.docker/webserver/apache2.conf:/etc/apache2/apache2.conf - ./.docker/webserver/entrypoint.sh:/usr/bin/entrypoint.sh command: /bin/bash -c "/usr/bin/entrypoint.sh" networks: - app-network pma: image: phpmyadmin/phpmyadmin:latest container_name: cms-pma-dev restart: unless-stopped depends_on: - mysql ports: - "5012:80" networks: - app-network networks: app-network: driver: bridge ipam: driver: default config: - subnet: 172.18.0.1/24
В терминал введем команду:
bash$ docker-compose up --build
И наш пустой web-сервер заработает, можно проверить по адресу localhost:5011
.
Настало время разобраться как же сюда впихнуть CMS ...
В случае когда работа осуществляется с целым инстансом CMS и этот инстанс CMS является продуктом, то на этом развертывание среды заканчивается - монтируем CMS, запукаем docker-compose, заходим на localhost:5011
и производим установку CMS.
Если говорить про плагины для Wordpress, 1С-Битрикс, Shop-Script и прочие CMS где плагин располагается в отдельной директории, то достаточно прокинуть только эту директорию.
Например, в корне есть такие директории:
shop-script
- исходники CMSsrc
- исходники плагинаymlvolumes: - ./shop-script/:/var/www/html/ - ./src/:/var/www/html/wa-apps/shop/plugins/mymodule/
А если файлы плагина внедряются смешиваясь с основными файлами CMS, как например сделано в OpenCart, то прокидывать файлы плагина надо по отдельности каждый.
Например, в корне есть такие диреткории:
opencart
- исходники CMSsrc
- исходники плагинаymlvolumes: - ./opencart/:/var/www/html/ - ./src/:/var/www/html/
Получим такую ошибку:
А вот так, многословно но работает:
ymlvolumes: - ./opencart/:/var/www/html/ - ./src/admin/controller/extension/module/mymodule.php:/var/www/html/admin/controller/extension/module/mymodule.php - ./src/catalog/controller/extension/module/mymodule.php:/var/www/html/catalog/controller/extension/module/mymodule.php - ./src/admin/language/ru-ru/extension/module/mymodule.php:/var/www/html/admin/language/ru-ru/extension/module/mymodule.php
В итоге мы получаем среду для работы с CMS в Docker контейнерах, организованных при помощи композиции контейнеров. При этом работа с CMS может осуществляться в двух вариантах:
localhost:5011
будет доступен сайт на CMS, а по адресу localhost:5012
будет доступен phpMyAdmin.