在容器环境中运行Laravel

简述

这是我个人的备忘录。
可能有术语错误或者理解略有出入,请理解这只是为了自己使用而准备的。

目标的含义。

建立容器环境,使得可以通过nginx访问Laravel。同时,确保Laravel能够访问到Mysql和Redis。

用法版本

将会使用截至2023年6月16日的最新Laravel版本。
并使用与此相对应的每个软件的版本。

Laravel:10
PHP:8.2
nginx: 1.25.1
mysql: 8.1.0
redis: 7.0

方法

准备一个目录

我在这次工作中创建了一个名为study的工作目录。
在这个工作目录中,我将创建一个名为docker的目录。

$ mkdir docker
$ ls
docker    

将与容器相关的文件添加到此处的docker目录中。

准备一个Dockerfile

创建nginx的Dockerfile

在docker目录下创建一个名为nginx的文件夹,并在该文件夹内创建一个Dockerfile。

$ pwd
/Users/username/study/docker
$ mkdir nginx
$ ls
nginx
$ cd nginx
$ vim Dockerfile

本次我们将使用稍作调整的 DockerHub 官方镜像。Docker Hub nginx 官方镜像。若要使用现有镜像,请不需要使用 Dockerfile 文件。

FROM nginx:1.25.1

ENV LANG ja_JP.UTF-8

尝试运行nginx容器

为了确认Dockerfile已正确准备好,我们试着运行nginx容器并进行本地访问。这一步骤可以选择跳过。

$ docker build -t nginx:latest .
$ docker run -it -d -p 80:80 --name nginx_container nginx
$ docker exec -it nginx_container bash
$ nginx -v ←コンテナ内で実行
nginx version: nginx/1.25.1

如果显示了版本号,那么就表示成功了。
在Web浏览器中访问localhost:80,会显示nginx的默认页面。
在启动时别忘了指定端口号…!

创建 PHP 的 Dockerfile

在docker目录下创建php目录,并在该目录内创建Dockerfile。

$ pwd
/Users/username/study/docker
$ mkdir php
$ ls
php
$ cd php
$ vim Dockerfile

这次我们将使用基于Docker Hub官方镜像稍作调整的版本。Docker Hub PHP 官方镜像。

FROM php:8.2-fpm

ENV LANG ja_JP.UTF-8

暂时只写这么多,之后我会继续添加很多内容,但为了按顺序写,我想先这样记录下来。

创建Mysql的Docker文件

在docker目录下创建mysql目录,并在mysql目录中创建Dockerfile。

$ pwd
/Users/username/study/docker
$ mkdir mysql
$ ls
mysql
$ cd mysql
$ vim Dockerfile

这次我们将使用稍作调整的DockerHub官方镜像。Docker Hub的MySQL官方镜像。

FROM mysql:8.1.0

ENV LANG ja_JP.UTF-8

创建reids的Dockerfile

在docker目录中创建一个redis目录,并在redis目录中创建一个Dockerfile。

$ pwd
/Users/username/study/docker
$ mkdir redis
$ ls
redis
$ cd redis
$ vim Dockerfile

这次我们将使用基于Docker Hub官方镜像稍作调整的版本。
Docker Hub的Redis官方镜像。

FROM redis:7.0

ENV LANG ja_JP.UTF-8

创建一个docker-compose文件。

docker-compose是一个用于批量管理多个容器的工具。
通过在docker-compose.yml文件中预先设置各个容器的选项,可以自动执行容器的启动等操作,无需每次手动输入选项。

在docker文件夹的同一层级中创建一个docker-compose.yml文件。

$ pwd
/Users/username/study
vim docker-compose.yml
version: '3'

services:
  nginx:
    build: docker/nginx
    ports:
      - "80:80"
    depends_on:
      - php-fpm

  php-fpm:
    build: docker/php
    depends_on:
      - mysql
      - redis

  mysql:
    build: docker/mysql
    volumes:
      - docker/mysql/var/lib/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: test
      MYSQL_USER: test
      MYSQL_PASSWORD: test

  redis:
    build: docker/redis
Nginx (一个开源的高性能 Web 服务器)

nginxコンテナにはコンテナの外からアクセスがいくので、ポートを指定しておく必要があります。
今回はホストコンピュータ/nginxコンテナの両ポート共に80に設定してあります。
また、nginxコンテナはphp-fpmコンテナ起動後に起動してほしいため、起動順序の設定も記載しておきます。

php-fpm

また、php-fpmコンテナはmysqlコンテナとredisコンテナの起動後に起動してほしいため、起動順序の設定を記載しておきます。

mysql

