如何使用Docker Compose设置Laravel,Nginx和MySQL

在过去的几年里,Docker已成为部署应用程序的常用解决方案,这要归功于它如何简化在临时容器中运行和部署应用程序的过程。 Docker Compose允许开发人员在单个文件中定义其基础结构,从而进一步简化了开发过程。 在本教程中,您将使用Laravel框架构建Web应用程序,其中Nginx作为Web服务器,MySQL作为数据库,所有这些都在Docker容器中。

作者选择FreeBSD基金会作为Write for DOnations计划的一部分接受捐赠。

介绍

在过去几年中, Docker已成为部署应用程序的常用解决方案,这要归功于它如何简化在临时容器中运行和部署应用程序的过程。 当使用LEMP应用程序时,例如,使用PHPNginxMySQLLaravel框架,Docker可以显着简化设置过程。

Docker Compose允许开发人员在单个文件中定义其基础架构(包括应用程序服务,网络和卷),从而进一步简化了开发过程。 Docker Compose提供了运行多个docker container createdocker container run命令的有效替代方法。

在本教程中,您将使用Laravel框架构建Web应用程序,其中Nginx作为Web服务器,MySQL作为数据库,所有这些都在Docker容器中。 您将在docker-compose文件中定义整个配置,以及PHP,MySQL和Nginx的配置文件。

先决条件

在开始之前,您将需要:

第1步 - 下载Laravel并安装依赖项

作为第一步,我们将获得最新版本的Laravel并安装项目的依赖项,包括Composer ,PHP的应用程序级包管理器。 我们将使用Docker安装这些依赖项,以避免必须全局安装Composer。

首先,检查您是否在主目录中并将最新的Laravel版本克隆到名为laravel-app的目录:

cd ~
git clone https://github.com/laravel/laravel.git laravel-app

进入laravel-app目录:

cd ~/laravel-app

接下来,使用Docker的composer镜像来安装Laravel项目所需的目录,并避免全局安装Composer的开销:

docker run --rm -v $(pwd):/app composer install

-v--rm标志与--rm docker run会创建一个临时容器,该容器将在被删除之前绑定到当前目录。 这会将~/ laravel-app目录的内容复制到容器中,并确保将Composer创建的vendor文件夹复制到当前目录中。

最后一步,在项目目录上设置权限,使其由非root用户拥有:

sudo chown -R $USER:$USER ~/laravel-app

在第4步中为应用程序映像编写Dockerfile时,这将非常重要,因为它将允许您使用应用程序代码并以非root用户身份在容器中运行进程。

有了应用程序代码,您可以继续使用Docker Compose定义服务。

第2步 - 创建Docker Compose文件

使用Docker Compose构建应用程序简化了基础架构的设置和版本控制过程。 要设置我们的Laravel应用程序,我们将编写一个docker docker-compose文件,用于定义我们的Web服务器,数据库和应用程序服务。

打开文件:

nano ~/laravel-app/docker-compose.yml

docker-compose文件中,您将定义三个服务: appwebserverdb 将以下代码添加到文件中,确保使用您选择的强密码替换MYSQL_ROOT_PASSWORDroot密码,该密码在db服务下定义为环境变量

〜/ laravel应用内/搬运工-compose.yml
version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge

这里定义的服务包括:

  • app :此服务定义包含Laravel应用程序并运行您将在第4步中定义的自定义Docker映像digitalocean.com/php 。它还将容器中的working_dir设置为/var/www
  • webserver :此服务定义从Docker中提取nginx:alpine图像并公开端口80443
  • db :此服务定义从Docker中提取mysql:5.7.22映像并定义一些环境变量,包括应用程序的laravel数据库和数据库的root密码。 您可以根据需要随意命名数据库,并且应该使用自己的强密码替换your_mysql_root_password 此服务定义还将主机上的端口3306映射到容器上的端口3306

每个container_name属性都定义容器的名称,该名称对应于服务的名称。 如果您没有定义此属性,Docker将通过组合历史名人的姓名和由下划线分隔的随机单词为每个容器指定一个名称。

为了促进容器之间的通信,服务连接到称为app-network的桥接app-network 桥接网络使用软件桥,允许连接到同一桥接网络的容器相互通信。 网桥驱动程序会自动在主机中安装规则,以便不同网桥上的容器无法直接相互通信。 这为应用程序创建了更高级别的安全性,确保只有相关服务才能相互通信。 它还意味着您可以定义连接到相关功能的多个网络和服务:例如, frontend应用程序服务可以使用frontend网络,后端服务可以使用backend网络。

