使用 Docker 来构建完美的 Laravel 本地开发环境

文章太长,不想看?

如果不想读下面的“长篇大论”想快速上手的话,可以直接进行如下步骤:
安装适合你操作系统版本的 Docker , 克隆 本项目, 将您的Laravel应用程序文件添加到src目录中,并从您刚刚克隆的根项目目录中运行如下命令:
docker-compose build && docker-compose up -d

简单介绍

在我们开始之前,你应该知道这篇文章着重讲述点不是如何学习Docker的基础完整教程,也不是有关工具集复杂性的说明。

相比使用Docker和docker-compose来配置本地开发环境,这套工具,简化了繁琐的流程——你不必在电脑上安装和配置LAMP工具集。

这或许会是最适合你开发Laravel应用的一套工具。

如果你还不知道Docker是什么,你可以根据下面的概述来了解一下(节选自opensource.com):

Docker 是一个被设计来用于基于“容器”轻松创建、部署和运行你的服务或应用的工具。 容器可以让开发者将项目和所需的类库(依赖)打包在一起,将它合并为一个完整的包。

你可以把Docker视为精简版的VM。

你也许会问,这样做有什么好处呢?如果您有多个运行不同版本的Linux,PHP或任何其他网络软件的生产服务器,则可以将这些变量复制到您的容器中,并且可以保证该应用程序将按预期的方式在生产服务器上正常运行。

如果您在本地计算机上有多个跨不同版本的Laravel项目,那一定要来尝试一下Docker,你可以为每个应用程序指定特定的Docker配置,而不用像PHP切换版本那样要去修改实际的系统的环境变量。您甚至可以同时访问两个项目,并且每个容器彼此独立运行,互不受环境变量的影响。

听起来激动吗? 让我们开始Docker之旅吧!

安装 Docker

在本文中, 屏幕截图和参考资料与 MacOS 用户相关。然而,安装和使用说明和在 Windows 上非常相似。

第一步,获取安装器: https://docs.docker.com/docker-for-mac/ins....

运行典型的安装步骤,完成后打开应用。首次打开时,你将会被要求通过操作系统密码验证授权给 Docker,然后您会在顶部状态栏中看到小鲸鱼图标。

项目结构

我一直在 Laravel + Docker 项目中,使用下面这种目录结构。你的目录结构不必完全像我一样,但是本文是在假设你的项目是按照这样的结构的。

my-project.com/
├── nginx/
│   └── default.conf
├── src/
│   └── (Laravel app files)
├── docker-compose.yml
└── Dockerfile

在接下来的两个部分,我将解释一下每个文件的作用,但是现在只要按照上面的结构创建对应的文件即可。另外,请添加(或创建)Laravel 项目文件到 src 文件夹。

创建项目容器栈

使用 Docker 最首要遵从的规则是一个容器提供单一的服务。由于我们要创建典型的 LEMP 类的应用栈,意味着我们要为 web 服务器(nginx),PHPMySQL 分别创建 docker 容器。 原理上,我们可以为这些服务分别创建一个容器,然后将它们配置联接在一起。Docker 内建有一个优秀的工具,名为 docker-compose 就是干这事儿的。

我们要做的是配置这些我们用到的,来自 Docker 提供配置好的服务容器,启动运行它们,并将它们包装在一个 虚拟网络(virtual network)上。这意味着所有这些服务容器可以互相访问及依赖。

让我们最开始的配置,打开上述项目根目录下的 docker-compose.yml 文件,在文件最开始确保如下显示内容:

docker-compose.yml screenshot beginning

简单解释上面所示这3行内容含义:

  • Version: 3, 推荐的,最新的 docker-compose 引擎版本。
  • Networks:  我们使用的的虚拟网络名称,这里只标识网络名,无其它选项配置的需要。当前例子中是 'laravel' 。
  • Services: 这下面分别依次指定我们用到的服务容器配置,这构成了我们的项目用到的服务栈。

加入 Nginx

在上述 docker-compose.yml 配置之后,在 'services:' 下,直接加入如下所示内容:

docker-compose.yml screenshot of nginx service

如上设置告诉 docker 需要一个名为 nginx 的容器,源自 nginx:stable-alpine docker 映像(其完全的源,参考 这里 )。我们使用 alpine 做为基础的 linux 系统映像,是它轻量及良好的响应能力。

接下来,我们命名这个容器为 nginx 且将容器的 80 端口映射到主机的 8080 端口。8080 端口号由你任意选择,只要它不与系统的知名端口冲突即可。

对于这个 nginx 容器构成的 web 服务器,在其卷(volumes)属性标签下,加入下面2个配置:

  • 我们主机的  ./src 文件夹(当前项目下的 src 子目录)绑定到容器的 /var/www 路径。不像符号链接,我们在 src 目录下的任何更改,立即反应在容器的 /var/www 目录下。
  •  ./nginx/default.conf 文件被连接映射到容器中的 /etc/nginx/conf.d/default.conf 文件,这将使我们具有直接在主机中修改配置容器 web 服务器的能力。

