如何在Kubernetes中使用Envoy作为负载均衡器

在如今高度分布式的世界中,单主机架构越来越多地被多个更小的微服务架构所取代(无论好坏),代理和负载均衡技术似乎有了复兴。除之前经典技术了之外,近年来还出现了几种新的代理技术,这些技术以各种技术实现,通过不同的功能推广自己,例如轻松集成到某些云提供商(“云原生”),高性能和低内存占用,或动态配置。
可以说两种最流行的“经典”代理技术是NGINX(C)和HAProxy(C),而其中包含的一些新生力量是Zuul(Java),Linkerd(Rust),Traefik(Go),Caddy(Go)和Envoy(C ++)。
所有这些技术都具有不同的功能集,并且针对某些特定方案或托管环境(例如,Linkerd经过微调以便在Kubernetes中使用)。
在这篇文章中,我不打算对这些进行比较,而只关注一个特定的场景:如何使用Envoy作为Kubernetes中运行的服务的负载均衡器。
Envoy是一个“高性能C ++分布式代理”,最初在Lyft实现,但从那时起就获得了广泛采用。它性能高,资源占用少,支持“控制平面”API管理的动态配置,并提供一些高级功能,如各种负载平衡算法,速率限制,熔断和镜像。
出于多种原因,我选择Envoy作为负载均衡器代理。

  • 除了能够使用控制平面API动态控制外,它还支持简单,硬编码的基于YAML的配置,这对我的目的很方便,并且易于上手。
  • 它内置了对其调用的服务发现技术的支持,该技术STRICT_DNS建立在查询DNS记录的基础上,并期望看到具有IP地址的A记录,用于上游集群的每个节点。这使得Kubernetes的无头服务变得简单易用。
  • 它支持各种负载平衡算法,其中包括:轮询round_robin 最小请求least_request 随机random

在开始使用Envoy之前,我通过service类型的对象访问Kubernetes中的服务LoadBalancer,这是从Kubernetes外部访问服务的一种非常典型的方式。负载均衡器服务的确切工作方式取决于托管环境。 如果它首先支持它。我使用的是Google Kubernetes Engine,其中每个负载均衡器服务都映射到TCP级别的Google Cloud负载均衡器,该负载均衡器仅支持轮询round_robin算法。

1.为应用程序创建Headless Service

在Kubernetes中有一种称为Headless Service的特定服务,恰好与Envoy的STRICT_DNS服务发现模式一起使用非常方便。

Headless Service不提供单个IP和负载平衡到底层pod,而是它只有DNS配置,它为我们提供A记录,其中包含与标签选择器匹配的所有pod的pod的IP地址。
此服务类型旨在用于我们希望实现负载平衡以及自己维护与上游pod的连接的场景,这正是我们可以使用Envoy执行的操作。
我们可以通过设置.spec.clusterIP字段来创建Headless Service "None"。因此,假设我们的应用程序pod具有app标签myapp,我们可以使用以下yaml创建Headless Service。

apiVersion: v1
kind: Service
metadata:
  name: myapp
  namespace: default
spec:
  clusterIP: None
  ports:
  - name: web
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: myapp
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata: 
  name: myapp
  namespace: default
spec:
  replicas: 3
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: nginx:1.10
        ports:
        - containerPort: 80

myapp运行情况

root@k8s-master-1:~# kubectl get pod,svc -n default -o wide
NAME                               READY   STATUS    RESTARTS   AGE    IP             NODE           NOMINATED NODE   READINESS GATES
pod/myapp-c78bcd8fb-fkkfh          1/1     Running   0          31m    172.20.3.103   192.168.2.13   <none>           <none>
pod/myapp-c78bcd8fb-plnkt          1/1     Running   0          126m   172.20.2.62    192.168.2.12   <none>           <none>
pod/myapp-c78bcd8fb-s87sv          1/1     Running   0          31m    172.20.1.207   192.168.2.11   <none>           <none>
pod/myapp-envoy-696b6d764d-nm6lv   1/1     Running   1          18h    172.20.3.101   192.168.2.13   <none>           <none>

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)           AGE    SELECTOR
service/kubernetes    ClusterIP   10.68.0.1      <none>        443/TCP           60d    <none>
service/myapp         ClusterIP   None           <none>        80/TCP            122m   app=myapp
service/myapp-envoy   ClusterIP   10.68.246.10   <none>        80/TCP,9901/TCP   18h    app=myapp-envoy

现在,如果我们检查Kubernetes集群内的服务的DNS记录,我们将看到具有IP地址的单独A记录。如果我们有3个pod,我们会看到类似于此的DNS摘要。

root@k8s-master-1:~# kubectl run --attach busybox --rm --image=busybox:1.27 --restart=Never -- sh -c "sleep 4 && nslookup myapp.default"
If you don't see a command prompt, try pressing enter.
Server:    10.68.0.2
Address 1: 10.68.0.2 kube-dns.kube-system.svc.cluster.local

