Laravel Docker Docker 对于本地 Laravel 开发的优势
总结
想要快速跳过下面的详细教程吗?请为你的操作系统安装Docker ,克隆此 repo,将你的 Laravel 应用程序文件添加到src目录,然后从刚刚克隆的根项目目录运行:docker-compose build && docker-compose up -d
。
简介
在开始之前,需要说明的是,本文并非 Docker 的完整教程,也不是对该工具集复杂细节的详尽讲解。它更像是一个精简的教程,指导您如何使用 Docker 和 docker-compose 快速搭建本地开发环境,而不是直接在机器上安装 LAMP 技术栈。虽然有一些注意事项,但以下方法是我发现在开发 Laravel 应用时最适合我的方法。
对于那些不知道 Docker 是什么的人,我们先来简单了解一下。根据 opensource.com 的介绍:
Docker是一款旨在简化使用容器创建、部署和运行应用程序的工具。容器允许开发人员将应用程序所需的所有组件(例如库和其他依赖项)打包在一起,然后将它们作为一个包发布。
您可以将 Docker 视为简化版的 VM。
为什么这有帮助或有用?好吧,如果你有多个运行不同版本 Linux、PHP 或任何其他 Web 软件的生产服务器,那么这些变量可以在你的容器中复制,并且可以保证应用程序在生产机器上按照预期运行。
与本文主题更契合的是,如果您在本地计算机上有多个跨不同版本的 Laravel 项目,则可以为每个应用程序设置特定的 Docker 配置,而无需实现类似 PHP 版本切换器的功能并修改实际计算机的配置。您甚至可以同时访问这两个项目,并且每个容器彼此独立运行。
听起来很刺激?那就开始吧!
安装 Docker
本文中的截图和参考资料将与 MacOS 用户相关。不过,Windows 上的安装和使用说明应该非常相似(即使不是几乎完全相同)。
首先,获取安装程序:https://docs.docker.com/docker-for-mac/install/。
运行典型的应用程序安装过程,完成后打开应用程序。首次打开时,系统会要求您通过系统密码授权 Docker,之后您将在顶部状态栏中看到小鲸鱼图标。
项目结构
以下是我在 Laravel + Docker 项目中一直使用的结构。您不必严格遵循此结构,但本文的其余部分将假设您的项目采用相同的布局。
my-project.com/
├── nginx/
│ └── default.conf
├── src/
│ └── (Laravel app files)
├── docker-compose.yml
└── Dockerfile
在接下来的几部分中,我将详细介绍每个文件的功能,但现在只需使用上面的布局将它们创建为空白占位符即可。此外,请在src/目录下添加(或创建)整个 Laravel 应用的文件。
创建我们的堆栈
使用 Docker 的一条重要原则是,每个容器应该只提供一项服务。由于我们创建的是典型的 LEMP 技术栈,这意味着我们的 Web 服务器(Nginx)、PHP和MySQL都需要一个容器。虽然理论上我们可以为每个服务创建单独的容器,然后尝试将它们连接在一起,但 Docker 内置了一个非常实用的工具,名为docker-compose。
我们要做的是定义将要使用的服务,Docker 在运行时将每个服务配置为一个容器,并将它们全部封装在一个虚拟网络中。这意味着每个服务都可以从每个容器访问。
首先,打开docker-compose.yml文件并在其顶部添加以下内容:
对于我们刚刚添加的内容,有一些简单的解释:
- 版本:3,docker-compose 引擎的最新和最推荐的版本
- 网络:我们只使用一个网络,laravel,除了名称之外,我们没有添加任何选项
- 服务:我们将在其中指定构成堆栈的图像
添加 Nginx
在我们上面的docker-compose.yml文件底部指定的服务标题下,您将添加以下内容:
上面我们所做的就是告诉 Docker,我们需要一个名为nginx的容器,该容器基于 nginx:stable-alpine 镜像构建(完整源代码可在此处查看)。我们使用 alpine linux 作为基础操作系统,因为它轻量且响应速度快。
接下来,我们将容器命名为nginx:80
,并将其端口公开:8080
为本地机器上的端口。这个端口号是我们最终访问网站的端口,您可以将其调整为任何您喜欢的非保留端口号。
对于 Web 服务器的卷,我们添加以下两个内容:
- 我们本地的/src文件夹绑定到了容器的/var/www路径。与符号链接类似,我们在 /src 中修改的任何内容都会立即在 /var/www 下的服务器上生效。
- 我们创建的/nginx/default.conf文件链接到/etc/nginx/conf.d/default.conf容器文件,并使我们能够在本地机器上修改 nginx Web 服务器。
您可以在此标题下指定任意数量的目录或文件,以将它们从本地计算机符号链接到 nginx 容器。
通过在depends_on项下添加php和mysql(我们接下来要创建的服务),我们告诉Docker在初始化时,php和mysql容器需要在nginx之前运行。此外,如果我们尝试只启动nginx容器,它也会启动这两个依赖容器。
最后,我们指定此容器明确位于我们在 docker-compose.yml 文件开头创建的laravel网络下。
添加 MySQL
我们要添加到docker-compose.yml文件的下一个服务是 MySQL。这个相对简单。
最初,我们指定图像和容器名称,以及设置一些我认为有助于维护 MySQL 在容器中的稳定性的杂项设置。
默认的 MySQL 端口:3306
是我们暴露给本地机器的端口,然后使用环境对象,我们可以设置一些初始化时使用的变量来修改创建的数据库。由于我们正在为 Laravel 应用配置 Docker,因此我使用典型的 Laravel .env 文件中的默认数据库名称/用户名/密码。
就像 nginx 一样,我们将此服务附加到laravel网络。✨
简单!
添加 PHP
与 Nginx 和 MySQL 不同,添加PHP容器需要走一条不同的、稍微复杂的路径。对于前两个服务,我们可以直接引用镜像来构建容器,但是由于 Laravel 需要依赖某个镜像,我们实际上需要根据本地 Dockerfile 构建自己的镜像。
在我们进入该部分之前,请将以下内容作为下一个(也是最后一个)服务添加到我们的docker-compose.yml文件中。
你已经发现了区别,我们用build替换了之前使用的镜像标题。在 build 标题下,我们将 context 指定为当前项目目录,并将 dockerfile 指定为 Dockerfile(我们之前已经创建过)。
与我们的 nginx 容器一样,我们为根目录指定相同的卷,然后公开:9000
容器的端口并将网络设置为laravel。
现在我们已经添加了该服务,接下来需要将以下内容添加到我们的Dockerfile中:
是的,就是这样。
我们在这里所做的就是:
- 指定我们希望从 PHP 映像构建我们的 php 容器
7.2-fpm-alpine
。 - 安装Laravel 的 ORM 及其数据库方法使用的 PHP 扩展
pdo
。pdo_mysql
该docker-php-ext-install
命令是 Docker 内置的(但文档不完善)。您可以传递任何 PHP 扩展,它会在我们新创建的容器中处理安装和配置。
配置 nginx
还记得我们创建的/nginx/default.conf文件吗?打开它并添加以下内容:
老实说,这里没什么好讨论的,因为它主要是用于大多数基本 Laravel 应用的 nginx 样板配置。请注意,根路径设置为我们将 Laravel 应用链接到的/var/www nginx 目录的公共文件夹。
启动 Docker
我们已经把所有单独的部分都整理好了,现在终于可以组装我们的 Docker 网络了!打开一个终端窗口,导航到这个项目的根目录。由于我们的一个容器(php)使用 Dockerfile 作为其镜像,而且这是我们第一次启动这些容器,所以我们需要做的第一件事就是运行build命令来生成镜像数据:
docker-compose build
这需要一点时间才能完成,一段时间内可能看起来什么都没发生。等待大约 1-2 分钟,你应该会在终端中看到“Successfully established”和“Successfully Tagged”的消息。然后,你可以继续使用以下命令启动容器:
docker-compose up -d
Docker 会创建我们的 laravel 网络,然后创建我们在 docker-compose.yml 文件的 services 部分中指定的三个容器。如果您对-d标志感兴趣,它代表分离状态,会在所有命令处理完毕后保持容器运行。否则,Docker 会在它们初始化完成后立即停止它们。这对于 Web 服务器来说毫无意义!
配置 Laravel
在首次访问我们的应用程序之前,我们需要对 Laravel 的 .env 文件进行一些小的调整。特别是关于数据库连接和应用程序域。打开src.env
目录中的项目文件并修改以下几行:
DB_HOST=mysql
- 这个名称来自我们在 docker-compose.yml 文件中创建的 MySQL 服务,并在 Docker 网络中用于从其他容器引用该服务。APP_URL=http://localhost:8080
- 添加您在我们的 nginx 容器中公开的端口号,以使其指向可解析的地址。
访问您的应用程序
假设上述步骤中的所有内容都成功启动,我们现在可以使用暴露的端口访问我们的容器并查看我们应用程序的登录页面!
在浏览器中,导航到http://localhost:8080,其中8080是您在 docker-compose.yml 文件中的 nginx 服务下指定的第一个端口。
💥 轰!我们的 Laravel 应用已经在 Docker 网络中运行了!
当然,如果你也想使用TablePlus之类的工具访问你的 MySQL 数据库,连接起来也同样简单。你只需要使用127.0.0.1
docker-compose.yml 文件中 MySQL 服务暴露的端口(本例中我们保留默认的3306)作为主机名即可。
我们在环境变量中分别指定了用户名和密码为MYSQL_USER
和MYSQL_PASSWORD
、homestead和secret。
注意:如果您计划为不同的项目同时运行多个网络,则必须指定在本地计算机上公开的不同端口(例如,一个网络使用 8080,另一个网络使用 8081)。否则,port is already allocated
容器初始化期间会报错。
运行命令
Laravel 经常使用命令行来执行迁移、队列和测试等操作。使用 docker-composeexec
命令在我们的 Docker 网络上执行这些操作非常容易。
Docker不像虚拟机那样,你可以通过 ssh 进入系统并直接在操作系统上执行命令,而是更倾向于将命令传递给容器,然后将这些命令的输出回显到你的终端。例如,让我们在项目根目录的终端中运行以下命令来运行 Laravel 自带的默认迁移:
docker-compose exec php php /var/www/artisan migrate
让我们稍微分析一下:
- docker-compose exec告诉 Docker 我们想要在容器网络上执行一个命令。
- php 是我们要在其中执行命令的容器名称。由于我们要执行 PHP 命令,因此该命令必须位于运行 PHP 的容器中。
- php /var/www/artisan migration 是我们正在运行的命令的实际名称。我们使用通过 ./src 本地卷符号链接的 Artisan 绝对路径,并运行标准的 Laravel 迁移。
运行我们的命令后,您应该会看到迁移输出,并且您的数据库现在将填充两个表!
我们可以在我们选择的 Docker 容器中从本地终端运行任意数量的命令。只需注意要执行命令的容器中已安装且可用的服务。
提示:如果您坚持要直接通过 ssh 进入容器执行命令,有一个非常简单的解决方法。运行该docker-compose exec {container_name} /bin/sh
命令将打开与 {container_name} 参数中指定的容器的持久连接。
线路末端
好了,大功告成!我们安装了 Docker,设置并配置了一个 docker-compose 文件,用于创建一个包含三个容器的 LEMP 栈,这些容器封装在一个网络中,并在该网络上暴露了端口,以便我们访问应用程序和数据库,甚至还通过 docker-compose 的 exec 方法运行了 cli 命令。
接下来,如果您想关闭容器和网络,只需导航到项目的根文件夹并运行 即可docker-compose down
。这将关闭并销毁容器以及存储在其中的任何相关的非卷数据。
当我同时处理多个跨 Laravel 版本的项目时,Docker 为我打开了无限的开发可能性。我可以轻松地使用 将一个项目运行在 Docker 网络和 PHP 容器上7.1
。如果我想查看当前项目在 PHP 中的运行情况,7.3
只需在 Dockerfile 中更改一个字符,重新构建容器,然后重新启动 docker-compose 网络即可。
我不否认,本地开发性能不会比直接在机器硬件上运行堆栈更好。但对我来说,性能与多功能性、易用性、并行环境和定制化之间的权衡,远远超过了这一点。
如果您有任何疑问、意见,或想进一步探讨PHP 和 Laravel,欢迎随时在Twitter
上联系我!如果您正在寻找一款专为 Laravel 应用打造的超级便捷的错误和日志监控服务,我已构建了Larahawk。它目前处于内测阶段,即将上线,每个应用每月仅需 5 美元。