LoginSignup
16
3

More than 3 years have passed since last update.

一見普通なのにKubernetesを破壊するyaml

Last updated at Posted at 2019-12-08

まずはこちらをご覧ください

お分かりいただけただろうか?

  • instance-1がmaster, instance-2がnodeのk8sクラスタ上で
  • kubectl create -fでyamlを投げた
    • yamlの中身はinstance-2のIPをexternalIPに持つService
投げたdestroy.yaml
apiVersion: v1
kind: Service
metadata:
  name: destroy
spec:
  ports:
  - port: 6666
  externalIPs:
  - 10.128.0.9 # ip of instance-2
  • するとinstance-2が落ちた
  • instance-2にSSHするとなぜかinstance-1にログインした

一見普通のyamlなのになぜ?

解説

この現象は次の要素を組み合わせると起きます

  • kube-proxy mode に IPVS modeを指定したKubernetesクラスタ
  • externalIPにノードのIPを指定したサービスを作る

kube-proxy mode, IPVS mode, externalIPについて説明してから、
なぜその組み合わせがノード障害を起こすのか見ていきます

kube-proxy modeとは?

  • Kubernetesdでは、Serviceをトラフィックの受け口として複数Podへのネットワークの振り分けが実現できます
    • クライアントはServiceのIPを介することで、Podにアクセスできます
  • この振り分けの実現方法を指定するのが kube-proxy mode です。
    • デフォルトではiptablesを使うiptables proxy modeです
    • IPVSというLinux Kernelのロードバランサ機能を用いるのがIPVS proxy mode です
      • v1.11でGAになりました

image.png

IPVS modeの挙動

IPVSは次の2つのコンポーネントを組み合わせてロードバランスを実現します

  • Virtual Server(IPVSサーバー): トラフィックの受け口
  • Real Server: トラフィックの転送先

IPVSでServiceのトラフィックの振り分けを実装することを考えると、
Real ServerにはPodを指定すればよいですが、IPVSサーバーに相当するものがありません。
image.png

そこで、KubernetesではノードをIPVSサーバーにしてしまいます。kube-ipvs0というダミーのインターフェース(NIC)を作り、
ServiceのIPはそのインターフェースに割り当てます

image.png

ExternalIPとは

  • デフォルトではServiceにはKubernetes内部でのみ使用可能なIPアドレスであるClusterIPだけが自動で割り当てられます
    • Kubernetes外部からはPodにアクセスできません
  • 外部からアクセス可能なIPをサービスに紐づけるのがExternalIPです
    • nodeのIPを指定することで、nodeのIPを介してPodへアクセスできるようになります

以上でやっと、冒頭の障害はなぜ起きるのかを説明できる準備ができました

冒頭の障害はなぜ起きるのか

  • destroy.ymlを投げると、クラスタは次の状態になっています
    • 作成するサービスのExternalIPにinstance-2のIPを指定しています
    • ipvsモードでは、サービスのipをノードのkube-ipvs0インターフェースに割り当てます
    • そのため、instance-1kube-ipvs0がExternalIPであるinstance-2のIPを持ってしまいます
      • instance-1instance-2の通信はすべてkube-ipvs0に吸収され、instance-1に戻ってしまいます
        • 通信不能でinstance-2downとKubernetesが判断
        • instance-2にsshするとinstance-1にログイン

image.png

補足

自分のクラスタのkube-proxy modeの設定を確認する方法

  • masterで次を実行すると確認できます
kubectl get configmap kube-proxy -n kube-system -o yaml | grep 'mode:'

IPVSモードは必要?

大規模環境では有効です

  • iptablesモードは次の理由から、大規模なクラスタでは重くなってしまいます
    • Podやサービスが増えるほどにiptablesのルールが大量に増える
    • パケットの転送はiptablesのテーブルを辿りながらマッチするルールを探索することになり、ルールが多いほど転送も重くなる(シーケンシャルリスト)
  • そのためIPVSモードが導入されました。
    • IPVSはハッシュテーブルのため、iptablesのような負荷は起きません

参考

16
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
3