12/8 は @FrozenVoice さんの Notion の使い方の記事でした。
自分も最近 Notion を使う機会が多いですが、いつも雰囲気で使っているので、かなりありがたい記事でした。
ありがとうございました。
この記事について
Laravel の環境を構築する際にはいつも @ucan-lab さんの docker-laravel にお世話になっているのですが、コピペするばかりでちゃんと理解できていなかったので、これを機会に調べてみることにしました。
以前社内の勉強会で記事を書いたのですが、そこからさらに掘り下げてみたいと思います。
この記事の目的は、あくまで自分で調べて理解することなので、
docker-laravel の解説が見たいって人はこの記事を参考にしてもらうのが一番いいと思います。
基本調べたことを書いていますが、自分の解釈が入っている部分もあります。
もし間違いがあれば指摘して欲しいです。
docker-compose.yml
version: "3.9" # ① docker-compose.yaml のバージョン
volumes: # ② ボリュームを生成
php-fpm-socket:
db-store:
psysh-store:
services: # ③ サービスの定義
app: # ④ サービスの名前
build: # ⑤ ビルド時に適応される構成
context: .
dockerfile: ./infra/docker/php/Dockerfile # Dockerfile の中身は後で確認します
volumes: # ⑥ バインドマウントやボリュームマウントなどの設定
- type: volume # ⑦ unixソケットをマウント
source: php-fpm-socket
target: /var/run/php-fpm
volume:
nocopy: true
- type: bind # ⑧ Laravel のソースコードをマウント
source: ./backend
target: /work/backend
- type: volume # ⑨ psysh をマウント
source: psysh-store
target: /root/.config/psysh
volume:
nocopy: true
environment: # ⑩ 環境変数を設定
- DB_CONNECTION=mysql
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=${DB_NAME:-laravel_local}
- DB_USERNAME=${DB_USER:-phper}
- DB_PASSWORD=${DB_PASS:-secret}
web:
build:
context: .
dockerfile: ./infra/docker/nginx/Dockerfile
ports: # ⑪ 公開用ポートをマッピング
- target: 80
published: ${WEB_PORT:-80}
protocol: tcp
mode: host
volumes:
- type: volume # ⑫ unixソケットをマウント
source: php-fpm-socket
target: /var/run/php-fpm
volume:
nocopy: true
- type: bind # ⑬ Laravel のソースコードをマウント
source: ./backend
target: /work/backend
db:
build:
context: .
dockerfile: ./infra/docker/mysql/Dockerfile
ports:
- target: 3306
published: ${DB_PORT:-3306}
protocol: tcp
mode: host
volumes:
- type: volume
source: db-store
target: /var/lib/mysql # ⑭ mysqlをマウント
volume:
nocopy: true
environment:
- MYSQL_DATABASE=${DB_NAME:-laravel_local}
- MYSQL_USER=${DB_USER:-phper}
- MYSQL_PASSWORD=${DB_PASS:-secret}
- MYSQL_ROOT_PASSWORD=${DB_PASS:-secret}
① docker-compose.yaml のバージョン
version: "3.9" # ① docker-compose.yaml のバージョン
- 指定されるバージョンによって docker-compose.yml の書き方が変わる
② ボリュームを生成
volumes: # ② ボリュームを生成
php-fpm-socket:
db-store:
psysh-store:
- Docker Engine 上で確保した領域にマウントすることでコンテナを削除してもデータが消えない
- 名前は任意につけて大丈夫
docker volume create php-fpm-socket
docker volume create db-store
docker volume create psysh-store
としているのと同じ
- ボリュームは Docker Engine 上で管理されるため、物理的な位置を意識する必要はない
- ボリュームはブラックボックスになっていて、Docker ホスト(自分のPC)からは変更することはできない
③ サービスの定義
services: # ③ サービスの定義
サービス名:
サービスの定義:
サービス名:
サービスの定義:
-
サービス1つ1つがコンテナ
-
今回の場合だと
app
コンテナ、web
コンテナ、db
コンテナを定義している
④ サービスの名前
app: # ④ サービスの名前
- 任意でつけて問題ない
⑤ ビルド時に適応される構成
build: # ⑤ ビルド時に適応される構成
context: .
dockerfile: ./infra/docker/php/Dockerfile # Dockerfile の中身は後で確認します
-
context
とdockerfile
の位置を明示的に指定している -
context
とはdocker build
コマンドを実行したカレントディレクトリ -
Docker はカレントディレクトリ(コンテキスト)外のファイルにはアクセスできない
-
context
でコンテキストをルートディレクトリに指定することで、dockerfile
からどのディレクトリへのアクセスも可能にしている
⑥ バインドマウントやボリュームマウントなどの設定
volumes: # ⑥ バインドマウントやボリュームマウントなどの設定
【バインドマウント】
-
Docker ホストにあらかじめディレクトリを作っておいて、それをマウントする方法。
-
ホストで変更した Laravel ファイルが Docker 内にも反映されるのはこいつのおかげ。
【ボリュームマウント】
-
ホスト上のディレクトリではなくて、 Docker Engine 上で確保した領域をマウントする方法。
-
確保した場所のことを「データボリューム」、「ボリューム」と言ったりする。
-
volumes
で作成した。
- 一行で記述する方法と、複数行で記述する方法がある。今回は複数行で記述してある。
複数行での記述方法
- type : マウントタイプ(volume, bind, tmpfs, npipe)
- source : マウント元
- target : マウントされるコンテナのパス
- read_only : 読み込み専用
- bind : バインドオプション
- propagation : バインドの伝播モード
- volume : ボリュームオプション
- nocopy : ボリューム生成時のコンテナからのデータコピーを無効
- tmpfs : tmpfsオプション
- size : tmpfsマウントのサイズ
⑦ unixソケットをマウント
- type: volume # ⑦ unixソケットをマウント
source: php-fpm-socket
target: /var/run/php-fpm
volume:
nocopy: true
type: volume
- ボリュームマウントを選択している。
source: php-fpm-socket
- マウント元。②で作成したボリュームを選択している。
target: /var/run/php-fpm
- ボリュームにコンテナの中の
/var/run/php-fpm
がマウントしている。
-
公式で PHP のイメージは4種類 用意されているらしい。
-
今回は、 PHP-fpm のイメージを使用している。(Dockerfile で指定している。)
-
PHP-fpm は FastCGI で動作させた PHP。
-
FastCGI は CGI を改良したもの。
- CGI は、 Web サーバー上でプログラムを動かして、動的にホームページを作成するための仕組み。
-
-
PHP には モジュール版と CGI 版の2種類がある
- モジュール版は、 Apache や Nginx のプロセス内で PHP を実行する
- CGI 版は、 Apache や Nginx とは別プロセスで PHP を実行する
-
PHP-fpm と Nginx を連携させるには、 TCP か UNIX ドメインソケットのどちらかで通信する
-
/var/run/php-fpm
をマウントさせているのは UNIX ドメインソケットで通信するため
- UNIX ドメインソケットの方が TCP と比べて早い
- UNIX ドメインソケットは同じマシン上で動いているプロセスが通信を行うためのソケット
Nginx と PHP-fpm の連携のイメージ
-
UNIX ドメインソケットは、ファイルシステムを利用して Nginx と PHP-fpm の通信を行なっている
-
php-fpm.sock
を使っている
-
-
var/run/php-fpm
配下にphp-fpm.sock
が生成される。 - そのため、
var/run/php-fpm
にボリュームにマウントして共有することで、Nginx (Web)と PHP (App) コンテナの通信ができるようにしている
nocopy: true
nocopy: ボリュームの生成時にはコンテナーからのデータコピーを無効にします。
「nocopy」 モードを指定すると、コンテナ内に要求したボリューム・パスに対して、
ボリュームの保存している場所に自動コピーを無効にします。
名前付きボリュームの場合は、「copy」がデフォルトのモードです。
copy モードは、バインド・マウントしたボリュームではサポートされていません。
ちょっとよくわからん。
copy
ボリュームを生成する時に、マウントしているコンテナ内のディレクトリのデータを自動的にコピーする設定らしい。
ボリュームの生成時にはボリュームは空で生成して欲しいから、ここは nocopy
になっている。
⑧ Laravel のソースコードをマウント
- type: bind # ⑧ Laravel のソースコードをマウント
source: ./backend
target: /work/backend
- バインドマウント
- ホスト側を書き換えるとコンテナ内も書き換わる
-
./backend
を/work/backend
にマウントしている-
./backend
内の Laravel のコードを書き換えると、コンテナ内に反映させることができる
-
⑨ psysh をマウント
- type: volume # ⑨ psysh をマウント
source: psysh-store
target: /root/.config/psysh
volume:
nocopy: true
- Laravel の thinker が psysh のラッパーらしい
- プルリクを見る限り thinker の履歴を残したいからマウントしているみたい
⑩ 環境変数を設定
environment: # ⑩ 環境変数を設定
- DB_CONNECTION=mysql
- DB_HOST=db
- DB_PORT=3306
- DB_DATABASE=${DB_NAME:-laravel_local}
- DB_USERNAME=${DB_USER:-phper}
- DB_PASSWORD=${DB_PASS:-secret}
Laravelの .env の内容を書き換えるという手順を省くためサーバー環境変数を設定しています。
ちなみにLaravelの .env よりもサーバー環境変数の値の方が優先されます。
${VARIABLE:-default} は VARIABLE がセットされていないか空文字であるときに default として評価されます。
- 環境変数を指定している
⑪ 公開用ポートをマッピング
ports: # ⑪ 公開用ポートをマッピング
- target: 80
published: ${WEB_PORT:-80}
protocol: tcp
mode: host
- target: コンテナー内部のポート。
- published: 公開ポート。
- protocol: ポートプロトコル。(tcpまたはudp)
- mode: hostは各ノード向けにホストポートを公開、またingressはロードバランスを行うためのスウォームモードポート。
target & published
-
.env の WEB_PORT で設定されているポートと nginx の 80 ポートをマッピングしている
- WEB_PORT を設定していない場合は 80 番
${WEB_PORT:-80}
- WEB_PORT を設定していない場合は 80 番
- http://localhost:80 にアクセスすると nginx の 80 番ポートにアクセスすることができる
protocol
- tcp での通信を指定
mode
mode: hostは各ノード向けにホストポートを公開、またingressはロードバランスを行うためのスウォームモードポート。
つまりどういうことだろ? わからん。
hostは各ノード向けにホストポートを公開
コンテナのポートを公開するよってことらしい。
ポートを公開しているおかげでホスト側からコンテナのポートにアクセスできる。
ただし、host
か ingress
しか設定はない。
ロードバランスをしなくていいなら ingress
にする必要はない。
⑫ unixソケットをマウント
- PHP コンテナ (app) と同じように unix ソケットをマウントしている。
- PHP コンテナに port が設定されていないのは unix ソケットで nginx と通信できているため
- PHP コンテナに外部から直接アクセスすることはない
- nginx コンテナに PHP はインストールされていないが、 PHP コンテナと連携することで PHP の処理を行うことができる
- AP サーバーのイメージ
⑬ Laravel のソースコードをマウント
- PHP コンテナと同じく Laravel のソースコードをマウント
- なぜ PHP と Nginx 両方でマウントしているのか
- まず、 HTTP のリクエストは Nginx に送られてくる
- 静的なコンテンツを返す
- PHP の処理が必要な場合は PHP コンテナに処理を任せる
- そのため、両方のコンテナに同じ Laravel のソースコードをマウントしている、という理解
(unix ソケットで通信云々ってとこがまだ理解が浅いな、、)
Nginx と PHP-fpm の連携のイメージ
⑭ mysqlをマウント
- mysql をマウントすることでコンテナを削除しても DB のデータが消えてしまわないようにしている
環境全体のイメージ
おわり
docker の構成を全部理解できるようにしようと思っていましたが、Docker Compose だけでかなり長くなってしまったので Docker Compose と Dockerfile の2部構成にしようかと思います。
Dockerfile 編は多分そのうち描きます。
(アドベントカレンダーの担当の日がもう1日あるのでその時にでも書こうかな。)
明日は @Nyokki さんの SQL アンチパターンの記事らしいです。
よろしくお願いします!
参考
直接リンクを貼っていないもの