Как настроить Docker для PHP-разработки в команде: опыт Бишкека (2016)
Коротко: docker-compose.yml с сервисами nginx:1.10, php:7.0-fpm, mysql:5.7, redis:3.2. Маунтинг кода как volume. docker-compose up -d — и всё работает идентично у всех членов команды. На слабом интернете (что актуально для Кыргызстана): кэшируйте образы локально, используйте .dockerignore для ускорения сборки.
Проблема до Docker
Наша команда из 4 разработчиков в Бишкеке:
- Разработчик 1: MacBook, MAMP, PHP 5.6
- Разработчик 2: Ubuntu, установленный PHP 7.0 вручную
- Разработчик 3: Windows, XAMPP, PHP 7.1
- Разработчик 4: Ubuntu, OpenServer
Результат: «У меня работает» несколько раз в месяц. Особенно с кодировкой (UTF-8 vs windows-1251 в XAMPP) и версиями PHP.
docker-compose.yml
# docker-compose.yml
version: '2'
services:
nginx:
image: nginx:1.10-alpine
container_name: project_nginx
ports:
- "80:80"
volumes:
- .:/var/www/html:cached
- ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- php
networks:
- app
php:
build:
context: ./docker/php
dockerfile: Dockerfile
container_name: project_php
volumes:
- .:/var/www/html:cached
environment:
APP_ENV: local
APP_DEBUG: "true"
DB_HOST: mysql
DB_PORT: 3306
DB_DATABASE: myproject
DB_USERNAME: myproject_user
DB_PASSWORD: secret
REDIS_HOST: redis
depends_on:
- mysql
- redis
networks:
- app
mysql:
image: mysql:5.7
container_name: project_mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: rootsecret
MYSQL_DATABASE: myproject
MYSQL_USER: myproject_user
MYSQL_PASSWORD: secret
volumes:
- mysql_data:/var/lib/mysql
- ./docker/mysql/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
command: >
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--innodb-buffer-pool-size=256M
networks:
- app
redis:
image: redis:3.2-alpine
container_name: project_redis
networks:
- app
networks:
app:
driver: bridge
volumes:
mysql_data:
docker/php/Dockerfile
FROM php:7.0-fpm
# Системные зависимости
RUN apt-get update && apt-get install -y \
git \
unzip \
libmcrypt-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& rm -rf /var/lib/apt/lists/*
# PHP расширения
RUN docker-php-ext-configure gd --with-freetype-dir=/usr --with-jpeg-dir=/usr \
&& docker-php-ext-install \
pdo \
pdo_mysql \
mbstring \
gd \
opcache \
mcrypt \
zip
# Redis расширение
RUN pecl install redis-3.0.0 \
&& docker-php-ext-enable redis
# Composer
COPY --from=composer:1 /usr/bin/composer /usr/bin/composer
# PHP конфигурация для разработки
COPY php-dev.ini /usr/local/etc/php/conf.d/90-custom.ini
RUN useradd -u 1000 -m developer
USER developer
WORKDIR /var/www/html
docker/php/php-dev.ini
; Разработческие настройки
error_reporting = E_ALL
display_errors = On
log_errors = On
error_log = /dev/stderr
memory_limit = 256M
max_execution_time = 120
upload_max_filesize = 50M
post_max_size = 50M
; Часовой пояс: Бишкек
date.timezone = Asia/Bishkek
; OPcache: проверять изменения файлов каждые 0 секунд (разработка)
opcache.enable = 1
opcache.revalidate_freq = 0
opcache.validate_timestamps = 1
opcache.memory_consumption = 128
; mbstring: UTF-8 по умолчанию
mbstring.internal_encoding = UTF-8
mbstring.language = Russian
docker/nginx/default.conf
server {
listen 80;
server_name localhost;
root /var/www/html/public;
index index.php index.html;
charset utf-8;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS off;
include fastcgi_params;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
expires 1d;
access_log off;
}
location ~ /\. {
deny all;
}
# Увеличить лимит загрузки для файлов
client_max_body_size 50M;
}
.dockerignore для медленного интернета
# .dockerignore — исключить из Docker build context
# Критично при медленном интернете (скорость сборки)
.git
.gitignore
node_modules
vendor
storage/logs
storage/framework/cache
*.log
.env
.env.*
tests/
docs/
*.md
Makefile для удобства
# Makefile — короткие команды вместо длинных docker-compose ...
up:
docker-compose up -d
down:
docker-compose down
restart:
docker-compose restart
bash:
docker-compose exec php bash
artisan:
docker-compose exec php php artisan $(filter-out $@,$(MAKECMDGOALS))
composer:
docker-compose exec php composer $(filter-out $@,$(MAKECMDGOALS))
mysql:
docker-compose exec mysql mysql -u myproject_user -psecret myproject
logs:
docker-compose logs -f --tail=100
build:
docker-compose build --no-cache php
test:
docker-compose exec php php artisan test
migrate:
docker-compose exec php php artisan migrate
seed:
docker-compose exec php php artisan db:seed
.PHONY: up down restart bash artisan composer mysql logs build test migrate seed
# Использование:
make up
make bash
make artisan migrate
make artisan make:model Product
make composer require predis/predis
Решение проблемы с медленным скачиванием образов
# Проблема: в Бишкеке в 2016 скачать образ MySQL 5.7 (370 МБ) занимало 20–40 минут
# Решение: скачать образы один раз, перенести на флешке
# На компьютере с быстрым интернетом:
docker pull nginx:1.10-alpine
docker pull php:7.0-fpm
docker pull mysql:5.7
docker pull redis:3.2-alpine
# Сохранить в архив
docker save nginx:1.10-alpine php:7.0-fpm mysql:5.7 redis:3.2-alpine | gzip > docker-images.tar.gz
# ~640 МБ
# Перенести на флешке на другой компьютер:
docker load < docker-images.tar.gz
# Теперь docker-compose up не скачивает ничего
Результат после перехода на Docker
Через 2 месяца:
- Количество «у меня не работает» инцидентов: 4/месяц → 0
- Время онбординга нового разработчика: 4–6 часов → 45 минут
- Разница окружений между dev и prod: исчезла
- Случайные баги «только на Windows»: исчезли
Главный вывод: Docker в небольшой команде окупается за первый же месяц, даже если скорость интернета затрудняет первоначальную загрузку образов.