写点什么

如何在 K8S 集群中部署 Traefik Ingress Controller

  • 2020-05-25
  • 本文字数:8841 字

    阅读完需:约 29 分钟

如何在K8S集群中部署Traefik Ingress Controller

在生产环境中,我们常常需要控制来自互联网的外部进入集群中,而这恰巧是 Ingress 的职责。


Ingress 的主要目的是将 HTTP 和 HTTPS 从集群外部暴露给该集群中运行的服务。这与 Ingress 控制如何将外部流量路由到集群有异曲同工之妙。接下来,我们举一个实际的例子来更清楚的说明 Ingress 的概念。


首先,想象一下在你的 Kubernetes 集群中有若干个微服务(小型应用程序之间彼此通信)。这些服务能够在集群内部被访问,但我们想让我们的用户从集群外部也能够访问它们。因此,我们需要做的是使用反向代理将每个 HTTP(S)(例如,service.yourdomain.com)路由与相应的后端关联,并在该服务的不同实例之间(如,pod)进行负载均衡。与此同时,由于 Kubernetes 的性质会不断发生变化,因此我们希望跟踪服务后端的更改,以便能够在添加或删除新 Pod 时将这些 HTTP 路由重新关联到新 Pod 实例。


使用 Ingress 资源和关联的 Ingress Controller,你可以实现以下目标:


  • 将你的域 app.domain.com 指向你的私有网络中的微服务应用程序

  • 将路径 domain.com/web 指向你的私有网络中的微服务 web

  • 将你的域 backend.domain.com 指向你的私有网络中的微服务后端,并在该微服务的多个实例之间(Pod)进行负载均衡


现在,你理解了 Ingress 的重要性。它能够帮助将 HTTP 路由指向在 Kubernetes 集群中特定的微服务。


但是,流量路由并不是 Ingress 在 Kubernetes 中的唯一功能。例如,还可以将 Ingress 配置为负载均衡流量到你的应用程序、终止 SSL、执行基于名称的虚拟主机、在不同服务之间分配流量、设置服务访问规则等。


Kubernetes 有一个特别的 Ingress API 资源,它能够支持上述所有功能。但是,简单地创建一个 Ingress API 资源是没有作用的。你还需要一个 Ingress Controller。目前,Kubernetes 支持许多 Ingress controller,如 Contour、HAProxy、NGINX 以及 Traefik。


在本文中,我将使用 Traefik Ingress Controller 创建 Ingress。它能够实现现代 HTTP 反向代理和负载均衡器的功能,从而简化了微服务的部署。此外,Traefik 对 Docker、Marathon、Consul、Kubernetes、Amazon ECS 等系统和环境都提供了强大的支持。


Traefik 对于诸如 Kubernetes 之类的灵活性较强的系统十分有用。在 Kubernetes 中,每天需要多次添加、删除或升级服务,而 Traefik 可以监听服务镜像仓库/编排器 API 并立即生成或更新路由,因此你的微服务无需手动配置即可与外界连接。


除此之外,Traefik 支持多个负载均衡算法、Let’s Encrypt 的 HTTPS(支持通配证书)、断路器、WebSoket、GRPC 和多个监控程序(Rest、Prometheus、Statsd、Datadog、InfluxDB 等)。有关 Traefik 中可用功能的更多信息,请参考其官方文档:


https://docs.traefik.cn/

Ingress 资源

在教程开始之前,我们先来简单地讨论一下 Ingress 资源是如何工作的。以下是隐式使用 Nginx Ingress Controller 的 Ingress 示例。


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: ingress-example  annotations:    nginx.ingress.kubernetes.io/rewrite-target: /spec:  rules:  - http:      paths:      - path: /microservice1        backend:          serviceName: test          servicePort: 80
复制代码


以上 Ingress manifest 包含了一系列 HTTP 规则,它们用于规定 controller 如何路由流量。


可选主机。如果未指定主机(如上所示),则该规则适用于通过指定 IP 地址的所有入站 HTTP 流量。如果提供了主机(如 yourhost.com),则该规则仅适用于该主机。


