Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
49
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

Organization

GKEを使用している時に陥りがちな罠とトラブルシューティングについて

網羅されている訳ではないので、もっと色々な事例見つけたら教えてください。また個人の運用に経験に基づく知見なので、誤りがあれば指摘していただけると嬉しいです。

中にはある程度知識を持った上で使わないと危険なコマンドがありますので、検証は自己責任でお願いします。特にGKEのAutoScalerなどと不整合を起こす可能性のあるコマンドもあるため、注意してください

Kubernetes初期設定と操作クラスタの切り替え

  1. 前提としてクラスタを管理しているマシン上でmaster componentsが起動している必要がある(minikubeを使うとVM上に,GKE上ではGUI・CUIでクラスタを作ると勝手に立つと思われる。これは簡潔性のために同ホストで全てのmaster componentsを立ち上げるが個別の起動や自作サービスとの共存も可能(ただしやらない方がいいと書いてある))。
    参考:
    The Kubernetes Master is a collection of three processes that run on a single node in your cluster, which is designated as the master node. Those processes are: kube-apiserver, kube-controller-manager and kube-scheduler.

  2. kubectlコマンドはmaster componentsのうちkube-apiserverを指定・経由して操作したいホスト(クラスタ)に変更を加える(REST)
    (各ホストではkubeletとkube-proxyというデーモンが操作を待ち受けている or 新たに作成されたnode上でkubele, kube-proxyを起動させる「GCPの場合は、おそらくGKEクラスタの作成時にそれぞれのnode上でkubeletを起動させている」)

  3. kubectlで操作されるホスト群(クラスタ)の設定は(デフォルトでは)$HOME/.kube/configから読まれる

  4. 以下のコマンド

gcloud container clusters get-credentials $CLUSTER_NAME --zone=$ZONE_OF_CLUSTER

を実行するとkubectlの操作対象をGKE上のクラスタに設定できる - ここの設定は、.kubeを見る限りkubectlのREST先を切り替えている。minikube startを使うとリクエスト先がVMになる。)

  1. .kube/configに一度設定したクラスタはcontextというkeyのデータに格納される。
kubectl config use-context $CLUSTER_NAME

で操作対象のクラスタを自由に変えることができる。

参考(https://github.com/kubernetes/kubernetes/issues/25383)

手動でkubectlの操作先を決定する最小の設定方法

$ kubectl config set-cluster --server=xxx
$ kubectl config set-credentials xx --username=xxx password=xxxx
$ kubectl config set-context xxx --cluster=xxx --user=xxx --namespace=xxxx
$ kubectl config use-context xxxx

gcloud container clusters get-credentials は、以上のコマンドを簡略化してくれていると思われる

現在kubectl実行環境に設定されているcontextのリストを確認する方法

kubectl config view -o jsonpath='{.contexts[*].name}'

また、kubectlのcontextの向き先を設定すればgoogle cloud console上のkuberctlでも操作が可能

設定情報を見る

dash_boardを使うと一覧できる。
gcp上のkubenetesの設定を確認したい場合は認証情報が必要なため、クレデンシャルを設定した端末でkubectl proxyを実行し、

$host:8001/ui

でアクセスすることにより本番環境の設定情報にもアクセスできる。gcp上の端末だとIPなどで弾かれるのでローカルマシンのkubectl proxyからlocalhostで接続するのが無難。

minikube

ローカルで実行する際はminikubeを使うとよい
minikube startを実行するとvirtual box上にkubernetesのnodeを作成できるコンテキストを自動生成する

異常なpodがないかチェック

kubectl get pods --all-namespaces | grep -v Running

Does not have minimum availability

こいつが起きるときはリソース不足だけとは限りません。コンテナの起動が失敗していたり、ヘルスチェックが失敗して、サービスからバックエンドのpodの接続が切断されてる時などにも表示されます。ちゃんとdescribeやイベントやステータスやログを読みましょう。特にこのエラーが出てる時に気づきにくい原因が以下二通り。

そもそもコンテナのビルドやデーモンの起動に失敗している

コンテナ内のログを読みましょう。意外と自分の実装したものがエラー出しててイメージビルドには成功しているが正しく起動してないバグは見落としがちですが、結構起きます。(ちゃんとCIでテストしていれば防げる話ですが。)

serviceのselectorで設定されているmatchLabelがマッチしていない、もしくは複数のPodsやContainerに該当して接続先が定まらない

kubeObjectのサービスはselectorで接続先を決定するので、実は設定ファイル外のPodsやコンテナを指定できる。陥りがちなのはこれによって接続先を間違えていたり複数存在させることによって、一意に定まらないケースで、問題が潜在化してしまうことが多いです。=> helmがいいです。

リソース足りてない問題

  • Sync Failed
  • Unscheduled
  • Pending

以上の二つは正しくpodsの起動ができなかったりrolling updateができない時に起きる。二通りの方法を試してみる。

  • リソースを増やして移行する
gcloud container clusters resize $cluster --node-pool default-pool --size 4 --zone asia-east1-c 
gcloud container node-pools create f1-micro-pool --machine-type f1-micro --num-nodes=5 --zone=asia-east1-c --cluster $cluster

https://qiita.com/superbrothers/items/d9766ebaff15d6954d03
https://qiita.com/tkusumi/items/946b0f31931d21a78058

  • Errorになってるコンテナを無理やり消すなどをしてリソースを開けて、オブジェクトを作り直す(createはだいたいコマンドをcreateに置き換えるか、逆方向のコマンドを打てば良いので省略)

    • podsを減らす

      kubectl scale --replicas=1 deploy/$deploymentName
      
    • podsを強制削除

      kubectl delete pods $podName --force --grace-period=0
      
    • nodeを指定してpodを他のnodeに退避させる

        kubectl drain $nodeName [Option]
      
    • nodeを強制削除
      注意: AutoScalerなどと一緒に使うと表示がバグるので、gcloud CLIまたは、GCP Consoleからの操作をお勧めします。ゾンビ化して強制削除せざるをえない時などに使ってください。

       kubectl delete nodes/$nodeName --force --grace-period=0    
      
    • node-poolを削除する

      gcloud container node-pools delete default-pool --zone $zoneName --cluster $clusterName 
      

ヘルスチェックうまく行っていない問題

Error例など

  • Unscheduled
  • Does not have minimum availability

よく陥りがちな罠

Ingressのヘルスチェックは接続先のサービスのヘルスチェックを再利用し、設定されていなければデフォルトで/にヘルスチェックを飛ばす。この時、status 200が/から返っていなければ、ingressが起動しません。特にdefault設定のままだと、stgにbasic認証を挟むなどの操作によって、気づかぬうちに、/がstatus 200を返さなくなるなどの理由で、PodがRunningであるのにserviceから接続がrejectされるなどの事故が起きます。(実話)この場合Cloud LoggingのIngressのヘルスチェックログが警告を発してるので、気づけます。基本的にhealth checkは設定推奨になります。

落ちた時にアラートを飛ばす

Stack Driver からUptime Checkを設定し、ヘルスチェックのパスにリクエストを飛ばしておくと良い

設定抜粋例)

    readinessProbe:
        httpGet:
          path: /healthz
          port: 80
        periodSeconds: 1
        timeoutSeconds: 1
        successThreshold: 1
        failureThreshold: 10

