nFact

n!

GKEのRegional Clusters(Beta)を試してみた

この記事はGoogle Cloud Platform Advent Calendar 2017 20日目の記事です。

先日、GKEにRegional Clustersと呼ばれる機能がBetaで発表されていたようです。

この記事では、Regional Clustersを実際に立ててみて、既存のクラスタとどのような違いがあるのかを試してみようと思います。
※Beta版の機能のため内容に変更が入る可能性があります。この記事は12月16~19日に書いたので、その時点での情報になります。

TL;DR

  • マスタノードをリージョン内のゾーンに分散させて可用性を向上させる仕組みです。
  • クラスタのアップグレード中とかでもkubectlが操作できるのは嬉しい!
  • クラスタに対する操作は通常のクラスタと比べて時間がかかるようです。

Regional Clusterとは

Regional Clustersは(1リージョン内の)各ゾーンにマスタノードを分散させることで可用性を高める仕組みのことです(すぐ上の方に書きましたが)。
具体的には、ゾーン障害やマスタのアップグレード等によるマスタのダウンタイムをゼロもしくは最小限に抑えることができるようです。

現行GKEでは、マスタノードは選択したゾーンに1つだけ動作させることができます。そのため、マスタノードが動作しているゾーンで障害が発生してしまった場合はマスタがダウンしてしまいます。
一方、Regional Clustersは1リージョン内の3ゾーンにマスタを分散させた状態で動作します。各マスタはLoad Balancer経由でのアクセスとなり、仮にゾーン障害等でどこかのマスタがダウンしてしまっても、別のマスタが応答するので問題ない、というところでしょうか。

f:id:noko_k:20171219192151p:plain:h400
引用元: Multi-Zone and Regional Clusters

構築

早速ですが比較のために、通常のGKEクラスタとRegional Clustersを構築します。

設定が異なるのは下記のみです。

現行GKEクラスタ Regional Clusters
ロケーション ゾーン(asia-northeast1-b) リージョン(asia-northeast1)

ほかは極力同じような設定にしています。

Regional Clustersの構築

先にRegional Clustersを構築します。 通常のクラスタでは、構築するロケーションを --zone "asia-northeast1-b" のように設定しますが、
Regional Clustersではゾーンではなくリージョンを設定するという点で違いがあり、--region "asia-northeast1"のようなオプションで指定します。
構築するロケーション(ゾーンかリージョンか)によって、現行GKEクラスタとなるかRegional Clustersになるか違いが出てくるようです。

Cloud Consoleの場合はKubernetesのクラスタ作成時のこの部分の選択肢が先日から増えていて、「リージョン」を選択するとRegional Clustersになります。

f:id:noko_k:20171219215806p:plain:h350

※ここから出てくるコマンドは、Cloud Shellで実行しています。また、Regional ClustersはまだBeta版なのでgcloud beta を用いる必要があります。

$ gcloud beta container clusters create "regional-cluster" \
--region "asia-northeast1" \
--cluster-version "1.7.11-gke.0" \
--machine-type "n1-standard-1" \
--image-type "COS" \
--num-nodes "1"

Regional Clustersでは、デフォルトでマルチゾーンクラスタのように各ゾーンに num-nodes で指定した数だけノードが立ちます。
上記のコマンドを実行した場合、asia-northeast1-a、b、cにノードが1台ずつ(計3台)立ちます。

asia-northeast1の場合はゾーンが3つあるのですべてのゾーンに分散しますが、ゾーンが4つ存在するus-central1は、4ゾーンではなくGKEが選択した3ゾーンで分散するようです。

※Regional Clustersを構築するときに、このような警告が出て進めなくなることがあります。

Warning: you invoked `gcloud beta`, but with current configuration 
Kubernetes Engine v1 API will be used instead of v1beta1 API.
If you intended to use v1beta1 API instead, please set 
container/use_v1_api_client property to false.

Do you want to continue (Y/n)?  

ERROR: (gcloud.beta.container.clusters.create) ResponseError: code=400, message='asia-northeast1' is not a valid zone.

メッセージに記載されているとおり、container/use_v1_api_clientプロパティにfalseセットすると実行できるようになります。 Beta版APIを利用するときに必要な設定のようですね。

