前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >traefik系列之二 | 路由(ingressRoute)

traefik系列之二 | 路由(ingressRoute)

作者头像
Amadeus
发布2023-04-27 20:13:12
2.2K0
发布2023-04-27 20:13:12
举报
文章被收录于专栏:linux技术

0. 前言

基于 centos7.9docker-ce-20.10.18kubelet-1.22.3-0traefik-2.9.10

1. 简介

参考文档:https://doc.traefik.io/traefik/routing/overview/

1.1 三种方式

Traefik 创建路由规则有多种方式,比如:

  • 原生 Ingress 写法
  • 使用 CRD IngressRoute 方式
  • 使用 GatewayAPI 的方式

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

1.2 匹配规则

规则

描述

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 和网段格式。

2. dashboard 案例

之前的部署章节中我们是以 nodePort 和 service nodePort 的方式访问的 traefik 的 dashboard,接下来以三种方式演示通过域名访问 dashboard

2.1 ingress

代码语言:javascript
复制
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: traefik-dashboard
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.ingress.kubernetes.io/router.entrypoints: web
spec:
  rules:
  - host: ingress.traefik.local
    http:
      paths:
      - pathType: Prefix
        path: /
        backend:
          service:
            name: traefik
            port:
              number: 9000

访问: http://traefik.local

2.2 ingressRoute

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: kube-system
spec:
  entryPoints:
    - web
  routes:
  - match: Host(`ingressroute.traefik.local`) && PathPrefix(`/`)
    kind: Rule
    services:
    - name: traefik
      port: 9000

访问:http://ingressroute.traefik.local

2.3 Gateway API

目前,Traefik 对 Gateway APIs 的实现是基于 v1alpha1 版本的规范,目前最新的规范是 v1alpha2,所以和最新的规范可能有一些出入的地方。

创建 gatewayClass

代码语言:javascript
复制
apiVersion: networking.x-k8s.io/v1alpha1
kind: GatewayClass
metadata:
  name: traefik
spec:
  controller: traefik.io/gateway-controller

创建 gateway

代码语言:javascript
复制
apiVersion: networking.x-k8s.io/v1alpha1
kind: Gateway
metadata: 
  name: http-gateway
  namespace: kube-system 
spec: 
  gatewayClassName: traefik
  listeners: 
  - protocol: HTTP
    port: 80 
    routes: 
      kind: HTTPRoute
      namespaces:
        from: All
      selector:
        matchLabels:
          app: traefik

创建 httproute

代码语言:javascript
复制
apiVersion: networking.x-k8s.io/v1alpha1
kind: HTTPRoute
metadata:
  name: traefik-dashboard
  namespace: kube-system
  labels:
    app: traefik
spec:
  hostnames:
  - "gateway.traefik.local"
  rules:
  - matches:
    - path:
        type: Prefix
        value: /
    forwardTo:
    - serviceName: traefik 
      port: 9000
      weight: 1

访问:http://gateway.traefik.local

3. myapp 环境准备

myapp1

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp1
spec:
  selector:
    matchLabels:
      app: myapp1
  template:
    metadata:
      labels:
        app: myapp1
    spec:
      containers:
      - name: myapp1
        image: ikubernetes/myapp:v1
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: myapp1
spec:
  type: ClusterIP
  selector:
    app: myapp1
  ports:
  - port: 80
    targetPort: 80

myapp2

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp2
spec:
  selector:
    matchLabels:
      app: myapp2
  template:
    metadata:
      labels:
        app: myapp2
    spec:
      containers:
      - name: myapp2
        image: ikubernetes/myapp:v2
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: myapp2
spec:
  type: ClusterIP
  selector:
    app: myapp2
  ports:
  - port: 80
    targetPort: 80

创建资源并访问测试

代码语言:javascript
复制
[root@k8s-node1 ~]# vim demo/app/myapp1.yml
[root@k8s-node1 ~]# vim demo/app/myapp2.yml
[root@k8s-node1 ~]# kubectl apply -f demo/app/
deployment.apps/myapp1 created
service/myapp1 created
deployment.apps/myapp2 created
service/myapp2 created
[root@k8s-node1 ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP   12d
myapp1       ClusterIP   10.100.229.135   <none>        80/TCP    33s
myapp2       ClusterIP   10.96.56.49      <none>        80/TCP    33s
[root@k8s-node1 ~]# curl 10.100.229.135
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-node1 ~]# curl 10.96.56.49
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>