让我们看看如何添加卷并将挂载绑定到服务定义以保留应用程序数据。

第3步 - 保留数据

Docker具有强大而方便的功能来保存数据。 在我们的应用程序中,我们将使用绑定挂载来持久化数据库,应用程序和配置文件。 卷为容器的生命周期之外的备份和持久性提供了灵活性,而绑定挂载有助于在开发期间更改代码,从而可以在容器中立即更改主机文件或目录。 我们的设置将使用两者。

警告:通过使用绑定装入,您可以通过容器中运行的进程更改主机文件系统,包括创建,修改或删除重要的系统文件或目录。 这是一种具有安全隐患的强大功能,可能会影响主机系统上的非Docker进程。 小心使用绑定挂载。

dbdata docker-compose文件中,在db服务定义下定义一个名为dbdata的卷以保留MySQL数据库:

〜/ laravel应用内/搬运工-compose.yml
...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
    networks:
      - app-network
  ...

命名卷dbdata持久保存容器内存在的/var/lib/mysql文件夹的内容。 这允许您在不丢失数据的情况下停止并重新启动db服务。

在文件的底部,添加dbdata卷的定义:

〜/ laravel应用内/搬运工-compose.yml
...
#Volumes
volumes:
  dbdata:
    driver: local

有了这个定义,您就可以跨服务使用此卷。

接下来,为您将在第7步中创建的MySQL配置文件的db服务添加绑定装载:

〜/ laravel应用内/搬运工-compose.yml
...
#MySQL Service
db:
  ...
    volumes:
      - dbdata:/var/lib/mysql
      - ./mysql/my.cnf:/etc/mysql/my.cnf
  ...

这个绑定挂载将~/laravel-app/mysql/my.cnf绑定到容器中的~/laravel-app/mysql/my.cnf

接下来,将绑定挂载添加到webserver服务。 将有两个:一个用于您的应用程序代码,另一个用于您将在第6步中创建的Nginx配置定义:

〜/ laravel应用内/搬运工-compose.yml
#Nginx Service
webserver:
  ...
  volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
  networks:
      - app-network

第一个绑定装置将~/laravel-app目录中的应用程序代码绑定到容器内的/var/www目录。 您将添加到~/laravel-app/nginx/conf.d/的配置文件也将挂载到/etc/nginx/conf.d/中的/etc/nginx/conf.d/ ,允许您根据需要添加或修改配置目录的内容。

最后,将以下绑定装入添加到app服务中以获取应用程序代码和配置文件:

〜/ laravel应用内/搬运工-compose.yml
#PHP Service
app:
  ...
  volumes:
       - ./:/var/www
       - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
  networks:
      - app-network

app服务将~/laravel-app文件夹(包含应用程序代码)绑定到容器中的/var/www文件夹。 这将加快开发过程,因为对本地应用程序目录所做的任何更改都将立即反映在容器中。 您还将PHP配置文件~/laravel-app/php/local.ini绑定到容器内的/usr/local/etc/php/conf.d/local.ini 您将在第5步中创建本地PHP配置文件。

你的docker-compose文件现在看起来像这样:

〜/ laravel应用内/搬运工-compose.yml
version: '3'
services:

  #PHP Service
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: digitalocean.com/php
    container_name: app
    restart: unless-stopped
    tty: true
    environment:
      SERVICE_NAME: app
      SERVICE_TAGS: dev
    working_dir: /var/www
    volumes:
      - ./:/var/www
      - ./php/local.ini:/usr/local/etc/php/conf.d/local.ini
    networks:
      - app-network

  #Nginx Service
  webserver:
    image: nginx:alpine
    container_name: webserver
    restart: unless-stopped
    tty: true
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./:/var/www
      - ./nginx/conf.d/:/etc/nginx/conf.d/
    networks:
      - app-network

  #MySQL Service
  db:
    image: mysql:5.7.22
    container_name: db
    restart: unless-stopped
    tty: true
    ports:
      - "3306:3306"
    environment:
      MYSQL_DATABASE: laravel
      MYSQL_ROOT_PASSWORD: your_mysql_root_password
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql
    volumes:
      - dbdata:/var/lib/mysql/
      - ./mysql/my.cnf:/etc/mysql/my.cnf
    networks:
      - app-network

#Docker Networks
networks:
  app-network:
    driver: bridge
#Volumes
volumes:
  dbdata:
    driver: local

完成更改后,保存文件并退出编辑器。

编写docker-compose文件后,您现在可以为应用程序构建自定义映像。

第4步 - 创建Dockerfile

