
家中群暉nas使用docker運行各種各樣的應(yīng)用也有幾年了,多半是自用,同時軟路由啟動著DDNS自動解析域名的服務(wù)。前幾天,想和朋友共享gitea,創(chuàng)建一個私有的git服務(wù)器,決定再次維護一次。
階段一:家中的各種docker容器均各自映射了各自的端口,通過路由器端口映射映射至互聯(lián)網(wǎng)。
缺點:1. 端口混亂難以記住 2. 缺乏統(tǒng)一日志記錄。
階段二:我又創(chuàng)建了一個docker內(nèi)部網(wǎng),在總?cè)肟趩恿艘粋€nginx容器,同時把各應(yīng)用加入到docker內(nèi)部網(wǎng)中,將應(yīng)用的端口統(tǒng)一,通過nginx配置虛擬主機,路由到不同的應(yīng)用下,后端地址依賴于容器的主機名解析。
缺點:1. 容器變動起來十分麻煩,無法輕松的增加容器副本的負載均衡;2. nginx重啟強制依賴于各服務(wù)的運行狀態(tài),否則會啟動失??;3. 繁瑣的配置懶得手動申請SSL。
階段三:因路由器的配置問題,上行速度無法跑滿,去掉了硬件路由器的方式,在群暉nas上啟動了lede軟路由,軟路由作為DMZ區(qū)域,所有出口流量走軟路由,速度極大的提升了,北京地區(qū)ms級別極速打開,上行速度跑滿,但上述問題,依然繁瑣。
我的VPS用過一段時間的caddy,可基于acme自動注冊SSL、續(xù)簽SSL??紤]到容器時代可能會自由啟停增加容器副本,nginx增改配置文件的方式,在服務(wù)配置、域名配置、SSL配置方面,顯得傳統(tǒng)而又繁瑣。
為了徹底改變這種落后的機制,剛好在研究k8s的時候,我發(fā)現(xiàn)了traefik,剛好能滿足我的需求。然而網(wǎng)上大部分內(nèi)容均為k8s相結(jié)合的ingress-traefik,雖然k8s確實香,但家用nas基本上和k8s扯不上關(guān)系也不需要,網(wǎng)上僅有一篇文章描述群暉如何安裝traefik1,決定分享一下我容器化部署taefik2的填坑經(jīng)驗。
Traefik

Traefik 是一個開源的可以使得服務(wù)發(fā)布變得輕松有趣的邊緣路由器。它負責接收你系統(tǒng)的請求,然后使用合適的組件來對這些請求進行處理。
使用 Traefik,不需要維護或者同步一個獨立的配置文件:因為一切都會自動配置,實時操作的(無需重新啟動,不會中斷連接)。使用 Traefik,你可以花更多的時間在系統(tǒng)的開發(fā)和新功能上面,而不是在配置和維護工作狀態(tài)上面花費大量時間。
除了眾多的功能之外,Traefik 的與眾不同之處還在于它會自動發(fā)現(xiàn)適合你服務(wù)的配置。當 Traefik 在檢查你的服務(wù)時,會找到服務(wù)的相關(guān)信息并找到合適的服務(wù)來滿足對應(yīng)的請求。
Traefik 部署
前提:
- 群暉打開了SSH
- 安裝了docker套件
- 默認磁盤目錄是volume1
SSH登錄至群暉,執(zhí)行如下命令:
cd /volume1/docker/
mkdir traefik
cd traefik
mkdir config
mkdir ssl
mkdir logs
# 創(chuàng)建traefik專屬網(wǎng)絡(luò)
docker network create traefik
touch docker-compose.yml
亮出我們的利器,通過docker-compose啟動,編輯剛剛創(chuàng)建的yml文件 docker-compose.yml:
version: '3.7'
services:
traefik:
container_name: traefik
image: traefik:v2.1.3
restart: always
environment:
- CF_API_EMAIL=CLOUDFLARE登錄郵箱
- CLOUDFLARE_DNS_API_TOKEN=CLOUDFLARE創(chuàng)建的DNS TOKEN
- CLOUDFLARE_ZONE_API_TOKEN=CLOUDFLARE創(chuàng)建的API TOKEN
ports:
- "52080:80"
- "52443:443"
- "52022:22"
networks:
- traefik
command: traefik --configFile /etc/traefik.toml
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./ssl/:/data/ssl/:rw
- ./traefik.toml:/etc/traefik.toml:ro
- ./config/:/etc/traefik/config/:ro
- ./logs/:/data/logs/:rw
healthcheck:
test: ["CMD-SHELL", "wget -q --spider --proxy off localhost:8080/ping || exit 1"]
networks:
traefik:
external: true
值得注意的是,因為運營商屏蔽了22、443、80端口,于是我使用52022、52443、52080做映射替代,如未被屏蔽,請忽略。
為了自動申請SSL證書,提交成功率,我才用DNS Challenge的方式校驗有效性,因此需Cloudflare的環(huán)境信息,如果你的域名沒有配置Cloudflare解析,可以根據(jù)這篇文章置換相應(yīng)變量。

