写点什么

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

评论

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

230页,看完之后你就会知道,原来Redis还能这么玩!

Java架构师迁哥

iOS底层学习【KVC】

程序员 iOS底层

【Vue2.x 源码学习】第二十五篇 - 数组依赖收集的原理

Brave

源码 vue2 8月日更

Vue进阶(五):与 Vuex 的第一次接触

No Silver Bullet

Vue vuex 8月日更

80后程序员感慨中年危机,如何设计一个优雅的RESTFUL的接口

Java 程序员 后端

解决方案|在线自习室

anyRTC开发者

音视频 在线教育 RTC RTM

网络攻防学习笔记 Day95

穿过生命散发芬芳

态势感知 网络攻防 8月日更

当一只「无头苍蝇」又何妨?

非著名程序员

读书笔记 提升认知 个人提升 8月日更

面试官:JVM的运行时数据区了解不?

程序员阿杜

Java JVM JVM、 8月日更

12~18k的前端面试会问个啥?

前端依依

学习 程序员 面试 大前端 经验分享

阿里人,五年心血汇聚而成这份Spring Cloud Alibaba开发手册

Java架构师迁哥

刷完这套200+大厂Java真题手册,成功拿到阿里,京东,美团的offer

Java 编程 架构 面试 架构师

如何洞察出消费者购买的关键时刻

石云升

用户体验 关键时刻 体验设计 8月日更

Nacos注册中心之概要设计

捉虫大师

微服务 nacos 服务发现

【网络安全】渗透工程师面试题总结大全

网络安全学海

面试 网络安全 信息安全 渗透测试 漏洞

Kong-To-APISIX:减轻你的迁移压力

API7.ai 技术团队

开源 网关 kong APISIX

IBM大面积辞退40岁+的员工,瞧一瞧

Java 程序员 后端

这些奥运“黑科技”运用了哪些AI技术?

澳鹏Appen

自动驾驶 机器学习 人脸识别 nlp 数据标注

读书日送书丨关于音视频技术你需要知道的二三事

声网

人工智能

Error SHA256 mismatch

一个大红包

8月日更

Java入门视频教程!Kotlin(2)-泛型与集合

Java 程序员 后端

万字长文 | 16张图解开AbstractQueuedSynchronizer

程序猿阿星

并发编程 AQS 线程安全 多线程并发

【前端 · 面试 】HTTP 总结(四)—— HTTP 状态码

编程三昧

面试 大前端 HTTP 8月日更

Java入门你值得拥有!浅谈Facade外观模式

Java 程序员 后端

金九银十想面BAT?那这些JDK动态代理的面试点你一定要知道

编程菌

Java 编程 程序员 计算机 技术宅

为了进阿里,我通宵达旦三个月,学了这些技术点(附Java思维导图)

Java 编程 架构 面试 架构师

Java入门你值得拥有!天天都是面对对象编程,你真的了解你的对象吗

Java 程序员 后端

带你使用FFMPEG将MP4视频文件转换为GIF

hanaper

Cloud Studio 2.0:云的开端

CODING DevOps

ide DevOps 开发环境 Cloud Studio

SpringBoot 整合 Drools

LeifChen

drools springboot 规则引擎 8月日更 业务规则

试错,然后成长

escray

学习 极客时间 朱赟的技术管理课 8月日更

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