使用 NGINX 和 MySQL 在 Docker 上部署 Laravel 应用
原文也上传到了这里:Laravel Application on Docker
如果您是 Django 开发人员,可以在这里找到一个非常全面的教程:Django on Docker
现在我们开始吧?
Docker,这位新来的“金靴”让所有人都兴奋不已。为什么?因为 Docker 能确保开发和生产周期的一致性,从而标准化你的环境,让开发变得无比轻松。
我猜你和我们一样对 Docker 充满热情,所以才会看到这篇文章。说实话,Docker 一开始确实很让人头疼,就像其他任何新概念一样,对新手来说都是噩梦。但一旦你掌握了它,就能节省大量部署时间。
这篇文章主要面向对 Docker 几乎一无所知的初学者。撰写这篇文章的初衷是,我在网上找不到任何全面的 Laravel Docker 教程。最终,我只能通过持续阅读多篇博客文章,并将所有内容整合起来,整理成一个庞大而全面的步骤,我将在本文中尝试记录这些步骤。
现在进入正题……
在开始之前,我假设您已经准备好了 Laravel 应用。如果您还没有,可以前往Laravel 文档页面创建一个应用,然后再回到这里继续阅读。
我还假设您的机器上已经安装了 Docker。如果没有,您可以选择以下方法:
- Windows 10 专业版用户:Docker Desktop
- Windows 10 专业版以下的 Windows 10 版本用户:Docker Toolbox。这是因为 Docker Desktop 对系统有一定要求。Docker Toolbox 利用了 VirtualBox 的功能。
- Linux 用户:Docker CentOS。您可以从弹出屏幕的侧边菜单中选择您的 Linux 发行版(如果不是 CentOS),然后按照该发行版的特定说明进行操作。
第一步:创建你的“docker-compose”文件
什么是 docker-compose 文件?这是一个定义所有 Docker 容器的文件,所有这些容器都可以通过运行一个相对简单的命令来启动,例如:
docker-compose -f docker-compose.prod.yml up --build
在这里,我们将搭建一个开发环境(稍作修改后,也可以用于生产环境,我将在下一篇文章中记录这些修改 :-))
在根目录下创建一个文件,并将其命名为:docker-compose.yml
接下来,您将在本文件的步骤中定义容器。
在我们的 docker-compose 文件中,我们定义了三个容器:mysql、nginx 和我们的 laravel 应用程序。
首先,我们的 Laravel 应用容器将定义如下:
version: '2'
services:
# The Application
app:
container_name: laravel_app
build:
context: ./
dockerfile: development/app.dockerfile
volumes:
- ./storage:/var/www/storage
env_file: '.env.prod'
environment:
- "DB_HOST=database"
- "REDIS_HOST=cache"
以上代码概述:
- 版本- 您可以随意更改此版本
- container_name - 您将使用此名称来引用您的容器。例如,如果您想关闭容器,您将使用此名称来专门引用它。您也可以根据需要随意更改此名称。
-
build - 用于从 Dockerfile 构建镜像。具有以下附加选项:
- 上下文- Docker 使用此上下文(基本上就是 Laravel 文件所在的位置)来引用其中的任何文件。在本例中,`./` 指的是 Laravel 的根文件夹,假设 docker-compose 文件存储在 Laravel 的根文件夹中。
- Dockerfile:Docker 镜像由 Dockerfile 构建,Dockerfile 通常包含在容器内运行的附加命令。在本例中,我们使用 Dockerfile 来构建应用程序容器。另请注意,我们使用了 `<path>
development/app.dockerfile` 标签。这意味着我们的 Dockerfile 位于 Laravel 应用程序根目录下的 `development` 文件夹中。
-
卷- Docker 容器使用卷在主机和正在运行的 Docker 容器之间共享文件。全冒号左侧代表主机,右侧代表 Docker 容器。在本例中,我们将 Laravel 应用存储文件夹中的所有数据共享给挂载在`/var/www/storage` 的Docker 容器。
-
env_file - 这定义了我们的 Laravel 的 .env 文件,在本例中是 env.prod,我们将使用它来输入 Docker 容器特定的环境变量,我们将在本文后面看到。
-
环境变量- 这定义了将在我们的 Docker 容器上设置的环境变量。在本例中,如果我们可以在 Linux 容器内执行 bash 命令并引用此处定义的环境变量,例如,
echo $DB_HOST将会输出:数据库
我们的 NGINX 容器定义如下:
# The Web Server
web:
container_name: nginx_server
build:
context: ./
dockerfile: development/web.dockerfile
volumes:
- ./storage/logs/:/var/log/nginx
ports:
- 8990:80
以上代码概述:
- container_name - 容器的名称,您可以选择更改它。
- 构建- 定义与上述相同。这里可以看到,我们将此容器的 Dockerfile 定义为 web.dockerfile。
- volumes - 定义同上。这里我们将 Laravel 的日志文件夹与 Nginx 的日志文件夹共享。
- 端口- 在这里,我们定义 Docker 容器将监听的主机端口以及 Docker 在容器部署期间创建的虚拟网络上的端口。这很容易理解:冒号左侧定义主机,因此定义主机上的端口;冒号右侧定义 Docker 容器,因此定义 Docker 容器上的端口。
我们的 MySQL 容器将定义如下:
# The Database
database:
container_name: mysql_database
image: mysql:5.7
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=Baly"
- "MYSQL_USER=phpmyadmin"
- "MYSQL_PASSWORD=phpmyadmin"
- "MYSQL_ROOT_PASSWORD=finallyJDBC2017."
ports:
- 8991:3306
以上代码概述:
- container_name - 请参考上文。
- 镜像- 在这种情况下,我们没有定义用于构建容器的 Dockerfile,而是定义了一个镜像。因此,我们的 Docker 容器将基于我们在此处定义的镜像构建
mysql5:7。您可以将此 MySQL 版本替换为您正在开发的版本。请记住,对于您的 Laravel 应用程序,最新版本的 MySQL 可能无法正常工作。这是因为最新版本的 MySQL 使用了不同的身份验证技术,而这种技术可能不被 MySQL 或 PDO PHP 扩展所支持。因此,在使用 `.`mysql:latest而不是 `.`时,请务必小心mysql:5.7。 - 卷- 概念仍然相同,只是现在我们已经
dbdata从主机定义了它将映射到/var/lib/mysqlDocker 容器。 - 环境- 与上述概念相同,不同之处在于,在这种情况下,我们的 MySQL 数据库将使用我们设置的变量进行初始化。因此,构建完成后,我们的容器将自动拥有一个名为 `<database_name>` 的数据库、一个名为`<user_name>`
database的用户(密码为 `<password>`)以及一个 root 用户(密码为 `<rootpassword>` )。您可以根据需要随意更改这些设置。我们在配置文件中定义这些设置,以避免当前配置文件设置与容器配置文件设置冲突。secretsecretsecret_rootenv.prod.env - 端口- 与上面相同,只是我们的 mysql 容器将在主机上的 8991 端口和容器网络上的 3306 端口(mysql 的默认端口)上监听。
定义您的命名卷
将以下内容复制粘贴到您的 docker-compose.yml 文件中:
volumes:
dbdata:
请确保保留 docker-compose.yml 文件中的缩进,以确保 docker-compose 能够正确读取。最终,您的 docker-compose 文件应如下所示:
version: '2'
services:
# The Application
app:
container_name: laravel_app
build:
context: ./
dockerfile: development/app.dockerfile
volumes:
- ./storage:/var/www/storage
env_file: '.env.prod'
environment:
- "DB_HOST=database"
- "REDIS_HOST=cache"
# The Web Server
web:
container_name: nginx_server
build:
context: ./
dockerfile: development/web.dockerfile
volumes:
- ./storage/logs/:/var/log/nginx
ports:
- 8990:80
# The Database
database:
container_name: mysql_database
image: mysql:5.7
volumes:
- dbdata:/var/lib/mysql
environment:
- "MYSQL_DATABASE=Baly"
- "MYSQL_USER=phpmyadmin"
- "MYSQL_PASSWORD=phpmyadmin"
- "MYSQL_ROOT_PASSWORD=finallyJDBC2017."
ports:
- 8991:3306
# redis
cache:
image: redis:3.0-alpine
volumes:
dbdata:
第二步:定义我们的 Dockerfile。
在这一步中,我们将为刚刚在 docker-compose 文件中定义的容器定义 Dockerfile。这些 Dockerfile 将代表一系列我们希望在 Docker 容器内运行的命令。
定义我们的“app”Dockerfile(laravel_app)
在 Laravel 应用的根目录下创建一个名为 `.laravel` 的文件夹development。在该文件夹内,创建一个名为 `.laravel.js` 的文件app.dockerfile(注意,不要有任何文件扩展名)。打开该文件,并将以下代码复制粘贴到其中:
FROM php:7.2-fpm
COPY composer.lock composer.json /var/www/
COPY database /var/www/database
WORKDIR /var/www
RUN apt-get update && apt-get -y install git && apt-get -y install zip
RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
&& php -r "if (hash_file('SHA384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
&& php composer-setup.php \
&& php -r "unlink('composer-setup.php');" \
&& php composer.phar install --no-dev --no-scripts \
&& rm composer.phar
COPY . /var/www
RUN chown -R www-data:www-data \
/var/www/storage \
/var/www/bootstrap/cache
RUN apt-get install -y libmcrypt-dev \
libmagickwand-dev --no-install-recommends \
&& pecl install mcrypt-1.0.2 \
&& docker-php-ext-install pdo_mysql \
&& docker-php-ext-enable mcrypt
RUN mv .env.prod .env
RUN php artisan optimize
上述代码概述
-
从 php:7.2-fpm 开始——这意味着我们将从镜像构建容器
php:7.2-fpm。此外,您可以根据您的开发环境需求更改此版本。 -
复制- 第一个复制命令将主机根目录下的文件复制
composer.lock到composer.jsonDocker/var/www/容器中。第二个复制命令将database主机上的文件夹复制到/var/www/databaseDocker 容器中的文件夹。这样做的原因有二:一是确保我们在开发环境(composer.json 文件)中使用的依赖项在下载依赖项时能够反映到容器中;二是确保在需要运行迁移migrate命令时,我们可以访问 Docker 容器内的迁移文件。 -
WORKDIR - 我们设置了工作目录,这意味着在需要运行 bash 命令的情况下,
/var/www我们不必进入此文件夹(移动到此文件夹)。cd -
运行- 在这里,我们将安装 Laravel 所需的所有依赖项,包括 Composer 及其依赖项。请注意这一行。其中定义的哈希值会随着每次更新而改变,因此,如果您的安装程序失败并显示“安装程序已损坏”的
if(hash_file('SHA384'...消息,请考虑从“获取哈希值”获取正确的哈希值。 -
COPY . /var/www - 此时,我们将所有文件夹内容复制到
/var/wwwdocker 容器中的文件夹中。 -
运行- 在最后的运行命令中,我们会清除应用程序缓存和其他缓存,并安装 Laravel 用于连接数据库的 MySQL 驱动程序。之后,我们将
.env.prod文件重命名,.env因为该文件将包含 Docker 容器环境特有的正确环境变量,因此 Laravel 应该使用它。我们运行命令php artisan optimize来删除该文件的缓存版本.env。
请注意,无需复制根文件夹(例如 vendor 文件夹)中的所有内容,Docker 提供了一个.dockerignore功能与 dockeringore 文件非常相似的文件.gitignore。我们的 dockeringore 文件内容如下:
.git
.idea
.env
node_modules
vendor
storage/framework/cache/**
storage/framework/sessions/**
storage/framework/views/**
development
将此文件保存在与您的 app.dockerfile 相同的文件夹中(开发文件夹)。
请.env.prod复制粘贴您的.env文件并将其重命名为.env.prod。在数据库设置中,将 更改为与您的MySQLDB_HOST容器名称匹配,并将密码更改为与您在文件中定义的密码匹配。如果您按照我的所有步骤操作且未做任何更改,那么您的 .env.prod 文件应该类似于以下内容:docker-compose.yml
DB_CONNECTION=mysql
DB_HOST=mysql_database
DB_PORT=3306
DB_DATABASE=Baly
DB_USERNAME=phpmyadmin
DB_PASSWORD=phpmyadmin
定义我们的“web”Dockerfile
在您刚刚创建的文件夹(开发文件夹)中,创建一个 Dockerfile 文件web.dockerfile。将以下内容复制粘贴到 Dockerfile 中:
FROM nginx:1.10-alpine
ADD development/vhost.conf /etc/nginx/conf.d/default.conf
COPY public /var/www/public
上述代码概述
我们从镜像构建 Dockerfile:。nginx:1.10-alpine然后我们将 nginx 的default.conf文件替换为vhost.conf我们稍后将创建的文件。
我们还将 Laravel 应用的公共目录复制到 Nginx 的公共目录中,Nginx 将为我们所有的公共资源提供服务。
在同一目录(开发目录)下创建 vhost.conf 文件,并将以下内容复制粘贴到该文件中:
server {
listen 80;
index index.php index.html;
root /var/www/public;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
location / {
try_files $uri /index.php?$args;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass app:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
我们的php-fpm容器将监听9000端口,因此app:9000
快到了……
所以,为了进行复核,您需要事先准备好以下文件:
- 根文件夹-
docker-compose.yml和.env.prod - 开发文件夹:
.dockerignoreapp.dockerfileweb.dockerfilevhost.conf
如果是这样,那么你就快完成了,但首先,还有一些前提条件:
如果您在 Windows 上使用 Docker Toolbox,并且您的 Laravel 应用文件夹位于除 `/etc/docker-compose up` 目录之外的其他文件夹中,C:/users则在主机和 Docker 容器之间共享卷时会遇到问题。这是因为当 Docker 虚拟机启动时,VirtualBox 不会挂载任何非 `/etc/docker-compose up` 目录的文件夹C:/users。因此,要解决此问题,请先运行以下命令停止正在运行的 Docker 虚拟机:
docker-machine stop
然后打开 VirtualBox,右键单击名为“default”的虚拟机,然后单击“设置”。导航到“共享文件夹”并单击它,然后添加一个新文件夹,用于存放 Laravel 应用文件夹。记得勾选“自动挂载”。之后,运行以下命令启动 Docker 虚拟机:
docker-machine start default
鼓声响起……
假设您已正确完成所有操作,请继续运行以下命令:
docker-compose up -d --build database && docker-compose up -d --build app && docker-compose up -d --build web
最后,执行以下命令进入 laravel_app 的 Docker 容器:
docker exec -it laravel_app bash
然后执行以下 Laravel 命令:
php artisan key:generate
php artisan config:cache
php artisan route:cache
请确保在 Laravel 应用的根目录下运行此命令。此命令会构建容器镜像并最终启动它们。如果一切顺利,您应该能够通过以下地址访问在容器中运行的 Laravel 应用:
0.0.0.0:8990
如果您使用了不同的端口,请将其替换8990为您在 docker-compose.yml 文件中定义的端口。
另外请注意,对于使用 Docker Toolbox 的用户,Docker 会创建一个虚拟网络并为其分配一个 IP 地址。您可以通过搜索docker quickstart terminal并运行命令来找到此 IP 地址。分配的 IP 地址将显示在弹出的终端窗口中,您可以通过以下方式访问您的 Laravel 应用:
your-docker-machine-ip:8990
好了,各位!你们已经成功将 Laravel 应用部署到 Docker 上了!敬请期待我的下一篇文章,我将在其中介绍如何将 Laravel 应用部署到生产环境。
文章来源:https://dev.to/balachbryan/deploying-your-laravel-app-on-docker-with-nginx-and-mysql-56ni