同時,我們在traefik目錄下創(chuàng)建traefik.toml文件,作為全局配置文件,一般不會有改動。
[global]
checkNewVersion = false
sendAnonymousUsage = false
[log]
level = "WARN"
format = "common"
filePath = "/data/logs/traefik.log"
[api]
dashboard = true
insecure = true
[ping]
[accessLog]
filePath = "/data/logs/access.log"
bufferingSize = 100
format = "json"
[accessLog.filters]
minDuration = "10ms"
[providers]
[providers.docker]
watch = true
exposedByDefault = false
endpoint = "unix:///var/run/docker.sock"
swarmMode = false
useBindPortIP = false
network = "traefik"
[providers.file]
watch = true
directory = "/etc/traefik/config"
debugLogGeneratedTemplate = true
[entryPoints]
[entryPoints.http]
address = ":80"
[entryPoints.https]
address = ":443"
[entryPoints.ssh]
address = ":22"
[certificatesResolvers.my.acme]
email = "CLOUDFLARE登錄郵箱"
storage = "/data/ssl/acme.json"
[certificatesResolvers.my.acme.dnsChallenge]
resolvers = ["1.1.1.1:53", "8.8.8.8:53"]
provider = "cloudflare"
delayBeforeCheck = 30
隨后,進入config目錄。
創(chuàng)建dashboard.nas.yfgeek.com.toml文件,作為traefik展示面板的配置文件,因為相對固化,所以采用文件配置文件的形式,traefik支持文件加載配置。
[http.middlewares.dash-compress.compress]
[http.middlewares.dash-auth.basicAuth]
users = [
"test:$apr1$ux2tmr06$Qz5r/BNEfzdxriR/0o30Z1",
]
[http.routers.dashboard]
rule = "Host(`dashboard.nas.yfgeek.com`)"
entrypoints = ["http"]
service = "dashboard@internal"
middlewares = ["dash-auth", "dash-compress"]
[http.routers.api]
rule = "Host(`dashboard.nas.yfgeek.com`) && PathPrefix(`/api`)"
entrypoints = ["http"]
service = "api@internal"
middlewares = ["dash-auth", "dash-compress"]
[http.routers.ping]
rule = "Host(`dashboard.nas.yfgeek.com`) && PathPrefix(`/ping`)"
entrypoints = ["http"]
service = "ping@internal"
middlewares = ["dash-auth", "dash-compress"]
這個文件中,我們設(shè)置了一個用于驗證的中間件,進入網(wǎng)站之前會默認進行驗證,密碼是htpasswd生成規(guī)則,例子中用戶名是test,密碼是test,如需定制,可到這個網(wǎng)站生成密碼。
全部創(chuàng)建好后,目錄結(jié)構(gòu)如下:
|____config
| |____dashboard.nas.yfgeek.com.toml
|____ssl
|____docker-compose.yml
|____traefik.toml
確認無誤,我們使用啟動大法,執(zhí)行如下命令。
docker-compose up -d
docker container logs traefik -f
不出意外,服務(wù)即將啟動成功,可以看到日志,如果有問題就見招拆招即可。

