Traefik 新一代轻量级云原生反向代理工具

1. 基础简介

Traefik 是一个为了让部署微服务更加便捷而诞生的现代 HTTP 反向代理、负载均衡工具。 它支持多种后台 (Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd, Zookeeper, BoltDB, Rest API, File...) 来自动化、动态的应用它的配置文件设置。

2. 核心组件

组件 作用
Providers 用来自动发现平台上的服务,可以是编排工具、容器引擎云提供商或者键值存储。Traefik 通过查询 Providers 的 API 来查询路由的相关信息,一旦检测到变化,就会动态的更新路由
Entrypoints 监听传入的流量,是网络的入口点,定义了接受请求的端口 (HTTP 或者 TCP)
Routers 分析请求 (Host, Path, Headers, SSL 等),负责将传入的请求连接到可以处理这些请求的服务上去
Middlewares 中间件,用来修改请求或者根据请求来做出判断,中间件被附件到路由上,是一种在请求发送到服务之前调整请求的一种方法
Service 中间件,用来修改请求或者根据请求来做出判断,中间件被附件到路由上,是一种在请求发送到服务之前调整请求的一种方法

当请求 Traefik 时,请求首先到Entrypoints,然后分析传入的请求,查看他们是否与定义的Routers匹配。如果匹配,则会通过一系列Middlewares处理,再到 traefik 的Services上做流量转发,最后请求到 kubernetes 的 services 上。

3. Traefik 对比 Nginx

Traefik 组件类比 Nginx 概念

组件名称 功能 Nginx 相同概念
Providers 监听路由信息变化,更新路由 修改 nginx 配置,reload 服务
Entrypoints 网络入口,监听传入的流量 配置文件 listen 指定监听端口
Routers 分析传入的请求,匹配规则 配置文件 server_name + location
Middlewares 中间件,修改请求或响应 location 配置段中添加的缓存、压缩、请求头等配置
Service 请求转发 http 配置段中的 upstream

Kubernetes 中 Traefik 与 Nginx-Ingress 对比

由于微服务架构以及 Docker 和 Kubernetes 编排工具最近几年才开始流行,所以一开始的反向代理服务器如 Nginx、Apache 并未提供支持,才会出现 Ingress Controller 这种东西来做 Kubernetes 和前端负载均衡器如 Nginx 之间做衔接。 Ingress Controller 的存在就是为了能跟 Kubernetes 交互,然后写入 Nginx 配置,最后 Reload。

  • Nginx-Ingress: 使用 Nginx 作为前端负载均衡,通过 Ingress Controller 不断的和 Kubernetes Api 交互,实时获取后端 Service,Pod 等的变化,然后动态更新 Nginx 配置,并刷新使配置生效,达到服务发现的目的。
  • Traefik-Ingress: Traefik 本身设计的就能够实时跟 Kubernetes Api 交互,感知后端 Service,Pod 等的变化,自动更新配置并重载。
Nginx Ingress Traefik ingress
协议 Http / Https、Http2、Grpc、Tcp / Udp Http / Https、Http2、Grpc、Tcp、Tcp + Tls
路由匹配 Host、Path Host、Path、Headers、Query、Path Prefix、Method
命名空间支持 - 共用或指定命名空间
部署策略 - 金丝雀部署、蓝绿部署、灰度部署
upstream 探测 重试、超时、心跳探测 重试、超时、心跳探测、熔断
负载均衡算法 轮询、会话保持、最小连接、最短时间、一致性Hash 加权轮询、动态轮询、会话保持
优点 简单易用,易接入 Golang 编写,部署容易,支持众多的后端,内置 WebUI
缺点 没有解决 Nginx Reload,插件多但是扩展性能差 性能略逊于 Nginx,但强于 HAProxy

Traefik 有自己的 Web UI,一般安装完成后通过 8080 端口访问:

4. Traefik 的各种 Providers 配置发现

Traefik 中的配置发现是通过下面的一些 providers 来实现的。providers 是现有的一些基础架构组件,可以是编排工具,容器引擎,云提供商或者 key-value 存储都可以。

Traefik 通过查询 providers 的 API 来查找有关路由的相关信息,Traefik 每次检测到更改时,都会动态更新路由。

编排器

虽然每个 provider 都是不同的,但是我们还是可以将这些 provider 大致分为4组:

  • 基于标签(每个部署的容器都附件了一组标签)
  • 基于键值(每个部署的容器使用相关信息来更新 key-value 存储)
  • 基于注解(带有注解的单独对象来定义容器的一些特性)
  • 基于文件(一些旧的配置文件)

支持的 Providers

下面列出的是现在 Traefik 支持的一些 providers:

Provider 类型 配置类型
File 手动 TOML/YAML 文件
Docker 编排器 标签
Kubernetes 编排器 自定义资源
Marathon 编排器 标签
Rancher 编排器 标签

