[docker] 分別建立 Nginx 和 PHP-FPM 容器

對於 docker 遜咖如我,通常習慣用那種包山包海的 image,例如 LAMP 全部打包在一起的,最後做出所謂 "fat container"。好處是容易上手、並能很直觀地檢視成果,然而這樣不只浪費效能,其實也降低了彈性。因此我接著要挑戰的,就是建立不含 web server 的 PHP-FPM 容器,再連接另外的 Nginx 做為它的 web server。

花了好多時間查資料,大家好像都弄得超複雜,自己改 Dockfile、加一堆指令或 script、改 port 改 config 位置啦,或弄一堆變數讓 Nginx config 有 template 啦…後來終於爬到這篇 Dockerise your PHP application with Nginx and PHP7-FPM,發現如果只是單純想把 Nginx 和 PHP-FPM 分裝的話,根本不用那麼麻煩!要注意的只有三點:

  1. 讓兩個容器處於同一 network 中。
  2. 讓兩個容器掛載同一個 volume,並將此目錄作為 Nginx config 中預設首頁目錄(即 "root")。
  3. PHP-FPM 容器的預設 port 是 9000,所以 Nginx config 的 fastcgi_pass,其參數便是 {{php id}}:9000

直接看 docker-compose.yml:

version: "3"
services:
  nginx:
    restart: unless-stopped
    image: nginx:latest
    container_name: nginx
    networks:
      - mynet
    ports:
      - 80:80
      - 443:443
  php74:
    image: php:7.4.3-fpm
    container_name: php74
    restart: unless-stopped
    networks:
      - mynet
    volumes:
      - ./projects:/projects
networks:
  mynet:
    external: true

我建立了兩個 containers,一個叫 "nginx",一個叫 "php74"。他們共同的 network 是 "mynet",並同時掛載 "projects" 這個本機目錄。

Nginx configuration:

server {
    index index.php index.html;
    server_name php-docker.local;
    error_log  /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;
    root /code;

    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass php74:9000;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
    }
}

設定好之後,把網頁或其他專案擺在 ./projects 目錄裡頭就可以了,一切的使用就像在本機一樣。
我們只建了兩個容器,如果是 fat container 的話,之後每個專案都要獨立建自己的容器呢!

另外還看到一種很酷的玩法:如果你需要運用不同版本的 PHP,只須建立各自的 PHP containers(比如說一個是 PHP 7.4,一個是 PHP 5.6),在 Nginx config 裡,透過讓不同的 server block 的 fastcgi_pass 連接到不同容器,就能輕鬆切換 PHP 版本。(覺得這段好饒舌)

標籤 (Tags)