Name:      myapp.default
Address 1: 172.20.2.62 172-20-2-62.myapp.default.svc.cluster.local
Address 2: 172.20.1.207 172-20-1-207.myapp.default.svc.cluster.local
Address 3: 172.20.3.103 172-20-3-103.myapp.default.svc.cluster.local
pod "busybox" deleted

Envoy的STRICT_DNS的服务发现工作原理是,它维护的DNS服务器返回的所有A记录的IP地址,并每两秒钟刷新组IP地址。

2.创建Envoy 镜像

在不提供动态API形式的控制平面的情况下使用Envoy的最简单方法是将硬编码配置添加到静态yaml文件中。
以下是对域名myapp给出的IP地址进行负载均衡的基本配置。

envoy.yaml

admin:
  access_log_path: /tmp/admin_access.log
  address:
    socket_address: { address: 0.0.0.0, port_value: 9901 }

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.http_connection_manager
        config:
          stat_prefix: ingress_http
          route_config:
            name: local_route
            virtual_hosts:
            - name: local_service
              domains: ["*"]
              routes:
              - match: { prefix: "/" }
                route: { host_rewrite: myapp, cluster: myapp_cluster, timeout: 60s }
          http_filters:
          - name: envoy.router
  clusters:
  - name: myapp_cluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    dns_lookup_family: V4_ONLY
    lb_policy: ${ENVOY_LB_ALG}
    hosts: [{ socket_address: { address: ${SERVICE_NAME}, port_value: 80 }}]

docker-entrypoint.sh

#!/bin/sh
set -e

echo "Generating envoy.yaml config file..."
cat /tmpl/envoy.yaml.tmpl | envsubst \$ENVOY_LB_ALG,\$SERVICE_NAME > /etc/envoy.yaml

echo "Starting Envoy..."
/usr/local/bin/envoy -c /etc/envoy.yaml

Dockerfile

FROM envoyproxy/envoy:latest

COPY envoy.yaml /tmpl/envoy.yaml.tmpl
COPY docker-entrypoint.sh /

RUN chmod 500 /docker-entrypoint.sh

RUN apt-get update && \
    apt-get install gettext -y && \
    rm -rf /var/lib/apt/list/* && \
    rm -rf /var/cache/apk/*

ENTRYPOINT ["/docker-entrypoint.sh"]

3.创建Envoy的Deployment

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: myapp-envoy
  labels:
    app: myapp-envoy
spec:
  selector:
    matchLabels:
      app: myapp-envoy
  template:
    metadata:
      labels:
        app: myapp-envoy
    spec:
      containers:
      - name: myapp-envoy
        image: 314315960/myapp-envoyproxy:latest
        imagePullPolicy: IfNotPresent
        env:
        - name: "ENVOY_LB_ALG"
          value: "LEAST_REQUEST"
        - name: "SERVICE_NAME"
          value: "myapp"
        ports:
        - name: http
          containerPort: 80
        - name: envoy-admin
          containerPort: 9901

应用此yaml后,Envoy代理应该可以运行,您可以通过将请求发送到Envoy服务的主端口来访问底层服务。

在此示例中,我仅添加了ClusterIP类型的服务,但如果要从群集外部访问代理,还可以使用LoadBalancer服务或Ingress对象。

image.png

4.Troubleshooting

在Envoy配置文件中,您可以看到admin部分,它配置Envoy的管理端点。这可用于检查有关代理的各种诊断信息。
一些有用的节点:

  • /config_dump: 打印代理的完整配置,这有助于验证pod上是否有正确的配置
  • /clusters: 显示Envoy发现的所有上游节点,以及为每个节点处理的请求数。这对于检查负载平衡算法是否正常工作非常有用。

image.png

5.验证

myapp-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myapp-ingress
  namespace: default
spec:
  rules:
  - host: myapp.k8s.io
    http:
      paths:
      - path: /
        backend:
          serviceName: myapp
          servicePort: web

myapp-envoy-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: myapp-envoy-ingress
  namespace: default
spec:
  rules:
  - host: myapp-envoy.k8s.io
    http:
      paths:
      - path: /
        backend:
          serviceName: myapp-envoy
          servicePort: 80


参考文档:
https://jimmysong.io/posts/envoy-archiecture-and-terminology/
https://blog.markvincze.com/how-to-use-envoy-as-a-load-balancer-in-kubernetes/
https://kubernetes.io/docs/concepts/services-networking/ingress/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,183评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,850评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,766评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,854评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,871评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,457评论 1 311
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,999评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,914评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,465评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,543评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,675评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,354评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,029评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,514评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,616评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,091评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,685评论 2 360

推荐阅读更多精彩内容