Dockerはいいぞ – docker-compose 実践編

沖縄チームのキリです。今回はさくっとdocker-composeを使ってphp-fpm + nginxの動作環境を構築します。

dockerの導入編はこちら

以前のdocker-composeはdockerとは別途で導入する必要がありましたが今は本家dockerに統合されたのでDocker Desktopをインストールしていれば既に使える状態になっています。まずはUbuntuのシェルを開いて作業ディレクトリを作成しましょう。

mkdir ~/docker-example

上記はユーザーのホームディレクトリにdocker-exampleというディレクトリを作成する例です。任意の名前に置き換えてください。

docker composeの設定ファイル

まずはdocker-compose.ymlファイルを作成します。

# ./docker-compose.yml
services:
  php:
    image: php:8.2-fpm
    volumes:
      - ./src:/var/www/app
  nginx:
    build:
      context: .
      dockerfile: docker/nginx/Dockerfile
    volumes:
      - ./src:/var/www/app
    ports:
      - ${APP_PORT:-80}:80

実にシンプルですね。nginxとphpという2つのコンテナを作成するための設定です。用語や詳しい概念については検索していただければわかりやすい記事が無数にありますので省略します。あまり理解していなくてもなんとなく使えるのがDockerの良いところです。

phpコンテナの方ですがDocker公式のリポジトリからphp:8.2-fpmというイメージを持ってきてそのまま使用しています。誰かが用意してくれたイメージがあれば何の設定もなく簡単に使い回せるということです。非常にお手軽です。volumesの./src:/var/www/appについては、docker-compose.ymlファイルを配置しているディレクトリにsrcというディレクトリがあればphpコンテナ上の/var/www/appに同期する設定です。nginxの設定ファイルの方で説明しますがsrcに.phpファイルを配置しておけばブラウザから実行できるようになります。

nginxコンテナの方は別途./docker/nginx/Dockerfileという設定ファイルを用意して独自のイメージをビルドします。buildのcontextは相対パスの開始ディレクトリを設定します。

context: ./docker/nginx
dockerfile: Dockerfile

のように書くこともできますが、Dockerfileで./docker/nginxより上の階層を参照できないので私は作業ルートを設定するのが好みです。詳しくは以下を参考にしてください…

docker-compose.ymlのbuild設定はとりあえずcontextもdockerfileも埋めとけって話

portsはホストのポート:コンテナのポートを対応付ける設定です。ホスト側のポートは任意のポートでOKです。上記の例では.envファイル等でAPP_PORTの環境変数を設定していればその値を使い、なければ80をデフォルト値として使うという設定になっています。これでlocalhost:80へのアクセスがnginxコンテナのポート80にポートフォワードされるようになりました。

nginxのDockerfile

# ./docker/nginx/Dockerfile
FROM nginx:latest

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

驚きのシンプルさです。公式のnginxイメージを使いホスト側の./docker/nginx/default.confファイルをnginxコンテナの/etc/nginx/conf.d/default.confにコピーしているだけです。特に説明することもないので次に進みます。

nginxの設定ファイル

server {
    listen 80;
    server_name localhost 127.0.0.1 0.0.0.0;
    root /var/www/app;

    index index.php index.html index.htm;

    location / {
        if (!-e $request_filename) {
            rewrite ^(.*)$ /$1.php;
        }
    }

    location ~ \.php$ {
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

これもそこまで複雑な設定ではないのではないでしょうか。server_nameで設定されたサーバー名のポート80でリクエストを受けたらこの設定が使用されます。rootで設定しているのはdocker-compose.ymlのvolumesで設定しているものと同じです。location ~ .php$ 以下で./srcに配置したphpファイルがあればfastcgi_passでphpコンテナのポート9000にリクエストを投げて処理を任せます。(この設定では.phpファイル以外のファイルはnginxコンテナだけで処理されます。)

真ん中のrewriteについてですが、例えば/hogeでアクセスがあったときに/var/www/app/hogeというファイルが存在しなければ/var/www/app/hoge.phpファイルを探します。必須ではないですが/var/www/app/hello-world.phpファイルを実行したいと思ったら/hello-worldでアクセスできるようになるのでブラウザでの確認がほんの少し捗ります。

Docker上でphpを実行する

さてここまで来たら準備万端です。Ubuntuのシェルで作業ディレクトリに移動したらdocker compose up コマンドを実行しましょう。最初はDockerイメージのダウンロードやコンテナイメージのビルドが実行されるので多少待つ必要があります。

docker compose up実行画面

Dockerコンテナが立ち上がると上記のようなログが表示されます。この状態でブラウザでlocalhostにアクセスするとsrc/index.phpが用意されていないため404エラーが表示されるかと思います。終了するときはCtrl+Cで終了できます。バックグラウンドで実行したい場合はdocker compose up -d とオプションを指定します。この場合はdocker compose down コマンドで終了します。

phpファイルの作成

実際にphpファイルが動作するか確認してみましょう。./src/index.phpファイルを作成します。

<?php
echo "Hello, World!";

ブラウザからlocalhostにアクセスしてHello, World!の文字列が表示されていれば成功です。もうひとつ、.phpの拡張子なしでも表示できることを確認します。./src/phpinfo.phpを以下の内容で作成しましょう。

<?php
phpinfo();

ブラウザからlocalhost/phpinfoにアクセスして以下のような画面が表示されれば成功です。

http://localhost/phpinfo をブラウザで確認

さてPHP Version 8.2.4 の表記の通り現在はphp8.2の環境となっています。ところがアサインした案件ではphp7.4を使うことになったとしたらどうでしょう?開発環境も同じバージョンに合わせたいですよね?バージョンの変更は非常に簡単です。docker-compose.ymlを開いてphpコンテナのimage: php:8.2-fpmの部分をimage: php:7.4-fpmに変更してください。Dockerが起動中であればCtrl+Cあるいはdocker compose downで終了してからdocker upで再起動します。そしてlocalhost/phpinfoに再度アクセスしてください。

http://localhost/phpinfo をリロードして再確認

PHP Version 7.4.33 になっていますね。ソフトウェアのバージョンを簡単に変更することができるのもDockerの強みです。これまでに作成してきたdocker-compose.ymlファイルやDockerfile等をgitに含めるなどして共有すればチームで開発環境を統一してdocker upのコマンド一つで実行環境が用意できます。今回はphpとnginxのイメージを使って環境構築しましたが他にも色々な公式のDockerイメージがあってあらゆるプロジェクトに対応することができます。ぜひDockerを使ってみてください!