总的来说,上述这些都是 Traefik 配置发现的方式,即 如何让你写的配置文件或者命令标签等被 Traefik 静态或者动态地读取生效 。基于篇幅原因,我们不完全例举所有的使用方式,下文主要演示一个完整的 Kubernetes 通过自定义资源方式的例子,其余方式大家可以自己参考官方文档: doc.traefik.io/traefik/pro...

5. Traefik 在 Kubernetes 中通过自定义资源对象实现 IngressRoute

首先我们需要定义自己的资源类型(IngressRoute/IngressRouteTCP/Middleware/TLSOption):

TraefikCRD.yml

yml 复制代码
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutes.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRoute
    plural: ingressroutes
    singular: ingressroute
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: ingressroutetcps.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: IngressRouteTCP
    plural: ingressroutetcps
    singular: ingressroutetcp
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: middlewares.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: Middleware
    plural: middlewares
    singular: middleware
  scope: Namespaced

---
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
  name: tlsoptions.traefik.containo.us

spec:
  group: traefik.containo.us
  version: v1alpha1
  names:
    kind: TLSOption
    plural: tlsoptions
    singular: tlsoption
  scope: Namespaced

同时注意 RBAC 授权资源,后面将通过部署 serviceAccountName 引用它们:

TraefikRBAC.yml

yml 复制代码
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller

rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.containo.us
    resources:
      - middlewares
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - ingressroutes
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - ingressroutetcps
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - traefik.containo.us
    resources:
      - tlsoptions
    verbs:
      - get
      - list
      - watch

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: traefik-ingress-controller

roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: traefik-ingress-controller
subjects:
  - kind: ServiceAccount
    name: traefik-ingress-controller
    namespace: default

接下来是服务 Service,一个是 Traefik 本身,另一个是其路由的 Web 应用程序 whoami :

TraefikService.yml

yml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: traefik

spec:
  ports:
    - protocol: TCP
      name: web
      port: 8000
    - protocol: TCP
      name: admin
      port: 8080
    - protocol: TCP
      name: websecure
      port: 4443
  selector:
    app: traefik

WhoamiService.yml

yml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: whoami

spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
  selector:
    app: whoami

接下来是部署 Deployment,同样,一个是 Traefik 的 pod, 另一个是 whoami 应用程序的 pod:

TraefikDeployment.yml

yml 复制代码
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: default
  name: traefik-ingress-controller

---
kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: default
  name: traefik
  labels:
    app: traefik

spec:
  replicas: 1
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      containers:
        - name: traefik
          image: traefik:v2.0
          args:
            - --api.insecure
            - --accesslog
            - --entrypoints.web.Address=:8000
            - --entrypoints.websecure.Address=:4443
            - --providers.kubernetescrd
            - --certificatesresolvers.default.acme.tlschallenge
            - --certificatesresolvers.default.acme.email=foo@you.com
            - --certificatesresolvers.default.acme.storage=acme.json
            # Please note that this is the staging Let's Encrypt server.
            # Once you get things working, you should remove that whole line altogether.
            - --certificatesresolvers.default.acme.caserver=https://acme-staging-v02.api.letsencrypt.org/directory
          ports:
            - name: web
              containerPort: 8000
            - name: websecure
              containerPort: 4443
            - name: admin
              containerPort: 8080

这里我们使用了 Let's Encrypt 来设置的 TLS 证书,Let's Encrypt 是一个线上免费证书颁发组织,能够颁发权威机构认证的证书。此组织已经是当前最受欢迎、用户数量最广的证书颁发组织。

WhoamiDeployment.yml

yml 复制代码
kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: default
  name: whoami
  labels:
    app: whoami

spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
        - name: whoami
          image: containous/whoami
          ports:
            - name: web
              containerPort: 80

注意:这里我们 Traefik Pod 端口无法从集群外部访问,这样会导致 ACME TLS 配置失败,在阿里云上我们可以购买 SLB 负载均衡,并且设置各个节点机器的端口映射来解决。

前边的步骤可以理解为安装过程,现在我们才开始设置我们的路由信息:

IngressRoutes.yml

yml 复制代码
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: simpleingressroute
  namespace: default
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`your.domain.com`) && PathPrefix(`/notls`)
    kind: Rule
    services:
    - name: whoami
      port: 80

---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroutetls
  namespace: default
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`your.domain.com`) && PathPrefix(`/tls`)
    kind: Rule
    services:
    - name: whoami
      port: 80
  tls:
    certResolver: default

HTTP 的路由规则