Docker允许您使用Dockerfile指定单个容器内的环境。 Dockerfile使您可以创建自定义映像,可用于安装应用程序所需的软件并根据您的要求配置设置。 您可以将创建的自定义映像推送到Docker Hub或任何私有注册表。

我们的Dockerfile将位于~/laravel-app目录中。 创建文件:

nano ~/laravel-app/Dockerfile

Dockerfile将设置基本映像并指定构建Laravel应用程序映像所需的命令和说明。 将以下代码添加到文件中:

〜/ laravel应用内/ PHP / Dockerfile
FROM php:7.2-fpm

# Copy composer.lock and composer.json
COPY composer.lock composer.json /var/www/

# Set working directory
WORKDIR /var/www

# Install dependencies
RUN apt-get update && apt-get install -y \
    build-essential \
    mysql-client \
    libpng-dev \
    libjpeg62-turbo-dev \
    libfreetype6-dev \
    locales \
    zip \
    jpegoptim optipng pngquant gifsicle \
    vim \
    unzip \
    git \
    curl

# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Install extensions
RUN docker-php-ext-install pdo_mysql mbstring zip exif pcntl
RUN docker-php-ext-configure gd --with-gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ --with-png-dir=/usr/include/
RUN docker-php-ext-install gd

# Install composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Add user for laravel application
RUN groupadd -g 1000 www
RUN useradd -u 1000 -ms /bin/bash -g www www

# Copy existing application directory contents
COPY . /var/www

# Copy existing application directory permissions
COPY --chown=www:www . /var/www

# Change current user to www
USER www

# Expose port 9000 and start php-fpm server
EXPOSE 9000
CMD ["php-fpm"]

首先,Dockerfile在php:7.2-fpm Docker镜像之上创建一个图像 这是一个基于Debian的映像,它安装了PHP FastCGI实现PHP-FPM 该文件还为Laravel安装了必备软件包: mcryptpdo_mysqlmbstringimagick with composer

RUN指令指定更新,安装和配置容器内设置的命令,包括创建名为www的专用用户和组。 WORKDIR指令将/var/www目录指定为应用程序的工作目录。

创建具有受限权限的专用用户和组可以减少运行Docker容器时的固有漏洞,该容器默认以root身份运行。 我们创建了www用户, --chown是以root用户身份运行这个容器,因为我们正在使用带有--chown标志的COPY指令来复制应用程序文件夹的权限,他对/var/www文件夹具有读/写权限。 。

最后, EXPOSE命令为php-fpm服务器公开容器中的端口9000 CMD指定创建容器后应运行的命令。 在这里, CMD指定"php-fpm" ,它将启动服务器。

完成更改后,保存文件并退出编辑器。

您现在可以继续定义PHP配置。

第5步 - 配置PHP

现在您已经在docker-compose文件中定义了基础结构,您可以将PHP服务配置为充当来自Nginx的传入请求的PHP处理器。

要配置PHP,您将在php文件夹中创建local.ini文件。 这是在第2步中绑定到容器内的/usr/local/etc/php/conf.d/local.ini的文件。创建此文件将允许您覆盖PHP读取的默认php.ini文件什么时候开始

创建php目录:

mkdir ~/laravel-app/php

接下来,打开local.ini文件:

nano ~/laravel-app/php/local.ini

为了演示如何配置PHP,我们将添加以下代码来设置上传文件的大小限制:

〜/ laravel应用内/ PHP / local.ini
upload_max_filesize=40M
post_max_size=40M

upload_max_filesizepost_max_size指令设置上传文件的最大允许大小,并演示如何从local.ini文件设置php.ini配置。 您可以在local.ini文件中放置要覆盖的任何特定于PHP的配置。

保存文件并退出编辑器。

使用PHP local.ini文件,您可以继续配置Nginx。

第6步 - 配置Nginx

配置PHP服务后,您可以修改Nginx服务以使用PHP-FPM作为FastCGI服务器来提供动态内容。 FastCGI服务器基于二进制协议,用于将交互式程序与Web服务器连接。 有关更多信息,请参阅有关在Nginx中理解和实现FastCGI代理的文章。

要配置Nginx,您将在~/laravel-app/nginx/conf.d/文件夹中创建一个带有服务配置的app.conf文件。

首先,创建nginx/conf.d/目录:

mkdir -p ~/laravel-app/nginx/conf.d

接下来,创建app.conf配置文件:

nano ~/laravel-app/nginx/conf.d/app.conf

将以下代码添加到文件中以指定Nginx配置:

