Я пытаюсь создать контейнер php-apache с установленными npm и composer и запускаю composer install, npm install в каждой сборке, но получаю ошибки.
# Dockerfile
FROM php:7.4-apache
RUN apt-get -y update && apt-get upgrade -y
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
npm \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
# Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
# Enable apache modules
RUN a2enmod rewrite headers
EXPOSE 80
#RUN composer install
#RUN npm install
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
# docker-compose.yml
version: "3"
services:
painel-admin:
build:
context: ./bin/painel-admin
container_name: 'painel-admin'
command: >
sh -c "php /usr/local/bin/composer install"
restart: 'always'
ports:
- "81:80"
- "82:443"
volumes:
- ${DOCUMENT_ROOT-..}:/var/www/html
- ${PHP_INI-./config/php/php.ini}:/usr/local/etc/php/php.ini
- ${VHOSTS_DIR-./config/vhosts}:/etc/apache2/sites-enabled
- ${LOG_DIR-./logs/apache2}:/var/log/apache2
ошибка журнала:
Действие «-D FOREGROUND sh -c php /usr/local/bin/composer install» завершилось неудачно.
Та же ошибка, если я попытаюсь с npm install.
Я могу запускать команды внутри докера, но я хочу автоматизировать это
Что вы пытались проверить на причину этой ошибки?


Вы можете попробовать поставить установку композитора в точку входа.
Я бы обычно использовал файл для этого. Возможно, вы захотите попробовать это.
точка входа.sh
#!/bin/sh
set -e
php /usr/local/bin/composer install
exec "$@"
и в вашем докерфайле
# ...
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
Что приведет к чему-то вроде этого.
/usr/local/bin/entrypoint.sh /usr/sbin/apache2ctl -D FOREGROUND
Поскольку последняя строка точки входа — exec "$@", она примет все параметры, переданные в entrypoint.sh, и выполнит ее.
Спасибо за ответ Жюльен. Но я думаю, что мне нужно запустить команду в docker-compose.yml, потому что мне нужен том, который я там указал
Может, тебе стоит попробовать. Тома должны существовать, когда используется точка входа.
Я думаю, что вы следуете за неправильным подходом. Эти команды являются частью процесса создания образа, поэтому они должны быть частью вашего Dockerfile.
И процесс сборки происходит до того, как тома станут доступны (контейнер не запущен, поэтому от них невозможно зависеть). Что вам нужно сделать, так это скопировать необходимые файлы в образ, который вы создаете, прежде чем запускать composer install.
Более разумным подходом, использующим многоэтапную сборку dockerfiles, будет:
## First stage. Copy project files and run composer
FROM composer:2 as composer_stage
RUN rm -rf /var/www && mkdir -p /var/www/html
WORKDIR /var/www/html
COPY composer.json composer.lock symfony.lock .env ./
COPY public public/
RUN composer install --ignore-platform-reqs --prefer-dist --no-scripts --no-progress --no-suggest --no-interaction --no-dev --no-autoloader
RUN composer dump-autoload --optimize --apcu --no-dev
COPY bin bin/
COPY config config/
COPY src src/
RUN composer run-script $NODEV post-install-cmd; \
chmod +x bin/console;
## Second stage. Build NPM dependencies
FROM node:12 as npm_builder
COPY --from=composer_stage /var/www/html /var/www/html
WORKDIR /var/www/html
COPY yarn.lock package.json webpack.config.js ./
COPY assets ./assets
RUN yarn install
RUN yarn encore prod
# I'm using yarn here, but using npm would be similar, depending on how your project is setup
# RUN npm install
# RUN npm run build # if necessary and the command exists in your project
## Third stage, mostly copied from your original Dockerfile
FROM php:7.4-apache
RUN apt-get -y update && apt-get upgrade -y
COPY --from=npm_builder /var/www/html /var/www/html
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
npm \
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
&& docker-php-ext-install -j$(nproc) gd
# Enable apache modules
RUN a2enmod rewrite headers
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
Таким образом, ваш окончательный результирующий образ не будет включать никаких зависимостей разработки. Образ предназначен в основном для производства, поэтому его можно собрать и развернуть.
Чтобы запустить его локально во время разработки, вы просто запускаете тот же образ локально с нужными точками монтирования тома. Вам нужно будет только перестроить образ всякий раз, когда ваши зависимости изменяются или обновляются.
Вам нужно будет настроить пути, чтобы они соответствовали желаемой конфигурации (я создаю проект на /var/www/html и указываю веб-серверу на /var/www/html/public, но вы можете легко изменить их).
Поскольку вы используете образ, который включает в себя как веб-сервер, так и среду выполнения PHP, это должно быть так.
Спасибо за ваш ответ @yivi. я использую Ларавель. так что я должен скопировать vendor и node_modules, чтобы избежать повторной установки всех пакетов в каждой сборке?
Нет, вы копируете только те файлы, которые я показываю в Dockerfile выше. composer.json и composer.lock, а затем package.json и package-lock.json. vendor и node_modules создаются в образе, а не копируются с вашего компьютера.
вы сказали, что указали веб-сервер на /var/www/html/public. Где ты это сделал?
Это не там. Конфигурация вашего веб-сервера также не включена в ваш вопрос. Где бы вы ни настраивали свой веб-сервер (в вашем случае apache), вы должны указывать на этот каталог.
Было бы лучше, если бы вы
RUN npm installв своем Dockerfile, как вы показываете. Это означало быCOPYвключение кода вашего приложения в образ, а не монтирование его вvolumes:. ИзменениеENTRYPOINTв изображении наCMDтакже заставит работать переопределениеcommand:, но это изменит контейнер для запуска команды времени сборки вместо демона HTTP.