使用 Docker + Caddy Server 配置高彈性的反向代理服務

date
Apr 2, 2023
slug
docker-and-caddy-server
status
Published
tags
DevOps
summary
趁連假在家,來翻新一下架構…
type
Post
在大學期間,因爲都是用 FreeBSD,不太好配置 Container,所以我都將服務直接跑在 host 上,並使用 nginx 當 reverse proxy,轉發到對應的 port。而大多數的服務都是 Node.js 應用,所以都用 pm2 去跑。但這樣的設計有幾個缺點:
  1. 直接跑在 host 上,所以外部也可以藉由對應的 port 進來 (當時甚至沒設防火牆,每個 port 都可以直連 🔥)
  1. port 管理複雜,需要進到 nginx 的設定檔一個一個看,才知道有多少 port 也經被用掉了
 
幾年前雖然改裝成 Ubuntu,但卻一直沒有對架構進行翻新。最近由於想要架幾個開源的 Low Code Tool 玩玩看,於是我決定重新配置整個伺服器的架構。
這次的架構打算都走 Docker Container 上,所有服務都跑在 Docker Network 上,並藉由唯一一個 Reverse Proxy 做轉發。如此便可以很好的隔離,並且在 Docker Network 上可以藉由 hostname 去做路由,增加彈性,不用再被共用的 port 號綁手綁腳。另外也打算採用前陣子很火紅的 Caddy Server,雖說印象中效能上 nginx 還是略勝一籌,但配置的方便程度上,我覺得 Caddyfile 的設計更為精簡,內建 Automatic HTTPS,也可以省去設定憑證的時間。
 
這次的環境是 Ubuntu 22.04 LTS

安裝 Docker 及 Docker Compose

 
  1. 更新 apt 並安裝以下套件
  1. 建立 Docker GPG key
  1. 設置 Docker Repository
  1. 安裝 Docker Engine, containerd 和 Docker Compose
  1. 安裝完成後可以跑 sudo docker run hello-world,有看到 Hello from Docker! 就代表安裝成功囉 🎉
notion image
 
下一步我們來安裝 Caddy Server

安裝 Caddy Server

Docker Hub 上的介紹寫得蠻詳細的,建議看一下
Docker Hub 上的介紹寫得蠻詳細的,建議看一下
 
我這次配置的 docker-compose.yml 如下:
 
從他的介紹來看,我們可以知道 /data 對應的 volume caddy_data 是需要持久化的,避免 docker compose down 時就被砍掉了,所以我們將它設成 external,並在 docker compose up 前先建立好
而為了達到多服務中透過 Docker Network 轉發,我們也需要建立一個 external Bridge Network,之後建立的服務如果放上去就不用額外暴露 port ,藉由 <container_hostname>:<port> 就可以打到對應的服務。
設置完成後我們就來啟動吧!
即使只有跑一個服務,我也習慣使用 docker compose,主要是參數都在 docker-compose.yml 內寫好了,省去每次重跑要記得帶哪些參數的麻煩。
 

配置 Caddyfile

Caddy server 支援兩種方式設定,一個是 JSON 檔,另一個便是 Caddyfile。相較於 JSON 檔,Caddyfile 格式更加精簡,且在 Caddy CLI 中也有支援 Formatter,可以方便地檢查設定檔格式是否正確。
另外,在設定完 Caddyfile 後需要 reload 才會載入新的設定檔,這裡也建議先跑一下 caddy fmt 避免噴一個 wrong format 的警告。
上面的指令會先 format 後 reload,建議可以設成一個 script 來使用,很方便。
最後附上設置一個應用時的範例:
 

結語

這次整體翻新效果其實不錯,維護上感覺更簡單,而且不再會有 port 要用幾號的問題,架設其他開源服務時,也比先前輕鬆順暢許多。
最後也來分享一個卡了快半天的問題,就是當我開始改第一次 Caddyfile 時就發現怎麼 reload 都沒有反應,看 log 上面寫 unchanged,再往 container 裏面找,竟然 Caddyfile 是舊的。Google 後才發現,這是因為在 docker-compose.yml 中,我們是 bind Caddyfile 進去的。
bind 的原理在於檔案相同的 inode,當你使用 vim 編輯檔案後 :wq 儲存,這個時候你的 inode 會被改掉,所以 binding 就失效了。解法是使用 w! 或用 nano 去做編輯。
順帶一提,你可以使用 stat 指令去看檔案的 inode,也可以用 find -inum <inode> 去找到對應 inode 的檔案。
 

© maxam 2023 - 2024