# 文章說明
這是將服務部署到雲端的專案。
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 名稱。