在 Traefik Proxy 2.5 中使用/開發(fā)私有插件
Traefik Proxy 在設(shè)計上是一個模塊化路由器,允許您將中間件放入您的路由中,并在請求到達預(yù)期的后端服務(wù)目的地之前對其進行修改。Traefik 內(nèi)置了許多這樣的中間件,還允許您以插件的形式加載自己的中間件。
- https://doc.traefik.io/traefik/middlewares/overview/
查找和安裝中間件插件的最簡單方法是通過 Traefik Pilot。Traefik Pilot 是一個軟件即服務(wù) (SaaS) 平臺,它為您的所有 Traefik 代理實例提供全球指標和警報系統(tǒng),并具有免費使用的內(nèi)置插件商店。在商店內(nèi),您可以瀏覽所有可用的開源插件,然后單擊按鈕進行安裝。
- https://doc.traefik.io/traefik-pilot/
- https://pilot.traefik.io/plugins
隨著 Traefik Proxy v2.5 的發(fā)布,有一種新方法可以直接從本地存儲加載插件(并且無需啟用 Traefik Pilot)。只需將您的插件源代碼放入一個名為 /plugins-local 的新目錄中。(您將相對于當(dāng)前工作目錄 [從您調(diào)用 traefik 的位置] 創(chuàng)建此目錄,如果您使用的是 traefik docker 映像,則入口點始終是根目錄 /。) Traefik Proxy 本身將負責(zé)構(gòu)建(解釋 ) 你的插件,所以你所要做的就是編寫源代碼,并在正確的目錄中提供它以便 Traefik Proxy 加載它。插件每次啟動僅加載一次(即,每次您希望重新加載插件源代碼時都必須重新啟動 traefik)。
- https://github.com/traefik/traefik/pull/8224
在以下場景中,您將找到使用 Traefik Proxy v2.5 編寫自己的 Docker 容器鏡像并將插件源代碼捆綁到該鏡像的 /plugins-local 目錄中的示例。在使用 Docker 在開發(fā)環(huán)境中測試您的插件之后(并且可能在為其創(chuàng)建持續(xù)集成構(gòu)建之后),您可以將此鏡像推送到容器 registry,并在生產(chǎn) Docker 服務(wù)器和/或 Kubernetes 集群中引用此鏡像。您可以將鏡像保密,也可以將其發(fā)布并在任何地方共享您的插件。
構(gòu)建 Traefik Proxy 容器鏡像并捆綁 demo 插件
這是一個示例 Dockerfile,它重新混合了標準 traefik:v2.5 docker 映像,并添加了一個從可配置的 git 存儲庫自動克隆的插件。
在某個地方創(chuàng)建一個臨時目錄,并在其中創(chuàng)建一個名為 Dockerfile.demo 的新文件:?
# Dockerfile.demo - Example for Traefik Proxy and a demo plugin from git:FROM alpine:3ARG PLUGIN_MODULE=github.com/traefik/plugindemoARG PLUGIN_GIT_REPO=https://github.com/traefik/plugindemo.gitARG PLUGIN_GIT_BRANCH=masterRUN apk add --update git && \
git clone $ PLUGIN_GIT_REPO /plugins-local/src/$ PLUGIN_MODULE \
--depth 1 --single-branch --branch $ PLUGIN_GIT_BRANCH FROM traefik:v2.5COPY --from=0 /plugins-local /plugins-local
默認構(gòu)建參數(shù)加載 Traefik Labs 發(fā)布的示例插件 demo,它本質(zhì)上是內(nèi)置 headers.customRequestHeaders 中間件的克隆,但作為插件。
- https://github.com/traefik/plugindemo
- https://doc.traefik.io/traefik/middlewares/headers/#customrequestheaders
在與 Dockerfile.demo 相同的目錄中,構(gòu)建鏡像:
docker build -f Dockerfile.demo --tag traefik-with-demo-plugin .
您現(xiàn)在剛剛構(gòu)建了一個 docker 鏡像,其中包含 Traefik v2.5 和演示插件。您現(xiàn)在可以運行鏡像來測試它:
docker run --rm -it traefik-with-demo-plugin \
--log.level=DEBUG \
--experimental.localPlugins.demo.moduleName=github.com/traefik/plugindemo
日志將打印顯示插件已加載且 Traefik 代理將運行的配置。你可以肯定地測試一下,按 Ctrl-C 停止容器,然后重新運行將 moduleName= 更改為 github.com/something/different 的命令,你會得到一個錯誤,說它不存在并立即退出。
使用您的自定義插件構(gòu)建 Traefik Proxy 容器鏡像
要創(chuàng)建您自己設(shè)計的新插件,請分叉此演示存儲庫。(要直接在 GitHub 上執(zhí)行此操作,您可以單擊標有 Use this template 的綠色按鈕,或者您可以將存儲庫克隆到另一臺服務(wù)器)。您可以選擇將此新存儲庫設(shè)為公共或私有,但說明會有所不同,具體取決于它是否需要身份驗證才能克隆它,因此將分別介紹每種情況。
- https://github.com/traefik/plugindemo
將您的分叉存儲庫克隆到您的工作站,并閱讀 readme.md 文件中的開發(fā)說明。創(chuàng)建您的插件代碼,更新 .traefik.yml 中的 import 行以匹配您的存儲庫名稱,將更改提交到 git,然后將更改推送回您的 git 服務(wù)器 (GitHub)。如果您只想測試示例插件代碼,則無需提交任何更改。此外,Traefik 不需要編譯插件源代碼:插件通過原始源代碼加載,并在運行時由 Yaegi 解釋。
- https://github.com/traefik/plugindemo/blob/master/readme.md
- https://github.com/traefik/yaegi
從公共存儲庫構(gòu)建鏡像
如果您將存儲庫公開,則構(gòu)建鏡像很容易。打開您的 shell 終端,并創(chuàng)建這些臨時環(huán)境變量以用作構(gòu)建參數(shù):
## Create temporary variables for your plugin and git repository details:## Optionally save these to build-env.sh and run "source build-env.sh" after.export DOCKER_IMAGE=traefik-with-my-pluginexport PLUGIN_MODULE=github.com/YOUR_NAME/YOUR_REPOSITORYexport PLUGIN_GIT_REPO=https://github.com/YOUR_NAME/YOUR_REPOSITORY.gitexport PLUGIN_GIT_BRANCH=master
更改這些變量以適合您的分叉插件存儲庫:
- DOCKER_IMAGE 是你的新 Docker 鏡像的 tag,它將捆綁 Traefik 和你的插件代碼。
- PLUGIN_MODULE 是插件的 Go 模塊的名稱(例如 github.com/traefik/plugindemo)。使用您自己的服務(wù)器、組織和分叉存儲庫名稱。
- PLUGIN_GIT_REPO 是插件存儲庫中心的完整 git clone URL。(此示例假設(shè)使用了公共存儲庫,并且不需要身份驗證,否則請參閱下一節(jié)。)
- PLUGIN_GIT_BRANCH 是您希望克隆和安裝的 git 分支名稱。
在克隆存儲庫的根目錄中,創(chuàng)建一個名為 Dockerfile.public 的新文件:
## Dockerfile.public - Bundle a Traefik plugin from a public git repositoryFROM alpine:3ARG PLUGIN_MODULE=github.com/traefik/plugindemoARG PLUGIN_GIT_REPO=https://github.com/traefik/plugindemo.gitARG PLUGIN_GIT_BRANCH=masterRUN apk update && \
apk add git && \
git clone $ PLUGIN_GIT_REPO /plugins-local/src/$ PLUGIN_MODULE \
--depth 1 --single-branch --branch $ PLUGIN_GIT_BRANCH FROM traefik:v2.5COPY --from=0 /plugins-local /plugins-local
構(gòu)建并標記鏡像,從環(huán)境中傳遞參數(shù):
docker build -f Dockerfile.public \
--tag $ DOCKER_IMAGE \
--build-arg PLUGIN_MODULE \
--build-arg PLUGIN_GIT_REPO \
--build-arg PLUGIN_GIT_BRANCH .
從私有 git 存儲庫構(gòu)建鏡像
從私有 git 存儲庫構(gòu)建鏡像更具挑戰(zhàn)性,因為您需要將 SSH 憑據(jù)傳遞到 Docker 構(gòu)建過程,以便按照 Dockerfile 中的腳本從私有 git 存儲庫進行克隆。
您需要將 Docker 安裝更新到版本 >=18.09,這允許在 docker 鏡像構(gòu)建過程中加載與 ssh-agent 通信和臨時使用工作站用戶帳戶的 SSH 密鑰所需的實驗性 BuildKit 增強功能。
- https://docs.docker.com/develop/develop-images/build_enhancements
在你的 shell 中設(shè)置這些環(huán)境變量:
## Optionally save these to build-env.sh and run "source build-env.sh" after.## Docker BuildKit is required for ssh-agent forwarding:export DOCKER_BUILDKIT=1## Edit these variables for your plugin and git repository:export DOCKER_IMAGE=traefik-with-my-pluginexport PLUGIN_MODULE=github.com/YOUR_NAME/YOUR_REPOSITORYexport PLUGIN_GIT_REPO=git@github.com:YOUR_NAME/YOUR_REPOSITORY.gitexport PLUGIN_GIT_BRANCH=master
主機 ssh-agent 直通需要修改 Dockerfile。創(chuàng)建一個名為 Dockerfile.private 的新文件:
# syntax=docker/dockerfile:1.0.0-experimental# The above line is required to turn on experimental BuildKit features.# Dockerfile.private - Build Traefik and plugin from a private git repository.# Loads SSH keys from the host `ssh-agent` to allow git clone.FROM alpine:3# Clone your plugin git repositories:ARG PLUGIN_MODULE=github.com/traefik/plugindemo
ARG PLUGIN_GIT_REPO=git@github.com:traefik/plugindemo.git
ARG PLUGIN_GIT_BRANCH=master
RUN apk add --update git openssh && \
mkdir -m 700 /root/.ssh && \
touch -m 600 /root/.ssh/known_hosts && \
ssh-keyscan github.com > /root/.ssh/known_hosts
RUN --mount=type=ssh git clone \
--depth 1 --single-branch --branch $ PLUGIN_GIT_BRANCH \ $ PLUGIN_GIT_REPO /plugins-local/src/$ PLUGIN_MODULE
FROM traefik:v2.5
COPY --from=0 /plugins-local /plugins-local
使用額外的 --ssh default 選項構(gòu)建鏡像。這將通過連接到運行 ssh-agent 的主機連接到構(gòu)建過程,以便您可以在構(gòu)建過程中使用 SSH 密鑰,并克隆私有 git 存儲庫:
docker build -f Dockerfile.private \
--ssh default --tag $ DOCKER_IMAGE \
--build-arg PLUGIN_MODULE \
--build-arg PLUGIN_GIT_REPO \
--build-arg PLUGIN_GIT_BRANCH .
注意:由于 docker-compose 中存在一個未解決的問題,您目前無法在 docker-compose 中使用 --ssh 參數(shù)(并且與 ssh-agent 的連接將失?。虼巳绻胧褂么诵薷暮蟮?nbsp;Dockerfile 以及 docker-compose,您必須首先使用上面列出的 docker build 命令手動構(gòu)建容器映像。如果您首先以這種方式構(gòu)建映像,則 docker-compose 可以依賴構(gòu)建緩存或顯式鏡像名稱,而無需再次構(gòu)建它。
- https://github.com/docker/compose/issues/7025
使用 docker-compose 作為插件開發(fā)環(huán)境
你可以使用 docker-compose 作為一個簡單的插件開發(fā)環(huán)境。
- https://docs.docker.com/compose/
將您的插件存儲庫克隆到您的工作站,然后將這些新文件創(chuàng)建到存儲庫的根目錄中:
創(chuàng)建 Dockerfile:
FROM traefik:v2.5## Default module name (put your setting in .env to override)ARG PLUGIN_MODULE=github.com/traefik/plugindemo
ADD . /plugins-local/src/$ PLUGIN_MODULE
創(chuàng)建 .env 設(shè)置文件:
## Traefik Proxy local plugin .env file## Configure your plugin name:PLUGIN_NAME=demo## Configure your module namespace:PLUGIN_MODULE=github.com/traefik/plugindemo## Configure whoami domain name for route testing:WHOAMI_TRAEFIK_HOST=whoami.example.com## Configure Email address for Let's Encrypt:## Uncomment and configure this for production only:# ACME_CA_EMAIL=you@example.com
創(chuàng)建 docker-compose.yaml:
# docker-compose.yaml for Traefik Proxy local plugin developmentversion: "3.3" networks: traefik-proxy: volumes: traefik-proxy:
services
traefik-proxy
build
context.
args
PLUGIN_MODULE $ PLUGIN_MODULE
restart unless-stopped
networks
traefik-proxy
security_opt
no-new-privileges:true
command#- "--log.level=DEBUG"
"--providers.docker=true"
"--providers.docker.exposedbydefault=false"
"--providers.docker.network=traefik-proxy"
## Entrypoints:
"--entrypoints.web.address=:80"
"--entrypoints.websecure.address=:443"
"--entrypoints.traefik.address=:9000"
## Automatically redirect HTTP to HTTPS
"--entrypoints.web.http.redirections.entryPoint.to=websecure"
## ACME TLS config:
"--certificatesresolvers.default.acme.storage=/data/acme.json"
## Uncomment for production TLS certificates (Let's Encrypt):
# - "--certificatesresolvers.default.acme.tlschallenge=true"
# - "--certificatesresolvers.default.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
# - "--certificatesresolvers.default.acme.email=${ACME_CA_EMAIL}"
## Enable Dashboard available only from the docker localhost:9000
"--api.dashboard=true"
"--api.insecure=true"
## Enable local plugins:
"--experimental.localPlugins.${PLUGIN_NAME}.moduleName=${PLUGIN_MODULE}"
ports
"80:80"
"443:443"
"127.0.0.1:9000:9000"
volumes
"traefik-proxy:/data"
"/var/run/docker.sock:/var/run/docker.sock:ro"
## The whoami container will run the demo plugin for testing purposes:
whoami
image traefik/whoami
networks
traefik-proxy
restart unless-stopped
labels
"traefik.enable=true"
"traefik.http.routers.whoami.rule=Host(`${WHOAMI_TRAEFIK_HOST}`)"
"traefik.http.routers.whoami.entrypoints=websecure"
# Configure the plugin as a new middleware:
"traefik.http.routers.whoami.middlewares=whoami-demo"
# Add a test header to all incoming requests:
# (the presense of this header in whoami response shows if the plugin works:)
"traefik.http.middlewares.whoami-demo.plugin.${PLUGIN_NAME}.headers.DoesPluginWork=YES"
"traefik.http.routers.whoami.tls.certresolver=default"
創(chuàng)建 .dockerignore 以從鏡像構(gòu)建中排除 .git 目錄:
# .dockerignore file exludes files from the image:.git
構(gòu)建鏡像并啟動測試實例:
docker-compose up
編輯您的 /etc/hosts 文件(或您的本地 DNS 服務(wù)器)并添加 whoami 路由域:
curl -k https://whoami.example.com
使用 curl 測試您的 DNS 是否正常工作,以及插件是否已生效(使用與您為 WHOAMI_TRAEFIK_HOST 和 /etc/hosts 配置的域名相同的域名):
curl -k https://whoami.example.com
您應(yīng)該得到 whoami 響應(yīng),并在輸出中顯示此測試頭:
DoespluginworkYES
這是插件配置為注入請求的相同頭和值,并從 whoami 回顯。如果你看到它,你就知道你的插件配置成功了。
為常規(guī)開發(fā)工作配置本地 DNS 服務(wù)
當(dāng)你需要測試大量不同的子域和 Traefik Proxy Host 路由器規(guī)則時,一個更好的 DNS 解決方案,而不是不斷編輯你的 /etc/hosts 文件,是在你的工作站上運行 dnsmasq 作為本地 DNS 服務(wù)器,它會響應(yīng)到通配符 DNS A 記錄查詢,用于整個根域或子域名。
dnsmasq 的配置是可選的,是對 /etc/hosts 文件的補充。dnsmasq 的安裝說明取決于您的操作系統(tǒng),但可以從大多數(shù)包管理器中獲得。 dnsmasq 將使您的開發(fā)工作更加順暢,并且是清理 /etc/hosts 文件的好方法。這是一個示例 /etc/dnsmasq.conf 配置文件,用于設(shè)置具有通配符域的本地 DNS 服務(wù)。您還需要按照注釋中的說明編輯您的 /etc/resolv.conf:
# /etc/dnsmasq.conf# Use this if you are tired of editing your /etc/hosts file.# This is a local DNS service bound only to the looback device on localhost.# To use this requires an /etc/resolv.conf file # with a single line (no leading space): nameserver 127.0.0.1# To prevent any changes to the host DNS config,# run: sudo chattr +i /etc/resolv.conf# (now all of your DNS queries will go through dnsmasq)interface=lo
listen-address=::1,127.0.0.1
bind-interfaces
cache-size=1000# Use cloudflare upstream DNS servers:server=1.1.1.1
server=1.0.0.1# Example wildcard domain names# All *.example.com names point to a single docker server IP address:address=/example.com/127.0.0.1# dnsmasq also loads your /etc/hosts file, so those host names still work.
檢查您的操作系統(tǒng)說明以啟用 dnsmasq 服務(wù),但通常使用 Systemd:
sudo systemctl enable --now dnsmasq.service
編輯 /etc/resolv.conf 以將 dnsmasq 服務(wù)器用于所有系統(tǒng) DNS 查詢:
domain your.domain.example.com
search domain.example.com
nameserver 127.0.0.1
有時其他服務(wù)(systemd-resolved)想要覆蓋這個文件,你可以通過在文件上應(yīng)用不可變標志來防止這種情況:
# This prevents editing the file, use -i to re-enable editing:chattr +i /etc/resolv.conf
您可以使用 dig、drill 或 nslookup 實用程序測試 DNS 服務(wù)器是否處于活動狀態(tài):
# dig or drill:dig test.example.com | grep -A1 "ANSWER SECTION"# or nslookup:nslookup test.example.com
任何這些工具的輸出都應(yīng)該報告您的 docker 主機的正確 IP 地址,現(xiàn)在您可以在 Traefik 代理路由中使用您想要的任何子域。
引用
- https://traefik.io/blog/using-private-plugins-in-traefik-proxy-2-5/