Докер: Как совместно использовать один и тот же код приложения между несколькими контейнерами / сервисами (например, PHP-FPM и NGINX) - PullRequest
0 голосов
/ 23 января 2019

ТЛ; др

  • Код приложения требует шага сборки (получение зависимостей)
  • нескольким контейнерам нужен один и тот же "встроенный" код

В: Какова хорошая стратегия / рабочий процесс для архивирования с помощью docker / docker-compose.

Long

Мы находимся в процессе стыковки приложения PHP с несколькими компонентами (контейнерами / службами), например,

  • Рабочие узлы (процессы PHP поддерживаются через супервизор)
  • Планировщик (управление рабочими и запуск повторяющихся задач в cron)
  • PHP-FPM / Nginx (веб-интерфейс)

Сервисы определены в файле docker-compose. Во время разработки мы монтируем код приложения через том из каталога на хосте в каждом контейнере, так что мы видим изменения «немедленно» в каждом сервисе ( Пример ). Жизнь была хорошей.

Сейчас мы настраиваем среду CI / CD на основе Jenkins, которая должна создавать (+ тестировать) контейнеры и нажмите на реестр позже. Поскольку "смонтировать с хоста" больше невозможно, мне сейчас интересно что лучше всего сделать так, чтобы код приложения находился в каждом контейнере.

Две вещи в нашей настройке делают это imho особенно сложным:

  1. у нас есть несколько контейнеров, которым нужен один и тот же код приложения
  2. «Артефакт сборки» не является отдельным двоичным файлом с само контейнером (как, например, с go) но "весь наш код + установленные зависимости" ==> "много файлов" (медленно ...)
  3. есть этап сборки, для которого требуется программное обеспечение, которое не требуется в конечном образе

Решение для «3». обычно: Используйте многоэтапные сборки. Мы делаем это. Но: все примеры там похоже, предполагается, что встроенный код будет использоваться только в одном другом контейнере (что в нашем случае неверно, см. 1).

Что мы сейчас делаем

  • структура папок
application-code/
  .docker/
    builder/
      Dockerfile
    php-fpm/
      Dockerfile
    docker-compose.yml
  build.sh
  index.php
  • ввести дополнительный контейнер "builder", который "собирает" приложение (получает «весь» код приложения в качестве контекста сборки; запускает «установку композитора»)
# ./builder/Dockerfile
COPY ./ /codebase
RUN cd /codebase && composer install
  • «копировать» из этого компоновщика в каждый контейнер, для которого требуется код приложения, например, через
# ./php-fpm/Dockerfile
ARG APP_CODE_PATH="/var/www/current"
COPY --from=builder --chown=www-data /codebase ${APP_CODE_PATH}
  • организован с помощью docker-compose
# ./docker-compose.yml
version: '3.7'

services:
  builder-ci:
    image: builder
    build:
      # ../ contains the "raw" application code
      context: ../
      dockerfile: ./.docker/builder/Dockerfile

    php-fpm:
      build:
        context: .
        dockerfile: ./php-fpm/Dockerfile
        args:
          - APP_CODE_PATH=/var/www/current
  • сборка через
# build.sh
## build builder
docker-compose -f ./.docker/docker-compose.yml --project-directory ./.docker build builder
## build the rest
docker-compose -f ./.docker/docker-compose.yml --project-directory ./.docker build --parallel

Pro

  • "меньших" изображения (в php-fpm не будет установлен композитор)
  • код приложения создается только один раз, а затем копируется поверх

Contra

  • контейнер конструктора не служит никакой другой цели, кроме как "встроенный" ==> не чувствует себя чистым
  • сборка "строителя" должна быть сделана до того, как будет построен любой другой контейнер
    • это означает, что у нас есть дополнительный

Альтернативы

  • не используйте контейнер конструктора, но "включите" этап сборки, например, в контейнер "Планировщик" с помощью многоэтапных сборок (поэтому в конечном изображении мы не получим композитора)
    • get избавился от "builder" - но теперь все другие службы зависят от "Scheduler" ==> чувствует себя еще более грязным
  • используйте том, чтобы поделиться кодом
    • нам не нужно «копировать» файлы в изображениях, мы можем просто «смонтировать том» ==> чувствует себя «чистым» / нет «дублирования файлов» (Сначала я подумал, что это действительно хороший подход ...)
    • НО:
    • вы не можете заполнять тома во время сборки, поэтому вам нужно "запустить" контейнер, чтобы получить код приложения "в" контейнере ==> у нас неожиданно появился не только контейнер компоновщика, но нам также нужно «запустить» его для заполнения тома
    • контейнеры больше не являются "самодостаточными", то есть вытащить "просто планировщик" из реестра не получится - мы ДОЛЖНЫ также иметь объем на месте И его должен заполнить строитель ==> оркестровка становится более сложной
    • том не является эфемерным, то есть он будет содержать «старый» код приложения до его обновления ==> это может привести к путанице и неожиданному поведению

Ссылки

1 Ответ

0 голосов
/ 23 января 2019

Беспокойство о количестве шагов не должно быть дискуссией. Вы должны беспокоиться о том, содержит ли изображение то, что вам нужно, без какого-либо шума.

Одна из вещей, которой явно не хватает вашему методу компоновщика, - это то, что вы продвигаете кодовую базу к производству, даже если вы запустили composer только с install. Чтобы запустить в производство кодовую базу производственного уровня, по крайней мере, вам нужно запустить composer install --prefer-dist --no-dev -o до:

  • исключение файлов, исключенных в .gitattributes с использованием --prefer-dist (это значение по умолчанию, поскольку компоновщик стабилен)
  • , исключив загрузку require-dev с помощью --no-dev
  • путем оптимизации файлов автозагрузчика с помощью -o

Эта команда полностью отличается от той, которая использовалась для запуска ваших тестов.

Конвейер по умолчанию при работе с контейнеризацией вашей кодовой базы будет:

  • build: оформить заказ, установить композитор и разрешить его повторное использование в следующих шагах или создать «образ тестирования»
  • test: запустить тесты и включить или отделить покрытие (в одновременный шаг)
  • prepare: повторно использовать файлы сборки и запустить установку composer с необходимыми рабочими флагами
  • image : создать изображение из предыдущего шага

Лично я считаю, что ответы на ваш вопрос весьма самоуверенны. Может быть, мой подход, используемый при работе с kubernetes, помогает.

...