一个路径列表(如,/microservice1),它指向由 serviceName 和 servicePort 定义的关联后端。


一个后端。向 Ingress 发出的 HTTP(和 HTTPS)请求将与给定规则的主机和路径匹配,然后将其路由到该规则中指定的后端服务。


在以上例子中,我们配置了一个名为”test“的后端,它将接收所有来自/microservice 路径的流量。然而,我们也可以配置一个默认后端,它将将为任何不符合规范中路径的用户请求提供服务。同时,如果不定义任何规则,Ingress 将路由所有流量到默认后端。例如:


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: test-ingressspec:  backend:    serviceName: defaultbackend    servicePort: 80
复制代码


在本例中,所有流量都被转发到默认后端中 defaultbackend。现在,我们理解了 Ingress 资源的基本概念,接下来我们来看看一些具体的例子。

Step 0:前期准备

如上文我们所说的,定义一个 Ingress 资源没有任何作用,除非你使用了 Ingress Controller。在本教程中,我们在 Kubernetes 集群中将 Traefik 设置为 Ingress Controller。


要完成教程,你需要进行以下准备:


  • 一个正在运行的 Kubernetes 集群。

  • 一个安装好的命令行工具,kubectl。并配置为与集群通信。


请注意:以下示例均假设你在本地计算上使用 Minikube 运行 Kubernetes 集群。

Step 1:启用 RBAC

首先,我们需要向 Traefik 授予一些权限,以访问集群中运行的 Pod、endpoint 和服务。为此,我们将使用 ClusterRole 和 ClusterRoleBinding 资源。但是,你也可以对命名空间范围内的 RoleBindings 使用最小特权方法。通常,如果集群的命名空间不会动态更改,并且 Traefik 无法监视所有集群的命名空间,那么这是首选的方法。


让我们创建一个新的 ServiceAccount,为 Traefik 提供集群中的身份。


apiVersion: v1kind: ServiceAccountmetadata:  name: traefik-ingress  namespace: kube-system
复制代码


要创建一个 ServiceAccount,需要在 traefik-service-acc.yaml 中保存以上 manifest 并运行:


kubectl create -f traefik-service-acc.yamlserviceaccount "traefik-ingress" created
复制代码


接下来,让我们创建一个具有一组权限的 ClusterRole,该权限将应用于 Traefik ServiceAccount。通过 ClusterRole,Traefik 可以管理和监视集群中所有命名空间中的资源,例如服务、endpoint、secret 以及 Ingress。


kind: ClusterRoleapiVersion: rbac.authorization.k8s.io/v1beta1metadata:  name: traefik-ingressrules:  - apiGroups:      - ""    resources:      - services      - endpoints      - secrets    verbs:      - get      - list      - watch  - apiGroups:      - extensions    resources:      - ingresses    verbs:      - get      - list      - watch
复制代码


将这一规范保存到文件 traefik-cr.yaml 中,并运行:


kubectl create -f traefik-cr.yamlclusterrole.rbac.authorization.k8s.io “traefik-ingress” created
复制代码


最后,启用这些权限,我们应该将 ClusterRole 绑定到 Traefik ServiceAccount 中。使用 ClusterRoleBinding manifest 可以完成这一操作:


kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1beta1metadata:  name: traefik-ingressroleRef:  apiGroup: rbac.authorization.k8s.io  kind: ClusterRole  name: traefik-ingresssubjects:- kind: ServiceAccount  name: traefik-ingress  namespace: kube-system
复制代码


保存这一规范到 traefik-crb.yaml 中,并运行以下命令:


kubectl create -f traefik-crb.yamlclusterrolebinding.rbac.authorization.k8s.io “traefik-ingress” created
复制代码

Step 2:部署 Traefik 到集群

接下来,我们将部署 Traefik 到 Kubernetes 集群。官方 Traefik 文档支持三种类型的部署:使用 Deployment 对象、使用 DaemonSet 对象或使用 Helm Chart。


在本教程中,我们将使用 Deployment manifest。相比其他选项,Deployment 有诸多优势。例如,它们能确保更好的可伸缩性,并为滚动更新提供良好支持。


让我们看一下 Deployment manifest:


kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: traefik-ingress  namespace: kube-system  labels:    k8s-app: traefik-ingress-lbspec:  replicas: 1  selector:    matchLabels:      k8s-app: traefik-ingress-lb  template:    metadata:      labels:        k8s-app: traefik-ingress-lb        name: traefik-ingress-lb    spec:      serviceAccountName: traefik-ingress      terminationGracePeriodSeconds: 60      containers:      - image: traefik        name: traefik-ingress-lb        ports:        - name: http          containerPort: 80        - name: admin          containerPort: 8080        args:        - --api        - --kubernetes        - --logLevel=INFO
复制代码


这个 Deployment 将在 kube-system 命名空间中创建一个 Traefik 副本。Traefik 容器将使用此 manifest 中指定的端口 80 和 8080。


将这个 manifest 保存到 traefik-deployment.yaml 文件中,并运行以下命令创建 Deployment:


kubectl create -f traefik-deployment.yamldeployment.extensions “traefik-ingress” created
复制代码


现在,让我们检查以下 Traefik Pod 是否都成功创建了:


kubectl --namespace=kube-system get podsNAME                         READY     STATUS    RESTARTS   AGE....storage-provisioner           1/1       Running   3          23dtraefik-ingress-54d6d8d9cc-ls6cs 1/1       Running   0          1m
复制代码


如你所见,Deployment Controller 启动了一个 Traefik 副本,并在正在运行,敲棒的!

Step 3:为外部访问创建 NodePorts

让我们创建一个服务来从集群外部访问 Traefik。为此,我们需要一个暴露两个 NodePorts 的服务。


kind: ServiceapiVersion: v1metadata:  name: traefik-ingress-service  namespace: kube-systemspec:  selector:    k8s-app: traefik-ingress-lb  ports:    - protocol: TCP      port: 80      name: web    - protocol: TCP      port: 8080      name: admin  type: NodePort
复制代码


将这个 manifest 保存到 traefik-svc.yaml,并创建服务:


kubectl create -f traefik-svc.yamlservice “traefik-ingress-service” created
复制代码


现在,让我们验证该服务是否创建:


kubectl describe svc traefik-ingress-service --namespace=kube-systemName:                     traefik-ingress-serviceNamespace:                kube-systemLabels:                   <none>Annotations:              <none>Selector:                 k8s-app=traefik-ingress-lbType:                     NodePortIP:                       10.102.215.64Port:                     web  80/TCPTargetPort:               80/TCPNodePort:                 web  30565/TCPEndpoints:                172.17.0.6:80Port:                     admin  8080/TCPTargetPort:               8080/TCPNodePort:                 admin  30729/TCPEndpoints:                172.17.0.6:8080Session Affinity:         NoneExternal Traffic Policy:  ClusterEvents:                   <none>
复制代码


如你所见,我们现在有两个 NodePorts(web 和 admin),它们分别路由到 Traefik Ingress Controller 的 80 和 8080 容器端口。“admin” NodePort 将用于访问 Traefik Web UI,“web” NodePort 将用于访问通过 Ingress 暴露的服务。

Step 4:访问 Traefik

为了能在浏览器中访问 Traefik Web UI,你可以使用“admin”NodePort 30729(请注意,你的 NodePort 值可能会有所不同)。因为我们还没有添加任何前端,所以 UI 此时应该是空的。


由于我们尚未给 Traefik 进行任何配置,因此我们会收到 404 的响应。


curl $(minikube ip):30565404 page not found
复制代码

Step 5 :添加 Ingress 到集群

现在我们在 Kubernetes 集群中已经将 Traefik 作为 Ingress Controller 了。然而,我们依旧需要定义 Ingress 资源和暴露 Traefik Web UI 的服务。


首先,我们创建一个服务:


apiVersion: v1kind: Servicemetadata:  name: traefik-web-ui  namespace: kube-systemspec:  selector:    k8s-app: traefik-ingress-lb  ports:  - name: web    port: 80    targetPort: 8080
复制代码


保存 manifest 到 traefik-webui-svc.yaml 中,并运行:


