Kubernetes 集群中使用 Traefik 反向代理

1、Traefik 介绍

在日常工作中,我们经常使用 Nginx、Apache 等工具作为反向代理、负载均衡,而 Træfik 是一个为了让部署微服务更加便捷而诞生的 HTTP 反向代理、负载均衡工具。它支持多种后台 (Docker、Swarm、Kubernetes、Mesos、Consul、Etcd…) 来自动、动态的刷新配置文件,以实现快速地服务发现。在 Kubernetes 集群中使用,可以完全替代 ngxin + Ingress Controller,快速实现服务的暴漏。

引用 Traefik 官网文档 中的一张图片,可以简要说明一下什么是 Traefik。

这里写图片描述

从上图可以看出,在我们日常业务开发中,我们会部署一系列微服务,外部网络要通过 domainpath、负载均衡等转发到后端私有网络中,微服务之所以称为微,是因为它是动态变化的,它会经常被增加、删除、干掉或者被更新。而且传统的反向代理对服务动态变化的支持不是很方便,也就是服务变更后,我们不是很容易立马改变配置和热加载。traefik 的出现就是为了解决这个问题,它可以时刻监听服务注册或服务编排 API,随时感知后端服务变化,自动重新更改配置并热重新加载,期间服务不会暂停或停止,这对于用户来说是无感知的。

Traefik 还有很多特性如下:

  • 速度快
  • 不需要安装其他依赖,使用 GO 语言编译可执行文件
  • 支持最小化官方 Docker 镜像
  • 支持多种后台,如 Docker, Swarm mode, Kubernetes, Marathon, Consul, Etcd, Rancher, Amazon ECS 等等
  • 支持 REST API
  • 配置文件热重载,不需要重启进程
  • 支持自动熔断功能
  • 支持轮训、负载均衡
  • 提供简洁的 UI 界面
  • 支持 Websocket, HTTP/2, GRPC
  • 自动更新 HTTPS 证书
  • 支持高可用集群模式

上一篇文章 初试 Kubernetes 暴漏服务类型之 Nginx Ingress 中大概介绍了 Kubernetes 使用 Nginx Ingress 暴漏服务,接下来我们使用 Traefik 来替代 Nginx + Ingress Controller 来实现反向代理和服务暴漏。

那么二者有什么区别呢?简单点说吧,在 Kubernetes 中使用 nginx 作为前端负载均衡,通过 Ingress Controller 不断的跟 Kubernetes API 交互,实时获取后端 Service、Pod 等的变化,然后动态更新 Nginx 配置,并刷新使配置生效,来达到服务自动发现的目的,而 Traefik 本身设计的就能够实时跟 Kubernetes API 交互,感知后端 Service、Pod 等的变化,自动更新配置并热重载。大体上差不多,但是 Traefik 更快速更方便,同时支持更多的特性,使反向代理、负载均衡更直接更高效。

2、环境、软件准备

Kubernetes 集群中使用 Traefik 反向代理,前提我们需要有一个正常运行的集群服务,这里我采用 kubeadm 搭建的 Kubernetes 集群,具体搭建步骤可以参考我上一篇文章 国内使用 kubeadm 在 Centos 7 搭建 Kubernetes 集群 讲述的比较详细,这里就不做演示了。上边说了 Traefik 提供最小化官方 Docker 镜像,这次就不需要翻墙或者找替代品了哈,去 Docker Hub 下载最新版本的镜像即可。

3、部署 Traefik

在 Kubernetes 上部署 Traefik 很简单,只需 Yaml 创建一下即可。

$ cd /home/wanyang3/k8s/
$ git clone https://github.com/containous/traefik.git
# ll traefik/examples/k8s/
总用量 32
-rw-r--r--. 1 root root 1805 11月  9 16:23 cheese-deployments.yaml
-rw-r--r--. 1 root root  519 11月  9 16:23 cheese-ingress.yaml
-rw-r--r--. 1 root root  509 11月  9 16:23 cheese-services.yaml
-rw-r--r--. 1 root root  504 11月  9 16:23 cheeses-ingress.yaml
-rw-r--r--. 1 root root  978 11月  9 16:23 traefik-deployment.yaml
-rw-r--r--. 1 root root 1128 11月  9 16:23 traefik-ds.yaml
-rw-r--r--. 1 root root  694 11月  9 16:23 traefik-rbac.yaml
-rw-r--r--. 1 root root  466 11月  9 16:43 ui.yaml