高負荷に耐えられない問題

  • podのスケーリング設定を行う色々なオプションがあるので、状況に合わせて使う
    例)
    - 通常時の設定
    desired のpod数、scalingの条件などを設定する

        ```
       kubectl autoscale rc (or deployment) foo --min=2 --max=5 --cpu-percent=80
        ```
    
    - Rolling Update時の, Scaling 条件を設定する
        - maxSurge:  Rollin Updateの際にdesiredレプリカ数を基準に何個まで、podsをスケールさせてもよいか設定する。defaultは25%少数は切り上げ
        - maxUnavailable:  defaultは25%。少数は切り下げ。
    

わざとリソースを食いつぶしてみる

練習としてcordon、drain、taintによって、podのスケジューリングできないnodeの数を調整し、その状態でどれくらいリソースを確保したら、クラスタが復元できるか検証してみる。

  • cordon

NodeにPodsを置けなくする。Uncordonはその逆。

  kubectl cordon $nodeName [Option]
  kubectl uncordon $nodeName [Option]
  • drain

NodeをUnscheduledに(cordonと同じ処理)してからpodをevictして他のNodeに移行する。

 kubectl drain $nodeName [Option]
  • taint tolerationsという条件を設定して、条件を越えると、podsを他のNodeへevictionが走るようにできる
taint.yaml
tolerations:
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoSchedule"
- key: "key1"
  operator: "Equal"
  value: "value1"
  effect: "NoExecute"

cordonしたNodeには新たなコンテナが配備できなくなるため、ReadyになっているNodeのみでリソース調整ができる。これによって、適度なNode数やpodsを配備した状態でエラーを起こしてみて、復旧をテストしてみる。

Ingressがゾンビ化する

IngressはGKEのリソースではなく、GCEにロードバランサーと設定が立つため、イレギュラーな削除の仕方をするとゾンビ化する

特に

kubectl delete ing $ingName

などのコマンドを実行してIngressを削除するよりも前に、GKEのクラスタを削除してしまうと、GCE上にGCEロードバランサーのインスタンスが稼働し続けstatic IPも解放されないという現象が起きるため、クラスタを削除する前に上記コマンドの実行を忘れないようにしておく必要がある。
なお、忘れてしまった場合は、GCE・VPCのコントロールから以下の設定を削除する必要がある。

  • ネットワークサービス > 負荷分散 > ロードバランサ > 該当のロードバランサを削除
  • ネットワークサービス > 負荷分散 > バックエンド > ロードバランサが設定されていないバックエンドを削除
  • VCPネットワーク > ファイアウォールルール > 削除
  • VCPネットワーク > 外部IPアドレス > gcloud addresses delete $ip
  • GCE > ヘルスチェック > 未使用なものから検索をかける > 削除
  • GCE > インスタンスグループ > 未使用なものから検索をかける > 削除

本番環境の設定忘れた・担当者が職場を去ったが設定してあるものがわからない

kubectl get $resorceType -o yaml

で設定を復元できます。ベンダーごとのメタデータがついてたり,secretはbase64設定されていますが、復元できます。

問題点を探す

  • GKE上のダッシュボードで確認するそれぞれのkubeObjectに遷移しyaml,イベント,ログを確認
  • Stack Driver Loggingやモニタリングをみる
  • kubectl top $resorceType
  • kubectl describe $resorceType

set imageに失敗した失敗した失敗した失敗した失敗した…時

kubectl rollout history deployment/nginx-deployment --revision=2
kubectl rollout undo deployment/nginx-deployment 
kubectl rollout undo deployment/nginx-deployment --to-revision=2

のいずれかを使う。

コンテナログイン

kubectl exec $pod-name -c $container-name  /bin/bash

Nodeにログインする(裏技)

裏側知りたい時や調査以外で非推奨

gcloud instances list (NodeNameを調べる)
gcloud compute  ssh $nodeName
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
49
Help us understand the problem. What are the problem?