kubectl create -f traefik-webui-svc.yamlservice “traefik-web-ui” created
复制代码


让我们验证服务是否已经创建:


kubectl describe svc traefik-web-ui --namespace=kube-systemName:              traefik-web-uiNamespace:         kube-systemLabels:            <none>Annotations:       <none>Selector:          k8s-app=traefik-ingress-lbType:              ClusterIPIP:                10.98.230.58Port:              web  80/TCPTargetPort:        8080/TCPEndpoints:         172.17.0.6:8080Session Affinity:  NoneEvents:            <none>
复制代码


如你所见,服务的 ClusterIP 是 10.98.230.58,并在 manifest 中分配指定端口。


接下来,我们需要创建一个 Ingress 资源,指向 Traefik Web UI 后端:


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: traefik-web-ui  namespace: kube-systemspec:  rules:  - host: traefik-ui.minikube    http:      paths:      - path: /        backend:          serviceName: traefik-web-ui          servicePort: web
复制代码


本质上,Ingress 将所有请求路由到 traefik-ui.minikube,在上述步骤中创建的服务暴露 Traefik Web UI。


将规范保存到 traefik-ingress.yaml,并运行:


kubectl create -f traefik-ingress.yamlingress.extensions “traefik-web-ui” created
复制代码


为了能够通过 traefik-ui.minikube 在浏览器中可以访问 Traefik Web UI,我们需要添加新的条目到我们/etc/hosts 文件中。该条目将包含 Minikube IP 和主机名。你可以通过运行 minikube ip 来获取 minkube 实例的 IP 地址,然后将新主机的名称保存到/etc/hosts 文件中,如下所示:


echo "$(minikube ip) traefik-ui.minikube" | sudo tee -a /etc/hosts192.168.99.100 traefik-ui.minikube
复制代码


现在,你应该能够在浏览器中访问 http://traefik-ui.minikube:<AdminNodePort>并查看 Traefik Web UI。别忘了附加”admin”NodePort 到主机地址。



在 dashboard 中,你可以点击 Health 链接来查看应用程序的健康状况:


Step 6:实现基于名称的路由

现在,我们来演示如何使用 Traefik Ingress Controller 为前端列表设置基于名称的路由。我们将使用简单的单页网站创建 3 个 Deployment,并显示动物图像:熊、野兔和驼鹿。


---kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: bear  labels:    app: animals    animal: bearspec:  replicas: 2  selector:    matchLabels:      app: animals      task: bear  template:    metadata:      labels:        app: animals        task: bear        version: v0.0.1    spec:      containers:      - name: bear        image: supergiantkir/animals:bear        ports:        - containerPort: 80---kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: moose  labels:    app: animals    animal: moosespec:  replicas: 2  selector:    matchLabels:      app: animals      task: moose  template:    metadata:      labels:        app: animals        task: moose        version: v0.0.1    spec:      containers:      - name: moose        image: supergiantkir/animals:moose        ports:        - containerPort: 80---kind: DeploymentapiVersion: extensions/v1beta1metadata:  name: hare  labels:    app: animals    animal: harespec:  replicas: 2  selector:    matchLabels:      app: animals      task: hare  template:    metadata:      labels:        app: animals        task: hare        version: v0.0.1    spec:      containers:      - name: hare        image: supergiantkir/animals:hare        ports:        - containerPort: 80
复制代码


每个 Deployment 都将有两个 Pod 副本,而每个 Pod 将在 containerPort 80 上服务“动物“网站。


让我们保存这些 Deployment manifest 到 animals-deployment.yaml 中,并运行:


kubectl create -f animals-deployment.yamldeployment.extensions “bear” createddeployment.extensions “moose” createddeployment.extensions “hare” created
复制代码


现在,让我们为每个 Deployment 创建一个服务,使得 Pod 可以访问:


---apiVersion: v1kind: Servicemetadata:  name: bearspec:  ports:  - name: http    targetPort: 80    port: 80  selector:    app: animals    task: bear---apiVersion: v1kind: Servicemetadata:  name: moosespec:  ports:  - name: http    targetPort: 80    port: 80  selector:    app: animals    task: moose---apiVersion: v1kind: Servicemetadata:  name: hare  annotations:    traefik.backend.circuitbreaker: "NetworkErrorRatio() > 0.5"spec:  ports:  - name: http    targetPort: 80    port: 80  selector:    app: animals    task: hare
复制代码


