跳转至

Kubernetes集群 服务暴露 Traefik install

1.1 什么是 traefik ?

image-20240414223501102

1.2 traefix 特性

  • 非常快
  • 无需安装其他依赖,通过Go语言编写的单一可执行文件
  • 支持 Rest API
  • 多种后台支持:Docker, Swarm, Kubernetes, Marathon, Mesos, Consul, Etcd, 并且还会更多
  • 后台监控, 可以监听后台变化进而自动化应用新的配置文件设置
  • 配置文件热更新。无需重启进程
  • 正常结束http连接
  • 后端断路器
  • 轮询,rebalancer 负载均衡
  • Rest Metrics
  • 支持最小化官方docker 镜像
  • 前、后台支持SSL
  • 清爽的AngularJS前端页面
  • 支持Websocket
  • 支持HTTP/2
  • 网络错误重试
  • 支持Let’s Encrypt (自动更新HTTPS证书)
  • 高可用集群模式

1.3 traefik 与 nginx ingress 对比

image-20240414223844772

1.4 traefik 核心概念及能力

Traefik是一个边缘路由器,它会拦截外部的请求并根据逻辑规则选择不同的操作方式,这些规则决定着这些请求到底该如何处理。Traefik提供自动发现能力,会实时检测服务,并自动更新路由规则。

image-20240414223501102

假设你已经在你的基础设施上部署了一堆微服务。你可能使用了一个服务发现系统(例如 etcd 或 consul)或者一个资源管理框架(swarm,Mesos/Marathon)来管理所有这些服务。 如果你想让你的用户去从互联网访问你的某些微服务, 你就必需使用虚拟hosts或前缀路径来配置一个反向代理:

  • 域名 api.domain.com 将指向你的私有网络中的微服务 api
  • 路径 domain.com/web 将指向你的私有网络中的微服务 web
  • 域名 backoffice.domain.com 将指向你的私有网络中的微服务 backoffice ,在你的多台实例之间负载均衡

但一个微服务的结构时动态的。。。 服务在会经常被添加、移除、杀死或更新,可能一天之内就会发生许多次。 传统的反向代理原生不支持动态配置。你不可能轻易的通过热更新更改它们的配置。 这时,Træfɪk就诞生了。

我们将 Træfɪk 放大,一起看看它内部的结构:

image-20240414223928047

  • 请求在入口点处结束, 顾名思义, 它们是Træfɪk的网络入口(监听端口, SSL, 流量重定向...)。
  • 之后流量会导向一个匹配的前端。 前端是定义入口点 到 后端之间的路由的地方。 路由是通过请求字段(Host, Path, Headers...) 来定义的,它可以匹配或否定一个请求。
  • 前端 将会把请求发送到 后端。后端可以由一台或一个通过负载均衡策略配置后的多台服务器组成。
  • 最后, 服务器 将转发请求到对应私有网络的微服务当中去。

总而言之,请求首先会连接到 entrypoints,然后分析这些请求是否与定义的 rules 匹配,如果匹配,则会通过一系列 middlewares ,再到对应的 services 上。

以下是几个重要的核心组件。

1. Entrypoints

Entrypoints 是 Traefik 的网络入口,它定义接收请求的接口,以及是否监听 TCP 或者 UDP 。

image-20240420151538999

针对http、https 和 udp 不同的配置方式:

## Static configuration
entryPoints:
  web:
    address: ":80"
  websecure:
    address: ":443"
  streaming:
    address: ":1704/udp"

2. Routers

  1. Providers 是基础组件,Traefik 的配置发现是通过它来实现的,它可以是协调器,容器引擎,云提供商或者键值存储。
  2. Traefik 通过查询 Providers 的 API 来查询路由的相关信息,一旦检测到变化,就会动态的更新路由。
  3. Routers 主要用于分析请求,并负责将这些请求连接到对应的服务上去,在这个过程中,Routers 还可以使用 Middlewares 来更新请求,比如在把请求发到服务之前添加一些 Headers。

image-20240420152239288

配置/foo开始的请求路由到的后端服务。
## Dynamic configuration
http:
  routers:
    my-router:
      rule: "Path(`/foo`)"
      service: service-foo

路由可以配置不同的的规则,比如针对请求 host 和请求路径进行匹配。

rule = "Host(`example.com`) || (Host(`example.org`) && Path(`/traefik`))"

路由可以配置不同的的规则

规则 描述
Headers(key, value) 请求头校验规则
HeadersRegexp(key, regexp) 请求头校验规则,value 正则匹配
Host(example.com, ...) 请求域名校验规则
HostRegexp(example.com, {subdomain:[a-z]+}.example.com, ...) 请求域名正则匹配规则
Method(GET, ...) 请求方法校验规则,支持GET\POST\PUT\DELETE\PATCH\HEAD
Path(/path, /articles/{cat:[a-z]+}/{id:[0-9]+}, ...) 请求路径匹配规则,精确匹配,支持正则
PathPrefix(/products/, /articles/{cat:[a-z]+}/{id:[0-9]+}) 请求路径前缀匹配规则,支持正则
Query(foo=bar, bar=baz) 请求参数匹配规则
ClientIP(10.0.0.0/16, ::1) 请求 IP 匹配规则

3. Middlewares

  1. 中间件,用于对请求进行处理和转换,类似过滤器、拦截器,有些人可能把他理解成很多网关中的插件,但是其实在 Traefik 里面也有插件的概念,并且可以发布分享,可以参考 plugins.traefik.io/create。

  2. Traefik 提供了多种内置的中间件,比如日志记录、重定向、身份验证和限流等第,此外,也可以根据需要自定义中间件。

  3. Middlewares 用来修改请求或者根据请求来做出一些判断(authentication, rate limiting, headers, …),中间件被附件到路由上,是一种在请求发送到你的服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。 image-20240420153625317

配置方式:
# As a Docker Label
whoami:
  #  A container that exposes an API to show its IP address
  image: traefik/whoami
  labels:
    #  `foo-add-prefix` 中间件
    - "traefik.http.middlewares.foo-add-prefix.addprefix.prefix=/foo"
    - "traefik.http.routers.router1.middlewares=foo-add-prefix@docker"

列出一些 HTTP 中间件列表,基本上基础的网关鉴权、熔断、限流都有默认的插件。

中间件 描述
AddPrefix 路径添前缀
BasicAuth 鉴权
Buffering 缓冲
Chain 中间件链,可以定义可重用的中间件组合
CircuitBreaker 熔断
Compress 压缩
Headers 请求头操作,可以添加、删除请求头
IPWhiteList IP 白名单
RateLimit 限流
Retry 重试

4. Services ( Traefik-Services )

服务指的是 Traefik 服务,每个服务都有一个唯一标识符,并可以配置不同的负载均衡规则和健康检查策略。

需要注意的是这里的服务指的是 Traefik 自身的 service,并非是我们自己的服务。

image-20240420154543733

配置示例:
## Dynamic configuration
http:
  services:
    my-service:
      loadBalancer:
        servers:
        - url: "http://<private-ip-server-1>:<private-port-server-1>/"
        - url: "http://<private-ip-server-2>:<private-port-server-2>/"

根据以上的概念,实际上在 Traefik 中一个请求的流程:

  1. 当客户端发送请求时,请求首先会被协议处理器接收并解析。
  2. 请求会被路由器匹配到相应的路由规则,并根据规则将请求转发给相应的中间件链。
  3. 中间件链会按照顺序执行各个中间件,并根据需要对请求进行处理和转换。
  4. 处理完请求后,请求会被转发给相应的后端服务器。
  5. 后端服务器将处理完请求后的响应返回给 Traefik。
  6. Traefik 将响应返回给客户端。

1.5 traefik 部署

helm 部署 traefik

1. 配置 Helm Repo
helm repo add traefik https://helm.traefik.io/traefik
helm repo update
2. 安装 Traefik 至 traefik 命名空间,可根据需要替换。
# deployment.replicas=3                设置Traefik部署副本数
# pilot.dashboard=false                禁用Dashboard中Pilot链接
# ingressRoute.dashboard.enabled=false 禁用默认Dashboard入口规则(将在后续步骤中手动创建)

helm upgrade --install traefik traefik/traefik \
  --namespace traefik \
  --create-namespace \
  --set deployment.replicas=3 \
  --set pilot.dashboard=false \
  --set ingressRoute.dashboard.enabled=false
3. 查看 traefik 服务 是否启动
kubectl get all -n traefik
4. 获取 traefik 服务的负载均衡器地址。执行该命令,记录返回的 EXTERNAL-IP 地址备用。本次演练环境中,已将local.choral.io和*.local.choral.io指向该地址。
kubectl get svc traefik -n traefik 

配置访问 traefik dashboard 路由规则

Traefik 应用已经部署完成,但是想让外部访问 Kubernetes 内部服务,还需要配置路由规则,上面部署 Traefik 时开启了 Traefik Dashboard,这是 Traefik 提供的视图看板,所以,首先配置基于 HTTP 的 Traefik Dashboard 路由规则,使外部能够访问 Traefik Dashboard。这里使用 IngressRoute方式进行演示。

Traefik 创建路由规则方法

  • 原生ingress
  • CRD IngressRoute
  • Gateway API

通过原生 ingress 方式暴露 traefik dashboard

1. 查看 service 相关资源
kubectl get svc -n traefik && kubectl get endpoints -n traefik
2. 编写 traefik-dashboard-native-ingress.yaml 资源清单
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx-traefik
  namespace: traefik
spec:
  ingressClassName: nginx
  rules:
  - host: traefik.k8s.huichengcheng.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: traefik
            port:
              number: 80
3. 编写 traefik.dashboard-ingress-route.yaml 资源清单文件
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: traefik
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.k8s.huichengcheng.com`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
      kind: Rule
      services:
        - name: api@internal
          kind: TraefikService
1. 下载并修改配置文件
[root@k8smaster001 ingress]#  curl -k https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml  -o deploy.yaml
1. 下载并修改配置文件
[root@k8smaster001 ingress]#  curl -k https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml  -o deploy.yaml

YAML 自定义部署 (创建包含类型定义的 Traefik CRD IngressRoute)

helm虽然实现了一键安装部署,但是查看helm包的value.yaml配置发现总共有500多行配置,当需要修改配置项或者对traefik做一下自定义配置时,并不灵活。如果只是使用traefik的基础功能,推荐使用helm部署。如果想深入研究使用traefik的话,推荐使用自定义方式部署。

获取 traefik 部署前置资源清单文件

Install Traefik Resource Definitions:

wget -q https://raw.githubusercontent.com/traefik/traefik/v2.11/docs/content/reference/dynamic-configuration/kubernetes-crd-definition-v1.yml -O 001-kubernetes-crd-definition-v1.yml
kubectl apply -f 001-kubernetes-crd-definition-v1.yml

Install RBAC for Traefik:

002-kubernetes-crd-rbac.yml
apiVersion: v1
kind: ServiceAccount
metadata:
  namespace: kube-system
  name: traefik-ingress-controller
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: traefik-ingress-controller

rules:
  - apiGroups:
      - ""
    resources:
      - services
      - endpoints
      - secrets
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
      - networking.k8s.io
    resources:
      - ingresses
      - ingressclasses
    verbs:
      - get
      - list
      - watch
  - apiGroups:
      - extensions
      - networking.k8s.io
    resources:
      - ingresses/status
    verbs:
      - update
  - apiGroups:
      - traefik.io
      - traefik.containo.us
    resources:
      - middlewares
      - middlewaretcps
      - ingressroutes
      - traefikservices
      - ingressroutetcps
      - ingressrouteudps
      - tlsoptions
      - tlsstores
      - serverstransports
    verbs:
      - get
      - list
      - watch

---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
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: kube-system
1. 创建 rbac 资源
kubectl apply -f 002-kubernetes-crd-rbac.yml

创建 traefik 配置文件

由 traefik 配置多,通过 CLI 定义不方便,一般都通过配置文件对 traefik 进行参数配置,例如使用 ConfigMap 将配置挂载至 traefik 中。

003-traefik-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik
  namespace: kube-system
data:
  traefik.yaml: |-
    serversTransport:
      insecureSkipVerify: true ## 略验证代理服务的 TLS 证书
    api:
      insecure: true  ## 允许 HTTP 方式访问 API
      dashboard: true  ## 启用 Dashboard
      debug: true  ## 启用 Debug 调试模式
    metrics:
      prometheus: ""  ## 配置 Prometheus 监控指标数据,并使用默认配置
    entryPoints:
      web:
        address: ":80" ## 配置 80 端口,并设置入口名称为 web
      websecure:
        address: ":443"  ## 配置 443 端口,并设置入口名称为 websecure
      metrics:
        address: ":8082" ## 配置 8082端口,并设置入口名称为 metrics
      tcpep:
        address: ":8083"  ## 配置 8083端口,并设置入口名称为 tcpep,做为tcp入口
      udpep:
        address: ":8084/udp"  ## 配置 8084端口,并设置入口名称为 udpep,做为udp入口
    providers:
      kubernetesCRD: ""  ## 启用 Kubernetes CRD 方式来配置路由规则
      kubernetesingress: ""  ## 启用 Kubernetes Ingress 方式来配置路由规则
      kubernetesGateway: "" ## 启用 Kubernetes Gateway API
    experimental:
      kubernetesGateway: true  ## 允许使用 Kubernetes Gateway API
    log:
      filePath: "" ## 设置调试日志文件存储路径,如果为空则输出到控制台
      level: error ## 设置调试日志级别
      format: json  ## 设置调试日志格式
    accessLog:
      filePath: ""  ## 设置访问日志文件存储路径,如果为空则输出到控制台
      format: json  ## 设置访问调试日志格式
      bufferingSize: 0  ## 设置访问日志缓存行数
      filters:
        retryAttempts: true  ## 设置代理访问重试失败时,保留访问日志
        minDuration: 20   ## 设置保留请求时间超过指定持续时间的访问日志
      fields:             ## 设置访问日志中的字段是否保留(keep 保留、drop 不保留)
        defaultMode: keep ## 设置默认保留访问日志字段
        names:
          ClientUsername: drop  
        headers:
          defaultMode: keep  ##  设置 Header 中字段是否保留,设置默认保留 Header 中字段
          names:  ## 针对 Header 中特别字段特别配置保留模式
            User-Agent: redact
            Authorization: drop
            Content-Type: keep
1. 创建 traefik 配置文件。
kubectl apply -f 003-traefik-configmap.yaml

设置节点 Label

由于使用 DaemonSet 方式部署 Traefik ,所以需要为节点设置 label,当应用部署时会根据节点 Label 进行选择。

1. 设置节点标签。
kubectl label nodes --all IngressProxy=true 
2. 查看节点标签。
kubectl get nodes --show-labels
3. 如需要取消时,可执行下述命令。
kubectl label nodes --all IngressProxy-

部署 Traefik

1. Daemonset 资源清单文件准备

本次将用 Daemonset 方式部署 traefik,便于后期扩展

本次部署通过 hostport方式 把 Pod 中容器内的80、443映射到物理机,方便集群外访问。

004-traefik-DaemonSet.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  namespace: kube-system
  name: traefik
  labels:
    app: traefik
spec:
  selector:
    matchLabels:
      app: traefik
  template:
    metadata:
      labels:
        app: traefik
    spec:
      serviceAccountName: traefik-ingress-controller
      terminationGracePeriodSeconds: 1
      containers:
        - name: traefik
          image: traefik:v2.11
          args:
            - --configfile=/config/traefik.yaml
          volumeMounts:
            - mountPath: /config
              name: config
          ports:
            - name: web
              containerPort: 80
              hostPort: 80  ## 将容器端口绑定所在服务器的 80 端口
            - name: websecure
              containerPort: 443
              hostPort: 443  ## 将容器端口绑定所在服务器的 443 端口
            - name: admin
              containerPort: 8080  ## Traefik Dashboard 端口
            - name: tcpep
              containerPort: 8083
              hostPort: 8083  ## 将容器端口绑定所在服务器的 8083 端口
            - name: udpep
              containerPort: 8084
              hostPort: 8084  ## 将容器端口绑定所在服务器的 8084 端口
              protocol: UDP
      volumes:
        - name: config
          configMap:
            name: traefik
      tolerations:              ## 设置容忍所有污点,防止节点被设置污点
        - operator: "Exists"
      nodeSelector:             ## 设置node筛选器,在特定label的节点上启动
        IngressProxy: "true"
1. 创建 DaemonSet 资源
kubectl apply -f 004-traefik-DaemonSet.yaml

2. Service 资源清单文件准备

005-traefix-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: traefik
  namespace: kube-system
  labels:
    app: traefik
    app.kubernetes.io/name: traefik-dashboard
spec:
  ports:
    - protocol: TCP
      name: web
      port: 80
    - protocol: TCP
      name: admin
      port: 8080
    - protocol: TCP
      name: websecure
      port: 443
    - protocol: TCP
      name: tcpep
      port: 8083
    - protocol: UDP
      name: udpep
      port: 8084
  selector:
    app: traefik
1. 创建 Service 资源
kubectl apply -f 005-traefix-service.yaml 

Install ingressRoutes

1. 通过原生 ingress 方式暴露 traefik dashboard

1. 查看 traefik 的 service
kubectl get svc traefik -n kube-system
2. 查看 traefik 的 endpoints
kubectl get endpoints traefik -n kube-system
006-traefik-dashboard-native-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx-traefik
  namespace: traefik
spec:
  ingressClassName: nginx
  rules:
  - host: traefik.k8s.huichengcheng.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: traefik
            port:
              number: 80
1. 创建 ingress 规则
kubectl apply -f 006-traefik-dashboard-native-ingress.yaml

2. 创建 dashboard ingress route 资源清单文件

1. 创建 007-traefik-dashboard-ingress-route.yaml 资源
kubectl apply -f 007-traefik-dashboard-ingress-route.yaml
007-traefik-dashboard-ingress-route.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
    - match: Host(`traefik.k8s.huichengcheng.com`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))
      kind: Rule
      services:
      - name: traefik
        port: 8080

接下来我们就可以通过浏览器 http://<域名>/dashboard/(注意 URL 中的尾部斜杠,这是必须的)访问 Traefik Dashboard ,现在应该可以看到在仪表板的 Features 部分启用了 Prometheus 指标。

image-20240416141847613

此外我们还可以访问 curl :8080/metrics|head 端点来查看 Traefik 提供的一些 metrics 指标

image-20240416142150091