なぜGKEのノード自動アップグレードでアプリケーションサービスが停止するのか

概要

GKEに用意されているノードの自動アップグレードは便利ですが、インスタンスの再起動を考慮していない構成・設定だとアプリケーションサービスが停止します。
解決している問題は少ないですがアプリケーションサービスが停止するケースと解決方法をまとめました。

環境

  • Kubernetes(GKE): >= v1.6

アプリケーションサービスが停止するケース

Podの配置が偏っている

spec.replicas: 2のDeploymentをapplyすると、以下の図のように1つのインスタンスに偏るケースが発生します。
image.png

ノードのアップグレードは1台づつkubectl drainするため、PodAが同じタイミングでterminateされます。
image.png

この状態になるとPodAと通信ができないので、アプリケーションサービスの停止につながります。

解決方法

  • PodDisruptionBudgetを設定する

    • kubectl drain実行時にmaxAvailableを設定することでPodの起動数を調整可能
    • minAvailableを利用する場合、spec.replicasの数値が小さいとALLOWED DISRUPTIONSの数値が0になるので注意

    image.png

  • PodAffinityを設定する

    • 必須ではないがアップグレード時間が短縮し、耐障害が向上

Podの配置が偏っている(kube-dns)

namespace=kube-system のkube-dnsについても同様の問題が発生します(GKE v1.6で確認)。
前の問題と同様にPodDisruptionBudgetを設定することは可能です。
しかしEvict処理で別インスタンスに移動したPodがなぜかterminateされ、kubectl drainの処理がタイムアウトするまで処理が停止します。
これはkube-dns-autoscalerが独自にkube-dnsのPodをコントロールしているためだと思います。

解決方法

解決できていません。
kube-dnsにPodDisruptionBudgetの設定するIssueもあるので将来的には解消されると思います。
kube-dnsの起動は数秒なので、10秒程度のダウンタイムを許容できるアプリケーションサービスであれば問題になりません。
kube-dnsdelete podすることで、インスタンスを移動させる事も可能ですが、アップグレード中に再び偏る可能性があるので効果は薄いです。

Statefulなアプリケーションの再起動処理が考慮されていない

これは単純に永続化が必要なデータにPersistentVolumeの設定がされていないミスや、StatefulSetsなアプリケーション、ミドルウェアの初期化スクリプトが漏れているケースです。
例えばRedisClusterの場合、init-containersの処理でクラスターに復帰したり、リシャーディングするスクリプトが必要となります。
解決方法も個々の対応となるので本記事には記載しません。

ノード数が3未満になっている

クラスターを作るときにノード数が3未満だと以下の警告がでます。
image.png
理由が記載されいませんが、n1-standard-16のなどの高いリソースを持つマシーンタイプ2台でも同じ警告がでるため、リソース以外の理由が考えられます。

解決方法

深く考えることをやめて、ノード数を3以上にする。

その他のアプリケーションサービスが停止するケース

  • ネットワーク関連のエラーが発生してしまう
    • Golangアプリでgetsockopt: no route to hostのエラーが発生
      • 名前解決まではできていたが詳しくは未調査

備考

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.