为 Laravel 创建多阶段 Docker 构建

发布时间 作者

Creating Multi-Stage Docker Builds for Laravel image

从 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 file
touch Dockerfile
 
# Generate the yarn lockfile
yarn install
 
git init
git 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 paths
COPY . /var/www/html

例如,忽略 `vendor/` 文件夹意味着我们从构建中获得 Composer 依赖项的原始构建。

Dockerfile

我们的应用程序 Dockerfile 将使用三个部分将应用程序构建的每个阶段分解

  1. 安装 Composer 依赖项
  2. 构建前端依赖项
  3. 从前两个阶段复制我们的应用程序代码和工件

阶段 1

第一阶段将是 Composer 依赖项。我们可以使用 官方 Composer 镜像 来首先在项目的根目录中 `Dockerfile` 中安装应用程序依赖项

#
# PHP Dependencies
#
FROM composer:1.7 as vendor
 
COPY database/ database/
 
COPY composer.json composer.json
COPY 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 container
bash-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 container
root@faa6904a98df:/app# ls -la
root@faa6904a98df:/app# ls -la public/{js,css}
root@faa6904a98df:/app# exit

请随时在容器中调查前端路径,最后退出正在运行的容器。我们准备使用已创建的工件构建最终阶段!

阶段 3

Docker 构建的最后阶段涉及从源代码中复制应用程序文件,并从早期构建阶段复制工件。

要创建最终构建阶段,将以下内容追加到 `Dockerfile`

#
# Application
#
FROM php:7.2-apache-stretch
 
COPY . /var/www/html
COPY --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 container
root@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.json
COPY 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/html
COPY --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 新闻会获得一小部分回馈,以帮助运营本网站。

Paul Redmond photo

Laravel 新闻的编外撰稿人。全栈 Web 开发人员和作家。

Cube

Laravel 新闻通讯

加入 40,000 多名其他开发者,永不错过新的技巧、教程等。

Laravel Forge logo

Laravel Forge

轻松创建和管理您的服务器,并在几秒钟内部署您的 Laravel 应用程序。

Laravel Forge
Tinkerwell logo

Tinkerwell

Laravel 开发人员必备的代码运行器。使用 AI、自动完成功能和对本地和生产环境的即时反馈进行调试。

Tinkerwell
No Compromises logo

无妥协

来自 No Compromises 播客的两名经验丰富的开发者 Joel 和 Aaron,现在可以为您的 Laravel 项目提供服务。 ⬧ 固定价格 7500 美元/月。 ⬧ 无需冗长的销售流程。 ⬧ 无需签订合同。 ⬧ 100% 退款保证。

无妥协
Kirschbaum logo

Kirschbaum

提供创新和稳定性,确保您的 Web 应用程序取得成功。

Kirschbaum
Shift logo

Shift

正在运行旧版本的 Laravel? 立即自动升级 Laravel 并对代码进行现代化改造,以保持应用程序的新鲜度。

Shift
Bacancy logo

Bacancy

只需每月 2500 美元,即可为您的项目配备一名拥有 4-6 年经验的资深 Laravel 开发者。 获得 160 小时的专业知识和 15 天的无风险试用期。 立即预约通话!

Bacancy
Lucky Media logo

Lucky Media

立即体验幸运 - Laravel 开发的理想选择,拥有十多年的经验!

Lucky Media
Lunar: Laravel E-Commerce logo

Lunar: Laravel 电子商务

Laravel 电子商务。 一个开源软件包,将现代无头电子商务功能的强大功能引入 Laravel。

Lunar: Laravel 电子商务
LaraJobs logo

LaraJobs

官方 Laravel 工作板

LaraJobs
SaaSykit: Laravel SaaS Starter Kit logo

SaaSykit: Laravel SaaS 启动套件

SaaSykit 是一个 Laravel SaaS 启动套件,它包含运行现代 SaaS 所需的所有功能。 支付、精美结账、管理面板、用户仪表板、身份验证、即用型组件、统计信息、博客、文档等等。

SaaSykit: Laravel SaaS 启动套件
Rector logo

Rector

您无缝升级 Laravel、降低成本并加速创新以实现成功公司的合作伙伴

Rector
MongoDB logo

MongoDB

通过 MongoDB 和 Laravel 的强大集成来增强您的 PHP 应用程序,使开发人员能够轻松高效地构建应用程序。 在使用熟悉的 Eloquent API 的同时,支持事务性、搜索、分析和移动用例。 了解 MongoDB 的灵活、现代数据库如何改变您的 Laravel 应用程序。

MongoDB
Maska is a Simple Zero-dependency Input Mask Library image

Maska 是一个简单的零依赖输入掩码库

阅读文章
Add Swagger UI to Your Laravel Application image

将 Swagger UI 添加到您的 Laravel 应用程序

阅读文章
Assert the Exact JSON Structure of a Response in Laravel 11.19 image

在 Laravel 11.19 中断言响应的精确 JSON 结构

阅读文章
Build SSH Apps with PHP and Laravel Prompts image

使用 PHP 和 Laravel 提示构建 SSH 应用程序

阅读文章
Building fast, fuzzy site search with Laravel and Typesense image

使用 Laravel 和 Typesense 构建快速模糊网站搜索

阅读文章
Add Comments to your Laravel Application with the Commenter Package image

使用 Commenter 包向您的 Laravel 应用程序添加评论

阅读文章