メインコンテンツにスキップ

Kubernetes の Service とはなんなのか —— iptables を確認して実態を探る

疑問

Kubernetesのserviceとはなんなのか?

「Podだけだと再起動が発生した時にIPが変わるので、Service経由でアクセスするのが良い」

これは、よく言われることだが、実際にServiceはどのようにPodにリクエストを送っているのか?、また負荷分散をどのように実現しているのかを探る。

Serviceには3つのタイプがある

  • ClusterIP
    • クラスタ内で使用できる仮想IP
    • FQDN(Fully Qualified Domain Name)が生成される
      • admin.namespace.svc.cluster.localみたいなやつ
  • NodePort
    • クラスタ外部からもアクセスが可能
  • LoadBalancer
    • Kubernetesが提供しているLBではなく外部のLBを利用して負荷分散する(AWSやGoogle Cloudなど)
    • NodePortを使用する方法と、ClusterIPを使用する方法がある

実験

以下のServiceを作成する。

apiVersion: v1
kind: Service
metadata:
  name: clusterip-svc
spec:
  type: ClusterIP
  selector:
    app: api-container
  ports:
    - protocol: TCP
      port: 5555
      targetPort: 5000

nodeに入り、iptablesを見ると、

# iptables -L -nv -t nat | grep lb-svc | grep KUBE-SEP
    0     0 KUBE-SEP-37QFZ7WS6YCMEGGL  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/lb-svc -> 10.244.1.3:5000 */ statistic mode random probability 0.33333333349
    0     0 KUBE-SEP-6SMVGQRJXVZRRJRN  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/lb-svc -> 10.244.1.4:5000 */ statistic mode random probability 0.50000000000
    0     0 KUBE-SEP-TQN37TW44HP3RSKY  0    --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/lb-svc -> 10.244.2.3:5000 */
  • /* default/lb-svc -> 10.244.1.3:5000 */ statistic mode random probability 0.33333333349
  • /* default/lb-svc -> 10.244.1.4:5000 */ statistic mode random probability 0.50000000000
  • /* default/lb-svc -> 10.244.2.3:5000 */

という3行の記述が存在している。

iptablesとは⇩

/* default/lb-svc -> 10.244.1.3:5000 */ statistic mode random probability 0.33333333349
/* default/lb-svc -> 10.244.1.4:5000 */ statistic mode random probability 0.50000000000
/* default/lb-svc -> 10.244.2.3:5000 */

これを解説すると

  1. 33% の確率で 10.244.1.3 にルーティング
  2. それ以外のリクエスト(100-33 = 約 67%)のうち 50%(= 約 33%)が 10.244.1.4 にルーティング
  3. 残りが 10.244.2.3 にルーティング(結果的に約 33%)

という挙動となる。

結果として、均等なラウンドロビン的な動作になる。

つまり、3分の1の確率で特定のPodにリクエストが流れるという負荷分散が行われている。このようにServiceの負荷分散はiptablesを使用しているため、L3/4での負荷分散である。

(L7負荷分散についてははIngressが行っている)

ここに全てが書いています

つまり、Serviceの実態はプロセスではなくiptables?→YES

Serviceのyamlをapplyした時の挙動は?

まずはk8sの構成要素について述べる必要がある

  • etcd
    • KVS
    • クラスタの全ての情報を保存する
    • kube-apiserverからのみアクセスできる
  • kube-apiserver
    • etcdにアクセスしてデータを管理
    • 他コンポーネントはkube-apiserverに定期的にあるべき状態を問い合わせて差分があれば更新する
  • kube-scheduler
    • workerに対するPodのスケジューリングを担当
    • manifestに書かれているresouce.cpu、resource.limitを考慮してノードの空き状況を確認する
  • kube-controller-manager
  • kube-proxy
  • kubelet
    • ノードで動くコンテナを監視/管理する

Serviceが作成されるまでは以下の流れである。

  1. Serviceのyamlをapply
  2. api-serverがetcdを変更
  3. kube-proxyがControl Planeのapi-serverを監視しており、kube-proxyがiptablesを変更する
  4. Podが除外/生成されても、api-serverを監視しているのでkube-proxyがiptablesを書き換えてルーティングが正しく機能し続ける

Serviceの実態がiptalbesというのは、公式ドキュメントにiptablesプロキシモード (https://kubernetes.io/ja/docs/concepts/services-networking/service/#proxy-mode-iptables ) として書かれている。

L7の負荷分散どうやってするの?という問いについてはIngressが行っている。

Ingressについてはまた別の機会に。

6 min read
ネットワーク