请注意:第三项服务使用断路器 annotation。断路器是 Traefik 的一项功能,可防止发生故障的服务器承受高负载。在本例中,我们防止服务器上的高负载超过 50%。当此条件匹配时,CB 进入“跳闸“状态,在该状态中它会使用预定义的 HTTP 状态代码进行响应或重定向到另一个前端。


保存这些服务 manifest 到 animals-svc.yaml 并运行:


kubectl create -f animals-svc.yamlservice “bear” createdservice “moose” createdservice “hare” created
复制代码


最后,为每个 Deployment 创建一个有 3 个前后端对的 Ingress。bear.minikube、moose.minikube 和 hare.minikube 将是我们指向相应后端服务的前端。


Ingress manifest 如下所示:


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: animals  annotations:    kubernetes.io/ingress.class: traefikspec:  rules:  - host: hare.minikube    http:      paths:      - path: /        backend:          serviceName: hare          servicePort: http  - host: bear.minikube    http:      paths:      - path: /        backend:          serviceName: bear          servicePort: http  - host: moose.minikube    http:      paths:      - path: /        backend:          serviceName: moose          servicePort: http
复制代码


保存规范到 animals-ingress.yaml 并运行:


kubectl create -f animals-ingress.yamlingress.extensions “animals” created
复制代码


现在,在 Traefik dashboard 内,你可以看到每个主机的前端以及相应的后端列表:



如果你再次编辑 etc/hosts,你应该能够在你的浏览器中访问动物网页:


echo “$(minikube ip) bear.minikube hare.minikube moose.minikube” | sudo tee -a /etc/hosts
复制代码


你应该使用“web“NodePort 来访问特定网页。例如,http://bear.minikube:<WebNodePort>


我们也可以将三个前端重新配置为在一个域下提供服务,如下所示:


apiVersion: extensions/v1beta1kind: Ingressmetadata:  name: all-animals  annotations:    kubernetes.io/ingress.class: traefik    traefik.frontend.rule.type: PathPrefixStripspec:  rules:  - host: animals.minikube    http:      paths:      - path: /bear        backend:          serviceName: bear          servicePort: http      - path: /moose        backend:          serviceName: moose          servicePort: http      - path: /hare        backend:          serviceName: hare          servicePort: http
复制代码


如果你激活这个 Ingress,使用相应的路径,三个动物在一个域下都能够访问——animals.minikube。别忘了将这个域添加到/etc/hosts。


echo “$(minikube ip) animals.minikube” | sudo tee -a /etc/hosts
复制代码


请注意:我们正在配置 Traefik,以使用 traefik.frontend.rule.type 注释,从 URL 路径中删除前缀。这样我们可以直接使用上一个示例中的容器。由于 traefik.frontend.rule.type: PathPrefixStrip 规则,你必须使用 http://animals.minikube:32484/moose/ 而不是 http://animals.minikube:32484/moose

Step 7:实现流量分配

借助 Traefik,用户可以使用服务权重以受控方式在多个 deployment 之间分配 Ingress 流量。这一功能可用于金丝雀发布,它最初应该获得少量但持续增长的流量。


让我们使用以下 manifest 在两个微服务之间分配 Traefik:


apiVersion: extensions/v1beta1kind: Ingressmetadata:  annotations:    traefik.ingress.kubernetes.io/service-weights: |      animals-app: 99%      animals-app-canary: 1%  name: animals-appspec:  rules:  - http:      paths:      - backend:          serviceName: animals-app          servicePort: 80        path: /      - backend:          serviceName: animals-app-canary          servicePort: 80        path: /
复制代码


请注意 traefik.ingress.kubernetes.io/service-weights 的注释。它指定了流量如何在指定后端服务(animals-app 和 animals-app-canary)之间分配。Traefik 将把 99%的用户请求路由到 animals-app deployment 支持的 Pod,并将 1%的用户请求路由到 animals-app-canary deployment 支持的 Pod。