mysqlコンテナは環境変数をいくつか設定する必要があります。
公式ドキュメントに沿って設定していきます。

MYSQL_ROOT_PASSWORD
ルートユーザーのパスワードを設定します。この変数は必須です。
本来はファイルに機密事項を記載しない方がよく、別ファイルから変数を読み込む方法がありますが、ひとまず割愛します。

MYSQL_DATABASE
设置在容器启动时要创建的数据库。
如果指定了用户名/密码,则该用户将被授予GRANT ALL的访问权限。

MYSQL_USER, MYSQL_PASSWORD
MYSQL_DATABASEで作成したデーターベースにアクセスできるユーザーを作成します。
この変数はオプションであり必須ではありませんが、ユーザー作成をする場合は両オプションを指定する必要があります。

また、今回使用するデータベースでは、コンテナを停止した際にもデータが消えないようにしたいので、追加で設定をしていきます。
公式ドキュメントに記載されている方法は2通りありますが、今回はホストコンピュータにデータ保存用のvarディレクトリを作成し、/var/lib_mysqlディレクトリにマウントします。
マウントの設定は上記のdocker-compose.ymlに記載した通りで、マウント用のディレクトリは下記手順で作成します。

$ pwd
/Users/username/study/docker/mysql
$ mkdir var
$ ls
Dockerfile var

当容器启动并生成数据时,相同的文件也会保存在var目录中。

redis

特に追加で必要な設定はないため、buildのみ指定しておきます。

docker-composeでコンテナを起動

docker-compose up -d

上記コマンドを実行することで、イメージのビルドからコンテナ起動までを一括で行ってくれます。
イメージが存在する場合はビルドがスキップされるので、Dockerfileを更新した場合は–buildオプションをつけて実行します。
また、作業ディレクトリ名_defaultという名前でネットワーク作成し、各コンテナをservice項目で指定したサービス名でこのネットワークに接続してくれます。

创建Laravel应用程序

由于容器创建已完成,我们将创建Laravel应用程序并对每个容器进行相应的Laravel调整。

安装所需的命令

为了安装Laravel,需要使用到Git和unzip等命令,因此我们需要在php-fpm容器的Dockerfile中添加安装命令。
本次使用的PHP镜像是基于debian:12-slim创建的,可以使用apt/apt-get命令来进行包的安装。

RUN apt-get update \
    && apt-get install -y git zlib1g-dev libzip-dev unzip \
    && pecl install zip \
    && docker-php-ext-enable zip

RUNコマンドは元となるdockerイメージに対して実行する処理を記述します。
バックスラッシュを用いることで、複数行に分けて記載可能です(見やすいように改行して記載できる)。
&&をつけることで1つのRUNコマンドに対して複数の処理を記載でき、これらを1つのレイヤとしてみなされるため、軽量になります。

コンテナに入って、試しにGitがインストールされていることを確認してみます。
php-fpmコンテナのイメージを更新したので、コンテナに反映するためには再ビルドする必要があります。
現在コンテナが起動状態のため、一度コンテナを停止・削除してから再ビルド・コンテナ作成・起動を行います。

$ docker-compose down
$ docker-compose up -d
$ docker exec -it <CONTAINER ID> bash
$ git -v
git version 2.39.2

我确认了Git的版本已显示。
确认完成后,我会先关闭容器。

$ exit
$ docker-compose down

安装Composer

php-fpmコンテナにComposerをインストールします。
今回はComposer公式ドキュメントに記載されている方法でインストールするので、インストールコマンドを実行するように、php-fpmコンテナのDockerfileに実行コマンドを追記します。

RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" \
   && php -r "if (hash_file('sha384', 'composer-setup.php') === 'e21205b207c3ff031906575712edab6f13eb0b361f2085f1f1237b7126d785e826a450292b6cfd1d64d92e6563bbde02') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" \
   && php composer-setup.php \
   && php -r "unlink('composer-setup.php');" \
   && mv composer.phar /usr/local/bin/composer

由于更新了php-fpm容器的镜像,因此需要重新构建容器才能将更新反映到容器中。

$ docker-compose up -d --build

我将重新启动完成。
接下来,进入php-fpm容器并确认Composer是否已安装。

$ docker exec -it <CONTAINER ID> bash
$ composer -v

如果上面的命令可以显示Composer的版本,那就可以了。
既然确认过了,我会先关闭容器。

$ exit
$ docker-compose down

安装Laravel。

次に、Composerを使用してLaravelをインストールします。
Composerはphp-fpmコンテナにインストールされているため、php-fpmコンテナ内でLaravelのインストールを行います。
また、コンテナ内のLaravelプロジェクト用ディレクトリとローカルのディレクトリをマウントさせておくことで、ローカルでの差分をすぐにコンテナに反映させることができるため、マウントの設定も追加していきます。

