🐳

Rancher DesktopでDocker環境を構築する!②

2023/02/14に公開

前回のあらすじ
Rancher DesktopでDocker環境を構築する!①
今回はもうちょっと実用的な環境をDockerで作っていきます。

目標

docker composeでLEMP環境を作ってみます。

  • PHP8
  • MySQL8
  • Nginx(読み: エンジンエックス)

フレームワークはLaravel9を採用してみます。

動作確認済み環境

  • MacBook Air(M1, 2020)
  • メモリ: 16GB
  • macOS: Ventura 13.0.1
  • Rancher Desktop Version 1.7.0 (1.7.0)
  • git version 2.37.1

本記事の想定読者

  • VirtualBoxやVagrantは使ったことあるけどDockerは触ったことがない方
  • なんとなく誰かが作ってくれたDocker環境で開発してるけどもうちょっとDockerに詳しくなりたい方

本記事執筆の目的

  • なんとなく誰かが作ってくれたDocker環境で開発してるけどもうちょっとDockerに詳しくなりたい方
    → まさに自分がこの状態だったので、改めてDockerの知識を基礎から身につける
  • Docker初心者が最低限の知識を獲得できる内容であること
  • エラーなど失敗ケースも含めて記載し、知見共有ができるような記事であること

本記事では取り扱わないこと

  • Git, GitHubの使い方詳細説明
  • Windowsでの環境構築

前提

  • Rancher Desktopがインストールされ、dockerの各種コマンドが叩けること

下準備

各種バージョン確認

git --version
git version 2.37.1
docker --version
Docker version 20.10.10, build b485636
docker compose version    
Docker Compose version v2.1.1

バージョンの細かい違いは気にしなくても大丈夫ですが、Docker Composeだけはv2以上になっているかご確認ください。

→もし入っていなければ(バージョン情報が出てこなければ)、最新・安定版をインストールする

作業用ディレクトリをMac上に作成

今回は dev/sandbox_laravel9 を作成してみる(場所も名前もなんでも良いです)

GitHub上でリモートリポジトリを作成する

※GitHubアカウントを持っていない場合は、あらかじめ作成・初期設定しておく必要があります。

  1. ブラウザからGitHubへログインし、Create a new repository画面にいく
  2. Repository name以外はいじらなくてもOK
  3. 画面下の Create repositoryボタンを押す
  4. リモートリポジトリの作成手順が出てくるのでそれに従ってコマンド入力
cd dev/sandbox_laravel9
echo "# sandbox_laravel9" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:{GitHubユーザーアカウント名}/sandbox_laravel9.git
git push -u origin main

PHPのアプリケーションサーバーのコンテナを作る

復習: コンテナを作るには

  1. Dockerイメージを作るためのdockerfileが必要 ※DockerHubのイメージを使う時は別
  2. dockerfileを元にDockerイメージのビルドが必要
  3. 作成したDockerイメージからコンテナが作れる

先にフォルダ群と空ファイル群を作っておく

ルートディレクトリ直下にこのようなフォルダ・ファイルを作成しておきます。

infra/
  L php/
   L dockerfile
   L php.ini
src/
docker-compose.yml

docker-compose.yml の中身は下記の通りになります。

version: "3.9"
services:
  app:
    build: ./infra/php
    volumes:
      - ./src:/data

volumes:
- ./src:/data

↑ここでホスト側のディレクトリをコンテナ側にマウントするための設定を行っています。
=ホストとコンテナの間でソースの内容を同期させるためのもの

dockerfile

dockerfile の中身は下記の通りになります。
composerでライブラリの管理・PHPの拡張モジュール追加をやりたいので色々書いてあります。

FROM php:8.1-fpm-buster

ENV COMPOSER_ALLOW_SUPERUSER=1 \
  COMPOSER_HOME=/composer

COPY --from=composer:2.2 /usr/bin/composer /usr/bin/composer