规则 描述
Headers(key, value) 检查 headers 中是否有一个键为key 值为 value 的键值对
HeadersRegexp(key, regexp) 检查 headers 中是否有一个键为key,值匹配正则表达式regexp的键值对
Host(domain-1, ...) 检查请求的域名是否包含在给定的domains域名中
HostRegexp(traefik.io, {subdomain:[a-z]+}.traefik.io, ...) 检查请求的域名是否匹配给定的regexp正则表达式。
Method(GET, ...) 检查请求的方法是否包含在给定的methods (GET, POST, PUT, DELETE, PATCH) 中
Path(/path, /articles/{category}/{id:[0-9]+}, ...) 匹配确定的请求路径,它接受一系列文字和正则表达式路径。
PathPrefix(/products/, /articles/{category}/{id:[0-9]+}) 匹配请求前缀路径,它接受一系列文字和正则表达式前缀路径。
Query(foo=bar, bar=baz) 匹配查询字符串参数,接受 key=value 的键值对序列。

TCP 的路由规则

规则 描述
HostSNI(`domain-1`, ...) 检查服务名标识是否和给定的 domains 对应。

6. Traefik 特色的 Middlewares 中间件

Middlewares 中间件被附件到路由上,是一种在请求发送到你的 Service 服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。

Traefik 内置了许多不同功能的中间件,其中一些可以修改请求,头信息,一些负责重定向,一些添加身份验证等等。

中间件可以通过链式组合的方式来适用各种情况。

可用中间件列表

中间件 用途 范围
AddPrefix 添加一个 Path 前缀 Path 修改器
BasicAuth Basic auth 认证机制 安全, 认证
Buffering 缓冲 request/response 请求生命周期
Chain 结合多个中间件 中间件工具
CircuitBreaker 停止调用不健康的服务 请求生命周期
Compress 压缩 response 响应 内容修改器
DigestAuth 添加 Digest 身份验证 安全, 认证
Errors 自定义错误页面 请求生命周期
ForwardAuth 使用外部服务转发身份验证 安全, 认证
Headers 添加/更新 头信息 安全
IPWhiteList 现在允许的客户端 IP 安全, 请求生命周期
InFlightReq 限制同时连接的数量 安全, 请求生命周期
PassTLSClientCert 在 Header 里面添加客户端证书 安全
RateLimit 限制调用频率 安全, 请求生命周期
RedirectScheme 客户端重定向 请求生命周期
RedirectRegex 客户端重定向 请求生命周期
ReplacePath 更改请求的 path 路径 Path 修改器
ReplacePathRegex 更改请求的 path 路径 Path 修改器
Retry 出现错误时自动重试请求 请求生命周期
StripPrefix 更改请求的 path 路径 Path 修改器
StripPrefixRegex 更改请求的 path 路径 Path 修改器

继续上边的例子,我们来看几个中间件在 Kubernetes 中的使用,CRD 和 RBAC 我们已经声明过了:

AddPrefix(添加一个 Path 前缀)

AddPrefix 中间件在转发请求之前更新请求的路径。

yml 复制代码
# Prefixing with /foo
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: add-foo
spec:
  addPrefix:
    prefix: /foo

ForwardAuth(使用外部服务转发身份验证)

ForwardAuth 中间件将身份验证委托给外部服务。如果服务用 2XX 代码回答,则授予访问权限,并执行原始请求。否则,将返回来自身份验证服务器的响应。

以下请求属性会以 X-Forwarded- 头的形式转发给认证服务:

Property Forward-Request Header
HTTP Method X-Forwarded-Method
Protocol X-Forwarded-Proto
Host X-Forwarded-Host
Request URI X-Forwarded-Uri
Source IP-Address X-Forwarded-For
yml 复制代码
# Forward authentication to example.com
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
  name: test-auth
spec:
  forwardAuth:
    address: https://example.com/auth
    trustForwardHeader: true ## 可信任所有X-Forwarded-*标头
    authResponseHeaders: ## 从认证服务器额外带到Response响应的Headers
      - X-Auth-User
      - X-Secret
    authRequestHeaders: ## 从Request请求额外带到认证服务器的Headers
      - "Accept"
      - "X-CustomHeader"
    authResponseHeadersRegex: ^X- ## 从Request请求额外带到认证服务器的Headers(正则表达式)

具体细节的中间件,大家可以自己参考官方文档: doc.traefik.io/traefik/mid...

相关推荐
锅包肉的九珍10 分钟前
Scala的Array数组
开发语言·后端·scala
心仪悦悦13 分钟前
Scala的Array(2)
开发语言·后端·scala
2401_882727571 小时前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
心仪悦悦1 小时前
Scala中的集合复习(1)
开发语言·后端·scala
wuxingge1 小时前
k8s1.30.0高可用集群部署
云原生·容器·kubernetes
代码小鑫2 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计
真心喜欢你吖2 小时前
SpringBoot与MongoDB深度整合及应用案例
java·spring boot·后端·mongodb·spring
激流丶2 小时前
【Kafka 实战】Kafka 如何保证消息的顺序性?
java·后端·kafka
志凌海纳SmartX2 小时前
趋势洞察|AI 能否带动裸金属 K8s 强势崛起?
云原生·容器·kubernetes
锅总2 小时前
nacos与k8s service健康检查详解
云原生·容器·kubernetes