php - docker-compose 覆盖容器中的目录

标签 php docker docker-compose composer-php dockerfile

上下文

我最近设置了一个 PHP 应用程序,以便在连接到不同容器中的数据库的 Docker 容器中工作。

在生产中,我们使用单个容器环境,因为它仅连接到托管在其他地方的数据库。尽管如此,为了简化开发工作流程,我们决定在本地使用两个容器和 docker-compose。

问题

我们遇到的问题是,第一次通过 docker-compose up --build 构建并运行应用程序时,Composer 的 vendor 目录在容器,即使我们在 Dockerfile 中有一个特定的 RUN Composer install 行。一旦容器运行,我们就必须在容器内执行composer install

找到解决方案

经过大量搜索后,我们发现有两种可能的解决方案:

  1. 将 Docker 镜像的默认命令更改为以下内容:
bash -c "composer install && /usr/sbin/apache2ctl -D FOREGROUND"
  • 或者简单地通过 docker-compose 的 command 将容器的默认命令覆盖到上面的命令.
  • 不同之处在于,如果我们通过 docker-compose 覆盖该命令,则在将应用程序部署到我们的服务器时,它将无缝运行,因为它应该,但是当更改 Dockerfile 中的默认命令时每次我们部署时,它都会遭受 1 分钟左右的停机时间。

    这在此过程中有所帮助:

    1. Running composer install within a Dockerfile

    一些(可能是错误的)结论

    我的结论是,那一分钟的停机时间是由于容器必须在运行 Apache 服务器之前通过 Composer 安装所有依赖项,而不是简单地运行服务器。

    此外,我从所有研究中得出的另一个结论是,docker-compose up --build 不会安装 Composer 依赖项的原因是因为我们在docker-compose.yml 覆盖容器中的目录。

    这些有帮助:

    1. https://stackoverflow.com/a/38817651/4700998

    2. https://stackoverflow.com/a/48589910/4700998

    实际问题

    我希望有人能够阐明这一切,因为我不太明白到底发生了什么 - 为什么运行 docker-compose 不会安装 PHP 依赖项,但包括 composer install 在默认命令中会以及为什么将 composer install 添加到 docker-compose.yml 更好。此外,卷是如何造成这一切的,它是所有麻烦的真正原因吗?

    我们当前的 docker 文件如下所示:

    FROM php:7.1.27-apache-stretch
    
    ENV DEBIAN_FRONTEND=noninteractive
    
    # install some stuff, PHP, Apache, etc.
    
    WORKDIR /srv/app
    COPY . .
    
    RUN composer install
    
    RUN service apache2 restart
    
    EXPOSE 80
    
    CMD ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
    

    我们当前的docker-compose.yml如下所示:

    version: '3'
    services:
      database:
        image: mysql:5.7
        container_name: container-cool-name
        command: mysqld --user=root --sql_mode=""
        ports:
          - "3306:3306"
        volumes:
          - ./db_backup.sql:/tmp/db_backup.sql
          - ./.docker/import.sh:/tmp/import.sh
        environment:
          MYSQL_DATABASE: my_db
          MYSQL_USER: my_user
          MYSQL_PASSWORD: password
          MYSQL_ROOT_PASSWORD: test
    
      app:
        build:
          context: .
          dockerfile: Dockerfile
        image: image-name
        command: bash -c "composer install && /usr/sbin/apache2ctl -D FOREGROUND"
        ports:
          - 8080:80
        volumes:
          - .:/srv/app
        links:
          - database:db
        depends_on:
          - database
        environment:
          DB_HOST: db
          DB_PORT: 3306
          DB_DATABASE: my_db
          DB_USER: my_user
          DB_PASSWORD: password
    

    最佳答案

    您在 Dockerfile 中安装的第一个 composer 工作正常,并且您生成的镜像具有 vendor/ 等。

    但是稍后您从该镜像创建一个容器,并且该容器在执行时整个目录被主机目录挂载替换:

    volumes:
          - .:/srv/app
    

    因此,您的 docker 镜像同时包含您的文件和已安装的供应商文件,但随后您将项目目录替换为主机上没有供应商文件的目录,最终结果看起来像是从未完成构建。

    我的建议是:

    • 不要将第二个命令构建添加到Dockerfile
    • 在容器中挂载单个文件夹,即不是 .:/srv/app,而是 ./src:/srv/app/src 等。
    • 或者,映射整个文件夹,但将供应商文件从镜像/容器复制到您的主机
    • 或者使用一些第三方实用程序来解决这个问题,例如http://docker-sync.io或许多其他

    关于php - docker-compose 覆盖容器中的目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56690385/

    相关文章:

    php - Ajax 是 "Getting"而不是 "Posting"

    php - Azure SAS 容器 PHP

    docker - Hyperledger Fabric 更改 fabcar 示例

    docker-compose 仅​​适用于某些容器

    php - Highcharts 中柱形图的 3 级向下钻取?

    docker - Visual Studio Team Service 失败任务 Docker 构建

    docker - 将 Docker 容器限制为单个 cpu 核心

    mongodb - 如何在 docker-compose 之后运行 Mongo shell 命令?

    docker - docker run vs. docker-compose up:相同的图像,不同的结果

    javascript - 我的“完成”按钮不知何故转到了空白页面,除非刷新 -ajax,否则删除将不起作用