# 文章說明
這是將服務部署到雲端的專案。
VM 建立好後,將專案 pull 到 /opt 下即可快速部署。
# 環境
每個服務程式碼由 GitHub 託管,並設置自動打包成 Docker image。
機器安裝 Docker,部署時 pull Docker image 啟動多個服務 container。
由 Nginx 控制請求進入服務。
# 專案資料夾結構
.
├── init.sh # 機器初始化
├── prod
│ ├── docker-compose.yml # 正式站 Docker Swarm Stack 設定
│ └── nginx.conf # 正式站 Nginx 設定
├── start-prod.sh # 啟動
└── stop-prod.sh # 停止
首先執行 init.sh 更新系統、安裝常用程式,參考 GCP VM 建置筆記。
# start-prod.sh
#!/bin/sh
# 啟動正式站 container
docker stack deploy --compose-file prod/docker-compose.yml --with-registry-auth company
這邊沒什麼好介紹的,就是用 docker stack deploy 啟動 Docker Swarm Stack。
--with-registry-auth 會把本機 docker login 的 registry 認證一併傳給 Swarm 節點,
讓節點在拉私有 image 時能順利通過授權;不加的話,私有倉庫常會出現拉不到 image 的錯誤。
# docker-compose.yml
# 正式站 container
version: '3.8'
services:
nginx:
image: nginx
restart: unless-stopped
volumes:
# Nginx 設定檔
- ./nginx.conf:/etc/nginx/conf.d/default.conf
environment:
TZ: Asia/Taipei
ports:
- target: 80
published: 80
protocol: tcp
mode: host
# 後端 API
backend:
image: ghcr.io/8loser/backend:main
restart: unless-stopped
environment:
TZ: Asia/Taipei
# 前端
frontend:
image: ghcr.io/8loser/frontend:main
restart: unless-stopped
environment:
TZ: Asia/Taipei
說明:
- 有 3 個服務; Nginx、frontend、backend。
- Nginx 不用
depends_on backend, frontend避免某個服務異常導致 Nginx 被牽連停止。 - Nginx
mode: host直接用主機 80 對外提供服務,Load Balancer 流量導入 Nginx 80 port,僅有跑該服務的節點會開 80。 - Nginx 設定檔直接掛載
prod/nginx.conf檔案。 - Stack 會使用 Swarm overlay network,
proxy_pass http://frontend/與proxy_pass http://backend/會解析到同一個 Stack 的 service。 ghcr.io是 GitHub Container Registry,用於存放 Docker image。
# nginx.conf
# 正式站 Nginx
# 預設 server; 使用 IP 或未匹配的域名都會進入
server {
listen 80;
server_name _;
# 不合法 Host 訪問 /,不返回內容
location / {
return 204;
}
}
server {
listen 80;
# 允許的域名
server_name www.*******.com *******.com;
# Load Balancer Public IP address
set_real_ip_from <LB_IP>/32; # 填入你的 LB IP
# Google CIDR 網段
set_real_ip_from 130.211.0.0/22;
set_real_ip_from 35.191.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
# 阻擋的 User Agent
if ($http_user_agent ~* "ApacheBench|pingback|YisouSpider|MJ12bot|AhrefsBot|360JK|Jorgee|FeedDemon|BOT/0.1 (BOT for JCE)|CrawlDaddy|Java|Jullo|Feedly|UniversalFeedParser|Swiftbot|YandexBot|jikeSpider|ZmEu phpmyadmin|WinHttp|EasouSpider|HttpClient|Microsoft URL Control|YYSpider|jaunty|oBot|Python-urllib|Indy Library|FlightDeckReports Bot|Linguee Bot" )
{return 101;}
# 正式站設定 robots.txt 允許爬蟲
location = /robots.txt {
add_header Content-Type text/plain;
return 200 "User-agent: *\nAllow: /\n";
}
# 前端
location / {
proxy_pass http://frontend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Custom-Referrer smc_identity_layer;
}
# 後端
location /api/ {
proxy_pass http://backend/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Custom-Referrer smc_identity_layer;
}
}
說明:
- 預設 server 用於攔截未匹配的 Host,直接回 204。
/走 frontend、/api/走 backend,使用proxy_pass轉發請求。set_real_ip_from用來限定可信任的轉發來源(LB 與 Google CIDR),才能正確還原 client IP,避免被偽造的X-Forwarded-For影響。proxy_pass http://backend/的backend對應docker-compose.yml的 service 名稱。