RUN apt-get update && \
  apt-get -y install --no-install-recommends git unzip libzip-dev bicu-dev libonig-dev && \
  apt-get clean && \
  rm -rf /var/lib/apt/lists/* && \
  docker-php-ext-install intl pdo_mysql zip bcmath

COPY ./php.ini /usr/local/etc/php/php.ini

WORKDIR /data

dockerfileの命令文の詳細は↓を参照させていただきました。
https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4#補足infraphpdockerfile

php.ini

php.ini の中身は下記の通り。ひとまずこの辺の設定だけ入れておきます。

zend.exception_ignore_args = off
expose_php = on
max_execution_time = 30
max_input_vars = 1000
upload_max_filesize = 64M
post_max_size = 128M
memory_limit = 256M
error_reporting = E_ALL
display_errors = on
display_startup_errors = on
log_errors = on
error_log = /dev/stderr
default_charset = UTF-8

[Date]
date.timezone = Asia/Tokyo

[mysqlnd]
mysqlnd.collect_memory_statistics = on

[Assertion]
zend.assertions = 1

[mbstring]
mbstring.language = Japanese

ビルドしてイメージを作成する

今回はdockerfileに加え、docker-compose.ymlも使用してビルドし、Dockerイメージを作ってみます。
dev/sandbox_laravel9上で、

docker compose build


FINISHEDとなっていれば成功です。

作成したDockerイメージからコンテナを作成する

先ほどと同様のディレクトリで(docker-compose.ymlが置いてあるディレクトリ)

docker compose up -d


up はdocker-compose.ymlに書いてあるサービスを起動すること
-d は「デタッチドモード」で起動しますよ、のオプション(-dをつけないデフォルトの状態では「アタッチドモード」での起動になる)
今回は、バックグラウンドでの起動を意味する「デタッチドモード」を使いました。

コンテナ一覧を確認してみます

docker compose ps


STATUSがrunning(起動状態)になっています

作ったコンテナに入ってみましょう

docker compose exec app bash

app はymlファイルで指定したサービス名ですね

各種バージョン・PHP拡張機能を確認してみて問題がないか確認します

php -v
composer-V
php -m

exit でコンテナからでます

☕️ 余談

ちょっとした確認ならわざわざコンテナに入らなくても実行可能です💡
docker compose exec app php -v

ここまで作業内容をコミットする

キリが良いのでこの辺でgit commitしておきます。

一旦コンテナを破棄しておく

docker-compose.ymlはあとで内容を変更するので、一旦コンテナを破棄しちゃいます。
(気楽に破棄しても簡単に戻せるので大丈夫)

docker compose down

アプリケーションサーバー作りはここまで。
続いてwebサーバー(nginx)を作っていきます。

Nginxのwebサーバーのコンテナを作る

追加でフォルダ群と空ファイル群を作っておく

+ の箇所が追加部分です

 infra/
   L php/
    L dockerfile
    L php.ini
+ L nginx/
+   L default.conf
 src/
+ L public/
+   L index.html (動作確認用・後で消す)
+   L phpinfo.php (動作確認用・後で消す)
 docker-compose.yml

docker-compose.ymlに手を入れる

version: "3.9"
services:
  app:
    build: ./infra/php
    volumes:
      - ./src:/data

  web:
    image: nginx:1.20-alpine
    ports:
      - 8080:80
    volumes:
      - ./src:/data
      - ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
    working_dir: /data

↑ web:~以降を追加しました。

💀 (落とし穴ポイント)

追記時は、インデントに注意して記載してください。
docker-compose.ymlではインデントがズレるとうまく動作しません。

services:
 L app:
   L build: ~~~
   L volumes: ~~~
 L web:
   L image: ~~~
   L ports: 
      - ~~~
   L volumes:
      - ~~~
      - ~~~
   L working_dir: ~~~

こんなイメージです。

なお、インデントがズレると↓のようなエラーが発生します

docker compose up -d
(root) Additional property web is not allowed

参考
https://qiita.com/mida12251141/items/2e07cb332e436e56fcc9

また、NginxはDockerHubで公開されているDockerイメージをそのまま使うので、今回はNginx用にdockerfileは使いません。
https://hub.docker.com/_/nginx

docker-compose.yml追記部分の解説

ports:
- 8080:80
これは、ホスト側からコンテナ側にアクセスするための公開用の設定で、
ポート設定がないとアプリケーションサーバーとwebサーバーの繋がりが作れないため設定を書いています。

volumes:
- ./src:/data
- ./infra/nginx/default.conf:/etc/nginx/conf.d/default.conf
working_dir: /data
ホスト側にあるディレクトリ、ファイルをコンテナ内へマウント(同期)させるための設定です。
前回記事では、無理やり手動でソースの同期を行いましたが、この設定により自動的にソースの内容が同期できるようになります😇

infra/nginx/default.confの中身を書く

server {
    listen 80;
    server_name example.com;
    root /data/public;

    add_header X-Frame-Options "SAMEORIGIN";
    add_header X-XSS-Protection "1; mode=block";
    add_header X-Content-Type-Options "nosniff";

    index index.php;

    charset utf-8;

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

    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }

    error_page 404 /index.php;

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

    location ~ /\.(?!well-known).* {
        deny all;
    }
}

root, fastcgi_pass のドキュメントルート設定を書き換えています。
設定の詳細はこちらを参照ください
https://nginx.org/en/docs/beginners_guide.html

いよいよビルドしてみる

アプリケーションサーバーの時同様、docker-compose.ymlのあるディレクトリでビルドのコマンドを実行します。

docker compose up -d

念の為確認

docker compose ps


問題なさそうです

Nginxのバージョン確認もしてみます

docker compose exec web nginx -v

nginx version: nginx/1.20.2

バージョンが表示されていれば成功です。

ブラウザで画面表示できるか確認してみる

src/public内の2ファイルに表示確認ができそうなことを書いてみましょう。

  • index.html
<p>Hello, world!</p>
  • phpinfo.php
<?php phpinfo(); ?>

この状態でブラウザを確認し、

  • http://localhost:8080/index.htmlHello, world! と表示されていること、
  • http://localhost:8080/phpinfo.php で、phpの環境情報の画面が表示されること
    これら2点が確認できれば成功です。

💀 (落とし穴ポイント)

余談: この時点でinfra/nginx/default.confがなかったり、中身が空っぽだと、
ブラウザ上ではレスポンスが返ってこないというエラーが出てしまうので注意。

ブラウザ表示確認ができたのでindex.htmlとphpinfo,phpは削除しちゃいましょう。

rm -rf src/*

rm -rf は実行すると取り返しのつかない強制削除なので警告が出ますが、このまま"y"(yes)を入力して実行してください。

ここまで作業内容をコミットする

キリが良いのでこの辺でgit commitしておきます。

Laravelをインストールする

手順

  1. appコンテナに入る
  2. composerでLaravelをインストールする
  3. ブラウザ上でLaravelの初期画面が出るか確認する

appコンテナに入ります

docker compose exec app bash

コンテナに入ったらcomposerでLaravelをインストールします

composer create-project --prefer-dist "laravel/laravel=9.*" .

💀 (落とし穴ポイント) /data/vendorディレクトリがない

インストールを進めていると、諸々のエラーが表示されてしまいます。
また、このままブラウザでアクセスするとエラーが表示されLaravelのwelcome画面が表示されません。
http://localhost:8080

色々とエラーが表示されていますが、
結論から言うと、

/data/public/../vendor/autoload.php を開くのに失敗してエラーになっていることを確認します。
git cloneが終わった状態では app コンテナ内に /data/vendor ディレクトリが存在しないためです。

参考
https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4#構築環境使用技術
というわけで色々対処が必要そうです。

😇 解決方法

appコンテナに入ります

docker compose exec app bash

書き込み権限がないとキャッシュやログにエラーを書き込めないので、権限を付与

chmod -R 777 storage bootstrap/cache

vendor ディレクトリへライブラリ群をインストール

composer install

もう一度、 http://localhost:8080 にアクセスします。

💀 (落とし穴ポイント) No application encryption key has been specified.

さっきとは違うエラーが出てきます。
これは、

「アプリケーション暗号化キーが指定されていません。」というエラーになります。
.env の APP_KEY に値が設定されてないと表示されるエラーです。

.env.example はありますが、 .env ファイルが存在しません。
理由は .env はGit管理対象外に設定されているからです。

参考
https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4#構築環境使用技術

😇 解決方法

.env.example を元に .env コピーして作成してみましょう
(.envはLaravelアプリケーション全体の設定ファイル)
appコンテナに入った状態で

cp .env.example .env

💀 (落とし穴ポイント) APP KEYがない

また同じエラーが出てきました。APP KEYがないとかどうとか言われています。
現時点で .env の中身を見ると確かに'APP_KEY=' となっておりAPP KEYが設定されていないようです。

😇 解決方法

APP KEYを設定します

root@6fbff122b578:/data# php artisan key:generate

   INFO  Application key set successfully.

改めて .env を確認すると、何らかの乱数がAPP_KEYに設定されています。

再度ブラウザで確認すると・・・

welcome画面が表示されました🎉

シンボリックリンクを張る

→ システムで生成したファイル等をブラウザからアクセスできるよう公開するためのものです。

root@6fbff122b578:/data# php artisan storage:link

   INFO  The [public/storage] link has been connected to [storage/app/public].

🤔 シンボリックリンクが必要な理由

例えば、Laravelでファイルアップロード機能と、アップロードされた画像やPDFなどファイルをブラウザ表示させる機能を作る場合、シンボリックリンクがないとファイルを外部に公開することが出来ません。
そのため、Laravelの php artisan storage:link コマンドによって、
公開用のディレクトリを作成し、そこからアップロードされたファイルが保存されたディレクトリを参照することが出来るようにする必要があるという訳です。

ここまで作業内容をコミットする

キリが良いのでコンテナから exit して、git commitしておきます。

おわりに

今回はアプリケーションサーバーとwebサーバーのコンテナを作成しました。
これでPHPとLaravelが動作する状態になりました。

次回ではまたまたdocker-compose.ymlを変更することになります。
そのため、一旦コンテナは破棄しましょう。

 docker compose down

次はDBコンテナを作成していきます。

続く

Discussion