你可以在 volumes 下指定任意数量的主机和容器间的目录或文件的映射。

接着,在 depends_on 下加入 nginx 对 php ,mysql 的依赖项,它告诉 docker ,若运行本 nginx 容器,必须先启动运行 php 和 mysql 服务容器,这也意味着,若启动运行 nginx 容器,必须先启动运行它依赖的那些容器。

最后,在 networks 下,指定 nginx 容器运行在 laravel 虚拟网下。这是我们在 docker-compose.yml 文件一开始就设置过的虚拟网络名。

加入 MySQL

docker-compose.yml 文件中加入的下一个服务容器是 MySQL ,这些配置相对简单直接。

docker-compose.yml screenshot adding the mysql service

初始,指定 docker 映像和容器名称,之后的配置是一些我觉得可使 MYSQL 容器稳定的一些杂项配置。

MySQL 容器服务端口 3306 被映射暴露到主机的相同端口,接下来 environment (环境变量)的一些配置在容器初始化时对创建的数据库的设定。由于容器为 laravel 项目服务,对默认数据库的设置来自于一般 laravel 项目中 .env 文件中对数据库 数据库名/用户名/密码 等的相同配置。

与 nginx 容器配置相同,我们将 MYSQL 数据库容器纳入到虚拟网络 laravel 下。
✨ 简单吧!

加入 PHP

不像 Nginx 和 MySQL 服务容器,加入我们自己的 PHP 服务容器将使用与前2个服务容器稍有不同的配置流程。之前2个容器是直接引用 docker 上现有的映像创建我们自己的容器。然而,由于我们项目对 Laravel 的依赖,需要我们通过自定的 docker 配置文件(Dockerfile)创建自己的 PHP docker 映像。

完成这部分的配置,在 docker-compose.yml 文件中加入如下及接下来的几节内容:

docker-compose.yml screenshot of adding the php service

你已发现配置的不同,这里已没有了前2个容器配置中的 image 相关配置内容,代替它的是 build 的配置。指定通过 Dockerfile 文件创建容器(我们之前在目录下已创建了 Dockerfile 文件)。

与之前容器的配置相同,我们指定 PHP 容器的卷主目录为我们主机上的项目根目录,映射主机的相同端口 9000 ,并将容器纳入到同一虚拟网络 laravel 下。

现在是时候加入容器的创建配置了,具体配置加入到项目根目录下的 Dockerfile 中:

Dockerfile screenshot for building the PHP image

是的,就是这样。

这里,我们配置如下:

  • 指定依 「php:7.2-fpm-alpine 」 PHP 映像创建我们的 PHP 容器。
  • 加载安装 Laravel ORM 项目必要使用的操作数据库的插件,pdopdo_mysql

docker-php-ext-install 配置命令是 docker 内建命令(参考: 如何安装 php 插件) 。你可以在其命令中传递任何欲安装的 php 插件,安装到现有容器中,而不用新建容器。

配置 nginx

还记得我们项目目录树中 /nginx/default.conf 文件吧,打开它,加入如下配置:

Screenshot of the default nginx configuration

老实说,这里没啥好讨论的,这就是 laravel 项目最基本的 nginx 服务配置范例。注意,其 laravel 网站根目录指定到 nginx 容器的 /var/www 下的 public 目录。

启动 Docker

我们已经完成了所有配置流程片段,现在是时候装配起我们的 Docker 虚拟网络的时候了。打开一个终端窗口,进入到我们项目的主目录。由于我们 PHP 容器是通过 Dockerfile 配置文件创建的,我们启动这些容器时,还需一个 build (创建)命令去创建 PHP 容器的映像数据。

docker-compose build

这将花费些时间完成,开始终端中没什么提示,等个几分钟后,你将在终端中看到类似 Successfully builtSuccessfully tagged 的提示信息。接下来,你就可以开始实际的启动容器的命令:

docker-compose up -d

Docker 将创建我们 laravel 项目的虚拟网络且创建我们在 docker-compose.yml 文件中指定的3个服务容器。若你好奇命令行中 -d 的含义,它代表 detached (解离)的意思,意味着,每个容器完成启动命令后继续运行。若无此选项,容器启动完成后将终止运行并退出,这对于 web 服务器显然是不合适的。

配置 Laravel

在首次访问我们应用前,我们需要对我们 Laravel 目录下的 .env 文件进行一些小小的配置调整。主要考虑对数据库的连接及应用域名的配置。打开主机项目主目录下 src 文件夹,打开项目文件 .env 文件,修改如下配置行:

  • DB_HOST=mysql - 这个配置值 'mysql' 来自我们创建的容器配置文件docker-compose.yml 中 MySQL 服务容器配置段,它做为项目在 Docker 虚拟网络下其它容器访问的引用名称。
  • APP_URL=http://localhost:8080 -  加入端口号,这个端口号是在 nginx 服务配置中映射的主机端口号。

访问项目应用

假设你成功完成上述所有的配置和执行步骤,就可使用浏览器访问 nginx 容器绑定的 web 协议端口,将看到你项目应用的首页!