4. ingressRoute

4.1 http 路由

实现目标:集群外部用户通过访问 http://myapp1.test.com 域名时,将请求代理至myapp1应用。

创建 ingressRoute

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: myapp1
spec:
  entryPoints:
  - web              # 与 configmap 中定义的 entrypoint 名字相同
  routes:
  - match: Host(`myapp1.test.com`) # 域名
    kind: Rule
    services:
      - name: myapp1  # 与svc的name一致
        port: 80      # 与svc的port一致

部署

代码语言:javascript
复制
[root@k8s-node1 ~]# vim demo/ingressroute/http-myapp1.yml
[root@k8s-node1 ~]# kubectl apply -f demo/ingressroute/http-myapp1.yml
ingressroute.traefik.containo.us/myapp1 created

访问测试

image-20230419131939361
image-20230419131939361

4.2 https 路由

自签名证书

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

创建 tls 类型的 secret

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

创建 ingressRoute

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: myapp2
spec:
  entryPoints:
    - websecure                    # 监听 websecure 这个入口点,也就是通过 443 端口来访问
  routes:
  - match: Host(`myapp2.test.com`)
    kind: Rule
    services:
    - name: myapp2
      port: 80
  tls:
    secretName: myapp2-tls         # 指定tls证书名称

部署

代码语言:javascript
复制
[root@k8s-node1 ~]# vim demo/ingressroute/https-myapp2.yml
[root@k8s-node1 ~]# kubectl apply -f  demo/ingressroute/https-myapp2.yml
ingressroute.traefik.containo.us/myapp2 created

访问测试,由于是自签名证书,所以会提示不安全

image-20230419132537993
image-20230419132537993

5. ingressRouteTCP

5.1 不带 TLS 证书

部署mysql

代码语言:javascript
复制
apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql
  labels:
    app: mysql
  namespace: default
data:
  my.cnf: |
    [mysqld]
    character-set-server = utf8mb4
    collation-server = utf8mb4_unicode_ci
    skip-character-set-client-handshake = 1
    default-storage-engine = INNODB
    max_allowed_packet = 500M
    explicit_defaults_for_timestamp = 1
    long_query_time = 10    
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: mysql
  name: mysql
spec:
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: abc123
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: /etc/mysql/conf.d/my.cnf
          subPath: my.cnf
          name: cm
      volumes:
        - name: cm
          configMap:
            name: mysql
---
apiVersion: v1
kind: Service
metadata:
  name: mysql
  namespace: default
spec:
  ports:
    - port: 3306
      protocol: TCP
      targetPort: 3306
  selector:
    app: mysql

ingressRouteTCP

SNI为服务名称标识,是 TLS 协议的扩展。因此,只有 TLS 路由才能使用该规则指定域名。非 TLS 路由使用带有 * 的规则来声明每个非 TLS 请求都将由路由进行处理。

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: mysql
  namespace: default
spec:
  entryPoints:
    - tcpep  # 9200 端口
  routes:
  - match: HostSNI(`*`) # 由于 Traefik 中使用 TCP 路由配置需要 SNI,而 SNI 又是依赖 TLS 的,所以我们需要配置证书才行,如果没有证书的话,我们可以使用通配符*(适配ip)进行配置
    services:
    - name: mysql
      port: 3306

部署

代码语言:javascript
复制
[root@k8s-node1 ~]# vim demo/ingressrouteTCP/mysql.yml
[root@k8s-node1 ~]# kubectl apply -f demo/ingressrouteTCP/mysql.yml
configmap/mysql created
deployment.apps/mysql created
service/mysql created
[root@k8s-node1 ~]# vim demo/ingressrouteTCP/route.yml
[root@k8s-node1 ~]# kubectl apply -f  demo/ingressrouteTCP/route.yml
ingressroutetcp.traefik.containo.us/mysql created

集群外主机验证

  • 添加 hosts (mysql.test.com)
  • 以 root & abc123 访问 9200 端口