traefik/examples/k8s/ 这个目录下就是示例 Traefik 启动所需要的 yaml 文件,Traefik 提供了适配各个类型服务编排的部署方式,kubernetes 启动方式支持 Deployment 和 DaemonSet,二选一都可以。

$ kubectl create -f traefik/examples/k8s/traefik-rbac.yaml
clusterrole "traefik-ingress-controller" created
clusterrolebinding "traefik-ingress-controller" created

$ kubectl create -f traefik/examples/k8s/traefik-deployment.yaml
serviceaccount "traefik-ingress-controller" created
deployment "traefik-ingress-controller" created
service "traefik-ingress-service" created

$ kubectl get pods --all-namespaces -o wide
NAMESPACE     NAME                                         READY     STATUS    RESTARTS   AGE       IP              NODE
kube-system   traefik-ingress-controller-833033881-1lnlt   1/1       Running   0          10s         10.96.4.23      node0.localdomain
...

好了,此时 Traefik 已经启动成功了,它同时启动了 80 和 8080 端口,80 对应的服务端口,8080 对应的 UI 端口,我们可以通过查看服务暴漏端口号浏览器访问下了提供的 UI 界面。

$ kubectl get service --all-namespaces
NAMESPACE     NAME                      CLUSTER-IP       EXTERNAL-IP   PORT(S)                       AGE
default       kubernetes                10.96.0.1        <none>        443/TCP                       2d
kube-system   elasticsearch-logging     10.99.38.47      <none>        9200/TCP                      2d
kube-system   kibana-logging            10.107.203.145   <none>        5601/TCP                      2d
kube-system   kube-dns                  10.96.0.10       <none>        53/UDP,53/TCP                 2d
kube-system   kubernetes-dashboard      10.96.156.22     <nodes>       80:30659/TCP                  2d
kube-system   traefik-ingress-service   10.96.8.191      <nodes>       80:30016/TCP,8080:30960/TCP   3m

访问 http://<node_ip>:<node_port>/dashboard/#/,这里 <node_ip> 可以为 master 或者 node 节点 IP 均可,这里我使用的是 Master IP,如:http://10.222.76.93:30960/dashboard/#/

这里写图片描述

这里写图片描述

初次访问,我们发现 Providers 下 Kubernetes 什么服务都没有,Health里面也没有任何信息,这是因为我们还没有指定任何 Ingress 规则。

4、部署 Traefik UI

从上边可以看到 Traefik 提供了一套简洁的 UI 供我们使用,是由 Angular JS 编写的,它是以 Ingress 方式暴露服务的,只需要 Yaml 创建一下即可。

# 先修改一下 host,默认为 traefik-ui.minikube ,这里我改成 traefik-ui.k8s 更直观些。
vim ui.yaml
...
spec:
  rules:
  - host: traefik-ui.k8s
    http:
      paths:
      - path: /
        backend:
          serviceName: traefik-web-ui
          servicePort: web
...          

$ kubectl create -f ui.yaml
service "traefik-web-ui" created
ingress "traefik-web-ui" created

$ kubectl get service --all-namespaces
NAMESPACE     NAME                      CLUSTER-IP       EXTERNAL-IP   PORT(S)                       AGE
default       kubernetes                10.96.0.1        <none>        443/TCP                       2d
kube-system   elasticsearch-logging     10.99.38.47      <none>        9200/TCP                      2d
kube-system   kibana-logging            10.107.203.145   <none>        5601/TCP                      2d
kube-system   kube-dns                  10.96.0.10       <none>        53/UDP,53/TCP                 2d
kube-system   kubernetes-dashboard      10.96.156.22     <nodes>       80:30659/TCP                  2d
kube-system   traefik-ingress-service   10.96.8.191      <nodes>       80:30016/TCP,8080:30960/TCP   25m
kube-system   traefik-web-ui            10.98.14.250     <none>        80/TCP                        13s

此时,我们不需要刷新浏览器 UI 界面,就可以看到 traefik-ui.k8s/ 已经显示出来了,速度很快,用户无感知。

这里写图片描述

5、部署自定义 Ingress

好了,上边我们通过部署一个 Traefik 提供的 traefik-web-ui 服务,初窥了一下 Traefik,现在我们自定义一个 Ingress 来实现服务暴漏。从已安装的服务列表中可以看到,我们已经安装了很多服务,这里还是选择 kubernetes-dashboard 和 elasticsearch-logging 来演示一下,基于域名访问虚拟主机的 Ingress 配置,Yaml 文件如下。

$ vim dashboard-ela-k8s-traefik.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: dashboard-ela-k8s-traefik
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: dashboard.k8s.traefik
    http:
      paths:
      - path: /  
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
  - host: ela.k8s.traefik
    http:
      paths:
      - path: /  
        backend:
          serviceName: elasticsearch-logging
          servicePort: 9200

