写点什么

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

评论

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

程序员去大公司面试,小程序FMP优化实录,已拿offer入职

欢喜学安卓

android 程序员 面试 移动开发

可能是绝唱!阿里资深工程师深度解读Netty底层核心源码

Java架构追梦

Java 源码 架构 面试 Netty

Go Storage存储包封装

非晓为骁

storage Go 语言

报名倒计时 | 有道技术沙龙,聊聊明星语音背后的故事

有道技术团队

活动

百度直播消息服务架构实践

百度Geek说

手机 直播 移动端

定义结构体访问结构成员的三种方法

Emotion

C 语言性能优化:循环条件i<=n与i!=0的性能差异

1

有道技术岗大揭秘!这么幸福的生活,真的是熬夜掉发Top1的职业吗?

有道技术团队

招聘

从解决Github TimeOut到经典面试题:从输入URL到浏览器显示页面发生了什么?

秦怀杂货店

GitHub TCP 网络 HTTP DNS

我在阿里实习做开源

阿里巴巴云原生

阿里巴巴 云原生 dubbo 个人提升 中间件

2021最新分享三面百度提前批(Java开发岗)面经 已拿Offer

比伯

Java 编程 架构 面试 程序人生

被MySQL慢日志查询搞废了?3分钟教你快速定位慢查询问题!

观测云

云计算

python编译器中出现了绿色波浪线,光标放上去出现的提示是什么意思?

Emotion

为什么python中程序的结果会一直输出,需要怎么解决

Emotion

Go Mysql Driver 集成 Seata-Golang 解决分布式事务问题

阿里巴巴云原生

Java 微服务 云原生 seata Go 语言

Flink 执行引擎:流批一体的融合之路

Apache Flink

flink

阿里面试官:Android开发真等于废人?已拿offer附真题解析

欢喜学安卓

android 程序员 面试 移动开发

一周信创舆情观察(3.15~3.21)

统小信uos

透过 3.0 Preview 看 Dubbo 的云原生变革

阿里巴巴云原生

容器 运维 云原生 dubbo 应用服务中间件

行业资讯 | Android WebView 致安卓应用闪退,mPaaS 助你规避这波 Bug

蚂蚁集团移动开发平台 mPaaS

android webview mPaaS 离线包 UC内核

从无到有实现音视频通讯

anyRTC开发者

ios android 音视频 WebRTC RTC

字节抖音iOS客户端实习 123hr面 面经

iOSer

ios 字节跳动 面试 抖音

为了跳槽刷完1000道Java面试真题,没想到老板直接给我升职了

Java 程序员 架构 面试

OpenKruise 如何实现 K8s 社区首个规模化镜像预热能力

阿里巴巴云原生

Serverless 容器 云原生 k8s 调度

这个GItHub上的Java项目开源了,2021最全的Java架构面试复习指南

Java 程序员 面试

活动 | Apache Pulsar Meetup 欢迎报名

有道技术团队

活动

力扣(LeetCode)刷题,简单题(第13期)

不脱发的程序猿

面试 LeetCode 28天写作 算法面经 3月日更

单账户实时记账能力达2万笔每秒 蚂蚁启用新一代高性能记账引擎

DT极客

LeetCode题解:92. 反转链表 II,迭代,JavaScript,详细注释

Lee Chen

算法 大前端 LeetCode

实现跨生态互联,区块链赋能智能家居新体验

旺链科技

区块链应用 智能家居

实习就参与“服务过亿用户的项目”,是什么体验?

阿里巴巴云原生

开发者 云原生 调度 应用服务中间件 Go 语言

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