@Danbka

Как правильно разрабатывать symfony приложение локально?

Есть symfony приложение, в котором используется "doctrine/mongodb-odm-bundle". Я его упаковал в контейнер, в котором установил все зависимости, в т.ч. ext-mongodb. В контейнере оно прекрасно запускается.

Чтобы писать код локально и не получать в каждом файле ошибки "class not found" я хочу установить зависимости из composer.json, для этого запускаю

composer install --ignore-platform-reqs

и ожидаю, что мне не потребуется устанавливать mongodb локально, но получаю ошибку:

Executing script cache:clear [KO]
 [KO]
Script cache:clear returned with error code 1
!!  
!!  In DebugClassLoader.php line 296:
!!                                                                                 
!!    Class "MongoDB\Driver\Monitoring\CommandSubscriber" not found while loading  
!!     "Doctrine\Bundle\MongoDBBundle\APM\StopwatchCommandLogger".                 
!!                                                                                 
!!  
!!  
Script @auto-scripts was called via post-install-cmd


Если php расширение mongodb поставить локально, то все работает.

Как быть? Как правильно разрабатывать контейнеризированное приложение локально без необходимости устанавливать все зависимости на хост?
  • Вопрос задан
  • 174 просмотра
Решения вопроса 1
Я использую для локальной разработки docker compose.
В его конфигурационном файле собираю все нужные контейнеры (PHP, MySQL, Rabbit, Mongo и т.д.) в сеть. Для PHP делаю два контейнера из разных образов:
Один из образа php-fpm, это сам сервер.
Второй из образа php-cli, он используется как раз для всех консольных команд. Именню в него устанавливаю Composer.
Для того, чтобы не писать для запуска консольных команд постоянно это заклинание "docker compose run ...", я делаю Makefile, в котором прописываю часто-используемые команды.
И, набрав "make cc" на самом деле запускаю "docker-compose run --rm php-cli bin/console c:c"
Чтобы это всё работало без необходимости постоянно перезапускать docker-compose, я файлы проекта пробрасываю внутрь контейнеров не копированием, а через вольюм, и когда я буду их менять, они будут меняться и внутри контейнера. Так же подключаю прямо внутрь контейнера .env файл, чтобы все переменные окружения туда пробросились.
Я вам прямо закину кучу файлов из одного из своих старых проектов, может накопаете там идей каких-то для себя:
1. docker-compose.yml
version: '3.8'
services:
  # Поднимаю сразу реверс-прокси, чтобы пробросить всё наружу на нужный мне порт.m
  nginx:
    build:
      context: ./.docker/nginx
      dockerfile: Dockerfile.dev
    volumes:
      - ./:/app
    depends_on:
      - php-fpm
    ports:
      - "8080:80"

  php-fpm:
    build:
      context: ./.docker/php
      dockerfile: Dockerfile.fpm-dev
      args:
        IMAGE_ENV: dev
    volumes:
      # Вот тут вся магия) Мы просто подключаем файлы проекта в виде вольюма
      # Т.е. имеем доступ ко всем файлам и изнутри и снаружи контейнера. 
      # Внутри контейнера файлы будут видны по пути /app
      - ./:/app
    environment:
      # Даже XDEBUG можно пробросить для IDE
      XDEBUG_CONFIG: 'discover_client_host=true client_host=127.0.0.1 log_level=0 client_port=9003'
      PHP_IDE_CONFIG: "serverName=Docker"
    env_file:
      - .env.local
    depends_on:
      - mysql

  # Делаю отдельный контейнер для комманд-лайн утилит, 
  # чтобы не проще запускать консоль Symfony. Мне так удобнее.
  # Здесь будет всё практически как и у php-fpm, только без самого php-fpm процесса
  php-cli:
    build:
      context: ./.docker/php
      dockerfile: Dockerfile.cli-dev
      args:
        IMAGE_ENV: dev
    volumes:
      - ./:/app
      - composer:/root/.composer/cache
    environment:
      XDEBUG_CONFIG: 'discover_client_host=true client_host=127.0.0.1 log_level=0 client_port=9003'
      PHP_IDE_CONFIG: "serverName=Docker"
    env_file:
      - .env.local
    depends_on:
      - mysql

  mysql:
    build:
      context: ./.docker/db
      dockerfile: Dockerfile
    volumes:
      - mysql:/var/lib/mysql
    env_file:
      - .env.local
    environment:
      MYSQL_ROOT_HOST: '%'  # needs to be enclosed with quotes
    ports:
      - "6603:3306"

