Carpe Diem

備忘録

NEG(Network Endpoint Group)を使った負荷分散

概要

従来のGKEのロードバランサーはNodeに到達後iptablesで再度負荷分散するという2段階ロードバランシングでした。
これによりレイテンシの増加、分散のばらつきといった問題が生じていました。

f:id:quoll00:20210222013932g:plain

ref: Google Cloud Blog - News, Features and Announcements

しかしNEG(Network Endpoint Group)という機能を使うことで直接Pod宛てに負荷分散を行うことができ、上記の問題を低減することが可能となっています。

f:id:quoll00:20210222014123g:plain

ref: Google Cloud Blog - News, Features and Announcements

今回のそのNEGを実際に利用する方法を紹介します。

環境

  • GKE v1.18.12

NEGの種類

NEGは大きく3つ種類があります

  • Zonal NEG
    • GCE VMやGKE Podsにルーティングしたい
  • Internet NEG
  • Serverless NEG
    • GCPのサーバレスサービス(Cloud Functions/Cloud Run)にルーティングしたい

GKEを使う場合は Zonal NEG を利用します。

詳細な比較は Network endpoint groups overview  |  Load Balancing  |  Google Cloud で確認できます。

またZonal NEGにも2つあり、ざっくり分けるとIngressを用いるNEGか、手動で各々構築するStandalone NEGです。

f:id:quoll00:20210222025616p:plain

ref: Container-native load balancing through standalone zonal NEGs

Standalone NEGの場合はやや構築に手間がかかりますが、その分自由度が高いです。
例えば複数のGKEクラスタにあるServiceをそれぞれ Standalone NEGにすることで、単一のLoad BalancerのBackend Serviceとすることができます。

制限

Zonal NEGを使う上では以下の制限があります。

  • レガシーネットワークでは使えない
  • 内部TCP/UDPロードバランサ、ネットワーク(外部TCP/UDP)ロードバランサでは使えない
    • つまりk8s LoadBalancer Serviceでは使えない
      • つまりNginx Ingressでは使えない
  • 1 NEG あたりのエンドポイント数は10,000。上限引き上げ不可。

ref: ゾーン ネットワーク エンドポイント グループの概要  |  負荷分散  |  Google Cloud

構築

Ingressを使ったZonal NEGを構築してみます。

VPC ネイティブ クラスタの作成

NEGを使うにはVPCネイティブなクラスタを作成する必要があります。

$ gcloud container clusters create neg-demo-cluster \
    --enable-ip-alias \
    --create-subnetwork="" \
    --network=default \
    --zone=asia-northeast1-a

kubectlでアクセスできるようにクレデンシャルを取得しておきます。

$ gcloud container clusters get-credentials neg-demo-cluster --zone asia-northeast1-a

Deployment を作成

次に、クラスタにワークロードをデプロイします。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: neg-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: sample
        image: gcr.io/google-samples/hello-app:2.0
        ports:
        - containerPort: 8080

Serviceの作成

次にServiceを作成します。

ここでcloud.google.com/neg: '{"ingress": true}'アノテーションを付ける必要があります。

apiVersion: v1
kind: Service
metadata:
  name: neg-svc
  annotations:
    cloud.google.com/neg: '{"ingress": true}'
spec:
  type: ClusterIP
  selector:
    app: sample
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080

一定の条件下ではNEGがデフォルトなのでアノテーションは不要です。

Ingressの作成

外部からアクセスできるよう、Ingressを用意します。

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: neg-ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: neg-svc
          servicePort: 80

しばらく待つとグローバルIPが付与されたIngressが作成されます。

f:id:quoll00:20210222023853p:plain

動作検証

NEGが作成されているか確認

上記yamlをapplyするとKubernetes Service に相当する NEG が GCP 側に1つ作られています。

$ gcloud compute network-endpoint-groups list | grep neg-svc
k8s1-ad013dee-default-neg-svc-80-4a6a4d8c                       asia-northeast1-a  GCE_VM_IP_PORT  2

WebコンソールではGCE→ネットワーク エンドポイント グループから確認できます。

f:id:quoll00:20210222023118p:plain

NEGの中にはPodの個数分、Network Endpointが作られています。

$ gcloud compute network-endpoint-groups list-network-endpoints \
  k8s1-ad013dee-default-neg-svc-80-4a6a4d8c \
  --zone=asia-northeast1-a
INSTANCE                                             IP_ADDRESS  PORT  FQDN
gke-a13156-neg-demo-clus-default-pool-3af9a691-qbpl  10.80.0.5   8080
gke-a13156-neg-demo-clus-default-pool-3af9a691-fc6t  10.80.1.6   8080

疎通確認

curlを叩いてみると、ちゃんと疎通できておりかつバランシングされていることが分かります。

$ curl 35.xxx.yyy.zzz
Hello, world!
Version: 2.0.0
Hostname: neg-deployment-d64cb5c65-gmhvq

$ curl 35.xxx.yyy.zzz
Hello, world!
Version: 2.0.0
Hostname: neg-deployment-d64cb5c65-vl489

スケールアウトさせてみる

Pod数を2→4にスケールアウトしてみます。

$ kubectl get po -o wide
NAME                             READY   STATUS    RESTARTS   AGE   IP       
neg-deployment-d64cb5c65-gmhvq   1/1     Running   0          20m   10.80.1.6
neg-deployment-d64cb5c65-kvqzc   1/1     Running   0          95s   10.80.1.7
neg-deployment-d64cb5c65-pp4fj   1/1     Running   0          95s   10.80.2.4
neg-deployment-d64cb5c65-vl489   1/1     Running   0          20m   10.80.0.5

$ gcloud compute network-endpoint-groups list-network-endpoints \
  k8s1-ad013dee-default-neg-svc-80-4a6a4d8c \
  --zone=asia-northeast1-a
INSTANCE                                             IP_ADDRESS  PORT  FQDN
gke-a13156-neg-demo-clus-default-pool-3af9a691-qbpl  10.80.0.5   8080
gke-a13156-neg-demo-clus-default-pool-3af9a691-fc6t  10.80.1.6   8080
gke-a13156-neg-demo-clus-default-pool-3af9a691-fc6t  10.80.1.7   8080
gke-a13156-neg-demo-clus-default-pool-3af9a691-csrq  10.80.2.4   8080

するとPodの個数分Network Endpointが作られていることが確認できます。

まとめ

NEGというコンテナネイティブな負荷分散機能の紹介と使い方を説明しました。

参考