$ gcloud config set container/use_v1_api_client false
Updated property [container/use_v1_api_client].
$ gcloud beta container ...

現行GKEクラスタの構築

同じように、現行GKEの通常のクラスタを構築してみましょう。

現行GKEクラスタの構築で利用したコマンド列です。

$ gcloud beta container clusters create "single-master-cluster" \
--zone "asia-northeast1-b" \
--cluster-version "1.7.11-gke.0" \
--machine-type "n1-standard-1" \
--image-type "COS" \
--num-nodes "1" \
--node-locations "asia-northeast1-b","asia-northeast1-a","asia-northeast1-c"

今回はマスタに対する検証なのでノードはあまり関係無いと思うのですが、なんとなく同じ台数のノードがないといけない気がしたので、--node-locationsを追加してマルチゾーンクラスタとして構築しています。
現行のGKEはマルチゾーンクラスタに設定したとしても、増えるのはワーカーノードだけで、asia-northeast1-bに1台のみマスタノードが構築されます。

これで、2つのクラスタを準備できました。

$ gcloud container clusters list
NAME                   LOCATION           MASTER_VERSION  MASTER_IP      MACHINE_TYPE   NODE_VERSION  NUM_NODES  STATUS
regional-cluster       asia-northeast1    1.7.11-gke.0    xxxxxxxxxxxxx  n1-standard-1  1.7.11-gke.0  3          RUNNING
single-master-cluster  asia-northeast1-b  1.7.11-gke.0    xxxxxxxxxxxxx  n1-standard-1  1.7.11-gke.0  3          RUNNING

検証

クラスタが構築できたので、検証していきましょう。

※Regional Clustersがゾーン障害に強くなったとは言えゾーン障害を起こして検証することは Google側でタイミングよく何か大きく事故ってもらわないと 非常に難しいので、今回は構築した2つのクラスタに対して、

  • デフォルトノードプールのオートスケールOFF -> ON
  • マスタを1.7.11-gke.0 -> 1.8.4-gke.0へアップグレード

の操作を行っている最中に、GKE上で動いているサービス(Wordpress)がちゃんとレスポンスを返してくれるかと、
別セッションから接続したBashでkubectlが操作できるかどうかについて調べていきます。

準備

検証用のWordpress構築

今回はサクッと構築したいのでHelmを利用してWordpressを立てます。

資格情報の取得

$ gcloud container clusters get-credentials \ 
> single-master-cluster \
> --zone asia-northeast1-a \ 
> --project nfact-sandbox-2
Fetching cluster endpoint and auth data.
kubeconfig entry generated for single-master-cluster.

Helmの初期化

$ helm init
$HELM_HOME has been configured at /home/nokok_kz/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!

これで構築したクラスタでHelmが使えるようになりました。

Wordpressのインストール

$ helm install stable/wordpress
NAME:   whimsical-dolphin
LAST DEPLOYED: Sat Dec 16 15:23:40 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/PersistentVolumeClaim
NAME                         STATUS   VOLUME    CAPACITY  ACCESS MODES  STORAGECLASS  AGE
whimsical-dolphin-mariadb    Pending  standard  1s
whimsical-dolphin-wordpress  Pending  standard  1s

==> v1/Service
NAME                         TYPE          CLUSTER-IP    EXTERNAL-IP  PORT(S)                     AGE
whimsical-dolphin-mariadb    ClusterIP     10.23.249.67  <none>       3306/TCP                    1s
whimsical-dolphin-wordpress  LoadBalancer  10.23.242.54  <pending>    80:32213/TCP,443:30728/TCP  1s

==> v1beta1/Deployment
NAME                         DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
whimsical-dolphin-mariadb    1        1        1           0          1s
whimsical-dolphin-wordpress  1        1        1           0          1s

==> v1/Pod(related)
NAME                                          READY  STATUS   RESTARTS  AGE
whimsical-dolphin-mariadb-1518259378-2sv6c    0/1    Pending  0         1s
whimsical-dolphin-wordpress-3568978032-p7zs4  0/1    Pending  0         1s

