插件简介
在traefik2.3版本上线了插件支持功能,Traefik 虽然已经内置了很多中间件,可以满足我们大部分的日常需求,但是在实际工作中,用户仍然还是有自定义中间件的需求,为解决这个问题,推出了traefik插件功能,他允许开发人员向traefik添加更多的新功能。
在traefik2.3-2.7版本期间,插件的管理使用是通过Traefik Pilot,它可以集中管理在任何环境中运行的所有 Traefik 实例。它通过统一的仪表板提供对 Traefik 实例的观察性和控制,可提供详细的网络指标、服务器监控和安全通知。Traefik Pilot 还为自定义中间件插件托管了一个公共插件中心,支持流量整形、流量 QoS、流量速率限制等。但在traefik2.8以后的版本,弃用了Traefik Pilot,直接访问插件社区即可:https://plugins.traefik.io/plugins。原本的流量整形、流量 QoS、流量速率等功能由traefik hub实现。
与内置的中间件不同,插件是动态加载的,并由嵌入式解释器执行。无需编译二进制文件,所有插件都是100%跨平台的,使它们易于开发并与更广泛的Traefik社区共享。
在线安装插件
参考文档:https://plugins.traefik.io/install
我们以最简单的demo plugin为例,演示如何安装并使用插件
创建应用与服务
我们创建一个deployment控制器和cluster服务,部署whoami应用。
[root@tiaoban ingress]# cat whoami.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: whoami
spec:
selector:
matchLabels:
app: whoami
template:
metadata:
labels:
app: whoami
spec:
containers:
- name: whoami
image: traefik/whoami
resources:
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
name: http
---
apiVersion: v1
kind: Service
metadata:
name: whoami
spec:
selector:
app: whoami
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
[root@tiaoban ingress]# kubectl apply -f whoami.yaml
deployment.apps/whoami created
service/whoami created
[root@tiaoban ingress]# kubectl get pod
NAME READY STATUS RESTARTS AGE
flask-59c4df7867-jxs2q 1/1 Running 0 3h23m
myapp1-795d947b45-qbmx8 1/1 Running 1 15h
test 1/1 Running 1 94m
whoami-6f965cd45-dv7br 1/1 Running 0 28s
[root@tiaoban ingress]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
whoami ClusterIP 10.108.54.125 <none> 80/TCP 56s
安装插件
修改traefik配置文件,启用插件功能
[root@tiaoban traefik]# cat traefik-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: traefik
data:
traefik.yaml: |-
global:
checkNewVersion: false # 周期性的检查是否有新版本发布
sendAnonymousUsage: false # 周期性的匿名发送使用统计信息
serversTransport:
insecureSkipVerify: true # Traefik忽略验证代理服务的TLS证书
api:
insecure: true # 允许HTTP 方式访问API
dashboard: true # 启用Dashboard
debug: false # 启用Debug调试模式
metrics:
prometheus: # 配置Prometheus监控指标数据,并使用默认配置
addRoutersLabels: true # 添加routers metrics
entryPoint: "metrics" # 指定metrics监听地址
entryPoints:
web:
address: ":80" # 配置80端口,并设置入口名称为web
forwardedHeaders:
insecure: true # 信任所有的forward headers
websecure:
address: ":443" # 配置443端口,并设置入口名称为 websecure
forwardedHeaders:
insecure: true
traefik:
address: ":9000" # 配置9000端口,并设置入口名称为 dashboard
metrics:
address: ":9100" # 配置9100端口,作为metrics收集入口
tcpep:
address: ":9200" # 配置9200端口,作为tcp入口
udpep:
address: ":9300/udp" # 配置9300端口,作为udp入口
providers:
kubernetesCRD: # 启用Kubernetes CRD方式来配置路由规则
ingressClass: "" # 指定traefik的ingressClass名称
allowCrossNamespace: true #允许跨namespace
allowEmptyServices: true #允许空endpoints的service
log:
filePath: "/etc/traefik/logs/traefik.log" # 设置调试日志文件存储路径,如果为空则输出到控制台
level: "DEBUG" # 设置调试日志级别
format: "common" # 设置调试日志格式
accessLog:
filePath: "/etc/traefik/logs/access.log" # 设置访问日志文件存储路径,如果为空则输出到控制台
format: "common" # 设置访问调试日志格式
bufferingSize: 0 # 设置访问日志缓存行数
filters:
# statusCodes: ["200"] # 设置只保留指定状态码范围内的访问日志
retryAttempts: true # 设置代理访问重试失败时,保留访问日志
minDuration: 20 # 设置保留请求时间超过指定持续时间的访问日志
fields: # 设置访问日志中的字段是否保留(keep保留、drop不保留)
defaultMode: keep # 设置默认保留访问日志字段
names: # 针对访问日志特别字段特别配置保留模式
ClientUsername: drop
StartUTC: drop # 禁用日志timestamp使用UTC
headers: # 设置Header中字段是否保留
defaultMode: keep # 设置默认保留Header中字段
names: # 针对Header中特别字段特别配置保留模式
# User-Agent: redact# 可以针对指定agent
Authorization: drop
Content-Type: keep
experimental: # 实验性功能选项
plugins: # 插件配置
plugindemo:
moduleName: "github.com/traefik/plugindemo"
version: "v0.2.2"
[root@tiaoban traefik]# kubectl apply -f traefik-config.yaml
configmap/traefik-config configured
[root@tiaoban traefik]# kubectl delete pod -n traefik traefik-b5c445846-2gkwk
pod "traefik-b5c445846-2gkwk" deleted
查看traefik日志,插件已正常加载(如果有以下报错,说明github连接超时,可以使用加速或者添加github的hosts记录)
time="2022-10-09T11:53:29+08:00" level=debug msg="loading of plugin: plugindemo: github.com/traefik/plugindemo@v0.2.2"
time="2022-10-09T11:53:34+08:00" level=error msg="Plugins are disabled because an error has occurred." error="failed to download plugin github.com/traefik/plugindemo: failed to call service: Get \"https://plugins.traefik.io/public/download/github.com/traefik/plugindemo/v0.2.2\": context deadline exceeded (Client.Timeout exceeded while awaiting headers)"
创建中间件资源,指定插件配置
plugindemo插件的功能类似于header插件,可以自定义headers内容。
[root@tiaoban ingress]# cat demo-middleware.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: plugindemo
spec:
plugin:
plugindemo:
Headers:
whoami-header: hello world
[root@tiaoban ingress]# kubectl apply -f demo-middleware.yaml
middleware.traefik.containo.us/plugindemo created
查看dashboard面板,已成功加载插件
创建路由资源,指定中间件
[root@tiaoban ingress]# cat whoami-ingress.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: whoami
spec:
entryPoints:
- web
routes:
- match: Host(`whoami.test.com`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: plugindemo
[root@tiaoban ingress]# kubectl apply -f whoami-ingress.yaml
ingressroute.traefik.containo.us/whoami created
查看dashboard页面,已成功加载路由和中间件插件
访问验证,请求头已经包含了whoami-header: hello world
的信息
离线安装插件
虽然在线安装插件非常方便,但是每次重启traefik都会去github拉取代码,经常存在超时的情况。而且如果traefik机器在内网部署的情况下,就无法拉取代码了,此时就需要在本地环境加载插件。为解决这个问题,在 Traefik v2.5 版本后,就提供了一种直接从本地存储目录加载插件的新方法,只需要将插件源码放入一个名为 /plugins-local 的新目录,Traefik在启动时会自动加载它。
打包插件镜像
我们使用traefik2.9为基础镜像,然后使用alpine镜像安装git工具,将仓库克隆下来,拷贝到traefik镜像即可。打包后上传至镜像仓库,便于使用。
[root@tiaoban tmp]# mkdir traefik-plugins
[root@tiaoban tmp]# cd traefik-plugins/
[root@tiaoban traefik-plugins]# cat Dockerfile
FROM alpine:3 AS src
ARG PLUGIN_MODULE=github.com/traefik/plugindemo
ARG PLUGIN_GIT_REPO=https://github.com/traefik/plugindemo.git
RUN apk add --update git && \
git clone ${PLUGIN_GIT_REPO} /plugins-local/src/${PLUGIN_MODULE} --depth 1 --single-branch --branch master
FROM traefik:v2.9
COPY --from=src /plugins-local /plugins-local
[root@tiaoban traefik-plugins]# docker build -t traefik-demo-plugin:2.9.1 .
[root@tiaoban traefik-plugins]# docker push cuiliang0302/traefik-plugin:2.9.1
修改traefik配置
在traefik配置文件最后添加experimental相关配置,启用本地插件功能。
[root@tiaoban traefik]# cat traefik-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: traefik
data:
traefik.yaml: |-
global:
checkNewVersion: false # 周期性的检查是否有新版本发布
sendAnonymousUsage: false # 周期性的匿名发送使用统计信息
serversTransport:
insecureSkipVerify: true # Traefik忽略验证代理服务的TLS证书
api:
insecure: true # 允许HTTP 方式访问API
dashboard: true # 启用Dashboard
debug: false # 启用Debug调试模式
metrics:
prometheus: # 配置Prometheus监控指标数据,并使用默认配置
addRoutersLabels: true # 添加routers metrics
entryPoint: "metrics" # 指定metrics监听地址
entryPoints:
web:
address: ":80" # 配置80端口,并设置入口名称为web
forwardedHeaders:
insecure: true # 信任所有的forward headers
websecure:
address: ":443" # 配置443端口,并设置入口名称为 websecure
forwardedHeaders:
insecure: true
traefik:
address: ":9000" # 配置9000端口,并设置入口名称为 dashboard
metrics:
address: ":9100" # 配置9100端口,作为metrics收集入口
tcpep:
address: ":9200" # 配置9200端口,作为tcp入口
udpep:
address: ":9300/udp" # 配置9300端口,作为udp入口
providers:
kubernetesCRD: # 启用Kubernetes CRD方式来配置路由规则
ingressClass: "" # 指定traefik的ingressClass名称
allowCrossNamespace: true #允许跨namespace
allowEmptyServices: true #允许空endpoints的service
log:
filePath: "/etc/traefik/logs/traefik.log" # 设置调试日志文件存储路径,如果为空则输出到控制台
level: "DEBUG" # 设置调试日志级别
format: "common" # 设置调试日志格式
accessLog:
filePath: "/etc/traefik/logs/access.log" # 设置访问日志文件存储路径,如果为空则输出到控制台
format: "common" # 设置访问调试日志格式
bufferingSize: 0 # 设置访问日志缓存行数
filters:
# statusCodes: ["200"] # 设置只保留指定状态码范围内的访问日志
retryAttempts: true # 设置代理访问重试失败时,保留访问日志
minDuration: 20 # 设置保留请求时间超过指定持续时间的访问日志
fields: # 设置访问日志中的字段是否保留(keep保留、drop不保留)
defaultMode: keep # 设置默认保留访问日志字段
names: # 针对访问日志特别字段特别配置保留模式
ClientUsername: drop
StartUTC: drop # 禁用日志timestamp使用UTC
headers: # 设置Header中字段是否保留
defaultMode: keep # 设置默认保留Header中字段
names: # 针对Header中特别字段特别配置保留模式
# User-Agent: redact# 可以针对指定agent
Authorization: drop
Content-Type: keep
experimental: # 实验性功能选项
localPlugins: # 使用本地插件
plugindemo:
moduleName: "github.com/traefik/plugindemo"
[root@tiaoban traefik]# kubectl apply -f traefik-config.yaml
configmap/traefik-config configured
修改traefik镜像
修改deployment控制器的镜像为刚刚打包的包含插件的镜像。
[root@tiaoban traefik]# cat traefik-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: traefik
labels:
app: traefik
spec:
replicas: 1 # 副本数为1,因为集群只设置一台master为边缘节点
selector:
matchLabels:
app: traefik
template:
metadata:
name: traefik
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 1
containers:
- name: traefik
image: cuiliang0302/traefik-plugin:2.9.1
env:
- name: KUBERNETES_SERVICE_HOST # 手动指定k8s api,避免网络组件不稳定。
value: "192.168.10.10"
- name: KUBERNETES_SERVICE_PORT_HTTPS # API server端口
value: "6443"
- name: KUBERNETES_SERVICE_PORT # API server端口
value: "6443"
- name: TZ # 指定时区
value: "Asia/Shanghai"
ports:
- name: web
containerPort: 80
hostPort: 80 # 将容器端口绑定所在服务器的 80 端口
- name: websecure
containerPort: 443
hostPort: 443 # 将容器端口绑定所在服务器的 443 端口
- name: admin
containerPort: 9000 # Traefik Dashboard 端口
- name: metrics
containerPort: 9100 # metrics端口
- name: tcpep
containerPort: 9200 # tcp端口
- name: udpep
containerPort: 9300 # udp端口
securityContext: # 只开放网络权限
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --configfile=/etc/traefik/config/traefik.yaml
volumeMounts:
- mountPath: /etc/traefik/config
name: config
- mountPath: /etc/traefik/logs
name: logdir
- mountPath: /etc/localtime
name: timezone
readOnly: true
resources:
limits:
memory: "256Mi"
cpu: "1000m"
volumes:
- name: config
configMap:
name: traefik-config
- name: logdir
hostPath:
path: /data/traefik/logs
type: "DirectoryOrCreate"
- name: timezone #挂载时区文件
hostPath:
path: /etc/localtime
type: File
tolerations: # 设置容忍所有污点,防止节点被设置污点
- operator: "Exists"
hostNetwork: true # 开启host网络,提高网络入口的网络性能
nodeSelector: # 设置node筛选器,在特定label的节点上启动
IngressProxy: "true" # 调度至IngressProxy: "true"的节点
[root@tiaoban traefik]# kubectl delete -f traefik-deployment.yaml
deployment.apps "traefik" deleted
[root@tiaoban traefik]# kubectl apply -f traefik-deployment.yaml
deployment.apps/traefik created
访问验证
访问dashboard页面,插件已正确加载
访问whoami服务,已正确显示响应头信息
开发自定义插件
traefik 的插件是靠 Yaegi 解释器动态加载实现的,可以根据实际需求使用go语言按插件开发规范编写代码。官方参考文档:https://github.com/traefik/pluginproviderdemo,熟悉go语言的同学可以参考别人开发的插件demo:https://github.com/togettoyou/traefik-timer-plugin
克隆自定义插件项目
[root@tiaoban ~]# git clone https://github.com/togettoyou/traefik-timer-plugin
[root@tiaoban ~]# cd traefik-timer-plugin/
[root@tiaoban traefik-timer-plugin]# ls -la
总用量 8
drwxr-xr-x 2 root root 79 10月 9 20:29 .
drwxrwxrwt. 14 root root 4096 10月 9 20:29 ..
-rw-r--r-- 1 root root 28 10月 9 20:28 go.mod # 记录依赖文件
-rw-r--r-- 1 root root 0 10月 9 20:28 readme.md # 插件项目说明文件
-rw-r--r-- 1 root root 0 10月 9 20:28 timerplugin.go # 插件源代码文件
-rw-r--r-- 1 root root 0 10月 9 20:28 .traefik.yml # 插件信息配置文件
创建Dockerfile并构建镜像
[root@tiaoban traefik-timer-plugin]# cat Dockerfile
FROM traefik:v2.9
COPY . /plugins-local/src/github.com/togettoyou/traefik-timer-plugin/
[root@tiaoban traefik-timer-plugin]# docker build -t cuiliang0302/traefik-plugin:2.4 .
[root@tiaoban traefik-timer-plugin]# docker push cuiliang0302/traefik-plugin:2.4
修改traefik配置文件,导入插件
修改了experimental相关配置,注意插件的名称与.traefik.yml 文件以及插件存放路径要保持一致。
[root@tiaoban traefik]# cat traefik-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
namespace: traefik
data:
traefik.yaml: |-
global:
checkNewVersion: false # 周期性的检查是否有新版本发布
sendAnonymousUsage: false # 周期性的匿名发送使用统计信息
serversTransport:
insecureSkipVerify: true # Traefik忽略验证代理服务的TLS证书
api:
insecure: true # 允许HTTP 方式访问API
dashboard: true # 启用Dashboard
debug: false # 启用Debug调试模式
metrics:
prometheus: # 配置Prometheus监控指标数据,并使用默认配置
addRoutersLabels: true # 添加routers metrics
entryPoint: "metrics" # 指定metrics监听地址
entryPoints:
web:
address: ":80" # 配置80端口,并设置入口名称为web
forwardedHeaders:
insecure: true # 信任所有的forward headers
websecure:
address: ":443" # 配置443端口,并设置入口名称为 websecure
forwardedHeaders:
insecure: true
traefik:
address: ":9000" # 配置9000端口,并设置入口名称为 dashboard
metrics:
address: ":9100" # 配置9100端口,作为metrics收集入口
tcpep:
address: ":9200" # 配置9200端口,作为tcp入口
udpep:
address: ":9300/udp" # 配置9300端口,作为udp入口
providers:
kubernetesCRD: # 启用Kubernetes CRD方式来配置路由规则
ingressClass: "" # 指定traefik的ingressClass名称
allowCrossNamespace: true #允许跨namespace
allowEmptyServices: true #允许空endpoints的service
log:
filePath: "/etc/traefik/logs/traefik.log" # 设置调试日志文件存储路径,如果为空则输出到控制台
level: "DEBUG" # 设置调试日志级别
format: "common" # 设置调试日志格式
accessLog:
filePath: "/etc/traefik/logs/access.log" # 设置访问日志文件存储路径,如果为空则输出到控制台
format: "common" # 设置访问调试日志格式
bufferingSize: 0 # 设置访问日志缓存行数
filters:
# statusCodes: ["200"] # 设置只保留指定状态码范围内的访问日志
retryAttempts: true # 设置代理访问重试失败时,保留访问日志
minDuration: 20 # 设置保留请求时间超过指定持续时间的访问日志
fields: # 设置访问日志中的字段是否保留(keep保留、drop不保留)
defaultMode: keep # 设置默认保留访问日志字段
names: # 针对访问日志特别字段特别配置保留模式
ClientUsername: drop
StartUTC: drop # 禁用日志timestamp使用UTC
headers: # 设置Header中字段是否保留
defaultMode: keep # 设置默认保留Header中字段
names: # 针对Header中特别字段特别配置保留模式
# User-Agent: redact# 可以针对指定agent
Authorization: drop
Content-Type: keep
experimental: # 实验性功能选项
localPlugins: # 使用本地插件
timerplugin:
moduleName: "github.com/togettoyou/traefik-timer-plugin"
修改traefik镜像,使用打包镜像
[root@tiaoban traefik]# cat traefik-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: traefik
namespace: traefik
labels:
app: traefik
spec:
replicas: 1 # 副本数为1,因为集群只设置一台master为边缘节点
selector:
matchLabels:
app: traefik
template:
metadata:
name: traefik
labels:
app: traefik
spec:
serviceAccountName: traefik-ingress-controller
terminationGracePeriodSeconds: 1
containers:
- name: traefik
image: cuiliang0302/traefik-plugin:2.4
env:
- name: KUBERNETES_SERVICE_HOST # 手动指定k8s api,避免网络组件不稳定。
value: "192.168.10.10"
- name: KUBERNETES_SERVICE_PORT_HTTPS # API server端口
value: "6443"
- name: KUBERNETES_SERVICE_PORT # API server端口
value: "6443"
- name: TZ # 指定时区
value: "Asia/Shanghai"
ports:
- name: web
containerPort: 80
hostPort: 80 # 将容器端口绑定所在服务器的 80 端口
- name: websecure
containerPort: 443
hostPort: 443 # 将容器端口绑定所在服务器的 443 端口
- name: admin
containerPort: 9000 # Traefik Dashboard 端口
- name: metrics
containerPort: 9100 # metrics端口
- name: tcpep
containerPort: 9200 # tcp端口
- name: udpep
containerPort: 9300 # udp端口
securityContext: # 只开放网络权限
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
args:
- --configfile=/etc/traefik/config/traefik.yaml
volumeMounts:
- mountPath: /etc/traefik/config
name: config
- mountPath: /etc/traefik/logs
name: logdir
- mountPath: /etc/localtime
name: timezone
readOnly: true
resources:
limits:
memory: "256Mi"
cpu: "1000m"
volumes:
- name: config
configMap:
name: traefik-config
- name: logdir
hostPath:
path: /data/traefik/logs
type: "DirectoryOrCreate"
- name: timezone #挂载时区文件
hostPath:
path: /etc/localtime
type: File
tolerations: # 设置容忍所有污点,防止节点被设置污点
- operator: "Exists"
hostNetwork: true # 开启host网络,提高网络入口的网络性能
nodeSelector: # 设置node筛选器,在特定label的节点上启动
IngressProxy: "true" # 调度至IngressProxy: "true"的节点
创建中间件,使用插件
修改中间件资源清单文件
[root@tiaoban ingress]# cat demo-middleware.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: timerplugin
spec:
plugin:
timerplugin: # 自定义的计时插件
log: true
查看traefik的dashboard页面,中间件已正常加载。
修改路由资源,使用中间件
[root@tiaoban ingress]# cat whoami-ingress.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: whoami
spec:
entryPoints:
- web
routes:
- match: Host(`whoami.test.com`)
kind: Rule
services:
- name: whoami
port: 80
middlewares:
- name: timerplugin
查看dashboard页面,已正常创建路由并加载中间件
接下来访问whoami.test.com
查看控制台输出内容。
time="2022-10-09T22:15:11+08:00" level=debug msg="请求花费时间: 3.562589ms" plugin=plugin-timerplugin module=github.com/togettoyou/traefik-timer-plugin
time="2022-10-09T22:15:13+08:00" level=debug msg="请求花费时间: 3.56132ms" plugin=plugin-timerplugin module=github.com/togettoyou/traefik-timer-plugin
time="2022-10-09T22:15:13+08:00" level=debug msg="请求花费时间: 3.287732ms" plugin=plugin-timerplugin module=github.com/togettoyou/traefik-timer-plugin
查看更多
微信公众号
微信公众号同步更新,欢迎关注微信公众号第一时间获取最近文章。
博客网站
崔亮的博客-专注devops自动化运维,传播优秀it运维技术文章。更多原创运维开发相关文章,欢迎访问https://www.cuiliangblog.cn