harukin721

主に学習記録 🔗 wantedly.com/id/harukin721

ひとり「トラブルシューティングから学ぶk8s勉強会」Part1

去年11月に社内でk8sの勉強会をしていただいたけど、その時は今よりもk8s何もわからん状態だった。その後k8sクラスタ再作成等をやったのでこれをもう1度やってみた。

トラブルシューティングから学ぶk8s

基本コマンド

kubectl = k 

Pod内のコンテナに対してコマンド実行

$ k exec -it <Pod名> -- /bin/bash

# コンテナの中
root@<Pod名>:/#

複数コンテナがあるPodで -c オプションでコンテナを指定してコマンド実行

$ k exec <Pod名> -c <コンテナ名> -- cat /var/log/nginx/access.log

新しいPodをコンテナイメージを指定して作成(デバッグ用Podとして使える)

※ --rm は シェルを終了すると、自動的にPodは削除される。

$ k run -it --rm <コンテナイメージ> --image=<Pod名>

PodやNodeのCPUやメモリのリソース量を確認

$ k top po <Pod名>
$ k top no

クラスタ内のPodやServiceにクラスタ外からアクセス(http://localhost:8080)

別ターミナルでアクセスログの確認ができる

$ k port-forward <Pod名> 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80

主にメンテナンスやログ収集、その他にもトラブルシューティング等でクラスタのNodeへアクセスしたいときに使用する

# Node上に特権コンテナがデプロイされ、シェルに接続される
$ k debug no/<Node名> -it --image=<コンテナイメージ>
Creating debugging pod node-debugger-<Node名>-69tns with container debugger on node <Node名>.
If you don't see a command prompt, try pressing enter.
[root@<Node名> /]#

# chroot /host を実行すると、Node上の全ファイルシステムにアクセス可能
[root@<Node名> /]# chroot /host

アプリケーションPodのトラブルシューティング

正常なPodはRunningステータスで動作し続けることが想定される

- Pending : PodがNodeにスケジューリングされていない状態

- Terminating : Podが終了中の状態

- Unknown : 何らかの理由でPodのステータスが確認できない状態

- CrashLoopBackOff : コンテナが起動と終了を繰り返している状態

- ContainerCreating : コンテナが作成中の状態

- CreateContainerConfigError : コンテナを作成するための設定に問題がある状態

- ErrImagePull/ImagePullBackOff : コンテナイメージのPullに失敗している状態

Podはひとつ以上のコンテナの集合体で構成される(Containers.<コンテナ名>.State)

Stateフィールドの情報からPod内に存在する各コンテナの状態が確認できる。

- Waiting : コンテナの作成が未完了

- Running : コンテナが実行中

- Terminated: コンテナが実行され、完了もしくは失敗した状態

トラブル1 (CrashLoopBackOffステータス)

# Eventフィールドを確認すると、Liveness Probeに失敗している
$ k describe po

--- snip ---

Events:
  Type     Reason     Age                   From               Message
----     ------     ----                  ----               -------
   Warning  Unhealthy  15m (x9 over 17m)     kubelet            Liveness probe failed: cat: can't open '/tmp/health': No such file or directory
  Normal   Killing    15m (x3 over 17m)     kubelet            Container liveness failed liveness probe, will be restarted

--- snip ---

Containers.<コンテナ名>.Last State: を見ると、Terminatedで終了している

Containers:
liveness:

--- snip ---

    State:          Waiting
      Reason:       CrashLoopBackOff
    Last State:     Terminated
      Reason:       Error
      Exit Code:    137

--- snip ---

Liveness probeに設定しているコマンドでチェックしているファイルのパスが間違っていることが原因だった。

トラブル2 (ContainerCreatingステータス)

# Eventフィールドを確認すると、ReasonがFailedMountと記録されている
$ k describe po mypod

--- snip ---

Events:
  Type     Reason       Age                From               Message
  ----     ------       ----               ----               -------
  Normal   Scheduled    46s                default-scheduler  Successfully assigned default/mypod to colima
  Warning  FailedMount  14s (x7 over 46s)  kubelet            MountVolume.SetUp failed for volume "foo" : configmap "mycnofigmap" not found

--- snip ---

Messageを見ると、コンテナにマウントするはずのvolumeがマウントできていないので、起動する前に待ち状態になってしまっている。また、fooボリュームとしてmycnofigmapというConfigMapリソースを指定しているが、見つかっていない。

# ConfigMapを確認
$ k get cm
NAME               DATA   AGE
myconfigmap        1      5m2s

ConfigMapはmyconfigmapなのでtypoしていることが原因だった。

トラブル3 (CreatingContainerConfigError)

# Eventフィールドを確認すると、ReasonがFailedと記録されている
$ k describe po mypod-2

--- snip ---

Events:
  Type     Reason       Age                From               Message
  ----     ------       ----               ----               -------
  Warning  Failed     15s (x4 over 49s)  kubelet            Error: couldn't find key USERNAME in Secret default/mysecret

--- snip ---

Messageを見ると、default/mysecretのUSERNAMEキーを参照しようとしているが、そのようなキーが見つからずにエラーとなっている。

# Secretを確認
$ k get secret
NAME       TYPE     DATA   AGE
mysecret   Opaque   1      4m22s

# 存在するキーはuserなのでPodの定義かSecretのキー名を修正する
$ k describe secret mysecret
Name:         mysecret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
user:  6 bytes

※ 今回はVolume Mount周りには問題がなく、ContainerCreatingフェーズは正常に終了した。その後に実行されるSecretからの値の参照処理に間違いがあって CreateContainerConfigError になっていた。

トラブル4 (ErrorImage/ImagePullBackOff)

# Eventフィールドを確認すると、ReasonがFailedと記録されている
$ k describe po my-busybox

--- snip ---

Events:
  Type     Reason       Age                From               Message
  ----     ------       ----               ----               -------
   Warning  Failed     27s (x3 over 73s)  kubelet            Failed to pull image "rancher/bosybux": rpc error: code = Unknown desc = failed to pull and unpack image "docker.io/rancher/bosybux:latest": failed to resolve reference "docker.io/rancher/bosybux:latest": pull access denied, repository does not exist or may require authorization: server message: insufficient_scope: authorization failed

--- snip ---

Messageを見ると、docker.io/rancher/bosybux:latestイメージをpullしようとしているが、アクセスが拒否されたかリポジトリにそのようなイメージが存在してないため、イメージの取得に失敗している。 

トラブル5 (ErrorImage/ImagePullBackOff その2)

# Podのステータスが ErrImagePull or ImagePullBackOff
$ k get po mysql
NAME    READY   STATUS         RESTARTS   AGE
mysql   0/1     ErrImagePull   0          77s

$ k get po mysql
NAME    READY   STATUS             RESTARTS   AGE
mysql   0/1     ImagePullBackOff   0          84s
# image pullに問題がある
$ k describe po mysql

--- snip ---

Events:
  Type     Reason       Age                From               Message
  ----     ------       ----               ----               -------
 Normal   Pulling    31s (x4 over 116s)  kubelet            Pulling image "<コンテナイメージ名>mysql:8"
Warning  Failed     31s (x4 over 116s)  kubelet            Failed to pull image "<コンテナイメージ名>/mysql:8": rpc error: code = Unknown desc = failed to pull and unpack image "<コンテナイメージ名>/mysql:8": failed to resolve reference "<コンテナイメージ名>/mysql:8": pulling from host <ホスト名> failed with status code [manifests 8]: 401 Unauthorized
  Warning  Failed     31s (x4 over 116s)  kubelet            Error: ErrImagePull
  Warning  Failed     18s (x6 over 116s)  kubelet            Error: ImagePullBackOff
Normal   BackOff    7s (x7 over 116s)   kubelet            Back-off pulling image "<コンテナイメージ名>/mysql:8"

--- snip ---

Messageを見ると、レジストリの<コンテナイメージ名>から401が返って、認証に失敗している。理由は認証情報を持っている人だけがアクセスできるプライベートレジストリであり、クラスタやPodには認証情報を設定していないのでコンテナイメージの取得に失敗している。

 

(Part2 に続く...)

 

その他

過去、基本的なやつはQiitaに残していた。