🧐

なんでPHPが実行できるかあなたにはわかりますか?

2021/09/20に公開

概要

友人とLaravelを使ってなにか作ろうとなり、記事を見てDocker環境を作成しました。
作成した環境は動いたのですが、自分にはなぜPHPもインストールされていないNginxのコンテナ上でLaravelが表示できているのかぱっとわかりませんでした。
さて、皆さんはなぜPHPもインストールされていないNginxのコンテナ上でLaravelが表示できているかわかるでしょうか?(挑戦的なタイトル&煽りですみません)

環境

このDocker環境の構成は以下のようになっています。

ディレクトリ構成

project
├ docker-compose.yml
├ docker
│  ├ php
│  │  ├ php.ini
│  │  └ Dockerfile
│  ├ nginx
│  │  └ default.conf
│  └ db
│     ├ data
│     ├ conf
│     └ sql
└ server

ファイル

docker/php/Dockerfile
FROM php:7.4.1-fpm

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

RUN apt update
RUN apt install -y wget git unzip libpq-dev

RUN apt install -y npm \
  && npm install n -g \
  && n 12

RUN apt install -y zlib1g-dev mariadb-client libzip-dev libonig-dev \
  && docker-php-ext-install zip pdo_mysql

RUN curl -sS https://getcomposer.org/installer | php \
  && mv composer.phar /usr/local/bin/composer \
  && composer self-update

WORKDIR /var/www

RUN chown -R www-data:www-data /var/www

RUN composer global require "laravel/installer"
docker/php/php.ini
[Date]
date.timezone = "Asia/Tokyo"
[mbstring]
mbstring.internal_encoding = "UTF-8"
mbstring.language = "Japanese"
docker/nginx/default.conf
server {
  listen 80;
  root /var/www/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$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000;
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
  location ~ /\.(?!well-known).* {
      deny all;
  }
 }
docker-compose.yml
version: '3'


services:
  php:
    container_name: php
    build: ./docker/php
    volumes:
    - ./server:/var/www
    environment:
      TZ: Asia/Tokyo

  nginx:
    image: nginx
    container_name: nginx
    ports:
    - 8080:80
    volumes:
    - ./server:/var/www
    - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
    depends_on:
    - php

  db:
    image: mysql:8.0
    container_name: db
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: database
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ: 'Asia/Tokyo'
    command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    volumes:
    - ./docker/db/data:/var/lib/mysql
    - ./docker/db/my.cnf:/etc/mysql/conf.d/my.cnf
    - ./docker/db/sql:/docker-entrypoint-initdb.d
    ports:
    - 33306:3306

このようにNginxコンテナは、公式のイメージを使用しているだけで、PHP自体は入っていません。

ですが、 localhost:8080にアクセスすると以下のようにLaravelのウェルカムページが表示されました。(コンテナ立てたあとLaravelのプロジェクト作成を行った上の状態です)

NginxコンテナにはPHPがはいっていないのになぜウェルカムページが表示されているか分かりましたか?

表示されていた訳

結果から言ってしまうと、NginxコンテナがPHPコンテナにリクエストを飛ばしてその結果を受け取り表示していたからウェルカムページが見れていました。
NginxコンテナからPHPコンテナにリクエスト飛ばす設定なんてどこに書いてあったの?
実は、下記のconfigファイルに書いてありました。

docker/nginx/default.conf
server {
  listen 80;
  root /var/www/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$ {
    try_files $uri =404;
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass php:9000; # <=ここ!!
    fastcgi_index index.php;
    include fastcgi_params;
      fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
      fastcgi_param PATH_INFO $fastcgi_path_info;
  }
  location ~ /\.(?!well-known).* {
      deny all;
  }
 }

fastcgi_pass php:9000 のようにかいてありました!!
実際にNginxコンテナからPHPコンテナにpingしたらちゃんと疎通していました!

root@68b3c6a6d28e:/# ping php
PING php (172.22.0.3) 56(84) bytes of data.
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=1 ttl=64 time=0.169 ms
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=2 ttl=64 time=0.141 ms
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=3 ttl=64 time=0.110 ms
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=4 ttl=64 time=0.120 ms
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=5 ttl=64 time=0.103 ms
64 bytes from php.nanka_default (172.22.0.3): icmp_seq=6 ttl=64 time=0.140 ms
^C
--- php ping statistics ---
6 packets transmitted, 6 received, 0% packet loss, time 93ms
rtt min/avg/max/mdev = 0.103/0.130/0.169/0.025 ms

dockerのログも確認すると以下のようにまずNginxコンテナにGETリクエストが来てその後PHPコンテナにもGETリクエストが来ていました。

・・・
nginx    | 172.22.0.1 - - [20/Sep/2021:04:33:35 +0000] "GET / HTTP/1.1" 200 17621 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36" "-"
php      | 172.22.0.4 -  20/Sep/2021:13:33:35 +0900 "GET /index.php" 200
・・・

終わりに

普段Nginxのコンフィグなど書かないのでこういった仕組みになっていることを全く知りませんでした。もっといろいろ触って体験してみないと疑問にすら思わず知らないままなのでやっていくぞ!
最後に、環境構築の参考にさせていただいた@A-Kiraさんありがとうございました。

参考資料

Discussion