46
49

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.

docker-laravel の Docker 構成をちゃんと理解する【docker-compose.yml 編】

Last updated at Posted at 2021-12-09

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 の中身は後で確認します

  • contextdockerfile の位置を明示的に指定している

  • 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 の連携のイメージ

イメージ.png

  • 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 よりもサーバー環境変数の値の方が優先されます。

environment

変数の置換

${VARIABLE:-default} は VARIABLE がセットされていないか空文字であるときに default として評価されます。

  • 環境変数を指定している

⑪ 公開用ポートをマッピング

ports: # ⑪ 公開用ポートをマッピング
  - target: 80
    published: ${WEB_PORT:-80}
    protocol: tcp
    mode: host

Ports の設定

  • target: コンテナー内部のポート。
  • published: 公開ポート。
  • protocol: ポートプロトコル。(tcpまたはudp)
  • mode: hostは各ノード向けにホストポートを公開、またingressはロードバランスを行うためのスウォームモードポート。

target & published

  • .env の WEB_PORT で設定されているポートと nginx の 80 ポートをマッピングしている
    • WEB_PORT を設定していない場合は 80 番 ${WEB_PORT:-80}
  • http://localhost:80 にアクセスすると nginx の 80 番ポートにアクセスすることができる

protocol

  • tcp での通信を指定

mode

mode

mode: hostは各ノード向けにホストポートを公開、またingressはロードバランスを行うためのスウォームモードポート。

つまりどういうことだろ? わからん。

hostは各ノード向けにホストポートを公開

コンテナのポートを公開するよってことらしい。
ポートを公開しているおかげでホスト側からコンテナのポートにアクセスできる。
ただし、hostingress しか設定はない。
ロードバランスをしなくていいなら 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 の連携のイメージ

イメージ (2).png

⑭ mysqlをマウント

  • mysql をマウントすることでコンテナを削除しても DB のデータが消えてしまわないようにしている

環境全体のイメージ

イメージ (3).png

おわり

docker の構成を全部理解できるようにしようと思っていましたが、Docker Compose だけでかなり長くなってしまったので Docker Compose と Dockerfile の2部構成にしようかと思います。

Dockerfile 編は多分そのうち描きます。
(アドベントカレンダーの担当の日がもう1日あるのでその時にでも書こうかな。)

明日は @Nyokki さんの SQL アンチパターンの記事らしいです。
よろしくお願いします!

参考

直接リンクを貼っていないもの

46
49
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
46
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?