【问题标题】:RUN composer install and npm install in every build of a container在容器的每个构建中运行 composer install 和 npm install
【发布时间】:2021-03-26 16:41:15
【问题描述】:

我正在尝试创建一个安装了 npm 和 composer 的 php-apache 容器,并在每个构建中运行 composer installnpm 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,也会出现同样的错误。

我可以在 docker 中运行命令,但我想自动化

【问题讨论】:

  • 最好像你展示的那样在你的 Dockerfile 中 RUN npm install。这意味着COPY将您的应用程序代码放入映像中,而不是将其绑定安装在volumes: 中。将映像中的 ENTRYPOINT 更改为 CMD 也会使 command: 覆盖工作,但它会更改容器以运行构建时命令而不是 HTTP 守护进程。
  • 您尝试检查什么原因导致该错误?

标签: docker npm docker-compose composer-php


【解决方案1】:

我认为您跟踪您的方法不正确。这些命令是映像构建过程的一部分,因此它们应该是 Dockerfile 的一部分。

并且构建过程发生在卷可用之前(容器未运行,因此不可能依赖这些)。您需要做的是在运行 composer install 之前将必要的文件复制到您正在构建的映像中。

利用multi-stage build 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。我正在使用 Laravel。所以我应该复制 vendor 和 node_modules 以避免在每个构建中再次安装所有包?
  • 不,您只复制我在上面Dockerfile 中显示的文件。 composer.jsoncomposer.lock,然后是 package.jsonpackage-lock.jsonvendornode_modules 是在图像创建的,而不是从您的计算机复制的。
  • 您说您将网络服务器指向/var/www/html/public。你是在哪里做的?
  • 它不在里面。您的网络服务器配置也不包含在您的问题中。无论您在哪里配置网络服务器(在您的情况下为 apache),您都将指向该目录。
【解决方案2】:

您可以尝试将您的作曲家安装放在您的入口点中。

我通常会为此使用文件。你可能想试试这个。

入口点.sh

#!/bin/sh
set -e

php /usr/local/bin/composer install

exec "$@"

在你的 dockerfile 中

# ...

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 中运行命令,因为我需要我指向的音量
  • 也许你应该试一试。使用入口点时,卷应该存在。
猜你喜欢
  • 2016-12-13
  • 1970-01-01
  • 2015-11-09
  • 2018-03-28
  • 2023-03-14
  • 1970-01-01
  • 2021-12-14
  • 1970-01-01
  • 2016-05-03
相关资源
最近更新 更多