〜/ laravel应用内/ nginx的/ conf.d / app.conf
server {
    listen 80;
    index index.php index.html;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /var/www/public;
    location ~ \.php$ {
        try_files $uri =404;
        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;
    }
    location / {
        try_files $uri $uri/ /index.php?$query_string;
        gzip_static on;
    }
}

服务器块使用以下指令定义Nginx Web服务器的配置:

  • listen :该指令定义服务器将监听传入请求的端口。
  • error_logaccess_log :这些指令定义用于写入日志的文件。
  • root :该指令设置根文件夹路径,形成本地文件系统上任何请求文件的完整路径。

php位置块中, fastcgi_pass指令指定app服务正在监听端口9000上的TCP套接字。 这使得PHP-FPM服务器通过网络而不是Unix套接字进行监听。 尽管Unix套接字在速度上比TCP套接字略有优势,但它没有网络协议,因此会跳过网络。 对于主机位于一台计算机上的情况,Unix套接字可能有意义,但是如果您在不同主机上运行服务,则TCP套接字提供了允许您连接到分布式服务的优势。 因为我们的app容器在与我们的webserver容器不同的主机上运行,​​所以TCP套接字对我们的配置最有意义。

完成更改后,保存文件并退出编辑器。

由于您在第2步中创建的绑定装载,您在nginx/conf.d/文件夹中所做的任何更改都将直接反映在webserver容器中。

接下来,让我们看看我们的MySQL设置。

第7步 - 配置MySQL

配置PHP和Nginx后,您可以启用MySQL作为应用程序的数据库。

要配置MySQL,您将在mysql文件夹中创建my.cnf文件。 这是在第2步中绑定到容器内的my.cnf的文件。此绑定装置允许您在需要时覆盖my.cnf设置。

为了演示其工作原理,我们将向my.cnf文件添加设置,以启用常规查询日志并指定日志文件。

首先,创建mysql目录:

mkdir ~/laravel-app/mysql

接下来,制作my.cnf文件:

nano ~/laravel-app/mysql/my.cnf

在该文件中,添加以下代码以启用查询日志并设置日志文件位置:

〜/ laravel应用内/ MySQL的/ my.cnf中
[mysqld]
general_log = 1
general_log_file = /var/lib/mysql/general.log

my.cnf文件启用日志,将general_log设置定义为1以允许常规日志。 general_log_file设置指定日志的存储位置。

保存文件并退出编辑器。

我们的下一步将是启动容器。

第8步 - 运行容器和修改环境设置

现在您已在docker-compose文件中定义了所有服务并为这些服务创建了配置文件,您可以启动容器。 但是,作为最后一步,我们将复制.env.example默认包含的.env.example文件,并将副本命名为.env ,这是Laravel期望定义其环境的文件:

cp .env.example .env

一旦启动容器,我们将在此文件中配置我们的设置的具体细节。

docker-compose文件中定义了所有服务后,您只需发出一个命令来启动所有容器,创建卷,以及设置和连接网络:

docker-compose up -d

当你第一次运行docker-compose up时,它会下载所有必要的Docker镜像,这可能需要一段时间。 下载图像并将其存储在本地计算机后,Compose将创建您的容器。 -d标志守护进程,在后台运行容器。

该过程完成后,使用以下命令列出所有正在运行的容器:

docker ps

您将看到以下输出,其中包含有关您的appwebserverdb容器的详细信息:

CONTAINER ID        NAMES               IMAGE                             STATUS              PORTS
c31b7b3251e0        db                  mysql:5.7.22                      Up 2 seconds        0.0.0.0:3306->3306/tcp
ed5a69704580        app                 digitalocean.com/php              Up 2 seconds        9000/tcp
5ce4ee31d7c0        webserver           nginx:alpine                      Up 2 seconds        0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp

此输出中的CONTAINER ID是每个容器的唯一标识符,而NAMES列出与每个容器关联的服务名称。 您可以使用这两个标识符来访问容器。 IMAGE定义每个容器的图像名称,而STATUS提供有关容器状态的信息:它是否正在运行,重新启动或停止。

您现在可以修改app容器上的.env文件,以包含有关您的设置的特定详细信息。

使用docker-compose exec打开文件,它允许您在容器中运行特定命令。 在这种情况下,您将打开文件进行编辑:

docker-compose exec app nano .env

找到指定DB_CONNECTION的块并更新它以反映您的设置的细节。 您将修改以下字段:

  • DB_HOST将是您的db数据库容器。
  • DB_DATABASE将是laravel数据库。
  • DB_USERNAME将是您将用于数据库的用户名。 在这种情况下,我们将使用laraveluser
  • DB_PASSWORD将是您要用于此用户帐户的安全密码。
