Для того чтобы быстро поднять рабочее окружение существует много способов. Один из них — поднять все необходимые сервисы в Docker-контейнерах. Чтобы ускорить создание новых проектов на Yii-framework я написал такую небольшую инструкцию, которую используют разработчики в нашей команде.
На старте у вас должны стоять docker, docker-compose, php и php-composer.
Создаем папку с проектом и в ней папку docker.
mkdir project-dir
cd project-dir && mkdir docker
В папке docker создаем файл конфигурации нашего контейнера Dockerfile.
# Базовый образ с nginx и php
FROM richarvey/nginx-php-fpm
# Добавляем наше веб приложение
ADD app /var/www/app
# Удаляем конфиги сайтов которые там есть
RUN rm -Rf /etc/nginx/sites-enabled/*
# Добавляем наш конфиг
ADD docker/conf/nginx/site.conf /etc/nginx/sites-available/site.conf
# Включаем его
RUN ln -s /etc/nginx/sites-available/site.conf /etc/nginx/sites-enabled/site.conf
В этой же папке docker создаем docker-compose.yml для поднятия окружения разработки.
# Последняя версия docker-compose
version: '3'
# Создаем общую сеть deafult для всех контейнеров
networks:
default:
driver: bridge
# Создаем отдельные контейнеры
services:
# Контейнер с веб-приложением
app:
# Собираем из Dockerfile
build:
# Корнем указываем корень основного проекта
context: ../
dockerfile: ./docker/Dockerfile
# Показываем наружу 80 порт
ports:
- "80:80"
# Подключаем к общей сети с другими контейнерами
networks:
- default
# Запускаем только после db
depends_on:
- db
# Линкуем внешнюю папку с исходниками внутрь
volumes:
- "../app:/var/www/app"
# Так же линкуем конфиг для nginx
- "./conf/nginx:/etc/nginx/sites-available"
# Контейнер с базой данных
db:
image: mysql:latest
# Подключаем к общей сети с другими контейнерами
networks:
- default
# Показываем наружу порт
ports:
- "3336:3306"
# Задаем параметры для инициализации БД
environment:
# Пароль к БД
MYSQL_ROOT_PASSWORD: root
# Создаваемая по умолчанию бд
MYSQL_DATABASE: yii-template-db
# Линкуем внешнюю папку для хранения БД
volumes:
- "./database:/var/lib/mysql"
Для nginx создаем папку docker/conf/nginx и файл site.conf в ней. Файлик может изменяться, в зависимости от того, как вы хотите настроить nginx на своем проекте. Его можно менять локально, т.к. он подключается через volume. Но надо не забывать внутри контейнера перезагружать nginx: nginx -s reload
server {
charset utf-8;
client_max_body_size 128M;
listen 80; ## listen for ipv4
root /var/www/app/frontend/web/;
index index.php;
access_log /var/www/app/log/frontend-access.log;
error_log /var/www/app/log/frontend-error.log;
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# uncomment to avoid processing of calls to non-existing static files by Yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
#error_page 404 /404.html;
# deny accessing php files for the /assets directory
location ~ ^/assets/.*\.php$ {
deny all;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php-fpm.sock;
try_files $uri =404;
}
location ~* /\. {
deny all;
}
}
Все команды выполняются из корневой папки.
- Выполняем команду создания проекта
composer create-project --prefer-dist yiisoft/yii2-app-advanced app
. - Запускаем окружение
docker-compose -f docker/docker-compose.yml up -d
- Инициализируем проект
app/init --env=Development --overwrite=All
- Открываем в редакторе файл app/common/config/main-local.php и заполняем его данными для подключения к БД. В примере у нас пароль root — root, хост БД — db, имя БД — yii-template-db.
- Подключаемся к контейнеру
docker exec -it docker_app_1 bash
- Выполняем команду миграции БД
php /var/www/app/yii migrate
- Создаем папку для логов
mkdir /var/www/app/log
- И выходим
exit
- Тормозим сервис
docker-compose -f docker/docker-compose.yml down
- Запускаем его заново
docker-compose -f docker/docker-compose.yml up -d
- Открываем localhost в браузере и смотрим на новый сайт.
Upd: Обязательно стоит упомянуть, что всегда есть официальный Docker-образ Yii2.
Комментарии (14)
radist2s
04.11.2018 02:00Я ни разу не являюсь специалистом по Docker, однако даже мне известно, что размещение более одного контейнера внутри докера, это нарушение самой сути контейнеров. Внутри контейнера
supervisord
забирает на себя все функции Docker'a. А процессами должен управлять сам Docker, следить за ними, показывать их адекватные метрики. Если очень хочется сделать такой бандл "все в одном", то пожалуйста — создавайте контейнер, внутрь которого пробрасываете сокет Docker'a, и внутри этого контейнера обычнымdocker-compose
или без него запускайте сколько угодно контейнеров, связанных между собой, но только непосредственно через Docker! И когда будет нужно, можно делать так жеdocker exec
на какой-тоentrypoint
, а от него пробрасывать команды на целевые контейнеры. Даже такой Docker внутри Docker это гораздо лучше, чем один контейнер с несколькими процессами, у которых Docker дажеpid
не знает, тогда зачем Docker нужен?
Описанный в статье инструмент можно использовать только для хоумпейджей или для девелопинга. Но кому оно надо, если Docker используются только в более менее крупных проектах, или просто нормальными системщиками. Все прочие используют "сPanel" или максимум
sftp
. А те, кто хотят войти в мир Docker'а начитаются таких статей, и делают неправильно с самого начала.antaresm Автор
04.11.2018 08:131. А где именно тут «все в одном»?
2. Да, статья именно про окружение для девелопингаradist2s
04.11.2018 13:38Все в одном здесь вот где:
FROM richarvey/nginx-php-fp
Ну даже учитывая, что это окружение для разработки, то я все равно не вижу в этом смысла. Смысл докера в том, чтобы использовать для разработки то же самое окружение для разработки, что и для продакшена. То есть php должен быть скомпилирован точно так же как для дев окружения, как и для прода. Один и тот же, чтобы не было никаких нюансов. Например, для дева запросы по https работают нормально, а на проде нет, потому что для прода php скомпилирован с другой версией OpenSSL. Вот и ломай потом голову, что не так.
antaresm Автор
04.11.2018 14:07Я правильно понимаю, что разделив nginx и php в разные контейнеры мы получим относительно верный вариант?
И что тогда делать с php-fpm? Его тоже отдельно, чтобы все было по канону?radist2s
04.11.2018 15:26Правило простое: 1 процесс на 1 контейнер. Если нужно определять свой
entrypoint
, то внутри обязательно делать:
#!/usr/bin/env sh # ... exec daemon-process
Или если ваш демон не умеет нормально обрабатывать сигналы прерывания(
SIGTERM
, например), а такое случается, то можно использоватьtini
. Он иpid
передаст куда следует, и за сигналами следить будет, а потом убивать запущенный им процесс. Так какtini
добавили в Docker с версии 1.13, можно вообще просто добавитьinit: true
для сервиса вdocker-compose.yml
, но тогда придется даунгрейднуть формат файла до версии 2.x, или наоборот проапргрейдить до 3.7. (Опцию--init
запуска Docker'a в связи с поддержкой Swarm дляdocker-compose
сначала удалили, а потом вернули) Между опциейinit: true
или модификацией параметров запуска контейнера фактически разницы нет, но в первом варианте вам вообще ничего с имеджем делать не нужно. Для нормальных имеджей ничего дополнительно делать не стоит, там уже все в порядке. Проверить же нормальность можно легко: выполняетеdocker-compose up
и после завершайте поCtrl + C
. Если процесс умирает сразу, а не после задержки в несколько секунд, то внутри все правильно, если нет, попробуйте добавитьinit: true
и процесс будет завершаться сразу, так как им уже будет управлятьtini
.
Даже если вам нужно использовать
cron
, то, по-хорошему, его нужно запускать не на хосте, а в отдельном контейнере, в него пробрасывать сокет Docker'а, и им же что-то делать черезdocker-compose
/docker
. Естественно такой имедж нужно будет создавать с установленным внутриdocker
.cat_crash
04.11.2018 16:32+1И это говорит человек который вначале декларирует:
Я ни разу не являюсь специалистом по Docker
. Страшно подумать что мог бы написать нам в ответ специалист Docker
OnYourLips
04.11.2018 16:33+1Правило простое: 1 процесс на 1 контейнер.
Одна задача на контейнер. Не процесс. В документации докера этот пункт best practice недавно обновили и расширили.
Тот же php-fpm — это набор процессов, но это не нарушает правило.
Или apache + mod_php, хотя процессов много.
antaresm Автор
04.11.2018 16:57Да, согласен что по канону стоит вынести nginx в отдельный контейнер.
Но вопрос в том, что стоит ли это делать, если есть гарантии что в продакшене будет точно такая же связка, которая точно не будет менять на протяжении всего проекта?Zhuravljov
04.11.2018 18:24Дело даже не в том, чтобы именно по канону. Кроме прочего, просто так удобнее. В случае с разделенными php-fpm и nginx вы будете использовать официальные образы с поддержкой и актуальной документацией.
SakhalinDDF
04.11.2018 16:21Ну как минимум у вас в одном контейнере одновременно находится и nginx и php. А докер подход состоит в том, что бы каждый контейнер выполнял всего одну конкретную задачу, тоесть как минимум nginx и php должны разбиты на отдельные контейнеры. Если подразумевается использование каких то второстепенных сервисов — типа кэшируеющего или почтового сервера — то на них так же предлагается заводить свой отдельный сервис. К примеру на одном из поддерживаемых мной проектов вот такой список сервисов на текущий момент
1. webserver (nginx)
2. php
3. events (nodejs)
4. db
5. cache (redis)
При этом я честно говоря не смог с наскока вынести почтовый сервер в отдельный контейнер, поэтому подсадил его рядом с php (каюсь). Но обещаю исправиться =)
iproger
04.11.2018 03:33Сколько не встречаю обзоров, но никак пока не понял как развертывать приложение с существующим проектом из гита? В каждом руководстве create-project.
Я вообще клонирую мастер и делаю composer install и т.к.
Fantyk
Думаю логично тут оставить ссылку на официальный yii2 docker образ.
antaresm Автор
Спасибо, ссылку добавил. Просто цель статьи была показать как создавать свои окружения в docker'e. Кроме того, в официальном докер образе все собрано в один контейнер (приложение и база), что не всегда удобно