k8s整合Traefik

介绍

公司的k8s云测试环境,集群和核心组件研究部署的差不多了,此处用阿里云进行模拟,记录安装traefik过程

Traefik 是一个开源的可以使服务发布变得轻松有趣的边缘路由器。它负责接收你系统的请求,然后使用合适的组件来对这些请求进行处理。

traefik architecture

除了众多的功能之外,Traefik 的与众不同之处还在于它会自动发现适合你服务的配置。当 Traefik 在检查你的服务时,会找到服务的相关信息并找到合适的服务来满足对应的请求。

Traefik 兼容所有主流的集群技术,比如 Kubernetes,Docker,Docker Swarm,AWS,Mesos,Marathon,等等;并且可以同时处理多种方式。(甚至可以用于在裸机上运行的比较旧的软件。)

使用 Traefik,不需要维护或者同步一个独立的配置文件:因为一切都会自动配置,实时操作的(无需重新启动,不会中断连接)。使用 Traefik,你可以花更多的时间在系统的开发和新功能上面,而不是在配置和维护工作状态上面花费大量时间。

核心概念

Traefik 是一个边缘路由器,是你整个平台的大门,拦截并路由每个传入的请求:它知道所有的逻辑和规则,这些规则确定哪些服务处理哪些请求;传统的反向代理需要一个配置文件,其中包含路由到你服务的所有可能路由,而 Traefik 会实时检测服务并自动更新路由规则,可以自动服务发现。

traefik architecture overview

首先,当启动 Traefik 时,需要定义 entrypoints(入口点),然后,根据连接到这些 entrypoints 的路由来分析传入的请求,来查看他们是否与一组规则相匹配,如果匹配,则路由可能会将请求通过一系列中间件转换过后再转发到你的服务上去。在了解 Traefik 之前有几个核心概念我们必须要了解:

  • Providers 用来自动发现平台上的服务,可以是编排工具、容器引擎或者 key-value 存储等,比如 Docker、Kubernetes、File
  • Entrypoints 监听传入的流量(端口等…),是网络入口点,它们定义了接收请求的端口(HTTP 或者 TCP)。
  • Routers 分析请求(host, path, headers, SSL, …),负责将传入请求连接到可以处理这些请求的服务上去。
  • Services 将请求转发给你的应用(load balancing, …),负责配置如何获取最终将处理传入请求的实际服务。
  • Middlewares 中间件,用来修改请求或者根据请求来做出一些判断(authentication, rate limiting, headers, ...),中间件被附件到路由上,是一种在请求发送到你的服务之前(或者在服务的响应发送到客户端之前)调整请求的一种方法。

安装

首先下载helm,根据自己的k8s版本来选择相应的版本,此处K8s的版本为v1.22.3

[root@iZbp1h218d2igdnxe7q5o9Z ~]# tar -zvxf helm-v3.6.3-linux-amd64.tar.gz
linux-amd64/
linux-amd64/helm
linux-amd64/LICENSE
linux-amd64/README.md
[root@iZbp1h218d2igdnxe7q5o9Z ~]# mv linux-amd64/helm /usr/local/bin/
[root@iZbp1h218d2igdnxe7q5o9Z ~]# helm version
version.BuildInfo{Version:"v3.6.3", GitCommit:"d506314abfb5d21419df8c7e7e68012379db2354", GitTreeState:"clean", GoVersion:"go1.16.5"}
[root@iZbp1h218d2igdnxe7q5o9Z ~]#

使用 Helm 来快速安装 traefik,首先获取 Helm Chart 包:

git clone https://github.com/traefik/traefik-helm-chart

[root@iZbp1h218d2igdnxe7q5o9Z ~]# cd traefik-helm-chart
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# ll
总用量 44
-rw-r--r-- 1 root root   205 4月  22 13:36 artifacthub-repo.yml
-rw-r--r-- 1 root root   915 4月  22 13:36 CONTRIBUTING.md
-rw-r--r-- 1 root root   327 4月  22 13:40 dashboard.yaml
-rw-r--r-- 1 root root  1514 4月  22 13:38 deployment-prod.yaml
-rw-r--r-- 1 root root 11573 4月  22 13:36 LICENSE
drwxr-xr-x 2 root root    67 4月  22 13:36 lint
-rw-r--r-- 1 root root  3847 4月  22 13:36 Makefile
-rw-r--r-- 1 root root   473 4月  22 13:49 nginx-ir.yaml
-rw-r--r-- 1 root root  3231 4月  22 13:36 README.md
-rw-r--r-- 1 root root  2360 4月  22 13:36 TESTING.md
drwxr-xr-x 5 root root   157 4月  22 13:36 traefik
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