/var/www/.env
DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=laravel
DB_USERNAME=laraveluser
DB_PASSWORD=your_laravel_db_password

保存更改并退出编辑器。

接下来,使用php artisan key:generate命令为Laravel应用程序设置应用程序密钥。 此命令将生成密钥并将其复制到.env文件,以确保您的用户会话和加密数据保持安全:

docker-compose exec app php artisan key:generate

您现在拥有运行应用程序所需的环境设置。 要将这些设置缓存到文件中,这将提高应用程序的加载速度,请运行:

docker-compose exec app php artisan config:cache

您的配置设置将加载到容器上的/var/www/bootstrap/cache/config.php中。

最后一步,在浏览器中访问http:// your_server_ip 您将看到Laravel应用程序的以下主页:

Laravel主页

随着容器的运行和配置信息的到位,您可以继续在db容器上配置laravel数据库的用户信息。

第9步 - 为MySQL创建用户

默认的MySQL安装仅创建管理帐户,该帐户在数据库服务器上具有无限权限。 通常,最好避免在与数据库交互时使用管理帐户。 相反,让我们为应用程序的Laravel数据库创建一个专用的数据库用户。

要创建新用户,请使用docker-compose execdb容器上执行交互式bash shell:

docker-compose exec db bash

在容器内,登录MySQL 管理帐户:

mysql -u root -p

docker-compose文件中安装期间,系统将提示您输入为MySQL root帐户设置的密码。

首先检查您在laravel docker-compose文件中定义的名为laravel的数据库。 运行show databases命令以检查现有数据库:

show databases;

您将看到输出中列出的laravel数据库:

+--------------------+
| Database           |
+--------------------+
| information_schema |
| laravel            |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

接下来,创建将允许访问此数据库的用户帐户。 我们的用户名将是laraveluser ,但如果您愿意,可以使用其他名称替换它。 请确保您的用户名和密码与您在上一步中的.env文件中设置的详细信息相符:

GRANT ALL ON laravel.* TO 'laraveluser'@'%' IDENTIFIED BY 'your_laravel_db_password';

刷新权限以通知MySQL服务器更改:

FLUSH PRIVILEGES;

退出MySQL:

EXIT;

最后,退出容器:

exit

您已为Laravel应用程序数据库配置了用户帐户,并准备好迁移数据并使用Tinker控制台。

第10步 - 迁移数据和使用Tinker控制台

在您的应用程序运行时,您可以迁移数据并使用tinker命令进行实验,该命令将启动预装了Laravel的PsySH控制台。 PsySH是用于PHP的运行时开发人员控制台和交互式调试器,而Tinker是专门用于Laravel的REPL。 使用tinker命令将允许您从交互式shell中的命令行与Laravel应用程序进行交互。

首先,通过运行Laravel artisan migrate命令测试与MySQL的连接,该命令在容器内部创建数据库中的migrations表:

docker-compose exec app php artisan migrate

此命令将迁移默认的Laravel表。 确认迁移的输出将如下所示:


Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

迁移完成后,您可以使用tinker命令运行查询以检查是否已正确连接到数据库:

docker-compose exec app php artisan tinker

通过获取刚刚迁移的数据来测试MySQL连接:

\DB::table('migrations')->get();

您将看到如下所示的输出:

=> Illuminate\Support\Collection {#2856
     all: [
       {#2862
         +"id": 1,
         +"migration": "2014_10_12_000000_create_users_table",
         +"batch": 1,
       },
       {#2865
         +"id": 2,
         +"migration": "2014_10_12_100000_create_password_resets_table",
         +"batch": 1,
       },
     ],
   }

您可以使用tinker程序与数据库进行交互并尝试使用服务和模型。

有了Laravel应用程序,您就可以进行进一步的开发和实验。

结论

您现在已经在服务器上运行了LEMP应用程序,您已通过访问Laravel欢迎页面并创建MySQL数据库迁移来测试该应用程序。

这种安装简单的关键是Docker Compose,它允许您使用单个命令创建一组Docker容器,这些容器在单个文件中定义。 如果您想了解有关如何使用Docker Compose进行CI的更多信息,请参阅如何在Ubuntu 16.04上使用Docker和Docker Compose配置持续集成测试环境 如果您想简化Laravel应用程序部署过程,那么如何在Ubuntu 16.04上使用Deployer自动部署Laravel应用程序将是一个相关资源。


分享按钮