【チュートリアル】 AmazonEC2で作業して作る、ECSのためのphp動作環境
前回の続き
dockerコンテナでphpを動作させる環境について
これは主に2タイプある
-
apache2
にphpモジュールを組込む手法 (1つのコンテナで完結する) -
nginx
+php-fpm
で頑張る方法 (1つのコンテナで完結する方法もあるけど通常は2つのコンテナを使う)
現状のnginxの構成を確認後、nginxとphp用に分離させていく
前回まででの構成では
./Dockerfile
./index.html
このようにプロジェクトのルートに雑に展開するというシンプルな構成になっているが、まず、この構造を変更していく。
ディレクトリ構造を変更する
- nginxというディレクトリを作り、Dockerfileを移動する
- さらにpublicというディレクトリを作り、index.htmlを移動する
ここでさらにplacehold.jp
というサービスでダミーの画像を作り、これをpublic/logo.pngとして保存する
curl 'https://placehold.jp/300x300.png?text=LOGO' -o public/logo.png
ここまでで以下のような構成を取るようにファイルを移動する事
.
├── nginx
│ └── Dockerfile # Nginx用Dockerfile (ルートから移動)
└── public
├── index.html # 静的HTMLファイル (ルートから移動)
└── logo.png # ダミーロゴ画像 (新規に追加)
作業ログ
admin@ip-172-31-29-222:~/my-ecs-project$ mkdir public nginx
admin@ip-172-31-29-222:~/my-ecs-project$ ls
Dockerfile index.html nginx public
admin@ip-172-31-29-222:~/my-ecs-project$ mv index.html public/
admin@ip-172-31-29-222:~/my-ecs-project$ mv Dockerfile nginx/
admin@ip-172-31-29-222:~/my-ecs-project$ curl 'https://placehold.jp/300x300.png?text=LOGO' -o public/logo.png
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 4339 100 4339 0 0 27440 0 --:--:-- --:--:-- --:--:-- 27636
admin@ip-172-31-29-222:~/my-ecs-project$ find
.
./nginx
./nginx/Dockerfile
./public
./public/logo.png
./public/index.html
nginx/Dockerファイルを書き換えてDockerイメージにpublicの内容をコピーする
FROM nginx:alpine
COPY ./public /usr/share/nginx/html
EXPOSE 80
以上のように変更してビルドを試す
$ ls
nginx public
このようにプロジェクトのトップディレクトリから以下のコマンドを実行する
docker build -t my-ecs-nginx -f ./nginx/Dockerfile .
イメージ名をmy-ecs-nginx
に変更している。作成されたイメージはdocker image ls
で見られる。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
my-ecs-nginx latest 179f135ac531 2 minutes ago 50.9MB
nginx alpine f9d642c42f7b 8 weeks ago 50.9MB
前のが残っててもあんま気にしなくていい(掃除方法は調べるとすぐ出てくる)。
ここでmy-ecs-nginx
が作成された事に注目する。
nginxのイメージからデフォルト設定をコピーし、編集後、再配置する
ここでpullしてきたnginxイメージの中に入っている /etc/nginx/conf.d/default.conf をコピーし、設定の雛形として利用する。dockerイメージからのコピーは以下のようにして行う事ができる。
docker run --rm -v $(pwd):/host nginx:alpine cp /etc/nginx/conf.d/default.conf /host/
dockerはイメージからコンテナーを生成して実行するのであるが、このコマンドはコンテナを一度だけ生成してコマンド実行後にコンテナーを消滅させる。ともあれこれでカレントディレクトリにdefault.confが存在しているはずである。
取得できたconfig
server {
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;
#}
}
このように比較的シンプルな設定になっている。
これを nginx/ ディレクトリへと移動しておく
cp default.conf nginx/
sudo rm default.conf
(コンテナからコピーすると権限が権限揃ってないので、これを変更するのが面倒だったのでcopyして消しただけ)
現状
.
├── nginx
| ├── index.html
│ └── default.conf # Nginxコンテナーからコピーしたオリジナルのdefault.conf
└── public
├── index.html # 静的HTMLファイル
└── logo.png # ダミーロゴ画像
nginx/default.confの確認し、phpを実行するための設定に変更する
ここで設定を変更する。まずphp関連の設定のコメントを外し、以下のようにする
location ~ \.php$ {
root /usr/share/nginx/html; # PHPスクリプトのルートディレクトリ
fastcgi_pass php-fpm:9000; # PHP-FPMサービス名とポート
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params; # 必須のFastCGIパラメータをインクルード
}
ここでパラメーターの変更などは特に解説しないが、fastcgi_pass php-fpm:9000
の指定に着目すると、php-fpm
というhostのポート9000
に通信の指定を行っている。すなわち、php-fpm
という名前で通信できるホストを別途作る必要があるという事になる。
document_root fastcgi_script_name; の解説
fastcgi_param SCRIPT_FILENAME 元の設定
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
ここでは、PHPスクリプトが /scripts ディレクトリ以下に存在すると仮定している。$fastcgi_script_name
はリクエストされたスクリプト名(例えば: /index.php)を表しており、
つまり、この設定では、すべてのPHPスクリプトを /scripts ディレクトリの中から探そうとしている
修正後の設定
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
$document_root
は現在のリクエストで設定された root ディレクティブの値(例: /usr/share/nginx/html)を表しており$fastcgi_script_name
は先述の通り、リクエストされたスクリプト名(例: /index.php)を表す。
この設定により、PHPスクリプトの実際のフルパスが root で指定したドキュメントルートに基づいて動的に解決される、ここでは
root /usr/share/nginx/html;
の設定により /usr/share/nginx/html からサーチされる。すなわち、このパスに基いてfastCGIの先を作らなければならない。、といっても今はそのサーチ先を作っていないので何を言ってるのかよくわからないはずなので、ここでは記憶に留めておくこと。
ダミーロゴを使うようにpublic/index.htmlを変更する
public/index.htmlの内容を以下のように変更する。
<!DOCTYPE html>
<html>
<head>
<title>My First Web Page</title>
</head>
<body>
<h1>Hello, ECS Fargate!</h1>
<p>This is my first containerized web page.</p>
<img src="logo.png"> <!-- これ -->
</body>
</html>
imgタグを追加しただけ
phpinfoを実行するスクリプトを作る
さらに public/info.phpに phpinfo()
するだけの簡単なphpファイルを作る。
<?php phpinfo();
ここで public/ 以下は現状、以下のようになっているはずだ
.
├── nginx
| ├── index.html
│ └── default.conf # Nginxコンテナーからコピーしたオリジナルのdefault.conf
└── public
├── index.html # 静的HTMLファイル
├── logo.png # ダミーロゴ画像
└── info.php # phpinfo()を実行するたけのもの
設定を含めnginxにコピーするDockerfile
FROM nginx:alpine
COPY ./public /usr/share/nginx/html
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
ここまでのファイル
nginx/Dockerfile
FROM nginx:alpine
COPY ./public /usr/share/nginx/html
COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
nginx/defaults.conf
server {
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;
root /usr/share/nginx/html;
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME $document_root$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;
#}
}
確実にビルドする
設定を変更なりした時にビルドプロセスを忘れる事がよくあるので、現状のファイル構成に従って以上のファイルを確実にビルドしておく。
docker build -t my-ecs-nginx -f ./nginx/Dockerfile .
これにより
- nginxの設定が更新される
- public/の内容がnginx内 /usr/share/nginx/html 以下にコピーされる
なお、この段階だとphp-fpmが解決できないため、nginxは起動できなくなる
phpの実行環境を整える
ここでは2つ目のコンテナである、php-fpm
を作成する。これを構成するために、まずphp-fpm/ というディレクトリを作成する
mkdir php-fpm
この状態で php-fpm/Dockerfile を作成する
public以下をphp-fpmにコピーする
FROM php:8.4-fpm
COPY ./public /usr/share/nginx/html
ここでpublicの内容を php-fpmでも /usr/share/nginx/html にコピーしている。これは先述した
/usr/share/nginx/html からサーチされる。すなわち、このパスに基いてfastCGIの先を作らなければならない。
この設定によるものである。
確実にビルドする
この段階でphp-fpmコンテナもビルドする
docker build -t my-ecs-php-fpm -f ./php-fpm/Dockerfile .
docker-composeの設定
今はnginxとphp-fpmのコンテナをそれぞれ2つdocker runで起動したが、これらの2コンテナを相互に通信させるためにはdocker-compose
を使うのが楽。
前段の記事でこのツールの導入は済んでいるはずであるが、まだの場合は
sudo apt install docker-compose
で導入して欲しい
既存のdockerプロセスの停止
docker stop $(docker ps -q)
一括で停止できる。
IDを指定する事も可能だが、他のプロセスで止めたら駄目なものが無いならこれで停止すると楽であろう。
docker-compose.ymlの記述
docker-compose
はdocker-compose.ymlというファイルを参照してその設定に従ってコンテナーを起動するツールだ。従ってこれを作成する必要がある。
services:
php-fpm:
image: my-ecs-php-fpm
networks:
- app-network
nginx:
image: my-ecs-nginx
ports:
- "80:80"
depends_on:
- php-fpm
networks:
- app-network
networks:
app-network:
このように設定する。
この状態のまま
docker-compose up -d
で起動する。
疎通を確認する
docker-compose up -d
で起動できる
この状態でコンテナのシェルに入れるため、pingなどを行い名前解決と疎通を確認しておくと良いだろう。
nginx → php-fpm
docker-compose exec nginx sh
でコンテナに入り
ping nginx
とすると
admin@ip-172-31-29-222:~/my-ecs-project$ docker-compose exec nginx sh
/ # ping php-fpm
PING php-fpm (172.21.0.2): 56 data bytes
64 bytes from 172.21.0.2: seq=0 ttl=64 time=0.134 ms
^C
--- php-fpm ping statistics ---
1 packets transmitted, 1 packets received, 0% packet loss
round-trip min/avg/max = 0.134/0.134/0.134 ms
このように応答がある事を確認しておく
php-fpm → nginx
こちらは
docker-compose exec php-fpm sh
でシェルに入り(こっちはbashでもok)
apt update && apt install -y iputils-ping
した後
ping nginx
admin@ip-172-31-29-222:~/my-ecs-project$ docker-compose exec php-fpm sh
# pingが入っていない
# type ping
ping: not found
# apt update
# apt install iputils-ping
# ping nginx
PING nginx (172.18.0.3) 56(84) bytes of data.
64 bytes from my-ecs-project_nginx_1.my-ecs-project_app-network (172.18.0.3): icmp_seq=1 ttl=64 time=0.058 ms
^C
--- nginx ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.058/0.058/0.058/0.000 ms
# exit
nginx側にはpingが入ってなかったためaptでiputils-ping
を導入した。
再度起動
準備が整ったので、最新イメージで起動するようにdocker-composeをdownしてup
docker-compose down
docker-compose up -d
この状態で諸々確認してみよう
htmlの確認。ロゴも含めてok
phpの確認。phpinfo()
の出力ok
このようにphpinfo
が正しく表示されている。これに関してメカニズムを見ていこう
それぞれのコンテナーのファイルを確認してみる
まずnginxの方。これは以下のコマンドでシェルに入れるのだった
docker-compose exec nginx sh
コピー先の /usr/share/nginx/html にcdしてみる
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
50x.html index.html info.php logo.png
このように
- index.html
- info.php
- logo.png
- 50x.html
の4ファイルが見える。ここで、info.phpを削除してみよう
rm info.php
このようにしてもinfo.phpは確認できるはずだ
しかし、logo.pngを例えば削除すると
rm logo.png
消滅する(ブラウザーによりcacheが効いてる可能性は高いのですが)
ではexitして今度はphp-fpmに入ろう
docker-compose exec php-fpm bash
$ docker-compose exec php-fpm bash
root@abfa9786edd9:/var/www/html# cd /usr/share/nginx/html/
root@abfa9786edd9:/usr/share/nginx/html# ls
index.html info.php logo.png
このように移動すると、こちらは3ファイルある
ここでindex.htmlとlogo.pngを削除してみる
それでもphpは普通に見えるはずだ
大丈夫
ただし、info.phpを削除するとこれが消滅する
以上の事から理解できる事
- nginxはphp以外のファイルをサーブする
- php-fpmはphp関連のファイルのみサーブしている
このようになっている。例えば、laravelなどのフレームワークをサービスする場合はこの概念が非常に重要になってくる。これは次回以降記事にする。
awsへのデプロイ
ここまで割と記事が長くなってしまったのでawsへのデプロイは次回以降とする
Discussion