在浏览器中,访问 http://localhost:8080  网址,这里的 8080 是你在 docker-compose.yml 文件中 nginx 服务容器下配置的绑定端口。

Screenshot of a browser showing the Laravel landing screen

💥 砰!我们具备了在 Docker 虚拟网络下的 Lavarel 项目应用开发框架!

当然,若你想使用类似 TablePlus 的工具访问 MYSQL 服务容器中的数据库,只是使用 127.0.0.1 作为主机名,并指定在 docker-compose.yml 文件中 MYSQL 服务配置下的绑定端口(本例中是默认的 3306)。

数据库用户名和密码也是先前在 docker-compose.yml 中环境变量中 MYSQL_USERMYSQL_PASSWORD 字段中指定的值,分别是 homesteadsecret

Screenshot of TablePlus configuration

注意: 如果你计划运维多个项目,且每个项目使用不同的 docker 虚拟网络,你必须在不同的项目中绑定不同的端口(例如,8080 对一个项目,8081对另一个项目)。否则,在项目容器初始化时将收到 port is already allocated (端口已占用) 的错误信息。

在容器中执行命令

Laravel 很频繁地使用命令行运维项目,诸如迁移,队列或测试等。在 Docker 虚拟网络中完成这些非常容易,使用 docker-compose 的 exec 指令(docker-compose exec)。

与一般的主机与虚拟机(VM)利用 ssh 进行远程交互方式不同,Docker 是通过向容器传递命令的方式,与容器交互。命令执行结果直接输出到主机终端。举例,在我们终端项目根目录下,执行如下命令完成 Laravel 项目的默认迁移任务:

docker-compose exec php php /var/www/artisan migrate

这里稍做一些解释:

  • docker-compose exec 告诉 Docker 我们想在我们项目的虚拟网络中执行某些命令。
  • php 指定想执行命令的容器名称,由于我们将执行 PHP 命令,它需要在包含 PHP 服务的容器,即 php 容器中执行。
  • php /var/www/artisan migrate 实际执行的命令行。我们使用容器中的绝对路径 /var/www/ ,这已经通过容器配置映射到主机当前项目下的 src 目录。

Screenshot of a terminal after running a docker-compose migrate command

执行命令后,迁移动作的输出将显示在当前终端中,你的数据库将会迁移进2个数据库表。

从主机可以传递任意多的命令给容器,使其执行。只是要确定相应的服务已安装,传递的命令在容器中有效。

技巧: 若你坚定地想使用类似 ssh 的方式在容器中执行命令,有简单的变通方法,主机终端中执行 docker-compose exec {container_name} /bin/sh 命令,将打开一个永久连接到容器的终端,这里 {container_name} 是你想连接的容器名。

结语

好了,我们完成了整个流程!我们安装了 Docker ,创建且配置了一个 docker-compose 配置文件,它将包含3个服务容器的一个 LEMP 项目开发栈装配整合到一个 docker 虚拟网络上,服务容器间绑定主机端口进行交互,使得我们可以访问我们的项目应用及其数据库。甚至,我们通过 docker-compose exec 命令行使指定容器执行 cli 命令。

下一步,你有必要知道如何关闭并退出你的项目的 docker 虚拟网络及容器,使其停止运行。这也很容易,进入你的项目根目录并运行 docker-compose down 命令,这将关闭所有相关容器,退出虚拟网络。注意的是,相关的任何非存储在容器卷中的数据将被清除。

当我还纠结如何在不同的 Laravel 版本上布署多个开发项目时,Docker 技术打开了无限开发可能的一个全新世界。现在,我可以轻易地布署一个开发项目在基于使用 PHP 7.1 版本的 Docker 上,如果我想知道我这个项目在 PHP 7.3 版本的运行情况,我只需要在项目的 Docker 配置文件中修改 一个字符 ,重建容器,重启 docker-compose 即可。

不可否认,使用 Docker ,你不会得到在你本机硬件上直接布署开发项目所能得到更多的性能提升,但权衡其对开发多变性易用性并行环境定制性上的性能表现,我心属之。

Docker has opened up a whole world of development possibilities for me when I’m juggling multiple projects spanning different Laravel versions. I can easily have one project running on a Docker network with a PHP container using 7.1, and if I wanted to see how my current project would perform in PHP 7.3 it’s as simple as changing a single character in my Dockerfile, re-building the container, and bringing the docker-compose network back up.

I won’t deny it, you’ll get no better local development performance than running your stack directly on your machine’s hardware. But the tradeoff of performance for versatility, ease of use, parallel environments, and customization, greatly outweighs that for me.

本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://dev.to/aschmelyun/the-beauty-of-...

译文地址:https://learnku.com/server/t/39850

本帖已被设为精华帖!
本文为协同翻译文章,如您发现瑕疵请点击「改进」按钮提交优化建议
讨论数量: 2

这些代码截图都是什么工具做的呢?

4年前 评论

composer包是什么时候安装进去的,就是说为什么不用composer inatsll

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!