
В этой статье мы расскажем о переносе одного из компонентов монолитного SAAS-сервиса, а именно тестового интернет-магазина, в контейнеры Docker. Статья будет полезна тем, кто только приступил к изучению Docker.
Планируя перенос в Docker, мы ставили перед собой несколько задач.
Прежде всего, хотелось оценить возможность и трудоемкость переноса всего SAAS-сервиса интернет-магазинов в контейнеры. Предполагается, что такой перенос повлияет положительно на отказоустойчивость сервиса и масштабируемость при соответствующих изменениях в его архитектуре. После переноса появится возможность переработки технологии CI/CD с применением специально предназначенных для этого инструментов. Перенос в Docker создает предпосылки к переходу на микро-сервисную архитектуру.
Далее, возможность запуска магазинов в контейнерах упростит для программистов работы над программным обеспечением. Теперь они смогут очень быстро развернуть среду на своем домашнем компьютере без привлечения системного администратора.
И, конечно, использование контейнеров «модно и молодежно» и будет интересно программистам, занятым в сопровождении и развитии сервиса (рис. 1).

Так как раньше мы использовали Docker только для экспериментов и запуска отдельных готовых приложений, то прежде всего решили обновить свои познания в этой области.
В интернете можно найти немало курсов и статей на эту тему. Но наш SAAS-сервис написан на Perl, и довольно давно — работы были начаты примерно 20 лет назад. Чтобы было понятно, о чем идет речь, мы показали на рис. 2 портрет основателя сервиса и автора этой статьи, созданный Midjourney.

Большинство курсов, книг и статей, посвященных Docker, приводят примеры переноса в контейнеры приложений, написанных на других, более популярных сегодня языках программирования — Python, Go, JavaScript (NodeJS) и других.
В процессе переноса возникало множество вопросов. Мы читали документацию и различные статьи, искали ответы в интернете с помощью Google, YouTube, СhatGPT, а также различных групп Telegram.
Хотя СhatGPT не всегда подсказывал работающее решение, он сэкономил нам немало времени. Некоторые изображения для этой статьи были созданы при помощи нейросети Midjourney и фрагментов переписки с СhatGPT буквально за несколько минут.
Архитектура сервиса SAAS
Кратко расскажем о том, как устроена часть SAAS-сервиса, имеющая отношение к тестовым интернет-магазинам.
До переноса тестовые интернет-магазины создавались на виртуальных машинах Debian с установленной панелью управления ISPmanager или HestiaCP. Начальная подготовка такой виртуальной машины заключалась в установке OS Debian, одной из перечисленных выше панелей управления, а также в запуске скриптов начального развертывания среды SAAS-сервиса.
С учетом необходимой дополнительной ручной работы на подготовку такой виртуальной машины у системного администратора уходит 1–2 дня. Исторически такие инструменты, как Ansible, не использовались.
При переносе тестового интернет-магазина в контейнеры ставилась задача максимального облегчения работы программистов. В идеале они должны самостоятельно создавать и запускать на своих рабочих станциях нужные контейнеры, используя для работы с ПО те же самые инструменты, которыми пользовались раньше.
Кроме того, нужно было минимизировать изменения в ПО сайтов, связанные с переходом к работе в контейнерах Docker. Из этих соображений контейнеры должны были предоставлять совместимую среду выполнения для скриптов интернет-магазинов.
Тестовый интернет-магазин состоит из трех сайтов (рис. 3):
сайт витрины;
административный сайт;
сайт конфигуратора