首先,创建一个用于挂载的项目目录在本地。

$ pwd
/Users/username/study
$ mkdir project
$ ls
docker docker-compose.yml project

将docker-compose.yml文件中添加挂载配置。
给project目录授予读写权限。

  php-fpm:
    build: ./docker/php
    volumes:                                     
      - ./project:/project:rw  ← NEW!
    depends_on:
      - mysql
      - redis

当您再次启动时,将会挂载project目录。
重新启动容器,并在php-fpm容器内安装Laravel项目。

$ cd /
$ composer create-project laravel/laravel project

インストール完了後にローカルのprojectディレクトリを確認すると、Laravelがインストールされています。

在本地主机上访问Laravel。

当访问 localhost 时,需要修改 nginx 的设置以显示 Laravel 页面。

修改nginx的conf文件

需要对Laravel的public/index.php进行修改,以便在访问localhost时显示该文件。将nginx容器的default.conf复制到本地,并在需要时进行修改,然后在容器启动时将其覆盖到nginx容器的default.conf中。本地文件将被复制到docker/nginx/conf/default.conf。

$ pwd
/Users/username/study/docker/nginx
$ mkdir conf
$ cd conf
$ vim default.conf
$ cat /etc/nginx/conf.d/default.conf

以下是nginx容器中default.conf的内容。

server {
    listen       80;
    listen  [::]:80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    # proxy the PHP scripts to Apache listening on 127.0.0.1:80
    #
    #location ~ \.php$ {
    #    proxy_pass   http://127.0.0.1;
    #}

    # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
    #
    #location ~ \.php$ {
    #    root           html;
    #    fastcgi_pass   127.0.0.1:9000;
    #    fastcgi_index  index.php;
    #    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;
    #    include        fastcgi_params;
    #}

    # deny access to .htaccess files, if Apache's document root
    # concurs with nginx's one
    #
    #location ~ /\.ht {
    #    deny  all;
    #}
}

使用cat命令显示/复制的内容将复制到本地的default.conf文件中。然后根据Laravel官方文档来修改配置。

