Posted at

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

More than 1 year has passed since last update.


概要

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のエラーが発生


      • 名前解決まではできていたが詳しくは未調査






備考