东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

如何在 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:392775

评论

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

Zookeeper 客户端错误:Packet len8854970 is out of range!

看山

zookeeper 10月月更

Vue进阶(幺肆肆):(window,parent,opener,top).location.reload方法分析

No Silver Bullet

Vue 页面刷新 10月月更

谈 C++17 里的 Chain of Responsibility 模式

hedzr

设计模式 Design Patterns 职责链模式 c++17 消息分发

Docker环境搭建和使用

Fox

Docker

什么是aPaaS?低代码与高生产率的aPaaS和RAD相比如何?

优秀

低代码 aPaaS RAD

架构设计-电商微服务拆分

小智

架构训练营

linux之xargs使用技巧

入门小站

Linux

在线字符串长度计算,字符串统计工具

入门小站

工具

Go 中如何使用结构体标签

baiyutang

golang 10月月更

华为云数据库内核专家为您揭秘MySQL Volcano模型迭代器性能提升千倍的秘密

华为云数据库小助手

GaussDB 华为云数据库 GaussDB(for MySQL)

这部分布式事务开山之作,凭啥第一天预售就拿下当当新书榜No.1?

冰河

数据库 分布式 分布式事务 微服务 数据一致性

023云原生之Kubernetes的存储

穿过生命散发芬芳

云原生 10月月更

区块链与数字化转型携手并进

CECBC

Leetcode 题目解析:70. 爬楼梯

程序员架构进阶

LeetCode 动态规划 算法题 10月月更

央行数字货币已落地,来的太快,机遇在哪?

CECBC

Prometheus 内置函数(一)

耳东@Erdong

Prometheus 10月月更

架构实战营-模块一

瓜子葫芦侠

「架构实战营」

含爱奇艺,小米,腾讯,阿里,享学课堂怎么样

android 程序员 移动开发

对话凡泰极客联合创始人杨涛: 小程序生态市场潜力广阔

FinClip

小程序 金融科技 移动开发

谈一谈使用Python入门量化投资

Regan Yue

量化交易 10月月更

中软国际用一场自我进化,推动云市场跨入下一幕

脑极体

紧张的336小时53分钟21秒,我等来了字节跳动offer(Java岗)

Java 编程 程序员 架构 面试

自动驾驶 Lidar 激光雷达 易筋 ARTS 打卡 Week 73

John(易筋)

ARTS 打卡计划

看了CopyOnWriteArrayList后自己实现了一个CopyOnWriteHashMap

java金融

Java 程序员 CopyOnWrite;

三国与AI,交汇在中原

脑极体

【Quarkus技术系列】「云原生架构体系」在云原生时代下的Java“拯救者”是Quarkus,那云原生是什么呢?

洛神灬殇

云原生 Quarkus 10月月更

Java8 Lambda表达式与Stream

风翱

Lambda 10月月更

REST API 设计:过滤、排序和分页

devpoint

REST API 10月月更

聊聊产品的使用场景

石云升

场景应用 职场经验 10月月更

区块链是否正在慢慢演变为中心化的数据库?我们又该如何预防数据中心化?

CECBC

你真的会 Prometheus 查询吗?--PromQL 合集

耳东@Erdong

Prometheus PromQL 10月月更

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