server {
    :
    :
    root /project/public; 
    index index.php

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
    :
    :

在Laravel中,所有的处理都是从public/index.php文件开始的。因此,我们需要更改location的root为project/public,并将index更改为index.php,并将其写在location之外。try_files是一个按照顺序查找文件或目录的设置。

此外,我们也需要修改下面的配置。

server {
    :
    :

    location ~ \.php$ {
        fastcgi_pass php-fpm:9000;
        fastcgi_param  SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include        fastcgi_params;
    }
    :
    :

在fastcgi_pass中,需要指定php-fpm容器的服务名称和端口号。可以通过执行docker ps或docker-compose ps命令来确认端口号。fastcgi_param和include的值保持官方文档的原样。

接下来,我们将添加配置来在容器启动时覆盖php-fpm容器的default.conf文件。

COPY conf/default.conf /etc/nginx/conf.d/default.conf

可以使用COPY命令进行覆写。
将位于本地的文件路径写入Dockerfile。

另外,为了将Laravel项目部署到nginx容器中,我们需要在docker-compose.yml文件中添加挂载配置。

  nginx:
    build: ./docker/nginx
    volumes:
      - ./project:/project:ro ← NEW!
    ports:
      - "80:80"
    depends_on:
      - php-fpm

由于设置已完成,现在进行映像构建/容器启动。
访问localhost时,将显示Laravel的默认页面。

通过Laravel访问数据库

要从Laravel访问数据库,需要进行设置的补充。
Laravel访问数据库时使用的驱动程序设置在config/database.php文件中,并且在那里会从env文件中进行读取。
因此,需要修改.env文件。

DB_CONNECTION=mysql
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=test
DB_USERNAME=test
DB_PASSWORD=test

DB_HOSTにはdocker-compose.ymlで設定したMysqlコンテナのサービス名、DB_DATABASE/DB_USERNAME/DB_PASSWORDにはそれぞれMYSQL_DATABASE/MYSQL_USER/MYSQL_PASSWORDを記述します。

また、この設定を追加しただけではうまくドライバーを読み込んでくれないので、拡張モジュールをインストールする必要があります。
config/database.phpのmysqlのoptionsにpdo_mysqlをロードする旨が記載されているため、pdo_mysqlをインストールするようphp-fpmコンテナ用のDockerfileに下記を追記します。

RUN docker-php-ext-install pdo_mysql

ここでは新たにRUNコマンドを記載していますが、実際のファイルにはgit等をインストールしたときに記載したRUNコマンドに追記する形で記載しています。

用这个应该能够访问数据库。
为了确认,我们将创建一个适当的表格和数据,并确保能够从Laravel那边读取这些数据。
首先,从mysql容器登录mysql,然后在testDB中创建一个名为example_table的表格。
同时,我们还会创建两条适当的数据。

$ docker exec -it <CONTAINER ID> bash
$ mysql -utest -p --port 3306
mysql > use test
mysql > create table example_table (id int(11) auto_increment not null, name varchar(30) not null, age int(3) not null, primary key (id));
mysql> desc example_table;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| id    | int         | NO   | PRI | NULL    | auto_increment |
| name  | varchar(30) | NO   |     | NULL    |                |
| age   | int         | NO   |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
mysql> insert into example_table (name, age) values ('Sato', 25), ('Tanaka', 30);
mysql> select * from example_table;
+----+--------+-----+
| id | name   | age |
+----+--------+-----+
|  1 | Sato   |  25 |
|  2 | Tanaka |  30 |
+----+--------+-----+

データの作成が完了したので、artisanコマンドを使って実際にDBアクセスしてみます。

$ pwd
/project
php artisan db:table example_table
  example_table ...........................................  
  Columns ............................................... 3  
  Size ............................................ 0.02MiB  

  Column ............................................. Type  
  id autoincrement, integer ....................... integer  
  name string ...................................... string  
  age integer ..................................... integer  

  Index ...................................................  
  PRIMARY id .............................. unique, primary  

テーブル情報が正しく取得できました。
次にtinkerを実行し、テーブルデータを取得できるかどうかも確認してみます。

$ pwd
/project
$ php artisan tinker
> use Illuminate\Support\Facades\DB;
> DB::table('example_table')->get()
= Illuminate\Support\Collection {#6225
    all: [
      {#6228
        +"id": 1,
        +"name": "Sato",
        +"age": 25,
      },
      {#6230
        +"id": 2,
        +"name": "Tanaka",
        +"age": 30,
      },
    ],
  }

我已确认可以获取数据。

さらに、php-fpmコンテナからartisanコマンド経由でmysqlにログインできるようにします。
php-fpmコンテナのDockerfileにmysql-cliのインストールを追記します。

RUN apt-get install -y git default-mysql-client

重新构建并重新启动后,将安装mysq-cli。我将实际运行artisan命令来尝试一下。

$ pwd
/project
$ php artisan db
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.1.0 MySQL Community Server - GPL

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

MySQL [test]> 

artisanコマンド経由でmysqlにログインすることができました。

LaravelからRedisにアクセス

LaravelからRedisにアクセスするには設定の追加が必要になります。
LaravelのRedisアクセス時に使用するドライバーの設定は、config/database.phpに記載されており、さらにそこではenvファイルからの読み込みが行われています。
なので、.envファイルを修正する必要があります。

REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

REDIS_HOSTにはdocker-compose.ymlで設定したRedisコンテナのサービス名を記述します。

另外,仅仅添加这个设置是无法成功加载驱动程序的,所以我们需要向php-fpm容器添加扩展模块。

RUN pecl install redis \
    && docker-php-ext-enable redis

これで動くようになったか実際に確認してみます。
artisanコマンド経由でRedisに適当な値を保存してみます。

$ pwd
/project
$ php artisan tinker
> use Illuminate\Support\Facades\Redis;
> Redis::set(“example”, "test");
= true

Redisファサードを使用して保存したため、config/database.phpのdefaultの設定を使用しています。
今回はホスト以外の値はデフォルトのままなので、redisコンテナのDB0に保存されているはずです。
また、REDIS_PREFIXの設定をしていないため、デフォルトの設定によりlaravel_database_exampleというkeyで保存されます。

$ redis-cli
127.0.0.1:6379> get laravel_database_example
"test"

我已经确认了在Redis中保存了值。
还可以获取在Redis中保存的值。

$ redis-cli
127.0.0.1:6379> set laravel_database_example2 aaaaaaaaaaaaaa
OK
$ pwd
/project
$ php artisan tinker
> use Illuminate\Support\Facades\Redis;
> Redis::get("example2");
= "aaaaaaaaaaaaaa"

此外,我们将调整Dockerfile,以便在php-fpm容器内可以登录到redis。

RUN apt-get install -y redis-tools

再进行重建并应用后,可以在php-fpm容器中使用redis-cli工具。
通过将主机设置为redis,可以连接到redis容器的redis服务器。

$ redis-cli -h redis
redis:6379> 
广告
将在 10 秒后关闭
bannerAds