GKEのNEG(Network Endpoint Group)とIG(Instance Group)との違い、メリットを整理しました
はじめに
GCP の Cloud Armor について調べていたところ、ドキュメントに出てきた NEG という単語。
「VM インスタンスや NEG に対して WAF 機能を提供する」、とありましたが、NEG とはなんだろう?となってしまったため、 NEG について調べました。
NEG とは?
NEG についての記載があるページを参考にさせていただきました。
- Network Endpoint ( NE ) は Kubernetes の Pod に相当する
- Network Endpoint を複数まとめたグループが Network Endpoint Group ( NEG ) であり、Kubernetes の Service に相当する
- NEG を使うことで Kubernetes の Pod と Service を GCP 側で第一級市民として扱えるようになる
視覚化すると以下のようになります。
= GCP =====================================
+-------------+ +-------+ +---+
|Load Balancer| ----> |NEG | ----> |NE |+
+-------------+ +-------+ +---+|+
^ ^ +---+|
| | +---+
| | ^
| | |
= GKE =|===================|=============|=
| | |
+------------------+ +-------------------+
|Ingress Controller| |NEG Controller |
+------------------+ +-------------------+
| | |
+-------------+ +-------+ +---+
|Ingress | ----> |Service| ----> |Pod|+
+-------------+ +-------+ +---+|+
+---+|
+---+
GKE 上のリソースとして Ingress 、 Service 、 Pod がありますが、 GCP 上にも対になるリソースが生成されます。
NE は Pod に割り当てられている IP + Port のセットで一意となる GCP リソースです。
NEG を作成する NEG Controller
NEG の生成を担当するのは NEG Controller です。
GKE の Master 上で稼働しています。
NEG Controller は ある条件 に合致した Service が存在していた場合に、NEG を生成します。
NEG が作成される Service には、アノテーションの設定が必要
Load Balancer は、 GKE (Google Kubernetes Engine) に Ingress を作成したときに自動的に作成されます。
NEG(+NE) は、GKE に Serivce を作成しても ある条件 を満たさないと作成されません。
その条件というのは、Service に cloud.google.com/neg
から始まる アノテーション を付けるというものです。
apiVersion: v1
kind: Service
metadata:
name: my-svc
annotations:
cloud.google.com/neg: '{"ingress": true}'
spec:
type: ClusterIP
selector:
app: rails
ports:
- port: 80
protocol: TCP
targetPort: 3000
NEG Controller がアノテーションの存在を検知して、 NEG を生成してくれます。 ( おそらくですが、 NEG Controller はアノテーションが設定されていても Ingress が存在していなければ NEG を作らない )
GCP 上の NEG を確認したい
GCP 上に NEG が存在するかどうかは gcloud compute network-endpoint-groups list
コマンドを実行することで確認できます。 ( kubectl
コマンドではないことに注意。 )
試しに所有している GKE プロジェクトに対して実行してみた結果が以下になります。
# 一部情報をマスキングしています
$ gcloud compute network-endpoint-groups list
NAME LOCATION ENDPOINT_TYPE SIZE
k8s1-2c946***-***************************-3000-088839b7 asia-northeast1-b GCE_VM_IP_PORT 2
k8s1-2c946***-****************************-80-9f8f12d7 asia-northeast1-b GCE_VM_IP_PORT 2
k8s1-2c946***-******************************-4000-b93a9e5e asia-northeast1-b GCE_VM_IP_PORT 2
NEG がグルーピングしている NE を確認するためには gcloud compute network-endpoint-groups list-network-endpoints
コマンドを実行します。
$ gcloud compute network-endpoint-groups list-network-endpoints k8s1-2c946***-***************************-3000-088839b7
INSTANCE IP_ADDRESS PORT FQDN
gke-***************************-pool-9b7f1a43-245c 10.124.0.5 3000
gke-***************************-pool-9b7f1a43-pnsc 10.124.1.5 3000
間違いなく、3000 ポートで稼働している Pod が 2 つ存在していて、そちらを指し示しています。
Service リソースにアノテーションを設定したつもりがないが設定されている?
所有 GKE クラスタに NEG が存在していることを確認できました。
しかし気になることが。 僕は Service リソースにアノテーションを設定した記憶がありません。
ところが、既存の Service リソースを確認すると確かにアノテーションが設定されています。
# アノテーションが設定されている
$ kubectl describe svc neg-exist-cluster | grep neg
Annotations: cloud.google.com/neg: {"ingress":true}
cloud.google.com/neg-status:
では他のクラスタは?と確認してみたところ、他の GKE クラスタにはアノテーションが設定されていません。
# 何も表示されない
$ kubectl describe svc neg-not-exist-cluster | grep neg
アノテーションが設定される条件があるはずと思って調べてみると、GKE のドキュメントに記載がありました。
コンテナ ネイティブの負荷分散は、次のすべての条件が満たされている場合、デフォルトで Services に対して有効になります。
- GKE クラスタ 1.17.6-gke.7 以降で作成された Service の場合
- VPC ネイティブ クラスタの使用
- 共有 VPC を使用しない
- GKE ネットワーク ポリシーを使用しない
これらの条件では、Service 内に Pod IP をミラーリングするために
NEG が作成する必要があることを示す cloud.google.com/neg: '{"ingress": true}' が Service に自動的に付けられます。GKE 1.17.6-gke.7+ より前のバージョンで作成された既存の Service には、
サービス コントローラによって自動的にアノテーションが付けられないことに注意してください。
確かに、NEG が生成されているクラスタは v1.18.17-gke.700
で構築したものであり、 生成されていないクラスタは v1.16
のときに Service リソースを生成しています。
NEG を使うべきかどうかについては、 NEG の利用が推奨されているようです。
NEG がデフォルトではないクラスタの場合でも、
コンテナ ネイティブの負荷分散を使用することを強くおすすめしますが、
Service ごとに明示的に有効にする必要があります。
NEG を利用すると何がよいの?
Service リソース生成時にデフォルトで生成される NEG ですが、どんなメリットが有るのでしょう?
Ingress リソースを生成したときに GCP に作られる Load Balancer が Container Native Load Balancing という手法で Pod に対してリクエストを分散するようになります。
従来の負荷分散では、 Instance Group (IG) を利用していました。IG を利用した場合のネットワークパケットは以下のような経路で転送されます。
+- VM Instance --------+
+-------------+ |+--------+ +---+ |
--> |Load Balancer|---+--> ||iptables|--+->|Pod|+ |
+-------------+ | |+--------+ | +---+|+|
| | | +---+||
| | | +---+|
| +------------+---------+
| |
| +- VM Instance --------+
| |+--------+ | +---+ |
+--> ||iptables| +->|Pod|+ |
| |+--------+ +---+|+|
| | +---+||
| | +---+|
| +----------------------+
|
| +- VM Instance --------+
+--> | |
+----------------------+
- Load Balancer へリクエスト
- Load Balancer から VM Instance ( K8S Node ) に対して転送
- K8S Node 内の iptables で Pod へ転送
ここで、 3 の転送処理は自分の Node 内で稼働している Pod だけでなく、 別 Node の Pod へも転送される可能性がある という点に注意が必要です。
iptables をホップする分、また別 Node の Pod へも転送される可能性がある分、ロスがあります。
NEG を利用した Container Native Load Balancing 方式の場合、以下のようになります。
+- VM Instance --------+
+-------------+ | +---+ |
--> |Load Balancer|---+--> | ------------->|Pod|+ |
+-------------+ | | +---+|+|
| | +---+||
| | +---+|
| +----------------------+
|
| +- VM Instance --------+
| | +---+ |
+--> | ------------->|Pod|+ |
| | +---+|+|
| | +---+||
| | +---+|
| +----------------------+
|
| +- VM Instance --------+
+--> | |
+----------------------+
(どういう仕組なのかわかりませんが) Load Balancer は直接 Pod の持つ IP:Port に対してパケットを転送します。
転送効率が良いというわけです。
ひとこと
なかなか長い文章をまとめるのが得意ではないのでわかりにくい、誤りなどあるかと思います。
誤りあれば、お気軽にご指摘ください。
ディスカッション
コメント一覧
まだ、コメントがありません