创建一个定制的 values 配置文件:

deployment:
  enabled: true
  kind: Deployment

ingressClass:
  enabled: true
  isDefaultClass: false

ingressRoute:  # 不用自动创建,我们自己处理
  dashboard:
    enabled: false

#
# 配置 providers
#
providers:
  kubernetesCRD:  # 开启 crd provider
    enabled: true
    allowCrossNamespace: true  # 是否允许跨命名空间
    allowExternalNameServices: true  # 是否允许使用 ExternalName 的服务

  kubernetesIngress:  # 开启 ingress provider
    enabled: true
    allowExternalNameServices: true

logs:
  general:
    level: DEBUG
  access:
    enabled: true

ports:
  web:
    port: 8000
    hostPort: 80  # 使用 hostport 模式

  websecure:
    port: 8443
    hostPort: 443  # 使用 hostport 模式

  metrics:
    port: 9100
    hostPort: 9101
# 监听1024以下的端口需要修改traefik默认的安全上下文配置
securityContext:
  capabilities:
    drop: []
  readOnlyRootFilesystem: false
  runAsGroup: 0
  runAsNonRoot: false
  runAsUser: 0

nodeSelector:   # 固定到边缘节点
  kubernetes.io/hostname: "iZbp1h218d2igdnxe7q5o9Z"
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# kubectl get nodes
NAME                      STATUS   ROLES                  AGE    VERSION
izbp1h218d2igdnxe7q5o7z   Ready    <none>                 104m   v1.22.3
izbp1h218d2igdnxe7q5o8z   Ready    <none>                 104m   v1.22.3
izbp1h218d2igdnxe7q5o9z   Ready    control-plane,master   105m   v1.22.3
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

这里我们使用 hostport 模式将 Traefik 固定到 iZbp1h218d2igdnxe7q5o9Z节点上,因为只有这个节点有外网 IP,所以我们这里 是作为流量的入口点。直接使用上面的 values 文件安装 traefik:

[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#  helm upgrade --install traefik ./traefik -f ./values.yaml --namespace kube-system
Release "traefik" does not exist. Installing it now.
NAME: traefik
LAST DEPLOYED: Mon May 16 23:00:30 2022
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# kubectl get pods -n kube-system -l app.kubernetes.io/name=traefik
NAME                       READY   STATUS    RESTARTS   AGE
traefik-7586cd775d-8n58k   1/1     Running   0          3h2m
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

我们可以首先创建一个用于 Dashboard 访问的 IngressRoute 资源清单:

[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# cat dashboard.yaml
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
  namespace: kube-system
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`traefik.dalianpai.cn`)  # 指定域名
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

其中的 TraefikServiceTraefik Service 的一个 CRD 实现,这里我们使用的 api@internal 这个 TraefikService,表示我们访问的是 Traefik 内置的应用服务。

如果没有域名的话,则可以在hosts文件中进行配置,有的话直接阿里云配置域名解析

image-20220516215351689

进行访问

image-20220516215456815

如果要让 Traefik 去处理默认的 Ingress 资源对象,则我们就需要使用名为 traefik的 IngressClass 了,因为没有指定默认的:

[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# kubectl get ingressclass
NAME      CONTROLLER                      PARAMETERS   AGE
traefik   traefik.io/ingress-controller   <none>       3h7m
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

创建如下所示的一个 Ingress 资源对象,这里的核心是 ingressClassName 要指向 traefik 这个 IngressClass:

[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]# cat nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nginx-by-traefik
  namespace: default
spec:
  ingressClassName: traefik  # 使用 traefk 的 IngressClass
  rules:
  - host: wgr.nginx.com  # 将域名映射到 my-nginx 服务
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:  # 将所有请求发送到 my-nginx 服务的 80 端口
            name: nginx-svc
            port:
              number: 80
[root@iZbp1h218d2igdnxe7q5o9Z traefik-helm-chart]#

测试:

image-20220422164741398

HTTPS访问

由于测试环境中所有的应用都是通过https的方式进行访问,此处先用https的方式访问dashboard,操作如下:

image-20220516220919279

先去阿里云申请免费的SSL证书,然后通过 Secret 对象来引用证书文件:

kubectl create secret tls test-tls --cert=7783854_traefik.dalianpai.cn.pem --key=7783854_traefik.dalianpai.cn.key

创建资源清单

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: ingressroute-tls
spec:
  entryPoints:
    - websecure
  routes:
  - match: Host(`traefik.dalianpai.cn`)
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
  tls:
    secretName: test-tls

测试

image-20220516221408026

HTTP强转HTTPS

中间件

由于一开始创建了http访问dashboard的路由,如果我删除,只留出https,再通过 http 来访问的话呢就不行了,就会404了,因为我们根本就没有简单监听端口这个入口点。

image-20220516222015425

所以要想通过 http 来访问应用的话自然我们需要监听下 web 这个入口点。如果只希望用户通过 https 来访问应用的话呢?可以让 http 强制跳转到 https 服务去,对的,在 Traefik 中也是可以配置强制跳转的,只是这个功能现在是通过中间件来提供的了。如下所示,我们使用 redirectScheme 中间件来创建提供强制跳转服务:

apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
  name: redirect-https
spec:
  redirectScheme:
    scheme: https

然后将这个中间件附加到 http 的服务上面去,因为 https 的不需要跳转:

image-20220516221928277

apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: traefik-dashboard
spec:
  entryPoints:
  - web
  routes:
  - match: Host(`traefik.dalianpai.cn`)  # 指定域名
    kind: Rule
    services:
    - name: api@internal
      kind: TraefikService
    middlewares:
    - name: redirect-https

这样就可以通过http方式直接跳转到https,traefik还有很多插件,后面在介绍。

redirectTo方式

实际的测试环境中可能有几十上百个应用,如果通过中间件的方法,则都要绑定,过于繁琐,下面介绍一下web转发的方法。

创建测试nginx:

# 部署nginx
[root@iZbp1h218d2igdnxe7q5o9Z ~]# sudo kubectl create deployment nginx --image=nginx:1.14-alpine

# 暴露端口
[root@iZbp1h218d2igdnxe7q5o9Z ~]# sudo kubectl expose deployment nginx --port=80 --type=NodePort

# 查看服务状态
[root@iZbp1h218d2igdnxe7q5o9Z ~]# sudo kubectl get pods,service
NAME                         READY   STATUS    RESTARTS   AGE
pod/nginx-65c4bffcb6-bvf8w   1/1     Running   0          52m

NAME                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP        124m
service/nginx        NodePort    10.110.254.105   <none>        80:32701/TCP   52m

给nginx申请证书,并创建tls

image-20220516224821700

修改配置:

ports:
  web:
    port: 8000
    hostPort: 80  # 使用 hostport 模式
    redirectTo: websecure

先卸载之前的安装:

helm uninstall traefik -n kube-system

在重新应用

helm upgrade --install traefik ./traefik -f ./values.yaml --namespace kube-system

测试,http会自动跳转到https

image-20220516234827159

上面的配置使用的是hostport模式,ingress的话,一般采用hostnetwork,如果配置hostnetwork可以用下面的配置

# traefik是dashboard的配置,web和websecure是入口的配置
ports:
  traefik:
    expose: false
    port: 9000
  web:
    expose: false
    port: 80
    redirectTo: websecure
  websecure:
    expose: false
    port: 443


# 使用hostNetwork
hostNetwork: true

hostPort 与 hostNetwork 异同

相同点

​ hostPort 与 hostNetwork 本质上都是暴露 pod 宿主机 IP 给终端用户,因为 pod 生命周期并不固定,随时都有可能被完爆,故 IP 的不确定最终导致用户使用上的不方便;此外宿主机端口占用也导致不能在同一台机子上有多个程序使用同一端口。因此一般情况下,不要使用 hostPort 方式。

不同点

​ 使用 hostNetwork,pod 实际上用的是 pod 宿主机的网络地址空间:即 pod IP 是宿主机 IP,而非 cni 分配的 pod IP,端口是宿主机网络监听接口。

使用 hostPort,pod IP 并非宿主机 IP,而是 cni 分配的 pod IP,跟其他普通的 pod 使用一样的 ip 分配方式,端口并非宿主机网络监听端口,只是使用了 DNAT 机制将 hostPort 指定的端口映射到了容器的端口之上(可以通过 iptables 命令进行查看)。外部访问此 pod 时,仍然使用宿主机和 hostPort 方式

当 pod 同时使用了 hostNetwork 和 hostPort,那么 hostNetwork 将会直接使用宿主机网络命名空间,hostPort 其实就形同虚设了。可以认为 hostNetwork 选项优先级要高于 hostPort。

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