Все эти сайты работают с одной и той же базой данных Mariadb. При этом скрипты сайта витрины и административного сайта должны иметь доступ к файлам ядра ПО сервиса, которые хранятся в каталогах специально выделенного для этого пользователя core.
Для кеширования сайты используют memcached, а для ускорения поиска — Sphinx. Кроме того, с помощью Sphinx организован поиск в базе данных KLADR.
Административный сайт позволяет менеджерам интернет-магазина управлять каталогом товаров, обрабатывать заказы, работать с покупателями с помощью встроенной CRM, получать данные статистики и так далее.
В процессе управления каталогом административный сайт загружает изображения товаров в каталог сайта витрины. Поэтому скрипты административного сайта должны иметь доступ к файлам и каталогам сайта витрины.
Сайт конфигуратора управляет настройками административного сайта и сайта витрины. Ему нужен доступ к той же базе данных, которая используется первыми двумя сайтами.
Сайты витрины и административный сайт работают вместе. Вначале мы разместили эти сайты в одном контейнере, чтобы для программистов все было похоже на работу с существующими виртуальными машинами. Однако потом было принято решение выделить для каждого из этих сайтов отдельный контейнер (рис. 4).

В файле docker-compose.yml проекта были созданы соответствующие сервисы, названия которых показаны на рис. 4.
Как видно из рисунка, сервис app реализует функциональность административного сайта, app_shop — сайта витрины интернет-магазина, а сервис app_config — сервис конфигуратора.
В рамках сервиса mariadb работает одноименная СУБД, а сервис memcached кэширует запросы к базе данных (и к некоторым другим сервисам) со стороны сайтов.
Для работы с базами данных в процессе отладки используются сервисы adminer и phpmyadmin. При этом программисты могут выбрать тот инструмент, к которому они больше привыкли.
И, наконец, сервис обратного прокси nginx-proxy необходим для обеспечения доступа ко всем трем сайтам с использованием портов 80 и 443. Дополнительно он позволяет подключать к сайтам сертификаты SSL, как бесплатные Let`s Encrypt, так и приобретенные для конкретных доменных имен.
При таком разделении на контейнеры с применением систем оркестрации Swarm или Kubernetes в рабочем окружении появится возможность запуска контейнеров на разных узлах кластера. Это даст возможность повышения отказоустойчивости и нагрузочной способности.
Если какой-то из узлов выйдет из строя, контейнеры будут перенесены на другие узлы. Если же в пике продаж возрастет нагрузка на сайт интернет-магазина, появится возможность запуска дополнительных сервисов app_shop на других узлах системы.
Что пришлось изменить в проекте при переносе
Оказалось, что при соответствующей настройке контейнеров для запуска интернет-магазинов в Docker с целью разработки и отладки потребовалось не так много изменений. Фактически все свелось к правке строк конфигурации, имеющих отношение к соединению с базой данных и memcached.
В файле конфигурации сайтов в DSN базы данных и в подключении к сервису Memcached строки localhost и 127.0.0.1 заменили именами соответствующих контейнеров из файла docker-compose.yml, описанного ниже:
$this->{ db_dsn } = "DBI:mysql:gift_db:mariadb";
$this->{ mcached_servers } = ["memcached:11211"];
Аналогичное изменение было сделано и в файле конфигурации Sphinx:
source cities
{
type = mysql
sql_host = mariadb
sql_user = kladr
sql_pass = *********
sql_db = kladr
sql_port = 3306
…
}
Больше никакой адаптации скриптов делать не пришлось. При переводе архитектуры монолита на микро-сервисы планируется внести множество изменений, однако это уже будет другая история.
Файл docker-compose.yml
Ниже мы представили файл docker-compose.yml, который запускает все необходимые нам контейнеры:
version: '3'
services:
app:
build:
context: app
env_file: .env
ports:
- 8077:80
depends_on:
- memcached
- mariadb
volumes:
- mariadb-socket:/run/mysqld/
- ./app/home:/home
networks:
- mynet
app_config:
build:
context: app_config
env_file: .env
ports:
- 8078:80
depends_on:
- memcached
- mariadb
- app
volumes:
- mariadb-socket:/run/mysqld/
- ./app/home:/home
networks:
- mynet
app_shop:
build:
context: app_shop
env_file: .env
ports:
- 8079:80
depends_on:
- memcached
- mariadb
- app
volumes:
- mariadb-socket:/run/mysqld/
- ./app/home:/home
networks:
- mynet
memcached:
image: memcached
ports:
- "11211:11211"
restart: always
networks:
- mynet
mariadb:
image: mariadb
restart: always
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
CONFIG_DB: ${CONFIG_DB}
CONFIG_USER: ${CONFIG_USER}
CONFIG_DB_PASSWORD: ${CONFIG_DB_PASSWORD}
GIFT_DB: ${GIFT_DB}
GIFT_DB_USER: ${GIFT_DB_USER}
GIFT_DB_PASSWORD: ${GIFT_DB_PASSWORD}
KLADR_DB: ${KLADR_DB}
KLADR_USER: ${KLADR_USER}
KLADR_DB_PASSWORD: ${KLADR_DB_PASSWORD}
volumes:
- ../mariadb:/var/lib/mysql
- mariadb-socket:/run/mysqld/
- ./app/mariadb_conf:/etc/mysql/conf.d
- ./app/initdb:/docker-entrypoint-initdb.d
networks:
- mynet
user: "root"
command: --init-file /docker-entrypoint-initdb.d/01-create-db.sh
adminer:
image: adminer
restart: always
ports:
- 8080:8080
networks:
- mynet
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8087:80
environment:
- PMA_ARBITRARY=1
depends_on:
- mariadb
networks:
- mynet
nginx_proxy:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
networks:
- nginx_proxy_net
volumes:
mariadb-socket:
networks:
mynet:
nginx_proxy_net:
Сервисы для сайтов интернет-магазина
Так как контейнеры сайтов требуют индивидуальной настройки, например установки утилит и модулей Perl, то для каждого из них подготовлен файл Dockerfile. Эти файлы будут рассмотрены ниже в статье. Что касается сервисов Mariadb, Memcached и других, то они создаются на базе готовых образов, полученных с Docker Hub.
Блоки сервисов app, app_shop и app_config, определенные в файле docker-compose.yml, очень похожи. У них отличаются только пути к каталогу для сборки Docker-образа и отображение порта 80 контейнера на порты хоста :
app:
build:
context: app
env_file: .env
ports:
- 8077:80
depends_on:
- memcached
- mariadb
volumes:
- mariadb-socket:/run/mysqld/
- ./app/home:/home
networks:
- mynet
Для административного сайта app используется порт 8077, для сайта витрины app_shop — порт 8079, а для сайта конфигуратора app_config — порт 8078. Эти отображения заданы в соответствующих списках ports.
Скрипты сайтов исторически были написаны таким образом, что им нужен доступ к базе данных не только по сети через порт 3306, но и через сокет. Поэтому в разделе volumes указано, что в контейнере должен быть доступен сокет Mariadb, а также каталог app/home, содержащий файлы и скрипты трех сайтов:
volumes:
- mariadb-socket:/run/mysqld/
- ./app/home:/home
Доступность в контейнере каталога app/home
, отображающегося на каталог /home
контейнера, позволяет разработчикам менять файлы сайтов, не перезапуская контейнер.
Список depends_on определяет, что сервис app должен быть запущен после сервисов memcached и mariadb:
depends_on:
- memcached
- mariadb
Следует учесть, что на запуск зависимых сервисов, например, mariadb, может потребоваться некоторое время. Пор��док запуска не гарантирует, что сервис будет запущен после завершения инициализации сервисов, от которых он зависит.
Для связи сервисов app, app_shop, app_config, memcached и mariadb мы используем список сетей networks, в котором определена сеть mynet:
networks:
- mynet
Параметр env_file указывает файл .env, содержащий пароли доступа к базам данных, пользователям и другую конфиденциальную информацию, определенную в виде переменных среды:
env_file: .env
Вот как может выглядеть такой файл (пароли заменены символами *****):
GIFT_PASSWORD=*****
CORE_PASSWORD=*****
KLADR_PASSWORD=*****
CONFIG_PASSWORD=*****
GIFT_DB=gift
GIFT_DB_USER=gift
GIFT_DB_PASSWORD=*****
KLADR_DB=kladr
KLADR_USER=kladr
KLADR_DB_PASSWORD=*****
CONFIG_DB=config
CONFIG_USER=config
CONFIG_DB_PASSWORD=*****
MARIADB_ROOT_PASSWORD=*****
По соображениям безопасности файл .env добавлен в файл .gitignore и не сохраняется в проекте Gitlab.
Сервис memcached
Сервис memcached используется сайтами для снижения нагрузки на базу данных и для сокращения запросов к различным сервисам. Он определен в файле docker-compose.yml следующим образом:
memcached:
image: memcached
ports:
- "11211:11211"
restart: always
networks:
- mynet
Здесь нет ничего необычного. Указан стандартный для memcached порт 11211, а также сеть mynet.
Сервис mariadb
Для сервиса mariadb мы использовали готовый одноименный образ:
mariadb:
image: mariadb
restart: always
environment:
MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD}
CONFIG_DB: ${CONFIG_DB}
CONFIG_USER: ${CONFIG_USER}
CONFIG_DB_PASSWORD: ${CONFIG_DB_PASSWORD}
GIFT_DB: ${GIFT_DB}
GIFT_DB_USER: ${GIFT_DB_USER}
GIFT_DB_PASSWORD: ${GIFT_DB_PASSWORD}
KLADR_DB: ${KLADR_DB}
KLADR_USER: ${KLADR_USER}
KLADR_DB_PASSWORD: ${KLADR_DB_PASSWORD}
volumes:
- ../mariadb:/var/lib/mysql
- mariadb-socket:/run/mysqld/
- ./app/mariadb_conf:/etc/mysql/conf.d
- ./app/initdb:/docker-entrypoint-initdb.d
networks:
- mynet
user: "root"
command: --init-file /docker-entrypoint-initdb.d/01-create-db.sh
Параметр environment задает список переменных среды, значения которых берутся из упомянутого выше файла .env и передаются в контейнер mariadb. Они используются там для инициализации баз данных.
Параметр volumes связывает локальный каталог mariadb, расположенный в каталоге пользователя, запускающего docker-compose, и каталог /var/lib/mysql контейнера, в котором находятся файлы баз данных.
Кроме того, этот параметр предоставляет доступ к базе данных через сокеты, позволяет управлять конфигурацией mariadb через каталог /etc/mysql/conf.d
, а также задает каталог app/initdb
для хранения скриптов инициализации баз данных:
volumes:
- ../mariadb:/var/lib/mysql
- mariadb-socket:/run/mysqld/
- ./app/mariadb_conf:/etc/mysql/conf.d
- ./app/initdb:/docker-entrypoint-initdb.d
Когда контейнер применяется для отладки (как в нашем случае), мы можем позволить себе хранить файлы баз данных в каталоге локального компьютера. Напомним, что если хранить их в контейнере, то каждый раз при перезапуске контейнера базы данных придется создавать заново.
Если же контейнер будет использован в рабочем окружении, то каталоги /var/lib/mysql
и /etc/mysql/conf.d
придется монтировать на сетевое дисковое устройство. Например, подойдет NFS, iSCSI или FC, в зависимости от ваших возможностей и требований к быстродействию.
В файле docker-compose.yml для создаваемой базы данных задается пароль пользователя root (параметр MARIADB_ROOT_PASSWORD). Таким же образом можно создать еще одну базу данных, указав ее пароль.
В нашем случае нужны сразу три базы данных (для магазина, конфигуратора и KLADR). Для каждой базы требуется задать имя пользователя, пароль, кодировку, а также сортировку.
Для создания баз данных мы сделали отображение каталога /docker-entrypoint-initdb.d
на локальный каталог app/initdb
с файлом 01-create-db.sh:
#!/bin/bash
mysql -uroot -p${MARIADB_ROOT_PASSWORD} <<MYSQL_SCRIPT
CREATE DATABASE IF NOT EXISTS config CHARACTER SET cp1251 COLLATE cp1251_general_ci;
CREATE USER IF NOT EXISTS 'config'@'%' IDENTIFIED BY '${CONFIG_DB_PASSWORD}';
GRANT ALL PRIVILEGES ON config.* TO 'config'@'%';
CREATE DATABASE IF NOT EXISTS kladr CHARACTER SET cp1251 COLLATE cp1251_general_ci;
CREATE USER IF NOT EXISTS 'kladr'@'%' IDENTIFIED BY '${KLADR_DB_PASSWORD}';
GRANT ALL PRIVILEGES ON kladr.* TO 'kladr'@'%';
CREATE DATABASE IF NOT EXISTS gift CHARACTER SET cp1251 COLLATE cp1251_general_ci;
CREATE USER IF NOT EXISTS 'gift'@'%' IDENTIFIED BY '${GIFT_DB_PASSWORD}';
GRANT ALL PRIVILEGES ON gift.* TO 'gift'@'%';
FLUSH PRIVILEGES;
MYSQL_SCRIPT
Этот файл должен быть доступен для выполнения (используйте chmod + x
).
Поле инициализации базы данных файл 01-create-db.sh будет запущен, для чего в файле docker-compose.yml предусмотрены параметры user и command:
user: "root"
command: --init-file /docker-entrypoint-initdb.d/01-create-db.sh
Если вам нужно заново создать базы данных, следует сначала удалить каталог mariadb, созданный в каталоге пользователя локального компьютера, а потом запустить контейнеры заново.
Но как задать параметры для mariadb, работающей в контейнере?
Для этого мы создали файл db.cnf и записали его в локальный каталог app/initdb, отображаемый на каталог /etc/mysql/conf.d
контейнера:
[mysqld]
skip-name-resolve = 1
key_buffer_size = 256M
max_allowed_packet = 16M
…
innodb_buffer_pool_size = 256M
innodb_buffer_pool_instances = 1
Если вы привыкли оценивать необходимые изменения в параметрах работы Mariadb с помощью утилиты mysqltuner.pl, то сможете использовать ее и при работе этой СУБД в контейнере.
Прежде всего, определите с помощью команды docker ps
имя или идентификатор контейнера mariadb:
$ docker ps | grep mariadb
88ea97e408f0 mariadb "docker-entrypoint.s…" 59 minutes ago Up 59 minutes 3306/tcp gift-docker_mariadb_1
В данном случае имя контейнера — gift-docker_mariadb_1.
Далее подключитесь к контейнеру, запустив bash:
$ docker exec -it gift-docker_mariadb_1 bash
root@88ea97e408f0:/#
Вы увидите системное приглашение root, находясь внутри контейнера. Заметим, что подобным образом можно подключиться к любому работающему контейнеру, например, чтобы посмотреть журналы, просмотреть или отредактировать файлы, установить какие-либо дополнительные модули или программы, а также выполнить другие аналогичные действия.
Теперь загрузите программу mysqltuner.pl и запустите ее:
# apt update && apt install wget -y
# wget http://mysqltuner.pl/ -O mysqltuner.pl
# perl mysqltuner.pl --user root --pass 'passwordroot'
Укажите пароль root базы данных, заданный в параметре MARIADB_ROOT_PASSWORD файла .env.
В результате вы получите необходимые рекомендации. Внесите изменения в файл app/initdb/db.cnf
и перезапустите контейнер.
Если что-то пошло не так, посмотрите журнал контейнера mariadb:
$ docker logs gift-docker_mariadb_1
Подобным образом можно просматривать журнал любого запущенного контейнера.
Сервисы adminer и phpmyadmin
Панели управления сервером, такие как ISPmanager и HestiaCP, устанавливают для работы с базами данных приложение phpMyAdmin. Что касается Adminer, то это приложение практически ни в чем не уступает phpMyAdmin, однако его образ занимает в памяти почти в два раза меньше места.
В файле docker-compose.yml сервис adminer определен следующим образом:
adminer:
image: adminer
restart: always
ports:
- 8080:8080
networks:
- mynet
Для тех разработчиков, кто привык к phpMyAdmin, в файле docker-compose.yml подготовлено определение соответствующего сервиса:
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8087:80
environment:
- PMA_ARBITRARY=1
depends_on:
- mariadb
networks:
- mynet
Параметр PMA_ARBITRARY позволяет phpMyAdmin подключаться к любому серверу СУБД, а не только к тем, что определены в его файлах конфигурации.
В рабочем окружении сервисы adminer и phpmyadmin можно запускать только для отладки.
Сервис nginx_proxy
В файле docker-compose.yml мы определили три контейнера с сайтами, доступными на портах 8077, 8078 и 8079. Однако нам нужно сделать так, чтобы эти сайты открывались по своим доменным именам на портах 80 и 443.
Воспользуемся для этого обратным прокси Nginx Proxy Manager на базе готового образа jc21/nginx-proxy-manager, добавив в файл docker-compose.yml сервис nginx_proxy:
nginx_proxy:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
networks:
- nginx_proxy_net
В каталоге data сервис будет хранить базу данных SQLite и файлы конфигурации nginx.
Проект Nginx Proxy Manager представлен на сайте https://nginxproxymanager.com/ (рис. 5).

Детальное описание этого сервиса выходит за рамки данной статьи, однако в интернете есть различные руководства, дополняющие описание, представленное на сайте.
Отметим только, что с помощью Web-интерфейса Nginx Proxy Manager вы сможете легко настроить переадресацию для ваших доменных имен на нужные порты. Кроме этого, можно подключить к сайтам сертификаты SSL, а также настроить индивидуальные конфигурации Nginx для каждого из сайтов.
Сервис app
Для сборки контейнеров сайтов мы используем готовый образ debian:stable-slim. Этот образ выбран для лучшей совместимости, так как на виртуальных серверах разработчиков интернет-магазинов и на рабочих серверах установлена ОС Debian 11.
В файлах Dockerfile каждого из трех упомянутых выше сайтов выполняется установка необходимых программ и модулей Perl, а также другие действия.
В рамках сервиса app работает административный сайт интернет-магазина. Ниже мы привели сокращенный файл Dockerfile для этого сервиса:
FROM debian:stable-slim
RUN useradd -ms /bin/bash gift && useradd -ms /bin/bash core && useradd -ms /bin/bash kladr && \
DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y \
apt-utils \
build-essential \
net-tools \
curl \
wget \
sudo \
apache2 apache2-utils apache2-suexec-custom libapache2-mod-php \
git \
cron \
liblib-abs-perl libcache-memcached-perl \
…
libdbd-mysql-perl libmariadb-dev \
libimage-magick-perl \
imagemagick \
libgd-perl \
php-mysql php-curl php-gd php-json php-zip php && \
cpan -i App::cpanminus && cpan Net::SMTP::SSL && \
cpanm HTML::Entities Digest::SHA1 HTML::Template BSON::Time Class::Accessor LWP::UserAgent MIME::Lite Devel::SimpleTrace DBI \
…
Authen::Htpasswd Apache::Htaccess && \
apt clean && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
ADD https://cpan.metacpan.org/authors/id/B/BR/BROQ/Switch-Perlish-1.0.5.tar.gz /tmp/
RUN cd /tmp/ && tar -xzf Switch-Perlish-1.0.5.tar.gz && cd Switch-Perlish-1.0.5 && perl Makefile.PL && make install && make clean
…
WORKDIR /app
COPY ./data/itmatrix /app/itmatrix
WORKDIR /app/itmatrix
RUN tar xzf Installation.tar.gz && ./install.sh
WORKDIR /app
RUN rm -rf itmatrix
COPY ./httpd_conf/apache2.conf /etc/apache2/apache2.conf
COPY ./httpd_conf/000-default.conf /etc/apache2/sites-available/000-default.conf
COPY ./httpd_conf/admin.gift.shop2you.ru.conf /etc/apache2/sites-available/admin.gift.shop2you.ru.conf
RUN ln -s /etc/apache2/sites-available/admin.gift.shop2you.ru.conf /etc/apache2/sites-enabled/
WORKDIR /etc/apache2/mods-enabled
RUN ln -s ../mods-available/cgi.load cgi.load
COPY ./httpd_conf/suexec /etc/apache2/suexec/www-data
RUN a2enmod rewrite ssl suexec auth_digest && apachectl configtest
RUN mkdir /usr/local/sphinx/
COPY ./data/sphinx-3.5.1/bin /usr/local/sphinx
COPY ./data/sphinx-3.5.1/bin /usr/bin
RUN crontab -u gift -l | { cat; echo "* * * * * /usr/bin/perl /home/gift/data/www/admin.gift.shop2you.ru/cgi-bin/dbatch.pl"; } | crontab -u gift -
RUN cron
ADD start.sh ./start.sh
RUN chmod +x ./start.sh
EXPOSE 80
CMD ["./start.sh"]
В команде RUN файле Dockerfile сервиса app создаются пользователи для сайтов, устанавливаются утилиты и модули Perl. В частности, устанавливается Apache и все необходимое для него, а также PHP.
Что касается модулей Perl, то они устанавливаются пятью разными способами — из пакетов Debian, с помощью утилит cpan и cpanm, путем скачивания и распаковки архива с сайта cpan.metacpan.org, а также из приватного архива Installation.tar.gz. Некоторые модули устанавливаются без ошибок только из пакетов Debian, а для некоторых возможна установка только из дистрибутивов, загруженных с сайта cpan.metacpan.org (при этом нужна определенная версия модулей).
После завершения установки модулей Perl команда RUN копирует в каталог /etc/apache2/
файлы конфигурации для сайтов и добавляет ссылку на конфигурацию административного сайта в каталог /etc/apache2/sites-enabled/
.
На следующем этапе к конфигурации Apache добавляются необходимые модули, а также настраивается файл /etc/apache2/suexec/www-data
.
В ваших проектах только что перечисленные действия, скорее всего, будут другими. Они зависят от деталей реализации сайтов.
Для ускорения поиска сайты используют Nginx. В Dockerfile выполняется копирование предварительно загруженных бинарных файлов этого поискового сервера. Также выполняется настройка пакетного задания и запуск cron.
На финальной стадии Dockerfile с помощью команды CMD запускает пакетный файл start.sh.
Перед запуском Apache в файле start.sh устанавливаются пароли пользователей, заданные в файле .env, меняются владельцы файлов в каталогах сайтов и настраивается доступ к каталогу /home/core/
, содержащему модули Perl ядра интернет-магазина. Кроме этого, выполняется запуск Sphinx для поиска по базе данных KLADR:
#!/bin/bash
echo "gift:${GIFT_PASSWORD}" | chpasswd
echo "core:${CORE_PASSWORD}" | chpasswd
echo "kladr:${KLDAR_PASSWORD}" | chpasswd
chown -R gift:gift /home/gift
chown -R kladr:kladr /home/kladr
chown -R core:core /home/core
usermod -a -G core gift && chmod -R g+rx /home/core/
/usr/bin/indexer --config /home/kladr/data/kladr/sphinx/sphinx_linux.conf --all
/usr/bin/searchd --config /home/kladr/data/kladr/sphinx/sphinx_linux.conf
apache2ctl -D FOREGROUND
Сервис app_shop
Файл Dockerfile сервиса app_shop аналогичен только что рассмотренному файлу сервиса app. Отличия заключаются в блоках копирования конфигурации Apache:
COPY ./httpd_conf/gift.shop2you.ru.conf /etc/apache2/sites-available/gift.shop2you.ru.conf
RUN ln -s /etc/apache2/sites-available/gift.shop2you.ru.conf /etc/apache2/sites-enabled/
Кроме этого, в этом файле несколько другой состав устанавливаемых модулей Perl.
Содержимое файла start.sh показано ниже:
#!/bin/bash
echo "gift:${GIFT_PASSWORD}" | chpasswd
chown -R gift:gift /home/gift
/usr/bin/indexer --config /home/kladr/data/kladr/sphinx/sphinx_linux.conf --all
/usr/bin/searchd --config /home/kladr/data/kladr/sphinx/sphinx_linux.conf
apache2ctl -D FOREGROUND
Здесь перед запуском Apache устанавливается пароль пользователя gift, устанавливается владелец файлов каталога /home/gift
, а также запускается Sphinx для поиска в базе данных KLADR.
Сервис app_config
Для работы сайта конфигурации был подготовлен сервис app_config. В его Dockerfile копируются файлы конфигурации Apache этого сайта:
COPY ./httpd_conf/config.itmatrix.ru.conf /etc/apache2/sites-available/config.itmatrix.ru.conf
RUN ln -s /etc/apache2/sites-available/config.itmatrix.ru.conf /etc/apache2/sites-enabled/
В остальном Dockerfile аналогичен сайту витрины интернет-магазина.
Отладка
В процессе переноса монолита в контейнеры возникала необходимость отладки файлов Dockerfile, конфигурации Apache, Mariadb, а также Sphinx.
Как уже говорилось в статье, первоначально все три сайта работали в одном контейнере. Это упростило подготовку файла Dockerfile, так как все изменения, например добавление модулей Perl и настройку конфигурации Apache, можно было делать в одном месте.
Затем было принято решение перенести все эти сайты в отдельные контейнеры. Основная причина такого переноса — подготовка для системы оркестрации, такой как Swarm или Kubernetes. Размещение сайтов в отдельных контейнерах необходимо для обеспечения возможности масштабирования. Например, при возрастании нагрузки на сайт витрины интернет-магазина можно будет запустить для витрины дополнительные контейнеры.
Ошибки в docker-compose.yml и Dockerfile
Ошибки в файлах docker-compose.yml и Dockerfile можно увидеть при запуске. Для упрощения запуска подготовлен скрипт start.sh:
#!/bin/bash
sudo chown -R $USER:$USER $HOME/gift-docker
docker-compose up -d –build
Команда chown
здесь необходима из-за того, что при инициализации сервиса app происходит смена владельцев для каталогов из app/home.
Остановку контейнеров можно сделать скриптом stop.sh:
#!/bin/bash
docker-compose down
После того как контейнеры запустились, вы можете просмотреть их журналы с помощью команды docker logs:
docker logs gift-docker_app_1
В качестве параметра этой команде нужно передать имя контейнера. Имена всех работающих контейнеров легко определить с помощью команды “docker ps”.
Ошибки в конфигурации Apache
У сервиса Apache имеются свои журналы, путь к которым задается в файле конфигурации сервиса.
Чтобы посмотреть содержимое этих журналов, подключитесь к контейнеру следующим образом:
docker exec -it gift-docker_app_1 bash
Перейдите в каталог /var/log/apache2/
. Там находятся все нужные вам журналы:
access.log
error.log
other_vhosts_access.log
Вы можете посмотреть содержимое журналов, например, с помощью команды tail
:
# tail -f error.log
После обнаружения ошибки в файле конфигурации Apache перезапустите контейнер. Также в этот журнал могут попадать ошибки, связанные с работой скриптов ваших сайтов.
Ошибки в конфигурации Mariadb
Если сервис mariadb не запускается или с ним возникают проблемы, можно посмотреть журнал Mariadb следующим образом:
docker logs gift-docker_mariadb_1
Эта команда поможет вам при настройке файла конфигурации Mariadb.
Итоги
В результате проведенных работ были достигнуты все поставленные цели, а также намечен план дальнейших действий по переводу SAAS-сервис интернет-магазинов в Docker.
Теперь программисты могут самостоятельно разворачивать на своих рабочих станциях сайты интернет-магазинов, буквально за полчаса в автоматическом режиме и без привлечения системного администратора. Раньше на подготовку виртуальных машин разработчиков у системного администратора уходило 1-2 дня.
Отталкиваясь от достигнутых результатов, запланированы работы по разворачиванию тестового интернет-магазина сначала в Swarm, а затем в Kubernetes. На первом этапе будет подключено внешнее сетевое хранилище для размещения баз данных и файлов сайтов.
Если все работы завершатся успехом, планируется переход на микро-сервисную архитектуру. Это, однако, потребует внесения масштабных изменений в архитектуру, а также в исходные коды проекта.
Автор статьи: Александр Фролов.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.