如何在Kubernetes中使用Envoy作為負(fù)載均衡器

在如今高度分布式的世界中,單主機(jī)架構(gòu)越來(lái)越多地被多個(gè)更小的微服務(wù)架構(gòu)所取代(無(wú)論好壞),代理和負(fù)載均衡技術(shù)似乎有了復(fù)興。除之前經(jīng)典技術(shù)了之外,近年來(lái)還出現(xiàn)了幾種新的代理技術(shù),這些技術(shù)以各種技術(shù)實(shí)現(xiàn),通過(guò)不同的功能推廣自己,例如輕松集成到某些云提供商(“云原生”),高性能和低內(nèi)存占用,或動(dòng)態(tài)配置。
可以說(shuō)兩種最流行的“經(jīng)典”代理技術(shù)是NGINX(C)和HAProxy(C),而其中包含的一些新生力量是Zuul(Java),Linkerd(Rust),Traefik(Go),Caddy(Go)和Envoy(C ++)。
所有這些技術(shù)都具有不同的功能集,并且針對(duì)某些特定方案或托管環(huán)境(例如,Linkerd經(jīng)過(guò)微調(diào)以便在Kubernetes中使用)。
在這篇文章中,我不打算對(duì)這些進(jìn)行比較,而只關(guān)注一個(gè)特定的場(chǎng)景:如何使用Envoy作為Kubernetes中運(yùn)行的服務(wù)的負(fù)載均衡器。
Envoy是一個(gè)“高性能C ++分布式代理”,最初在Lyft實(shí)現(xiàn),但從那時(shí)起就獲得了廣泛采用。它性能高,資源占用少,支持“控制平面”API管理的動(dòng)態(tài)配置,并提供一些高級(jí)功能,如各種負(fù)載平衡算法,速率限制,熔斷和鏡像。
出于多種原因,我選擇Envoy作為負(fù)載均衡器代理。

  • 除了能夠使用控制平面API動(dòng)態(tài)控制外,它還支持簡(jiǎn)單,硬編碼的基于YAML的配置,這對(duì)我的目的很方便,并且易于上手。
  • 它內(nèi)置了對(duì)其調(diào)用的服務(wù)發(fā)現(xiàn)技術(shù)的支持,該技術(shù)STRICT_DNS建立在查詢DNS記錄的基礎(chǔ)上,并期望看到具有IP地址的A記錄,用于上游集群的每個(gè)節(jié)點(diǎn)。這使得Kubernetes的無(wú)頭服務(wù)變得簡(jiǎn)單易用。
  • 它支持各種負(fù)載平衡算法,其中包括:輪詢r(jià)ound_robin 最小請(qǐng)求least_request 隨機(jī)random 。

在開(kāi)始使用Envoy之前,我通過(guò)service類型的對(duì)象訪問(wèn)Kubernetes中的服務(wù)LoadBalancer,這是從Kubernetes外部訪問(wèn)服務(wù)的一種非常典型的方式。負(fù)載均衡器服務(wù)的確切工作方式取決于托管環(huán)境。 如果它首先支持它。我使用的是Google Kubernetes Engine,其中每個(gè)負(fù)載均衡器服務(wù)都映射到TCP級(jí)別的Google Cloud負(fù)載均衡器,該負(fù)載均衡器僅支持輪詢r(jià)ound_robin算法。

1.為應(yīng)用程序創(chuàng)建Headless Service

在Kubernetes中有一種稱為Headless Service的特定服務(wù),恰好與Envoy的STRICT_DNS服務(wù)發(fā)現(xiàn)模式一起使用非常方便。

Headless Service不提供單個(gè)IP和負(fù)載平衡到底層pod,而是它只有DNS配置,它為我們提供A記錄,其中包含與標(biāo)簽選擇器匹配的所有pod的pod的IP地址。
此服務(wù)類型旨在用于我們希望實(shí)現(xiàn)負(fù)載平衡以及自己維護(hù)與上游pod的連接的場(chǎng)景,這正是我們可以使用Envoy執(zhí)行的操作。
我們可以通過(guò)設(shè)置.spec.clusterIP字段來(lái)創(chuàng)建Headless Service "None"。因此,假設(shè)我們的應(yīng)用程序pod具有app標(biāo)簽myapp,我們可以使用以下yaml創(chuàng)建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運(yùn)行情況

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

現(xiàn)在,如果我們檢查Kubernetes集群內(nèi)的服務(wù)的DNS記錄,我們將看到具有IP地址的單獨(dú)A記錄。如果我們有3個(gè)pod,我們會(huì)看到類似于此的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的服務(wù)發(fā)現(xiàn)工作原理是,它維護(hù)的DNS服務(wù)器返回的所有A記錄的IP地址,并每?jī)擅腌娝⑿陆MIP地址。

2.創(chuàng)建Envoy 鏡像

在不提供動(dòng)態(tài)API形式的控制平面的情況下使用Envoy的最簡(jiǎn)單方法是將硬編碼配置添加到靜態(tài)yaml文件中。
以下是對(duì)域名myapp給出的IP地址進(jìn)行負(fù)載均衡的基本配置。

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.創(chuàng)建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

應(yīng)用此yaml后,Envoy代理應(yīng)該可以運(yùn)行,您可以通過(guò)將請(qǐng)求發(fā)送到Envoy服務(wù)的主端口來(lái)訪問(wèn)底層服務(wù)。

在此示例中,我僅添加了ClusterIP類型的服務(wù),但如果要從群集外部訪問(wèn)代理,還可以使用LoadBalancer服務(wù)或Ingress對(duì)象。

image.png

4.Troubleshooting

在Envoy配置文件中,您可以看到admin部分,它配置Envoy的管理端點(diǎn)。這可用于檢查有關(guān)代理的各種診斷信息。
一些有用的節(jié)點(diǎn):

  • /config_dump: 打印代理的完整配置,這有助于驗(yàn)證pod上是否有正確的配置
  • /clusters: 顯示Envoy發(fā)現(xiàn)的所有上游節(jié)點(diǎn),以及為每個(gè)節(jié)點(diǎn)處理的請(qǐng)求數(shù)。這對(duì)于檢查負(fù)載平衡算法是否正常工作非常有用。

image.png

5.驗(yàn)證

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/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1、基礎(chǔ)架構(gòu) 1.1 Master Master節(jié)點(diǎn)上面主要由四個(gè)模塊組成:APIServer、scheduler...
    阿斯蒂芬2閱讀 11,148評(píng)論 0 44
  • Kubernetes是Google開(kāi)源的容器集群管理系統(tǒng),其提供應(yīng)用部署、維護(hù)、 擴(kuò)展機(jī)制等功能,利用Kubern...
    devabel閱讀 6,526評(píng)論 0 13
  • kubernetes Service 參考文獻(xiàn):https://blog.csdn.net/watermelonb...
    碼二哥閱讀 2,723評(píng)論 1 5
  • 一、 K8s 是什么? Kubernetes(k8s)是自動(dòng)化容器操作的開(kāi)源平臺(tái),這些操作包括部署,調(diào)度和節(jié)點(diǎn)集群...
    loveroot閱讀 6,711評(píng)論 1 21
  • 摘要:Istio是一個(gè)用于連接、管理以及安全化微服務(wù)的開(kāi)放平臺(tái), 提供了一種簡(jiǎn)單的方式用于創(chuàng)建微服務(wù)網(wǎng)絡(luò),并提供負(fù)...
    暖夏未眠丶閱讀 3,024評(píng)論 0 1

友情鏈接更多精彩內(nèi)容