image-20230419134852960
image-20230419134852960
image-20230419134929324
image-20230419134929324

5.2 带 TLS 证书

参考地址 https://doc.traefik.io/traefik/routing/providers/kubernetes-crd/#kind-ingressroutetcp

大多数情况下 tcp 路由不需要配置 TLS ,下面仅演示两个关键步骤

创建 tls 类型的 secret

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

创建 ingressRouteTCP,需要携带 secret

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteTCP
metadata:
  name: redis
spec:
  entryPoints:
    - redisep
  routes:
  - match: HostSNI(`redis.test.com`)
    services:
    - name: redis
      port: 6379
  tls:
    secretName: redis-tls

6. ingressRouteUDP

创建应用

代码语言:javascript
复制
kind: Deployment
apiVersion: apps/v1
metadata:
  name: whoamiudp
  labels:
    app: whoamiudp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: whoamiudp
  template:
    metadata:
      labels:
        app: whoamiudp
    spec:
      containers:
        - name: whoamiudp
          image: traefik/whoamiudp:latest
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: whoamiudp
spec:
  ports:
    - port: 8080
      protocol: UDP
  selector:
    app: whoamiudp

配置 ingressRouteUDP

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRouteUDP
metadata:
  name: whoamiudp
spec:
  entryPoints:                  
    - udpep
  routes:                      
  - services:                  
    - name: whoamiudp                 
      port: 8080

直接访问 svc 验证

代码语言:javascript
复制
[root@k8s-node1 traefik]# kubectl get svc whoamiudp
NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
whoamiudp   ClusterIP   10.96.119.116   <none>        8080/UDP   2m22s
[root@k8s-node1 traefik]# echo "WHO" | socat - udp4-datagram:10.96.119.116:8080
Hostname: whoamiudp-6ff7dd6fb9-8qfc7
IP: 127.0.0.1
IP: 10.244.169.174
[root@k8s-node1 traefik]# echo "test" | socat - udp4-datagram:10.96.119.116:8080
Received: test

访问 udp 路由验证

代码语言:javascript
复制
[root@k8s-node1 traefik]# echo "WHO" | socat - udp4-datagram:k8s-node1:9300
Hostname: whoamiudp-6ff7dd6fb9-5l8rd
IP: 127.0.0.1
IP: 10.244.107.243
[root@k8s-node1 traefik]# echo "test" | socat - udp4-datagram:1.1.1.1:9300
Received: test

7. 负载均衡

代码语言:javascript
复制
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: myapp1
spec:
  entryPoints:
  - web              # 与 configmap 中定义的 entrypoint 名字相同
  routes:
  - match: Host(`lb.test.com`) # 域名
    kind: Rule
    services:
      - name: myapp1  # 与svc的name一致
        port: 80      # 与svc的port一致
      - name: myapp2  # 与svc的name一致
        port: 80      # 与svc的port一致

部署

代码语言:javascript
复制
[root@k8s-node1 ~]# vim demo/lb/lb.yml
[root@k8s-node1 ~]# kubectl apply -f  demo/lb/lb.yml
ingressroute.traefik.containo.us/myapp1 created

访问测试,可以发现循环相应 myapp1 和 myapp2 的内容

代码语言:javascript
复制
[root@k8s-node1 ~]# curl http://lb.test.com
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-node1 ~]# curl http://lb.test.com
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
[root@k8s-node1 ~]# curl http://lb.test.com
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-node1 ~]# curl http://lb.test.com
Hello MyApp | Version: v2 | <a href="hostname.html">Pod Name</a>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-04-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 0. 前言
  • 1. 简介
    • 1.1 三种方式
      • 1.2 匹配规则
      • 2. dashboard 案例
        • 2.1 ingress
          • 2.2 ingressRoute
            • 2.3 Gateway API
            • 3. myapp 环境准备
            • 4. ingressRoute
              • 4.1 http 路由
                • 4.2 https 路由
                • 5. ingressRouteTCP
                  • 5.1 不带 TLS 证书
                    • 5.2 带 TLS 证书
                    • 6. ingressRouteUDP
                    • 7. 负载均衡
                    相关产品与服务
                    负载均衡
                    负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档