kubernetesの無停止運用を意識した検証

こんにちは、ゲーム事業のCTOをやってます白井です。
てっくぼっとに出張してきました。

今回は、現在検討している kubernetes でのゲーム運用についてお話します。

ゲームの運用で必要となる要件として「無停止」があります。

この「無停止」をkubernetesを使ってどのように実現するのか、実現方法を検証した結果をまとめます。
kubernetes
kubernetes自体、耐障害性を持っています。

例えば、kubernetesの最小管理単位としてPodという概念があります。
また、Deploymentという概念によって状態が定義されています。

Pod,Deployment
Pod,Deployment

たとえば、Pod数が3、みたいな形です。

Deployment.yaml
Deploymentのyamlのサンプル replicaに3が設定されている

Deploymentで定義されたPod数をkubernetesは維持するように動きます。

何かしらの理由で一部のPodに障害が起きたときには、すぐに新しいPodを起動します(コンテナをデプロイする)。

そんな便利なkubernetesですが開発が活発なこともあり、ちょっと困ったことがあります。

それは、kubernetes自体のバージョンアップです。
この記事を書いている時点では、1.4.6です。
しかし、マイナーバージョンは、約3ヶ月に1回あがります。

kubernetes自体はクラスタ内にマスターのデーモンとノードのデーモン2つのデーモンで構成されています。

マスターのバージョンは無停止でアップグレードできるのですが、
ノードのバージョンは、バージョンアップ時にダウンタイムが発生する可能性があります。

ダウンタイムが発生する旨の警告がでる
ダウンタイムが発生する旨の警告がでる

これでは、ゲーム運用の要件の無停止が満たせなくなってしまいます。

そこで次のような方法(A)で回避することにしました。

(1)新規NodePoolを作成する

gcloud container node-pools create node-pool-v1.4-nodes --num-nodes=2

NodePoolはNodeのグループです(NodeはPodのホスト、つまりVMインスタンスと思ってください)
※node-pool-v1.4-nodesはNodePool名です

新規NodePoolは最新のkubernetesのバージョンで作成されます

(2)いままでつかっていたNodePoolでは新規Podが作成されないようにする(cordon)
kubectl cordon node-pool-v1.3-node1
kubectl cordon node-pool-v1.3-node2
※ node-pool-v1.3-node1、node-pool-v1.3-node2はNode名

(3)Node上のPodを新しいNodePoolへ移動させる(drain)

kubectl drain node-pool-v1.3-node1
kubectl drain node-pool-v1.3-node2

(4)すべてPodを移動させたら、いままでつかっていたNodePoolを削除する

gcloud container node-pools delete node-pool-v1.3-nodes

以上でバージョンアップ完了です。

では、運用を想定してアプリのデプロイ時の動作を考えてみましょう。

コンテナを使うからといって、マシンリソースを余らせるのはもったいないです。
そのため、通常の運用時では、Node数は必要なPodを立てるのに最低限必要な数しかないと思われます。

デプロイ時のみNode数を増やす運用にします。

現状のkubernetesでは、Node数を減らすときにどのNodeを減らすか指定できません。
(どのNodeにどのPodがのっているのか、管理する必要がない、という思想かもしれません)

そのため、デプロイ時にNodeを増やして、デプロイ後にNodeを減らす、といった操作を行うと、次のようなことが起こる可能性があります。



!!あたらしくデプロイしたPodがのっているNodeが減ってしまう!!

Podが再作成されるまで、サービス停止!

無停止の運用ができなくなってしまいます。

そこで(A)でやったことをデプロイ時にも実行します。
つまり、デプロイ毎にNodePoolを作成するというルールです。

デプロイする前に、Node数を増やすのではなく、新規のNodePoolを作成します。

その後デプロイします。

デプロイがおわったら、いままでつかっていた古い方のNodePoolを削除します。

NodePoolをコンテナのバージョンと結びつけることで、意図しないPodをが再作成されることを防ぐことが出来ます。

これで、運用要件の「無停止」が達成できそうです。

kubernetesは様々な機能、管理する概念が提供されています。

自分たちの運用要件によって、kubernetesの機能を組み合わせた検証結果となります。

今回の検証した内容が、みなさんの参考になれば幸いです。