本人 Ghost 博客以及自建私有云 Nextcloud 均已經穩定運行了一年有餘,期間經歷過兩次服務器遷移和屢次版本升級,均未發生過數據丟失和其餘問題,在遷移過程當中也曾分享過如何將 Docker Volumes 安全的跨服務器遷移。目前博客和網盤服務分別搭建於兩臺服務器,並統一使用另外一臺服務器做反代。web
在反代軟件上,一直使用的都是 Nginx,最近在研究 K8s,也對比較流行的雲原生反向代理工具 Traefik 產生了興趣,因而便花了一點時間將反代服務器上的 Nginx 換成了 Traefik。必定要吐槽的一點是,Traefik 的官方文檔寫得實在太糟糕了,初次接觸的用戶,想經過只看官方文檔把事情搞定,那是至關困難,因此我以爲很是有必要分享一下,讓其餘初次使用的用戶避免踩坑。docker
目前 Traefik 已經更新到了 2.1
版本,其 2.x
版本和 1.x
版本差別較大,本文天然將基於最新版本,新版本增長的自動配置 HTTPS 功能和 TCP 代理功能都十分有價值。apache
反向代理服務器的工做,天然就是截獲服務器流量,並將流量轉發至目標服務或地址,在這一基礎上,若是轉發的目標服務或地址是多個,就是負載均衡。Traefik 官方文檔中的圖片都是萌萌的,下面這張圖就比較清晰的說明了 Traefik 或者說通常反代軟件的功能:json
本人目前的需求比較簡單,就是未來自於pbeta.me
和www.pbeta.me
的訪問流量轉發至 博客IP:博客端口
,未來自於cloud.pbeta.me
的訪問流量轉發至 網盤IP:端口
,另外,考慮到演示須要,本文將完成如下目標:api
在安裝以前,我以爲有必要講一下 Traefik 這款工具的配置方式,搞清楚了基本的配置方式,在下面安裝和配置的過程當中纔能有清晰的思路,如下內容主要參考了官方文檔中的Configuration Introduction 頁面。安全
簡單的說,Traefik 的配置包括靜態配置和動態配置兩種,前者是 Traefik 自身的配置,須要重啓才能生效,後者則能夠理解爲被代理服務的配置,能夠經過配置實現爲即時生效。bash
若是配置內容不存在服務差別性,那就能夠統一在靜態配置中,不然就須要在動態配置中爲每個服務中單獨添加,動態配置中的多個服務也能夠共用同一配置內容,好比能夠配置一個basicAuth
的Middlewares
,由多個服務共用。服務器
不管靜態配置仍是動態配置,都有兩種配置方式:CLI
形式或者獨立文件形式。網絡
對於靜態配置,一個是 Traefik 鏡像啓動時的啓動參數,另外一個是單獨的配置文件(如 traefik.yml
),官方文檔提供示例時,也同時包括這兩種形式,分別對應的是 CLI
和 File(YAML)
,不過在查看官方的配置示例時,你會發現還包括 File(TOML)
,TOML 文件是對 YAML 的一種改進,本文暫時都使用 YAML,讀者能夠自行轉換。另外,官方文檔中也說明了靜態配置能夠經過環境變量實現,本文暫不使用此方式。hexo
配置項的優先級爲配置文件 > 命令行參數 > 環境變量,請注意配置文件與命令行參數是互斥的,若是你選擇使用配置文件,就不能再使用命令行參數,最終的配置並不是兩者的疊加。
而對於動態配置,能夠選擇直接在服務的 docker-compose
文件最下方經過 labels
實現,好比這樣:
# yaml
whoami:
# A container that exposes an API to show its IP address
image: containous/whoami
labels:
- "traefik.http.routers.whoami.rule=Host(`whoami.docker.localhost`)"
複製代碼
也能夠寫在單獨的配置文件中,這一文件在 Traefik 中通常命名爲 dynamic.yml
,你能夠將全部路由配置寫在此文件中,爲了清晰起見,本文統一使用後一種方式。
經過上面的說明,咱們能夠知道,在 Docker 中使用 Traefik 大體可能會涉及到三個文件:
再次重複一次,若是使用獨立配置文件來存放靜態配置,那麼
docker-compose.yml
文件中的command
部分將不會生效。
有了以上的文件,如何加載呢?docker-compose.yml
中的配置天然沒必要考慮這個問題,對於其餘兩個文件的加載則必需要綁定至容器。
當 Traefik 啓動時,將會在如下位置搜索配置文件,名稱能夠是 traefik.toml、traefik.yml 或者 traefik.yaml:
另外,能夠經過添加形式如 --configFile=foo/bar/myconfigfile.toml
的啓動參數覆蓋默認行爲。
根據官方文檔的以上描述,考慮到咱們是在 Docker 環境中運行 Traefik,因此建議將放置配置文件的目錄綁定到容器的 /etc/traefik
目錄便可。
動態配置文件的加載,則須要使用 Traefik 的 providers 啓動參數,形式以下:
CLI
形式--providers.file.directory=/etc/traefik
--providers.file.filename=dynamic.yml
--providers.file.watch=true
複製代碼
providers:
file:
directory: "/etc/traefik"
filename: "dynamic.yml"
watch: true
複製代碼
這三行啓動參數的含義很是容易理解,在官方文檔中我沒有注意到有默認目錄,因此咱們必定須要指定目錄,指定配置文件名,最後一行的watch=true
將開啓動態配置項的即時生效,再也不須要重啓容器。
與 traefik.yml
文件的加載相似,在 Docker 環境運行 Traefik 的狀況下,咱們須要將存放 dynamic.yml
的目錄綁定至容器的 /etc/traefik
目錄,這裏咱們使用了同一目錄,這樣就沒必要分別綁定兩個目錄了。
經過以上的描述,讀者應該基本明白了 Traefik 整個配置的運做方式,更加高級的用法能夠自行研究官方文檔。
咱們使用 Docker 安裝 Traefik,下文將以官方文檔中的相關示例爲模板,修正其錯誤,完成初步配置及安裝。
咱們使用的配置文件來自於官方文檔中Docker-compose with let's encrypt: TLS Challenge,內容以下:
version: "3.3"
services:
traefik:
image: "traefik:v2.0.0-rc3"
container_name: "traefik"
command:
#- "--log.level=DEBUG"
- "--api.insecure=true"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.mytlschallenge.acme.tlschallenge=true"
#- "--certificatesresolvers.mytlschallenge.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory"
- "--certificatesresolvers.mytlschallenge.acme.email=postmaster@mydomain.com"
- "--certificatesresolvers.mytlschallenge.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
whoami:
image: "containous/whoami"
container_name: "simple-service"
labels:
- "traefik.enable=true"
- "traefik.http.routers.whoami.rule=Host(`whoami.mydomain.com`)"
- "traefik.http.routers.whoami.entrypoints=websecure"
- "traefik.http.routers.whoami.tls.certresolver=mytlschallenge"
複製代碼
官方文檔中的這一示例,使用了 CLI
配置靜態配置的方式,但其提供的這一示例主要存在如下幾個問題:
下面咱們對其針對性的修改,另外爲了清晰,咱們將示例中提供的 whoami
應用在後面做爲單獨應用運行。
根據前文對 Traefik 配置方式的講解,咱們知道咱們既能夠選擇在 docker-compose.yml
文件中配置,也可使用獨立的 traefik.yml
配置,本人建議使用獨立的 traefik.yml
配置,下文也只提供這一種方式,熟悉了之後,讀者能夠自行切換。
靜態配置裏能夠有哪些內容,能夠參考官方文檔
咱們的配置文件內容以下:
docker-compose.yml
文件version: "3.3"
services:
traefik:
image: "traefik:latest" # 咱們直接部署最新版本,可自行調整
container_name: "traefik"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
# 自動申請的證書存放位置,咱們須要在當前目錄建立 letsencrypt 目錄
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
# 綁定咱們的配置目錄
- "./config:/etc/traefik"
複製代碼
./config/traefik.yml
文件providers:
docker: {}
file:
directory: "/etc/traefik"
filename: "dynamic.yml"
watch: true
log:
level: DEBUG
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
mytlschallenge:
acme:
email: "yourname@domain"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
api:
dashboard: true
複製代碼
./config/dynamic.yml
文件因爲咱們暫時不轉發任何服務,此文件暫時爲空。
啓動咱們的 docker-compose.yml
文件:
docker-compose up -d
複製代碼
稍等片刻,就能看到服務建立成功,使用 docker ps
查看,能夠看到容器正常運行。
Traefik 的 Dashboard 其實是其 API 功能的圖形化展現,因此咱們須要開啓配置中的 API 參數和 Dashboard 參數,參考官方文檔:
If you enable the API, a new special service named api@internal is created and can then be referenced in a router. And then define a routing configuration on Traefik itself with the dynamic configuration.
若是開啓了 api
,就會建立一個叫作 api@internal
的服務,咱們上面所使用的 traefik.yml
配置中,已經打開了 api
,也打開了 dashboard
。
官方配置中有一行
- "--api.insecure=true"
被咱們無視掉了,有興趣的朋友閱讀這裏。
而後按官方文檔說明,爲 Traefik 自身添加這一動態路由,因此咱們修改 dynamic.yml
文件:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.domain.com`)"
service: api@internal
複製代碼
Rule 的配置除了
Host
還有Path
、PathPrefix
等,配置邏輯運算符來實現配置,具體能夠查看這裏。另外,記得將域名提早解析到服務器 IP,若是是本地虛擬機測試,請自行修改hosts
文件。
以後從新運行 docker-compose up -d
便可,此時訪問綁定的域名就能看到 Traefik 的 Dashboard 了:
當咱們啓動一個 Docker 服務後,Traefik 就能發現服務併爲其建立默認路由,須要注意的一點是,若是 Traefik 要可以與新的 Docker 服務進行通訊,必須將其加入到同一網絡,咱們使用 docker-compose.yml
啓動 Traefik 時,就建立了 traefik_default
網絡,新加入的容器須要手動加入該網絡。
加入網絡的方式不少,能夠自行搜索,使用 docker run
時經過 --network traefik_default
,或者使用docker-compose.yml
時添加:
networks:
- traefik_default
複製代碼
下面咱們使用 Traefik 提供的 whoami
應用進行測試,使用 docker run
啓動應用:
docker run -d -P --name whoami --net traefik_default containous/whoami
複製代碼
以後咱們查看 Dashboard,就會發現 Traefik 已經自動發現了服務,服務名爲 whoami@docker
。下面咱們爲該服務配置路由,打開咱們的 ./config/dynamic.yml
文件,在下方增長 whoami
路由配置內容:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
複製代碼
配置完成並保存後,在 Dashboard 就能夠看到新添加的路由了,此時咱們訪問 http://traefik.pbeta.cn/whoami
就能訪問到咱們的服務了:
你會發現咱們並無告訴要轉發服務的哪一個端口,這是由於 Traefik 智能的進行了處理,若是服務只暴露一個端口,Traefik 就會自動選擇該端口,但若是服務暴露多個端口,你必須手動指定,具體請參考官方文檔。
咱們使用本機來模擬這一需求,在咱們的服務器上運行一個 Ghost 服務,可是並不加入 traefik_default
網絡,而是在 Traefik 中經過 服務器互聯網IP : 服務端口 來轉發。
啓動一個 Ghost 容器:
docker run -d -p 2368:2368 --name ghost ghost
複製代碼
咱們暴露了服務器的 2368 端口,此時直接在外部訪問 服務器IP:端口 就能訪問到網站(若是你防火牆開放了 2368 端口的話)
下面咱們就配置 Traefik 將 traefik.pbeta.cn/ghost
轉發至該地址,繼續修改咱們的 dynamic.yml
,分別添加一個服務和一個路由,完整的 dynamic.yml
文件以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
ghost:
entryPoints:
- "web"
rule: "Host(`ghost.pbeta.cn`) "
service: ghost
services:
ghost:
loadBalancer:
servers:
- url: "http://47.74.154.202:2368/"
複製代碼
保存以後訪問 http://ghost.pbeta.cn
便可打開咱們剛啓動的 Ghost 網站:
前面咱們一直使用的是 web
這一入口,經過簡單配置便可實現 HTTPS 訪問服務。官方文相關頁面有較多示例,可供參考。本文將只講解使用 Let's Encrypt 自動配置 HTTPS。
前面提供的 traefik.yml
中已經包括了相關的配置:
certificatesResolvers:
mytlschallenge:
acme:
email: "yourname@domain"
storage: "/letsencrypt/acme.json"
tlsChallenge: {}
複製代碼
咱們爲這一 certificatesRsolver
命名爲了 mytlschallenge
,以後在路由配置中添加 tls
部分使用該 resolver
便可,因此咱們打開 dynamic.yml
,進行編輯,爲服務額外添加一條路由配置:
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
複製代碼
保存以後稍等片刻,就已經配置好了 HTTPS:
能夠在多個網站使用同一個 certificatesResolver
,但爲了不衝突,支持經過 option
來進行區分,一個完整的配置示例以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
options: traefik
whoami:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
whoami-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`) && Path(`/whoami`)"
service: whoami@docker
tls:
certResolver: "mytlschallenge"
options: traefik
ghost:
entryPoints:
- "web"
rule: "Host(`ghost.pbeta.cn`)"
service: ghost
ghost-tls:
entryPoints:
- "websecure"
rule: "Host(`ghost.pbeta.cn`)"
service: ghost
tls:
certResolver: "mytlschallenge"
options: ghost
services:
ghost:
loadBalancer:
servers:
- url: "http://47.74.154.202:2368/"
tls:
options:
traefik: {}
ghost: {}
複製代碼
這樣咱們的三個路由的 HTTPS 訪問都就配置好了,你能夠注意到咱們使用了2個 options
,由於 traefik.pbeta.cn
和 ghost.pbeta.cn
須要不一樣的證書,因此必須以此進行區分,options
中也能夠自行根據文檔說明自行添加配置內容。
Traefik 提供了很是多的中間件,這些中間件能實現你須要的大部分功能,這裏分別以簡單權限認證和 HTTP 自動跳轉 HTTPS 爲例進行介紹。
爲了不配置文件過長,下面只以 Dashboard 進行示例。
Middlewares 的使用很是簡單,在動態配置文件中的 http
(或tcp
)下添加 middlewares
,以後在每個路由中使用便可,咱們添加一個自動跳轉 HTTPS 的 Middleware:
middlewares:
redirect:
redirectScheme:
scheme: https
複製代碼
以後咱們在以 web
爲入口的服務添加這一 middleware
:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- redirect
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
tls:
certResolver: "mytlschallenge"
options: traefik
middlewares:
redirect:
redirectScheme:
scheme: https
tls:
options:
traefik: {}
複製代碼
保存文件以後,訪問 http://traefik.pbeta.cn
將會自動跳轉至 https://traefik.pbeta.cn
。
這裏須要使用的中間件是 BasicAuth,具體的使用方式能夠參閱官方文檔。
在 K8s 中咱們使用 Secret 資源來管理密碼等,但在 Docker 中沒法經過這種方式,須要使用 users
或者 usersFile
參數管理密碼,這裏咱們使用 users
。
密碼的建立須要藉助於 htpasswd
,安裝方式以下:
yum -y install httpd-tools
複製代碼
apt install apache2-utils
複製代碼
咱們使用 htpasswd
命令來生成一用戶名爲test 密碼 爲test1234 的密碼對:
echo $(htpasswd -nb test test1234)
複製代碼
獲得的信息是 test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0
。
須要注意一點,因爲咱們是在單獨配置文件中使用,因此無須進行轉義,若是是以
CLI
形式使用的話,全部$
符號必須寫兩次,可使用官方文檔中的命令來生成轉義後的密碼echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
下面咱們就使用此密碼對來建立咱們的 BasicAuth Middleware,打開 dynamic.yml
文件進行修改,在上面建立的 redirect
下添加以下內容:
test-auth:
basicAuth:
users:
- "test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0"
複製代碼
以後在前面的路由下的 middlewares
下添加 test-auth
,完整的 dynamic.yml
文件以下:
http:
routers:
api:
entryPoints:
- "web"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- redirect
- test-auth
api-tls:
entryPoints:
- "websecure"
rule: "Host(`traefik.pbeta.cn`)"
service: api@internal
middlewares:
- test-auth
tls:
certResolver: "mytlschallenge"
options: traefik
middlewares:
redirect:
redirectScheme:
scheme: https
test-auth:
basicAuth:
users:
- "test:$apr1$k.xiBHjv$VdavfNvly69vNZvkKpB2j0"
tls:
options:
traefik: {}
複製代碼
保存文件後,再次訪問 http://traefik.pbeta.cn
,就會發現須要密碼登陸了:
輸入密碼後便可正常訪問。
經過以上內容,咱們對 Traefik 的配置方式有了比較深刻的瞭解,並實現了咱們的目標,Traefik 的官方文檔雖然雜亂,但不失詳盡,有了本文提供的基礎知識,再結合官方文檔,使用 Traefik 實現各類高級功能應該並不是難事。
在配置過程當中遇到任何問題,能夠在評論區中提問,本人將盡力協助。