$ kubectl create -f dashboard-ela-k8s-traefik.yaml
ingress "dashboard-ela-k8s-traefik" created

$ kubectl get ingress --all-namespaces
NAMESPACE     NAME                        HOSTS                                   ADDRESS   PORTS     AGE
kube-system   dashboard-ela-k8s-traefik   dashboard.k8s.traefik,ela.k8s.traefik             80        25s
kube-system   traefik-web-ui              traefik-ui.k8s                                    80        31m

再看一下 UI 页面,立马更新过来,可以看到刚刚配置的 dashboard.k8s.traefikela.k8s.traefik

这里写图片描述

接下来,看下通过域名下不同的路径转发到不同的服务上去的 Ingress 配置,Yaml 文件如下。

$ vim my-k8s-traefik.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-k8s-traefik
  namespace: kube-system
  annotations:
    kubernetes.io/ingress.class: traefik
    traefik.frontend.rule.type: PathPrefixStrip
spec:
  rules:
  - host: my.k8s.traefik
    http:
      paths:
      - path: /dashboard
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 80
      - path: /kibana
        backend:
          serviceName: kibana-logging
          servicePort: 5601

$ kubectl create -f my-k8s-traefik.yaml
ingress "my-k8s-traefik" created

$ kubectl get ingress --all-namespaces
NAMESPACE     NAME                        HOSTS                                   ADDRESS   PORTS     AGE
kube-system   dashboard-ela-k8s-traefik   dashboard.k8s.traefik,ela.k8s.traefik             80        12m
kube-system   my-k8s-traefik              my.k8s.traefik                                    80        4s
kube-system   traefik-web-ui              traefik-ui.k8s                                    80        43m

注意:这里我们根据路径来转发,需要指明 rule 为 PathPrefixStrip,配置为 traefik.frontend.rule.type: PathPrefixStrip

再看一下 UI 页面,也是立马更新过来,可以看到刚刚配置的 my.k8s.traefik/dashboardmy.k8s.traefik/kibana

这里写图片描述

最后在演示一下更新或删除服务,Traefik 是否能够实时监测的到,我们去 Kubernetes dashboard 上将 dashboard 服务增加两个 pod,操作过程就不多说了,直接看结果吧!

这里写图片描述

这里写图片描述

6、部分特性说明

文章开头列举了一下 Traefik 的众多特性,有很多我还没了解到,目前了解到其中有两个很好的特性。

6.1 自动熔断

在集群中,当某一个服务大量出现请求错误,或者请求响应时间过久,或者返回500+错误状态码时,我们希望可以主动剔除该服务,也就是不在将请求转发到该服务上,而这一个过程是自动完成,不需要人工执行。Traefik 通过配置很容易就能帮我们实现,Traefik 可以通过定义策略来主动熔断服务。

  • NetworkErrorRatio() > 0.5:监测服务错误率达到50%时,熔断。
  • LatencyAtQuantileMS(50.0) > 50:监测延时大于50ms时,熔断。
  • ResponseCodeRatio(500, 600, 0, 600) > 0.5:监测返回状态码为[500-600]在[0-600]区间占比超过50%时,熔断。

6.2 负载均衡策略

Traefik 提供两种负载均衡策略支持。一种是 wrr(加权轮训调度算法),一种是 drr(动态加权循环调度算法)。

从上边截图右侧我们看到提示 Load Balancer: wrr,默认的策略为根据权重轮训调度,从图上可以看出,新创建的 service 权重都是一样为 1,这样的话,请求会平均分给每个服务,但是这样很多时候会出现资源分配不均衡的问题,比如由于集群中每个机器配置不一样,而且服务消耗不一样,假设 A 资源使用率已经很高,而 B 属于空闲状态,如果还是均摊到每个服务的话,会加重 A 的负荷,这时候因该有一种策略能够主动识别并分担更多流量到 B 才对。

drr 就更加智能,它是一种动态加权轮训调度方式,它会记录一段时间内转发到 A 的请求数,跟转发到 B 的请求数对比,转发数量多,说明处理速度快,响应时间快。如果 A 处理请求速度比 B 快,那么就会调整 A 的权重,接下来的一段时间,就会转发更多请求给 A,相应的 B 的转发就少一些。整个过程都在不断的调整权重,实现请求的合理分配,从而达到资源使用最大化。

参考资料

猜你喜欢

转载自blog.csdn.net/bbwangj/article/details/82558076