==> v1/Secret
NAME                         TYPE    DATA  AGE
whimsical-dolphin-mariadb    Opaque  2     1s
whimsical-dolphin-wordpress  Opaque  2     1s

==> v1/ConfigMap
NAME                             DATA  AGE
whimsical-dolphin-mariadb        1     1s
whimsical-dolphin-mariadb-tests  1     1s


NOTES:
1. Get the WordPress URL:

  NOTE: It may take a few minutes for the LoadBalancer IP to be available.
        Watch the status with: 'kubectl get svc --namespace default -w whimsical-dolphin-wordpress'

  export SERVICE_IP=$(kubectl get svc --namespace default whimsical-dolphin-wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  echo http://$SERVICE_IP/admin

2. Login with the following credentials to see your blog

  echo Username: user
  echo Password: $(kubectl get secret --namespace default whimsical-dolphin-wordpress -o jsonpath="{.data.wordpress-password}" | base64 --decode)

しばらく待つと、Wordpressが立ち上がります。

すべてのPodがRunningとなるのを待ってから、

echo $(kubectl get svc --namespace default whimsical-dolphin-wordpress -o jsonpath='{.status.loadBalancer.ingress[0].ip}')

とすると立ち上がっているWordpressIPアドレスが表示されます。

アクセスしてみると、

image

無事立ち上がっていることがわかりましたので、この状態で検証をしてみます。(regional-clustersの方も同様に設定してWordpressを立ち上げます)

簡易監視プログラムの作成

現行GKEクラスタとRegional Clusterで立ってるWordpressに対して、curlでアクセスし続ける簡易的なShell Scriptを準備しました。

現行GKEクラスタ

$ cat connect_single.sh 
#!/bin/bash
echo -n `(date "+%Y-%m-%d %H:%M:%S")`" : " >> SINGLE_HISTORY
curl --connect-timeout 0.5 -s http://xxx.xxx.xxx.xxx/ -o /dev/null ; echo $? >> SINGLE_HISTORY &

Regional Clusters用

$ cat connect_regional.sh 
#!/bin/bash
echo -n `(date "+%Y-%m-%d %H:%M:%S")`" : " >> REGIONAL_HISTORY
curl --connect-timeout 0.5 -s http://xxx.xxx.xxx.xxx/ -o /dev/null ; echo $? >> REGIONAL_HISTORY &

リクエストを投げるIPアドレスと結果の出力先のみ異なります。(1ファイルでも良かったですが面倒だったのでコピペ)

このShell Scriptを実行すると、正常にアクセスが成功した場合は0、失敗したときはそれ以外の数字が表示されます。

2017-12-16 07:09:35 : 0
2017-12-16 07:09:36 : 0
2017-12-16 07:09:37 : 0
2017-12-16 07:09:38 : 7
2017-12-16 07:09:39 : 7
2017-12-16 07:09:40 : 28

簡単ではありますが、各操作中に0以外の数値が表示された場合は、ダウンタイムがあったとみなします。上の例の場合、7は接続失敗、28がタイムアウトです。
kubectlの検証についてはShellを別で起動させたうえでkubectl get pods等を走らせたときにI/Oタイムアウトや接続の拒否が発生した場合、ダウンタイムがあったとみなします。

検証

1. デフォルトノードプールのオートスケールOFF -> ON

現行GKEクラスタ
$ gcloud container clusters \
> update single-master-cluster \
> --enable-autoscaling \
> --min-nodes=1 \
> --max-nodes=1 \
> --zone "asia-northeast1-b" \
> --node-pool default-pool
Regional Clusers
$ gcloud beta container clusters \
> update regional-cluster \
> --enable-autoscaling \
> --min-nodes=1 \
> --max-nodes=1 \
> --region "asia-northeast1" \
> --node-pool default-pool

minとmaxが両方とも1で、既に3ノード分生やしているので、この設定によりノードが増えたり減ったりすることはありません。

結果

現行GKEクラスタ
マスタへのアクセス
$ kubectl get pods
Unable to connect to the server: dial tcp xxx.xxx.xxx.xxx:443: i/o timeout

gcloudコマンドを実行した直後からタイムアウトしてしまい、アクセスできませんでした。

サービスの稼働

ダウンタイムが発生せず、問題ありませんでした。(すべて0を返しました)

Regional Clusters
マスタへのアクセス
$ kubectl get pods
NAME                                         READY     STATUS    RESTARTS   AGE
ringed-hedgehog-mariadb-3682299131-5ql58     1/1       Running   0          22m
ringed-hedgehog-wordpress-3049966572-8zx7z   1/1       Running   0          22m

問題なくアクセスできます!すごいですね。

サービスの稼働

こちらもダウンタイムが発生せず、問題ありませんでした。

2. マスタを 1.7.11-gke.0 -> 1.8.4-gke.0へアップグレード

どちらもCloud Console上の「アップグレード可能」というところからクリックしてアップグレードを実施しました。

結果

現行GKEクラスタ
マスタへのアクセス
$ kubectl get pods
The connection to the server xx.xxx.xxx.xxx was refused - did you specify the right host or port?

先程とエラーは異なりますが、アクセスできなくなりました。

サービスの稼働

ダウンタイムが発生せず、問題ありませんでした。

Regional Clusters
マスタへのアクセス
$ kubectl get pods
NAME                                         READY     STATUS    RESTARTS   AGE
ringed-hedgehog-mariadb-3682299131-5ql58     1/1       Running   0          38m
ringed-hedgehog-wordpress-3049966572-8zx7z   1/1       Running   0          38m

マスタのアップグレート中も問題ないですね!

サービスの稼働

しつこいようですが、問題ありませんでした。

3. 操作中の書き込み系操作

Regional Clustersでは、クラスタに対して何らかの操作をしている最中でも別のセッションからであれば kubectl によって操作ができることがわかりました。
ここまでは読み取り系の操作しかしていなかったですが、書き込み系の操作をしてみましょう。

先程のRegional Clustersと同じクラスタを作成し、マスタのアップグレード中にWordpressを追加でいくつか立ててみたいと思います。

$ gcloud beta container clusters create "regional-cluster" \
--region "asia-northeast1" \
--cluster-version "1.7.11-gke.0" \
--machine-type "n1-standard-1" \
--image-type "COS" \
--num-nodes "1"

Cloud Console上で「アップグレード可能」をクリックしてから、アップグレード操作に入ったあとにWordpressを追加でインストールします。

$ helm install stable/wordpress
NAME:   whimsical-dolphin

...

ちょっとワンテンポ待ちましたが、問題なく操作出来ますね!
Cloud Consoleで見るとまだインジケータが回ったままでまさに「アップグレード中」の状態でしたが、それでもWordpressを追加で立ち上げることができました!

4. 操作時間

ここまでやってて気づいたのですが、Regional Clustersでは設定を反映させるために結構時間がかかってるように感じました。
試しにtimeコマンドにより時間を計測してみたところ、このような結果になりました。

現行GKEクラスタ Regional Clusters
クラスタの構築 約4分 約4分
オートスケーリング OFF -> ON 約2分30秒 約10分
マスタのアップグレード 約1分30秒 約10分

複数回試してみましたが、おおよそこのぐらいの時間で設定が反映できるようです。
クラスタの構築はほぼ変わらないのですが、それ以外の操作については体感で「待つなぁ~」と感じるぐらい時間がかかってしまいます。。。

Beta版だからということもありそうですが、そもそもマスタが物理的に3台あって切り替えながら作業をしていることを考えるとこの時間も納得です。むしろ早いほうかも?

まとめ

(あれ、GKEって元々サービス側に影響なしでマスタのアップグレードできたっけ?となってしまいサービス側の検証の不必要感が半端ないのと、そもそもから何かを間違えてるのでは?と途端に不安になっていますが、)
とりあえずマスタが落ちることなくマスタのアップグレード等ができることが分かりました。

今まではマスタのアップグレード中はkubectlからもCloud Console上からもPodの様子などを見ることはできなかったのですが、
今回試したRegional Clustersではアップグレード中でもマスタが応答してくれ、割りと色々なことができるようで安心感があります。
他には、1つのクラスタに対して複数人で作業しているような状況でも便利そうですね!積極的に使っていきたいと思います。

現在はBeta版なので無料で利用できますが、Betaだけあって随時調整が入っているようです。
リージョンで利用できるGKEのバージョンがコロコロ変わったり、同じコマンド列でコピペなのにAPIサーバーに400エラーを返されたりということがあったので、
試す上では注意が必要かもしれませんね。エラーで返されても何回か実行すると通ったり通らなかったりします。広い心で臨んでみましょう。

GAとなるのが待ち遠しいです!

以上「Regional Clusters(Beta)を試してみた」、でした!

GKEのマスタとノードで利用可能なバージョン一覧を取得する

--cluster-version とかに渡せるバージョンを一覧で出すコマンドです。

gloud container get-server-config --zone {ZONE}

$ gcloud container get-server-config --zone asia-northeast1-b
Fetching server config for asia-northeast1-b
defaultClusterVersion: 1.7.8-gke.0
defaultImageType: COS
validImageTypes:
- COS
- UBUNTU
validMasterVersions:
- 1.8.4-gke.0
- 1.8.3-gke.0
- 1.8.2-gke.0
- 1.8.1-gke.1
- 1.7.11-gke.0
- 1.7.10-gke.0
- 1.7.9-gke.0
- 1.7.8-gke.0
- 1.6.13-gke.0
- 1.6.11-gke.0
validNodeVersions:
- 1.8.4-gke.0
- 1.8.3-gke.0
- 1.8.2-gke.0
- 1.8.1-gke.1
- 1.7.11-gke.0
- 1.7.10-gke.0
- 1.7.9-gke.0
- 1.7.8-gke.0
- 1.7.8
- 1.7.6
- 1.7.5
- 1.6.13-gke.0
- 1.6.11-gke.0
- 1.6.11
- 1.6.10
- 1.6.9
- 1.5.7

このように出てきます。

ERROR: (gcloud.beta.container.clusters.create) ResponseError: code=400, message=Version "1.7.11-gke.0" is invalid

のようなエラーになったときに利用します。

gcloud source repos cloneが失敗するのを回避する

GCPGoogle Source Repositoriesからgitリポジトリをcloneできなくなったときの回避法です。

通常、下記のコマンドを用いることで、GCP上でホストされているプライベートリポジトリをGCPの認証情報を利用してcloneすることが出来ます。

gcloud source repos clone REPO_NAME --project=PROJECT_NAME

原因は分かっていませんが、cloneが行われるときに認証用のダイアログが表示されることがあります。
プライベートリポジトリなので入力しなければ、と考えてうっかりこのダイアログでIDとパスワードを入力してしまうと、そのIDが合っているかどうかにかかわらず、 gcloud init をし直す等をしてもcloneができなくなってしまいます。

>gcloud source repos clone app app
WARNING: If your system's credential.helper requests a password, choose cancel.
Cloning into '(略)'...
fatal: remote error:


Invalid authentication credentials.

Please generate a new identifier:
  https://source.developers.google.com/auth/start?scopes=https://www.googleapis.com/auth/cloud-platform


ERROR: (gcloud.source.repos.clone) Command '['git', 'clone', '(略)', '(略)', '--config', 'credential.helper=!gcloud.cmd auth git-helper --account=アカウント名 --ignore-unknown $@']' returned non-zero exit status 128

最初に WARNING: If your system's credential.helper requests a password, choose cancel. と警告が出ていますね。
このエラーをスルーして入力してしまうと、cloneできない問題が発生します。
一度失敗するとエラーで表示されている通り再認証を行っても、 gloud init を行っても、cloneがずっと失敗する状況になってしまうのがこの問題の厄介な点です。

この問題の解決方法

Gitに登録されている credential.helper の設定を削除し、再設定します。

Windowsであれば管理者権限で実行します。

git config --system --unset "credential.helper"
git config credential.helper gcloud.cmd

これでcloneができるようになりました。

なぜ?

この設定は、Source Repositoriesをリモートとして追加するときに実行する git config credential.helper gcloud.cmd によって書き込まれる設定で、
先程表示されたダイアログにID、パスワードを入力してしまうとここの設定がおかしくなってしまうようです。(gcloud.cmdとなっているべきところが、managerなど別のものになってしまう)
なので、この設定を再設定することで、cloneすることができるようになります。