如何在容器中安装Composer依赖?

7

我的目标

我正在尝试使用Docker将这个基于CodeIgniter 4构建的php应用程序进行容器化。该应用程序具有以下依赖项,通常通过composer安装:

"require": {
    "php": "^7.3 || ^8.0",
    "myth/auth": "dev-develop",
    "codeigniter4/framework": "^4.1",
    "codeigniter4/translations" : "^4.0"
},

项目结构如下所示:
docker
    database
    nginx
    php-fpm
    docker-compose.yml
src
    ... app files ...
tests
composer.json

docker-compose.yml文件中,我有一个名为php-fpm的服务,它会将所有应用文件复制到/var/www/html目录下,这是nginx公共目录。
php-fpm:
  container_name: boilerplate_app
  build:
    context: ./php-fpm
  volumes:
    - ../src:/var/www/html

我需要做的是使用composer安装应用程序所需的依赖库。 我尝试过的方法 最初,我打算在php-fpm文件夹中的Dockerfile中完成此操作:
FROM php:8.0.2-fpm-alpine

RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mysqli    

# Install Composer
COPY --from=composer /usr/bin/composer /usr/bin/composer

RUN composer require --working-dir=../../ app/boilerplate

COPY ./config/php.ini /usr/local/etc/php/

CMD ["php-fpm"]

EXPOSE 9000

本质上,我在容器中安装了composer,然后尝试从项目根目录下的composer.json文件中安装所有依赖项。

问题

不幸的是,当我运行命令docker-compose up --build时,会出现以下错误:

当前目录中没有composer.json(./composer.json),这可能是以下异常的原因。

似乎容器无法访问composer.json文件,或者我在路径参数working-dir方面做错了什么。

所以,我想到了另一个解决方案,在docker-compose.yml中定义另一个容器来分离composer实例:

composer:
  image: composer:2.0.9
  command: ["composer", "require", "app/boilerplate"]
  volumes:
    - /var/www/html

应该从根目录读取 composer.json 文件,然后通过命令 composer require app/boilerplate 安装所有依赖项,但是又出现了相同的错误:

Composer 在 /app 中找不到 composer.json 文件。

这是完整的 docker-compose.yml 文件:

version: '3'

services:
  php-fpm:
    container_name: boilerplate_app
    build:
      context: ./php-fpm
    volumes:
      - ../src:/var/www/html

  nginx:
    container_name: boilerplate_nginx
    build:
      context: ./nginx
    volumes:
      - ../src:/var/www/html
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/sites/:/etc/nginx/sites-available
      - ./nginx/conf.d/:/etc/nginx/conf.d
    ports:
      - "8881:80"
      - "8882:443"
    depends_on:
      - php-fpm

  database:
    container_name: boilerplate_db
    build:
      context: ./database
    environment:
      - MYSQL_DATABASE=boilerplate_db
      - MYSQL_ROOT_PASSWORD=test
      - MYSQL_USER=foo
      - MYSQL_PASSWORD=test
    volumes:
      - ./database/data.sql:/docker-entrypoint-initdb.d/data.sql

  composer:
    image: composer:2.0.9
    command: ["composer", "require", "app/boilerplate"]
    volumes:
      - /var/www/html

这是composer.json文件:

{
    "name": "app/boilerplate",
    "description": "CodeIgniter4 Boilerplate based on AdminLTE 3 with user management, roles, permissions, ...",
    "require": {
        "php": "^7.3 || ^8.0",
        "myth/auth": "dev-develop",
        "codeigniter4/framework": "^4.1",
        "codeigniter4/translations" : "^4.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^9.1",
        "fakerphp/faker": "^1.13"
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "autoload": {
        "psr-4": {
            "app\\boilerplate\\": "src"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "post-update-cmd": [
          "@composer dump-autoload"
        ],
        "test": "phpunit --colors=always -vvv"
    }
}

我该怎么修复这个问题?
文件夹结构图像预览: enter image description here

你尝试过什么来使它工作?我会假设在构建镜像时运行了composer require,而直到你运行它之前,你的应用程序数据才不会出现在该镜像中。 - Nico Haase
@Nico Haase 我尝试在 php-fpm 内部运行 composer require,因为它是将应用程序文件移动到 nginx 目录的容器。我认为必须在该容器中执行 composer:1. 复制应用程序文件 2. 安装依赖项。 - sfarzoso
是的,在将您的应用程序数据添加到容器之后再执行该操作。 - Nico Haase
@Nico Haase,我已经做了这个。问题在于composer.json文件位于app目录中,而Dockerfile无法运行composer require命令。 - sfarzoso
是的,正如我所想:在构建容器期间运行 composer require 是不起作用的,因为您稍后会挂载卷。 - Nico Haase
@NicoHaase,您能否尝试将此样板文件docker化:https://github.com/agungsugiarto/boilerplate 我做错了什么,但我不明白如何修复它。 - sfarzoso
1个回答

7

看起来你有几个问题。

首先,你依赖于绑定挂载。但是这些只在运行时可用,而不是在构建时可用。

所以,在运行composer install之前,你需要将composer.*文件复制到你的docker镜像中。

然后,你会遇到麻烦,因为你将构建上下文移动到了项目的子目录中,这将导致从父目录复制文件有问题。

首先,改变构建上下文,只需引用需要构建项目的Dockerfile

services:
  php-fpm:
    container_name: boilerplate_app
    build:
      dockerfile: ./php-fpm/Dockerfile
      context: .
    volumes:
      - ./src:/var/www/html
# the rest of your docker-compose.yml

在这之后,你需要调整你的 Dockerfile 以考虑现在它的构建上下文向上了一个目录,并添加所需的 COPY 语句。
我还更新了 Dockerfile 以利用 Docker 多阶段构建过程。
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 ./

# This are production settings, I'm running with 'no-dev', adjust accordingly 
# if you need it
RUN composer install --ignore-platform-reqs --prefer-dist --no-scripts --no-progress --no-interaction --no-dev --no-autoloader

RUN composer dump-autoload --optimize --apcu --no-dev

FROM php:8.0.2-fpm-alpine

WORKDIR /var/www/html

RUN docker-php-ext-install pdo_mysql
RUN docker-php-ext-install mysqli

COPY php-fpm/config/php.ini /usr/local/etc/php/

COPY --from=composer_stage /var/www/html /var/www/html

COPY src src/

CMD ["php-fpm"]

EXPOSE 9000

我还添加了一个COPY语句,用于复制您的项目的src目录,否则构建的镜像将只包含您的composer依赖项和其他内容。这样,您的应用程序就是一个完全自包含的容器(无意冒犯)。

您还应确保挂载src点。由于这些点与镜像构建没有实际关系,而仅在您实际运行容器时使用,因此我没有仔细审查它们。

将应用程序Docker化/容器化首先要构建正确的镜像,然后需要创建适当的使用文档。


以上是一个“可工作的示例”。您可以使用它来修复您的版本。 - yivi
我尝试了但无法运行它,错误显示Dockerfile不是有效的镜像。您能否上传代码? - sfarzoso
1
我根据你的项目结构和这个想法,快速搭建了一个“概念验证”链接。我刚刚尝试了docker-compose build,它可以成功构建。你可以将其作为修复自己项目的起点。 - yivi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接