0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

コンテナ環境でLaravelを動かす

Last updated at Posted at 2023-08-10

概要

自分用の備忘録です。
用語が間違っていたり、理解が微妙に違うこともあるかもしれませんが、あくまで自分用ですのでご了承ください。

目標

コンテナ環境を構築して、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 Official Image
※既存イメージをそのまま使用する場合はDockerfileは不要となります。

docker/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 Official Image

docker/php/Dockerfile
FROM php:8.2-fpm

ENV LANG ja_JP.UTF-8

後でたくさん書き足すのですが、順を追って書いていきたいのでひとまずこれだけ記載しておきます。

MysqlのDockerfileを作成

dockerディレクトにmysqlディレクトリを作成し、mysqlディレクトリ内にDockerfileを作成します。

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

今回はDockerHubの公式イメージを少し調整したものを使用します。
Docker Hub mysql Official Image

docker/mysql/Dockerfile
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 Official Image

docker/redis/Dockerfile
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
docker/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

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コマンドが使用できるようになっています。

docker/php/Dockerfile
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に実行コマンドを追記します。

docker/php/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のバージョンが表示されればOK。
確認ができたので、一旦コンテナを落としておきます。

$ exit
$ docker-compose down

Laravelをインストール

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

まず、ローカルにマウント用のprojectディレクトリを作成します。

$ 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プロジェクトをインストールします。

php-fpmコンテナ内
$ cd /
$ composer create-project laravel/laravel project

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

localhostでLaravelにアクセスする

locahostにアクセスしたときに、Laravelのページが表示されるようにします。
そのためにはnginxの設定を修正する必要があります。

nginxのconfファイルを修正

localhostにアクセスしたときに、Laravelのpublic/index.phpが表示されるように修正する必要があります。
nginxコンテナのdefault.confをローカルにコピーして、必要に応じて修正したものを、コンテナ起動時にnginxコンテナのdefault.confに上書きします。
ローカルのファイルはdocker/nginx/conf/default.confにコピーします。

ローカル
$ pwd
/Users/username/study/docker/nginx
$ mkdir conf
$ cd conf
$ vim default.conf
nginxコンテナ
$ cat /etc/nginx/conf.d/default.conf

nginxコンテナのdefault.confの内容は以下の通りです。

/etc/nginx/conf.d/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公式ドキュメントを参考に設定を修正していきます。

docker/nginx/conf/default.conf
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`は左から順にファイルまたはディレクトリを探してくれる設定です。
さらに下記の設定も修正します。

docker/nginx/conf/default.conf
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_paramincludeの値はは公式ドキュメントのままです。

次に、このdefault.confをコンテナ起動時にphp-fpmコンテナのdefault.confに上書きするための設定を追加します。

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

COPYコマンドで上書きが可能です。
ローカルに置いてあるファイルはDockerfileから見たパスを記載します。

また、nginxコンテナにもLaravelプロジェクトを配置するため、docker-compose.ymlにマウントの設定を追加します。

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

設定が完了したのでイメージのビルド/コンテナの立ち上げを行います。
localhostにアクセスすると、Laravelのデフォルトのページが表示されます。

LaravelからDBにアクセス

LaravelからDBにアクセスするには設定の追加が必要になります。
LaravelのDBアクセス時に使用するドライバーの設定は、config/database.phpに記載されており、さらにそこではenvファイルからの読み込みが行われています。
なので、.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に下記を追記します。

docker/php/Dockerfile
RUN docker-php-ext-install pdo_mysql

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

これでDBにアクセスできるはず。
確認のために、適当なテーブルとデータを作成し、そのデータをLaravel側から読み込みできるようにしてみます。
まずmysqlコンテナからmysqlにログインし、testDBにexample_tableテーブルを作成します。
また、2件の適当なデータも作成しておきます。

$ 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アクセスしてみます。

php-fpmコンテナ内
$ 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を実行し、テーブルデータを取得できるかどうかも確認してみます。

php-fpmコンテナ内
$ 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コンテナのDockerfilemysql-cliのインストールを追記します。

docker/php/Dockerfile
RUN apt-get install -y git default-mysql-client

再度ビルドし、立ち上げ直すとmysq-cliがインストールされます。
実際にartisanコマンドを叩いてみます。

php-fpmコンテナ内
$ 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ファイルを修正する必要があります。

.env
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379

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

また、この設定を追加しただけではうまくドライバーを読み込んでくれないので、php-fpmコンテナに拡張モジュールを追加します。

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

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

php-fpmコンテナ内
$ pwd
/project
$ php artisan tinker
> use Illuminate\Support\Facades\Redis;
> Redis::set(“example”, "test");
= true

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

redisコンテナ内
$ redis-cli
127.0.0.1:6379> get laravel_database_example
"test"

redisに値が保存されていることが確認できました。
redisで保存した値を取得することも可能です。

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

また、php-fpmコンテナ内からredisにログインできるようにDockerfileを調整します。

docker/php/Dockerfile
RUN apt-get install -y redis-tools

再ビルドして反映すると、php-fpmコンテナでredis-cliが使用できるようになります。
ホストをredisにすることで、redisコンテナのredisサーバーに接続することができます。

php-fpmコンテナ内
$ redis-cli -h redis
redis:6379> 
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?