为 Laravel 创建多阶段 Docker 构建
发布时间 作者 Paul Redmond
从 Docker 版本 17.05 开始,多阶段构建可用,可帮助您优化 Dockerfile。使用多阶段构建是设置 Docker 构建管道的简洁方法,它简化了您在 CI/构建服务器上创建应用程序 Docker 镜像所需的条件。
如果您不熟悉多阶段构建,不用担心!让我总结一下,在多阶段构建之前,如果您想在应用程序的 `docker build` 过程中安装 Composer 依赖项和前端依赖项,您的 Docker 镜像将需要安装 Node.js 等必要依赖项以及 Composer PHP。
生成的 Dockerfile 和镜像可能相当混乱,维护起来很麻烦。
我在构建环境中采用的另一种方法是在运行构建的 *服务器* 上安装 Composer 和 Node 依赖项,然后复制工件,例如 `vendor/` 文件夹和生产就绪的 JS 和 CSS 构建文件。
以下是一个在 Docker 外部构建依赖项并复制它们的简化版本
#!/usr/bin/env bash set -e tag=${1:-latest} composer install \ --ignore-platform-reqs \ --no-interaction \ --no-plugins \ --no-scripts \ --prefer-dist yarn install && yarn production docker build -t my-app:$tag .
以上脚本是一个简化版本,用于说明如何准备 PHP 和前端依赖项,以及 `docker build` 如何将项目复制到镜像中。
通过使用多阶段构建,您不再需要安装这些依赖项或将它们全部塞到 `Dockerfile` 中,从而使最终镜像大小膨胀!
多阶段方法
以 Laravel 5.6 应用程序为例,我们可以开始在一个包含多个阶段的 Dockerfile 中构建生产就绪镜像的依赖项。
设置
如果您正在学习,请使用以下命令从命令行创建一个演示项目
laravel new multi-stage-demo cd multi-stage-demo # Create the Dockerfile filetouch Dockerfile # Generate the yarn lockfileyarn install git initgit add .git commit -m"First commit"
接下来,在 Laravel 应用程序的根目录中创建一个 `.dockerignore` 文件,内容如下
.git/vendor/node_modules/public/js/public/css/yarn-error.log
我们不会深入探讨 `.dockerignore` 文件的工作原理,但需要了解的是,它会阻止在 `docker build` 过程中复制定义的路径。忽略文件意味着在 `Dockerfile` 中的 `COPY` 或 `ADD` 指令期间,不会复制 `vendor/` 文件夹。
# copies the Laravel app, but skips the ignored files and pathsCOPY . /var/www/html
例如,忽略 `vendor/` 文件夹意味着我们从构建中获得 Composer 依赖项的原始构建。
Dockerfile
我们的应用程序 Dockerfile 将使用三个部分将应用程序构建的每个阶段分解
- 安装 Composer 依赖项
- 构建前端依赖项
- 从前两个阶段复制我们的应用程序代码和工件
阶段 1
第一阶段将是 Composer 依赖项。我们可以使用 官方 Composer 镜像 来首先在项目的根目录中 `Dockerfile` 中安装应用程序依赖项
## PHP Dependencies#FROM composer:1.7 as vendor COPY database/ database/ COPY composer.json composer.jsonCOPY composer.lock composer.lock RUN composer install \ --ignore-platform-reqs \ --no-interaction \ --no-plugins \ --no-scripts \ --prefer-dist
请注意 `FROM` 指令中的 `as vendor` 部分。稍后在 `Dockerfile` 中复制工件(`vendor/` 文件夹)时,我们将引用此名称。
Dockerfile 的第一阶段复制了 Laravel 在 `composer.json` 自动加载类映射中配置的几个必要的路径。接下来,它复制了 Composer JSON 和锁定文件。最后,它运行 `composer install` 来安装依赖项。
如果您重新运行构建,您可以查看镜像并查看 `composer install` 命令的结果
docker build -t ms-laravel-test -f docker/Dockerfile . docker run --rm -it ms-laravel-test bash # Inside the running containerbash-4.4# ls -la vendor/...bash-4.4# exit
第一阶段完成!此构建阶段安装了我们稍后将复制的所有必要的 `vendor/` 文件。
阶段 2
构建的下一阶段是使用 Yarn(或 NPM,如果那是您的选择)安装我们的应用程序前端依赖项。在第一阶段之后,将以下内容追加到 `Dockerfile`
## Frontend#FROM node:8.11 as frontend RUN mkdir -p /app/public COPY package.json webpack.mix.js yarn.lock /app/COPY resources/assets/ /app/resources/assets/ WORKDIR /app RUN yarn install && yarn production
我们再次使用官方镜像,这次是 Node 的 LTS 版本,它也带有 `yarn`。我们创建一个 `/app/public` 目录并将所需文件复制到 `/app` 路径中,以便 Laravel Mix 可以构建 JavaScript 和 CSS。
最后,我们安装软件包依赖项并运行 `yarn production` 命令来完成前端资源的安装!
此时,我们可以再次构建镜像并检查前端依赖项
docker build -t ms-laravel-test .docker run --rm -it ms-laravel-test bash # Inside the running containerroot@faa6904a98df:/app# ls -laroot@faa6904a98df:/app# ls -la public/{js,css}root@faa6904a98df:/app# exit
请随时在容器中调查前端路径,最后退出正在运行的容器。我们准备使用已创建的工件构建最终阶段!
阶段 3
Docker 构建的最后阶段涉及从源代码中复制应用程序文件,并从早期构建阶段复制工件。
要创建最终构建阶段,将以下内容追加到 `Dockerfile`
## Application#FROM php:7.2-apache-stretch COPY . /var/www/htmlCOPY --from=vendor /app/vendor/ /var/www/html/vendor/COPY --from=frontend /app/public/js/ /var/www/html/public/js/COPY --from=frontend /app/public/css/ /var/www/html/public/css/COPY --from=frontend /app/mix-manifest.json /var/www/html/mix-manifest.json
我们首先将应用程序复制到镜像中。`.dockerignore` 文件确保忽略的路径不会从主机复制到镜像中。
请注意 `COPY --from` 指令,它们引用了早期阶段的名称(例如 `FROM node:8.11 as frontend`)。我们正在将早期阶段的工件复制到最终镜像中的适当位置。
如果您最后一次构建镜像,您就可以看到完整的应用程序,而无需 Node 包或 Composer 脚本的开销!
docker build -t ms-laravel-test .docker run --rm -it ms-laravel-test bash # Inside the running containerroot@1d6251d2362c:/var/www/html# ls -la...
我们的最终镜像是带有 Apache 的 PHP 7.2 镜像,但是,要运行此应用程序,我们需要修改默认的 Vhost 配置文件,使其指向 Laravel 期望的 `/var/www/html/public`。我们将跳过这一点,因为本文的重点是使用多阶段构建;)
以下是完整的最终 `Dockerfile`
## PHP Dependencies#FROM composer:1.7 as vendor COPY database/ database/ COPY composer.json composer.jsonCOPY composer.lock composer.lock RUN composer install \ --ignore-platform-reqs \ --no-interaction \ --no-plugins \ --no-scripts \ --prefer-dist ## Frontend#FROM node:8.11 as frontend RUN mkdir -p /app/public COPY package.json webpack.mix.js yarn.lock /app/COPY resources/assets/ /app/resources/assets/ WORKDIR /app RUN yarn install && yarn production ## Application#FROM php:7.2-apache-stretch COPY . /var/www/htmlCOPY --from=vendor /app/vendor/ /var/www/html/vendor/COPY --from=frontend /app/public/js/ /var/www/html/public/js/COPY --from=frontend /app/public/css/ /var/www/html/public/css/COPY --from=frontend /app/mix-manifest.json /var/www/html/mix-manifest.json
了解更多
您应该查看的第一份文档是来自官方 Docker 文档的 使用多阶段构建。多阶段构建非常有用,是构建最终应用程序工件而无需许多本地依赖项的绝佳方法。
如果您想了解更多关于使用 Docker 和 PHP(包括 Laravel)进行开发的信息,请查看我的书 Docker for PHP Developers。如果您不想要入门 Laravel 代码,也可以获得 仅书 版本。Laravel 新闻读者可以获得这两个版本书籍的折扣!您可以在 此处了解有关书籍公告的更多信息。
包含的链接是联盟链接,这意味着如果您决定购买,Laravel 新闻会获得一小部分回馈,以帮助运营本网站。