Docker Compose 多專案共用 nginx 容器方案

在有限的資源下在同一台機器上面要跑不同專案時,如果統一在每個專案運行各自的nginx 就會造成port 80 重複使用而造成容器啟動失敗。
此時如果將nginx 抽離變成獨立的容器在透過 docker networks 進行關聯 即可完成統一由一個nginx proxy 代理全部對外容器,但如果有資源的話 可以透過 docker volumes 先對外進行掛載。

根據上述可以先定義 工作目錄 /data/htdocs/prj_? 之後就可以進行後續規劃,以下將會一步一步說明。


Step 1 創建docker networks

可以透過以下命令創建一個docker 內的共享網絡,方便後續用於連接各個容器。

docker network create shared-network

創建完成後可以透過 docker network ls 查詢。

Step 2 創建nginx-proxy

創建一個專門用來代理各個專案們的容器,並且記得將工作目錄映射進

# 如果有些配置檔案例如 ssl / *.conf 都可以設置上去
# 該範例僅為了展示如何實作多專案共用同一個nginx 所以沒有額外多加配置

name: tools
services:
  nginx:
    image: nginx
    container_name: nginx
    restart: always
    volumes:
      - /data/htdocs:/data/htdocs
    ports:
      - 80:80
      - 443:443
    networks:
      shared-network:

networks:
shared-network:
  external: true # 表示這個網路是外部創建的,不是由這個 compose 檔案創建
  name: shared-network

Step 3 運行專案

該專案運行在 /data/htdocs/* 底下,透過 docker compose up -d 將檔案掛載進容器內,此時該http 也會自動掛載到 nginx 裡面。

而這份docker compose 主要關鍵是在於使用 和 nginx-proxy 共用同一個 docker networks。

name: a
services:
  php:
    image: docker.com/a/backend-php:test
    pull_policy: always
    container_name: ${COMPOSE_PROJECT_NAME}-php
    working_dir: /app
    volumes:
      - ./http/static/upload:/app/http/static/upload
      - ./http/static/assets:/app/http/static/assets
    extra_hosts:
      - "host.docker.internal:host-gateway"
    networks: 
      - shared-network
  web:
    image: docker.com/a/frontend:test
    pull_policy: always
    container_name: ${COMPOSE_PROJECT_NAME}-web
    working_dir: /app
    environment:
      - TZ=${TZ}
    networks:
      - shared-network
  
networks:
shared-network:
  external: true
  name: shared-network

Step 4 配置nginx-proxy *.conf

容器簡述:

web容器 : vue 編譯後的檔案放置於 /app 目錄, 已內建一個nginx 並且對80 開放。

php容器:檔案路徑也存放於 /app中,但唯一不太一樣的地方在於 /app/http/static 會存放一些生成的靜態資源需要保存,所以就映射到宿主機上。

server{
    listen 80;
    
    client_max_body_size 60M;
    client_body_buffer_size 512k;

    # 以下的配置 有將/data/htdocs 掛載進nginx 目錄
    # 可以讀取掛載在宿主機上的資源 處理靜態資源訪問
    location /static/assets/ {
      alias /data/htdocs/a/http/static/assets/; 
    }

    location /static/upload/ {
      alias /data/htdocs/a/http/static/upload/;  
    }

    # 前端反向代理 
    location / {
        proxy_pass http://test-web;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;

        # 添�~J|  CORS �~Y�| �
        #add_header Access-Control-Allow-Origin *;
    }

    # 以下均為後端反向代理
    # 而要注意的地方為 SCRIPT_FILENAME 要配置php 入口檔案
    location ^~ /sale/ {
        fastcgi_pass test-php:9000
        include fastcgi_params;

        fastcgi_param SCRIPT_FILENAME /app/http/sale.php;
        fastcgi_param REQUEST_URI $request_uri;
        fastcgi_param DOCUMENT_ROOT /app/http;
    }

    location ^~ /api/ {
        fastcgi_pass test-php:9000;
        include fastcgi.conf;

        fastcgi_param SCRIPT_FILENAME /app/http/api.php;
        fastcgi_param REQUEST_URI $request_uri;
        fastcgi_param DOCUMENT_ROOT /app/http;
    }

    location /backend/ {
        fastcgi_pass test-php:9000;
        include fastcgi_params;

        fastcgi_param DOCUMENT_ROOT /app/http;
        fastcgi_param SCRIPT_FILENAME /app/http/backend.php;
        fastcgi_param SCRIPT_NAME /backend.php;
        fastcgi_param REQUEST_URI $request_uri;

    }
}

Step 5 Nginx Reload

最後全部配置好且激活後,要記得將nginx 進行刷新 nginx -s reload ,往後若有其他專案 則可複製這個範本進行多次部署。

以下提供一個更新腳本,推送新的image時可以直接運行並且自動刷新nginx。

#!/bin/sh
DIR="$( cd "$( dirname "$0"  )" && pwd  )"

echo "--- 更新 docker compose ---"
docker-compose -f $DIR/docker-compose.yml up -d

echo "--- 刷新nginx ---"
docker exec nginx nginx -s reload