# Тут ещё два дополнительных вольюма. Один для кэша composer, а второй для файлов базы данных, чтобы она не убивалась при перезапуске наших контейнеров. Убивать мы её будем только сознательно. если нам надо её очистить.
volumes:
  composer:
  mysql:


2. Все три докерфайла
Файлы с конфигурациями, которые будут копироваться внутри докерфайлов, кидать не буду, у вас всё своё будет в любом случае.

Dockerfile.dev - для nginx.
# Образ Nginx
FROM nginx:alpine

# Копируем файл с настройками
COPY ./task/default.conf /etc/nginx/conf.d/default.conf

# Устанавливаем рабочую директорию
WORKDIR /app


Dockerfile.fpm-dev - для сервера php-fpm
# Образ php-fpm
FROM php:8.2-fpm

ARG IMAGE_ENV

# Устанавливаем нужные пакеты и расширения
RUN apt-get update && apt-get install -y -qq libpq-dev unzip libxml2-dev libicu-dev libonig-dev zlib1g-dev libpng-dev librabbitmq-dev \
    && docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd && docker-php-ext-install pdo_mysql && \
    docker-php-ext-configure intl && docker-php-ext-install intl && \
    pecl install xdebug amqp && rm -rf /tmp/pear && docker-php-ext-enable xdebug amqp && \
    rm -rf /var/lib/apt/lists/*

# Use the default development configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

# Копируем файл с настройками xdebug
COPY ./php.d/${IMAGE_ENV}/default.ini /usr/local/etc/php/conf.d/default.ini
COPY ./php.d/${IMAGE_ENV}/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini


# Создаем пользователя app, чтобы не работать под рутом
RUN adduser --disabled-password --gecos '' --uid 1000 app
USER app

# Устанавливаем рабочую директорию
WORKDIR /app


Dockerfile.cli-dev - это наш консольный php для запуска консольных команд. Тут практически то же самое, плюс тот самый Composer, ради которого это всё и писалось)
# Образ php-cli
FROM php:8.2-cli

ARG IMAGE_ENV

# Устанавливаем нужные пакеты и расширения
RUN apt-get update && apt-get install -y -qq git unzip libpq-dev libxml2-dev libicu-dev librabbitmq-dev && \
    docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd && docker-php-ext-install pdo_mysql && \
    docker-php-ext-configure intl && docker-php-ext-install intl && \
    pecl install xdebug amqp && rm -rf /tmp/pear && docker-php-ext-enable xdebug amqp && \
    rm -rf /var/lib/apt/lists/*

# Use the default development configuration
RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini"

# Копируем файл с настройками xdebug
COPY ./php.d/${IMAGE_ENV}/default.ini /usr/local/etc/php/conf.d/default.ini
COPY ./php.d/${IMAGE_ENV}/xdebug.ini /usr/local/etc/php/conf.d/xdebug.ini

# Качаем и устанавливаем composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/bin --filename=composer --quiet

# Если всё же будете работать в контейнере под рутом, то заставляем composer работать под рутом
# ENV COMPOSER_ALLOW_SUPERUSER 1

# Создаем пользователя app, чтобы не работать под рутом
RUN adduser --disabled-password --gecos '' --uid 1000 app
USER app

# Устанавливаем рабочую директорию
WORKDIR /app


3. И далее звезда шоу - Makefile с кучей разных скриптов, облегчающих жизнь.
make init - чистая сборка проекта, тут можно очищать базу и загружать в нее фикстуры
make up - просто запуск проекта, без очистки, перед началом обычного рабочего дня.
make down - остановка проекта
make cc - очистка кэша Symfony.
И т.д. и т.п.
# Если надо подключить shell переменные, то создаём тут же ..env.local файл и делаем.
include .env.local
export

# Поддержка возможности запускать шелл-скрипты
SHELL:=/bin/bash

# Кэш
c: cache-clear cache-warmup
cc: cache-clear
cw: cache-warmup
cache-clear:
	docker-compose run --rm php-cli bin/console c:c
cache-warmup:
	docker-compose run --rm php-cli bin/console c:w

up: docker-up
down: docker-down
restart: docker-down docker-up
init: docker-down init-common
reset: docker-down-clear init-common
init-common: clear docker-pull docker-build docker-up app-init
test: test
test-coverage: test-coverage
test-unit: test-unit
test-unit-coverage: test-unit-coverage

# Если в контейнере другой пользователь, то будут ошибки доступа при редактировании файлов.
# Поэтому надо сделать chown и chmod для папки var (кэш и логи)
chown:
	sudo chown -R 1000:1000 . # Тут указываем свои данные пользователя с хоста
	sudo chmod -R 777 ./var/

docker-up:
	docker-compose up -d

docker-down:
	docker-compose down --remove-orphans

docker-down-clear:
	docker-compose down -v --remove-orphans

docker-pull:
	docker-compose pull

docker-build:
	docker-compose build

app-init: composer-install app-wait-db app-migrations ready

clear:
	docker run --rm -v ${PWD}:/app --workdir=/app alpine rm -f .ready

ready:
	docker run --rm -v ${PWD}:/app --workdir=/app alpine touch .ready

test:
	docker-compose run --rm php-cli php bin/phpunit

test-coverage:
	docker-compose run --rm php-cli php bin/phpunit --coverage-clover var/clover.xml --coverage-html var/coverage

test-unit:
	docker-compose run --rm php-cli php bin/phpunit --testsuite=unit

test-unit-coverage:
	docker-compose run --rm php-cli php bin/phpunit --testsuite=unit --coverage-clover var/clover.xml --coverage-html var/coverage

composer-install:
	docker-compose run --rm php-cli composer -V
	docker-compose run --rm php-cli composer install

app-create-db:
	docker-compose run --rm php-cli ./bin/console doctrine:database:create

app-wait-db:
	#docker-compose exec lkui-mysql mysqladmin --user=root --password=password ping --silent --wait=60 &> /dev/null
	#sleep 20
	until docker-compose exec -T mysql mysqladmin ping -u root -P ${MYSQL_TCP_PORT} -p${MYSQL_ROOT_PASSWORD} | grep "mysqld is alive" ; do >&2 echo "MySQL is unavailable - waiting for it... " ; sleep 5 ; done

app-migrations:
	docker-compose run --rm php-cli ./bin/console doctrine:migrations:migrate --no-interaction

app-fixtures:
	docker-compose run --rm php-cli ./bin/console doctrine:fixtures:load --no-interaction

migration:
	docker-compose run --rm php-cli ./bin/console make:migration

migrate:
	docker-compose run --rm php-cli ./bin/console doctrine:migrations:migrate #--no-interaction

fixtures:
	docker-compose run --rm php-cli ./bin/console doctrine:fixtures:load
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
Поднять докер локально и запускать composer в нём.
Ответ написан
vabka
@vabka
Токсичный шарпист
Как правильно разрабатывать контейнеризированное приложение локально без необходимости устанавливать все зависимости на хост?

Можно использовать devcontainer. Поднимаешь контейнер со всеми зависимостями, внутрь vs code remote, а все исходники - в Volume
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы