Traefik 企业实战:路由规则篇

Traefik 路由规则

首先,当部署完后启动 Traefik 时,定义了入口点(端口号和对应的端口名称),然后 Kubernetes 集群外部就可以通过访问 Traefik 服务器地址和配置的入口点对 Traefik 服务进行访问,在访问时一般会带上 “域名” + “入口点端口”,然后 Traefik 会根据域名和入口点端口在 Traefik 路由规则表中进行匹配,如果匹配成功,则将流量发送到 Kubernetes 内部应用中与外界进行交互。这里面的域名与入口点与对应后台服务关联的规则,即是 Traefik 路由规则。Traefik 创建路由规则有多种方式:

  • 原生 Ingress 写法
  • 使用 CRD IngressRoute 方式
  • 使用 GatewayAPI 的方式(本节不介绍)

相较于原生 Ingress 写法,ingressRoute 是 2.1 以后新增功能,简单来说,他们都支持路径 (path) 路由和域名 (host) HTTP 路由,以及 HTTPS 配置,区别在于 IngressRoute 需要定义 CRD 扩展,但是它支持了 TCP、UDP 路由以及中间件等新特性,强烈推荐使用 ingressRoute

ingress方式

ingress-app.yaml:

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: ingress-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ingress-app
  template:
    metadata:
      labels:
        app: ingress-app
    spec:
      containers:
        - name: ingress-app
          image: nginx:latest
          lifecycle:
            postStart:
              exec:
                command:  ["/bin/sh", "-c", "echo Hello ingress app > /usr/share/nginx/html/index.html"]
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 200m
              memory: 256Mi

apiVersion: v1
kind: Service
metadata:
name: ingress-app
spec:
selector:
app: ingress-app
ports:
- name: http
port: 80
targetPort: 80
type: ClusterIP


apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-app
spec:
rules:
- host: ingress.kubesre.lc
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ingress-app
port:
name: http

部署查看效果

代码语言:javascript
复制
[root@localhost ~]# kubectl apply -f  ingress-app.yaml
deployment.apps/ingress-app created
service/ingress-app created
ingress.networking.k8s.io/ingress-app created

[root@localhost ~]# kubectl get pod,svc,ingress
NAME READY STATUS RESTARTS AGE
pod/ingress-app-578bb77b97-ps9q9 1/1 Running 0 24s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-app ClusterIP 10.100.253.185 <none> 80/TCP 24s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 118d

NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/ingress-app traefik ingress.kubesre.lc 80 24s

添加本地hosts解析

本地集群部署了Metallb负载均衡服务,可直接使用LoadBalancer地址

代码语言:javascript
复制
192.168.36.139 ingress.kubesre.lc

访问 http://ingress.kubesre.lc/

image.png

ingressRoute方式

ingressroute-app.yaml:

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingressroute-app
spec:
replicas: 1
selector:
matchLabels:
app: ingressroute-app
template:
metadata:
labels:
app: ingressroute-app
spec:
containers:
- name: ingressroute-app
image: nginx:latest
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello ingressroute app > /usr/share/nginx/html/index.html"]
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 200m
memory: 256Mi


apiVersion: v1
kind: Service
metadata:
name: ingressroute-app
spec:
selector:
app: ingressroute-app
ports:
- name: http
port: 80
targetPort: 80
type: ClusterIP


apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-app
spec:
entryPoints:

  • web
    routes:
  • match: Host(ingressroute.kubesre.lc) # 域名
    kind: Rule
    services:
    • name: ingressroute-app # 与svc的name一致
      port: 80 # 与svc的port name一致

部署查看效果

代码语言:javascript
复制
[root@localhost ~]# kubectl apply -f  ingressroute-app.yaml
deployment.apps/ingressroute-app created
service/ingressroute-app created
ingressroute.traefik.containo.us/ingressroute-app created

[root@localhost ~]# kubectl get pod,svc,ingressroute
NAME READY STATUS RESTARTS AGE
pod/ingressroute-app-64c6b5bd86-dqr2j 1/1 Running 0 94s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingressroute-app ClusterIP 10.103.84.46 <none> 80/TCP 94s

NAME AGE
ingressroute.traefik.containo.us/ingressroute-app 94s

添加本地hosts解析

代码语言:javascript
复制
192.168.36.139 ingressroute.kubesre.lc

访问 http://ingressroute.kubesre.lc/

image.png

匹配规则

更多匹配规则如下

规则

描述

Headers(key, value)

检查headers中是否有一个键为key值为value的键值对

HeadersRegexp(key, regexp)

检查headers中是否有一个键位key值为正则表达式匹配的键值对

Host(example.com, …)

检查请求的域名是否包含在特定的域名中

HostRegexp(example.com, {subdomain:[a-z]+}.example.com, …)

检查请求的域名是否包含在特定的正则表达式域名中

Method(GET, …)

检查请求方法是否为给定的methods(GET、POST、PUT、DELETE、PATCH)中

Path(/path, /articles/{cat:[a-z]+}/{id:[0-9]+}, …)

匹配特定的请求路径,它接受一系列文字和正则表达式路径

PathPrefix(/products/, /articles/{cat:[a-z]+}/{id:[0-9]+})

匹配特定的前缀路径,它接受一系列文字和正则表达式前缀路径

Query(foo=bar, bar=baz)

匹配查询字符串参数,接受key=value的键值对

ClientIP(10.0.0.0/16, ::1)

如果请求客户端 IP 是给定的 IP/CIDR 之一,则匹配。它接受 IPv4、IPv6 和网段格式。

Headers

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-app
spec:
entryPoints:

  • web
    routes:
  • match: Host(ingressroute.kubesre.lc) && Headers(X-Custom-Header, special-value)
    kind: Rule
    services:
    • name: ingressroute-app
      port: 80

在此示例中,IngressRoute 匹配具有以下条件的请求:

  • 主机头是 ingressroute.kubesre.lc
  • 该请求包含一个 X-Custom-Header 值为 的自定义标头 special-value。

如果传入请求满足这些条件,Traefik 会将请求路由到端口 80 上指定的服务ingressroute-ap,Headers 区分大小写。

代码语言:javascript
复制
[root@localhost ~]# curl -H "Host: ingressroute.kubesre.lc" -H "X-Custom-Header: special-value" http://ingressroute.kubesre.lc
Hello ingressroute app

Path

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-app
spec:
entryPoints:
  • web
    routes:
  • match: Host(ingressroute.kubesre.lc) && Path(/)
    kind: Rule
    services:
    • name: ingressroute-app
      port: 80
  • 在这个例子中,IngressRoute 配置会匹配 ingressroute.kubesre.lc 域名下的特定 URL 路径模式。URL 路径的模式是 / 测试访问如下:

    代码语言:javascript
    复制
    [root@localhost ~]# curl -H "Host: ingressroute.kubesre.lc" http://ingressroute.kubesre.lc/
    Hello ingressroute app

    Method

    代码语言:javascript
    复制
    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
    name: ingressroute-app
    spec:
    entryPoints:
  • web
    routes:
  • match: Host(ingressroute.kubesre.lc) && Method(GET)
    kind: Rule
    services:
    • name: ingressroute-app
      port: 80
  • 在这个例子中,IngressRoute 配置会匹配 ingressroute.kubesre.lc 域名下的使用 GET 方法的 HTTP 请求。

    代码语言:javascript
    复制
    [root@localhost ~]# curl -XGET -H "Host: ingressroute.kubesre.lc" http://ingressroute.kubesre.lc/
    Hello ingressroute app

    配置Https

    自签名证书

    代码语言:javascript
    复制
    openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=ingressroute.kubesre.lc"

    创建 tls 类型的 secret

    代码语言:javascript
    复制
    kubectl create secret tls myapp-tls --cert=tls.crt --key=tls.key

    创建 https的 ingressRoute ingressroute-app-https.yaml:

    代码语言:javascript
    复制
    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
    name: ingressroute-app-https
    spec:
    entryPoints:
  • websecure
    routes:
  • match: Host(ingressroute.kubesre.lc) # 域名
    kind: Rule
    services:
    • name: ingressroute-app # 与svc的name一致
      port: 80 # 与svc的port name一致
      tls:
      secretName: myapp-tls # 指定tls证书名称
  • 部署

    代码语言:javascript
    复制
    [root@localhost ~]# kubectl apply -f  ingressroute-app-https.yaml
    ingressroute.traefik.containo.us/example-ingressroute-https created

    [root@localhost ~]# kubectl get ingressroute
    NAME AGE
    ingressroute-app 8m57s
    ingressroute-app-https 2s

    访问 https://ingressroute.kubesre.lc/,此时 http 和 https 站点共存

    负载均衡

    代码语言:javascript
    复制
    apiVersion: traefik.containo.us/v1alpha1
    kind: IngressRoute
    metadata:
    name: ingressroute-app-lb
    spec:
    entryPoints:

    • web # 与 configmap 中定义的 entrypoint 名字相同
      routes:
    • match: Host(lb.kubesre.lc) # 域名
      kind: Rule
      services:
      • name: ingress-app # 与svc的name一致
        port: 80 # 与svc的port一致
      • name: ingressroute-app # 与svc的name一致
        port: 80 # 与svc的port一致

    部署

    代码语言:javascript
    复制
    [root@localhost ~]# kubectl apply -f  ingressroute-app-lb.yaml
    ingressroute.traefik.containo.us/ingressroute-app-lb created

    [root@localhost ~]# kubectl get ingressroute
    NAME AGE
    ingressroute-app 13m
    ingressroute-app-https 5m2s
    ingressroute-app-lb 27s

    添加本地hosts解析

    代码语言:javascript
    复制
    192.168.36.139 lb.kubesre.lc

    访问测试,可以发现 ingress-app 和 ingressroute-app 的内容

    代码语言:javascript
    复制
    [root@localhost ~]# curl http://lb.kubesre.lc/
    Hello ingressroute app
    [root@localhost ~]# curl http://lb.kubesre.lc/
    Hello ingress app
    [root@localhost ~]# curl http://lb.kubesre.lc/
    Hello ingressroute app
    [root@localhost ~]# curl http://lb.kubesre.lc/
    Hello ingress app