要使此设置正常工作,需要满足一些条件:


  • 所有服务后端必须共享相同的路径和主机。

  • 跨服务后端共享的请求总数应总计为 100%。

  • 百分比值应该在支持的精度范围内,目前 Traefik 支持 3 个小数位的权重。

总结

如你所见,Ingress 是将外部流量路由到 Kubernetes 集群中相应后端服务的强大工具。用户可以使用 Kubernetes 支持的许多 Ingress controller 来实现 Ingress。在本教程中,我们重点介绍了 Traefik Ingress controller,该控制器支持基于名称的路由,负载均衡以及 Ingress controller 的其他常见任务。


2020-05-25 16:392889

评论

发布
暂无评论
发现更多内容

openEuler、龙蜥Anolis、统信UOS系统下编译GreatSQL二进制包

GreatSQL

【坚果派-坚果】获取OpenHarmony 3.2 Release源码的两种方式

坚果

HarmonyOS OpenHarmony OpenHarmony3.2 三周年连更

危中蕴机:Oi! Network展现出的勇气和决心

股市老人

论程序员的为码之“道”

酱紫的小白兔

Go语言开发小技巧&易错点100例(三)

盐咔咔

Go 三周年连更

C生万物 | 反汇编深挖【函数栈帧】的创建和销毁

Fire_Shield

C语言 汇编 三周年连更 函数栈帧

程序员如何保住自己的饭碗?| 社区征文

liuzhen007

程序员 三周年征文

ContentProvider介绍

芯动大师

ContextClassLoader 三周年连更

Unity 之 使用原生UGUI实现随手移动摇杆功能经典实例

陈言必行

Unity 三周年连更

Spider实战-抓取视频

浅辄

三周年连更

从ReentrantLock角度解析AQS

Java AQS 并发

一文读懂封装

断墨寻径

#java 三周年征文

不要过于吹捧ChatGPT:人工智能生成文字还有很大提升空间

石头IT视角

kubernetes fifo源码解析

欢乐的阿苏

golang DevOps 后端 源码阅读 #Kubernetes#

数据库原理及MySQL应用 | 约束

TiAmo

数据库 MySQL数据库 三周年连更 数据库约束

如何使用 taosKeeper 做好监控工作,时序数据库 TDengine 3.0 监控工具详解

TDengine

大数据 tdengine 物联网 时序数据库 数据监控

RabbitMQ组件介绍

穿过生命散发芬芳

RabbitMQ 三周年连更

Golang并发编程实战:使用ring buffer实现高效的阻塞队列

Jack

【Linux】之【磁盘】相关的命令及解析[df、du、iostat、iotop]

A-刘晨阳

Linux 三周年连更 磁盘空间

Java程序控制结构

timerring

Java

对话ChatGPT:Prompt是普通人“魔法”吗?

Alter

一文掌握 Go 文件的读取操作

陈明勇

Go golang 文件读取 三周年连更

kubernetes delta_fifo源码解析

欢乐的阿苏

golang DevOps 后端 源码阅读 #Kubernetes#

AI日课@20230412:Prompt Engineering

无人之路

ChatGPT

Java数组、排序和查找

timerring

Java

影驰 GeForce RTX 4070显卡正式开售!星曜 OC系列首发评测抢先看

Geek_2d6073

kubernetes indexer源码解析

欢乐的阿苏

golang DevOps cache 源码阅读 #Kubernetes#

成都.NET线下技术沙龙倒计时一天

MASA技术团队

.net 开发者 MASA Stack

跨平台应用开发进阶(四十三)一文走近网络层抓包工具:WhireShark

No Silver Bullet

网络层 抓包工具 三周年连更

Unity 之 转微信小游戏本地数据存储

陈言必行

Unity 三周年连更

一定是疯了!在M1的Mac上玩OpenVINO,让Intel怎么看我?

IT蜗壳-Tango

OpenVINO Stable Diffusion 三周年连更

如何在K8S集群中部署Traefik Ingress Controller_文化 & 方法_Rancher_InfoQ精选文章