Gitea 部署
traefik啟動好后,我們還沒有應(yīng)用接入,接下來,整理一下原有的gitea容器,將其寫為docker compose文件,同理,在docker目錄下新建一個gitea目錄。
cd /volume1/docker/
mkdir gitea
cd gitea
touch docker-compose.yml
docker-compose.yml參考如下:
version: '3'
services:
gitea:
container_name: gitea
image: gitea/gitea:latest
restart: always
environment:
- USER_UID=1000
- USER_GID=1000
networks:
- traefik
expose:
- 3000
- 22
labels:
- traefik.enable=true
# 設(shè)置HTTP強制跳轉(zhuǎn)HTTPS 中間件
- traefik.http.middlewares.redirect-https.redirectscheme.scheme=https
- traefik.http.middlewares.redirect-https.redirectscheme.port=52443
# HTTP配置
- traefik.http.routers.gitea-web.rule=Host(`git.nas.yfgeek.com`,`git.yfgeek.com`)
- traefik.http.routers.gitea-web.entrypoints=http
- traefik.http.routers.gitea-web.service=gitea-web
- traefik.http.routers.gitea-web.middlewares=redirect-https
# HTTPS配置
- traefik.http.routers.gitea-web-secure.rule=Host(`git.nas.yfgeek.com`,`git.yfgeek.com`)
- traefik.http.routers.gitea-web-secure.entrypoints=https
- traefik.http.routers.gitea-web-secure.service=gitea-web
- traefik.http.routers.gitea-web-secure.tls=true
- traefik.http.routers.gitea-web-secure.tls.certresolver=my
- traefik.http.services.gitea-web.loadbalancer.server.port=3000
# SSH配置
- traefik.tcp.routers.gitea-ssh.rule=HostSNI(`*`)
- traefik.tcp.routers.gitea-ssh.entrypoints=ssh
- traefik.tcp.routers.gitea-ssh.service=gitea-ssh
- traefik.tcp.services.gitea-ssh.loadbalancer.server.port=22
volumes:
- /volume1/docker/gitea:/data
networks:
traefik:
external: true
traefik是通過增加label的方式,自動注冊服務(wù)的,無需任何配置文件,實時生效,如果容器掛了,轉(zhuǎn)發(fā)關(guān)系自動失效。配置文件中,利用redirectscheme的中間件方式,增加了HTTP強制跳轉(zhuǎn)至HTTPS。
針對HTTPS的訪問方式,traefik會自動注冊訪問域名rule=Host(`git.nas.yfgeek.com`,`git.yfgeek.com`)的兩個域名的,因此一定要確認無誤。
同時,為了實現(xiàn)后續(xù)的SSL自動簽發(fā)、host自動注冊,我在DDNS中增加了域名的泛解析配置。
確認無誤后,執(zhí)行如下命令
docker-compose up -d
這里有一個小坑,值得注意,acme申請證書需要一段時間,如果配置信息有誤,是不會申請成功的。因此需要查看下traefik的日志。
docker container logs traefik -f
找到問題見招拆招,如果是權(quán)限等問題,exec進入容器,通過chmod命令解決即可。
隨后訪問域名的HTTP(http://git.yfgeek.com:52080),將被強制跳轉(zhuǎn)至HTTPS(https://git.yfgeek.com:52443),即可看到SSL證書自動申請、配置成功。與此同時,基于TCP的SSH服務(wù)也被順利轉(zhuǎn)發(fā)。

反過來,我們查看dashboard,即可看到gitea的服務(wù)已經(jīng)成功在dashboard中注冊了,并且一切順利。


類似的,如果后續(xù)增加新的docker應(yīng)用,可直接編輯docker compose文件,增加label,配置域名,直接解析、自動申請SSL,方便極了,生產(chǎn)力得到了極大的提升。
下一期我將講講如何traefik+prometheus+grafana,實現(xiàn)自動采集數(shù)據(jù),歸集日志,構(gòu)建網(wǎng)站監(jiān)控系統(tǒng),歡迎持續(xù)關(guān)注。