Kubernetes の業務でよく使うコマンド集 （逆引き）

# Kubernetes の業務でよく使うコマンド集

## 概要
Kubernetes （以降 K8s） のコマンド集です。
業務でよく使うコマンドを、目的別に記載しています。

+ 期待する読者
    - 目的からの逆引きで、コマンドを探したい方
    - 実際の業務において、どんなコマンドを使うのか知りたい方

+ 前提
    - namespace の指定は省略します。
      適宜オプションを追加して読み替えてください
      - 例： `-n test-ns`


## Pod の NAME を取得する
1. 概要
    - Pod の NAME は、コンテナに対する操作で幅広く使用します。
      しかし、Pod を再起動すると変わってしまいます（英数字の羅列。固定できるのかは未調査）
    - なので、POD_NAME のような変数に格納しておくと、操作がスムーズになります
1. コマンド
    ```
    POD_NAME=$(kubectl get pods -l app=<APP_NAME> --no-headers | grep Running | awk '{ print $1 }')
    ```
1. オプション解説
    ```
    <APP_NAME>  ログインしたい Pod の metadata > labels > app の値 (例： nginx)
    ```
1. コマンド例
    - POD_NAME 変数に POD NAME の値を格納する
    ```
    POD_NAME=$(kubectl get pods -l app=test-app --no-headers | grep Running | awk '{ print $1 }')
    ```

## コンテナにログインする
1. 概要
    - 作成した Pod のコンテナにログインし、ログやプロセスの挙動を確認したい場合。
      特に、自作コンテナのログの確認や、エラー時の調査に使えます
    - 作成した Pod のコンテナに対し、特定のコマンドを実行したい場合。
      例えば、ls でファイルなどを確認したり、DB のクエリを実行するなど
1. コマンド
    ```
    kubectl exec [-it] <POD_NAME> --container <CONTAINER_NAME> -- <COMMAND>
    ```
1. オプション解説
    ```
    -i   コンテナに標準入力（stdin）の結果を渡す
         ※bash などでログインして操作するときに必要（コマンドの実行だけなら不要）
    -t   標準入力に tty を使う
         ※bash などでのログイン時に、UNIX ライクなプロンプトにしたい場合に必要（詳細は未調査）
    <POD_NAME>          ログインしたい Pod の NAME
    <CONTAINER_NAME>    ログインしたいコンテナ名
    <COMMAND>           実行したいコマンド（例： /bin/bash なら bash でのログイン）
    ```
1. コマンド例
    * コンテナに /bin/bash でログイン
    ```
    kubectl exec -it ${POD_NAME} -c test-container -- /bin/bash
    ```
    * PostgreSQL のバージョンを取得
    ```
    kubectl exec ${POD_NAME} -c postgres -- psql --version
    ```
    * InfluxDB の retention policy （データ保存期間）を取得
    ```
    kubectl exec ${POD_NAME} -c influxdb -- influx -database dbname -execute "show retention policies"
    ```
1. 注意点
    - 対象 Pod の STATUS が Running になっていないとログインできません
    - Pod のコンテナを指定してログインするため、
      Pod 内に複数のコンテナを同居している場合、
      操作対象のコンテナ名を正確に指定する必要があります
1. 補足
    - 私は、コンテナのテストデータ登録スクリプトの中で exec を使っています

## コンテナと母艦の間でファイルを転送する
1. 概要
    - コンテナに母艦（コンテナを起動しているホスト。またはコンテナにアクセスするホスト）からファイルを転送したい場合
    - コンテナのファイルを母艦に転送したい場合
    - 自作コンテナのファイルを直接直して変更を検証したい時や、
      DB に初期データを入れたい時に便利です
1. コマンド
    * 母艦のファイルをコンテナにコピー
    ```
    kubectl cp --no-preserve=true <SRC_FILE> <POD_NAME>:<DEST_FILE> -c <CONTAINER_NAME>
    ```
    * コンテナのファイルを母艦にコピー
    ```
    kubectl cp --no-preserve=true <POD_NAME>:<SRC_FILE> -c <CONTAINER_NAME> <DEST_FILE>
    ```
1. オプション解説
    ```
    <POD_NAME>   ログインしたい Pod の NAME
    <SRC_FILE>   コピー元のファイルパス（相対パスでも可）
    <DEST_FILE>   コピー先のファイルパス（相対パスでも可。コピー後のファイル名まで指定必須）
    <CONTAINER_NAME>  コピー先のコンテナ名。未指定の場合はデフォルトのコンテナが採用される
    --no-preserve=true  ローカルファイルのパーミッションやオーナーを保持しない。
                        （オプション無しの UNIX の cp コマンドと同様）
                        ◆なお、デフォルトは false ＝ 保持する なので、
                        ローカル側とコンテナ側のオーナー、パーミッションが一致していないと
                        誤動作の元になります。
                        コピー後に、chmod や chown で適宜変更することを推奨
                        
    ```
1. コマンド例
    * 母艦のファイルをコンテナにコピー
    ```
    kubectl cp /root/idb_bk_20231001.tgz ${POD_NAME}:/var/tmp/idb_bk.tgz -c php
    ```
    * コンテナのファイルを、母艦のカレントディレクトリにコピー
    ```
    kubectl cp ${POD_NAME}:/var/tmp/idb/idb_bk_20231001.tgz -c php ./idb_bk_20231001.tgz
    ```

## オブジェクトを再作成する
1. 概要
    - オブジェクト（稼働中のリソース）に変更を加えたい場合、apply や create ではなく replace を使います
    - 例えば、ConfigMap に値を追加した時、Pod のボリュームを追加した時など
1. コマンド
    ```
    kubectl replace -f <FILE_NAME>
    ```
1. オプション解説
    ```
    <FILE_NAME>   変更したリソースのマニフェストファイル
    ```
1. コマンド例
    * Pod の マニフェストファイルの変更を適用する
    ```
    kubectl replace -f manifest/test-app.yml
    ```
1. 注意点
    * Pod を再作成すると、Pod の NAME も変わります

## Pod を再起動する（Deployment を再起動する）
1. 概要
    - 用途としては、Pod に ConfigMap などの更新を反映したり、
    単純にプロセス自体を再起動したい場合に使います（メモリ消費が重くなってきた場合など）
    - なお、コマンド操作する対象は Pod リソースではなく、Deployment リソースです
1. コマンド
    ```
    kubectl rollout restart deployments <DEPLOYMENT_NAME>
    ```
1. オプション解説
    ```
    <DEPLOYMENT_NAME>   Deployments リソースの名前
                        ※Deployment リソースのマニフェストファイルの metadata > name の値
    ```
1. コマンド例
    ```
    kubectl rollout restart deployments test-app
    ```
    * 実行直後は、古い POD が Terminating で残ります（そのうち消えます）
    ```
    NAME                      READY   STATUS        RESTARTS   AGE
    test-app-12345678-abcde   1/1     Terminating   0          2d
    test-app-abcdefgh-12345   1/1     Running       0          5s
    ```

## Pod のログを見る
1. 概要
    - 主に、Pod の状態が Running にならない場合の調査に使います
    - デフォルトだと、Pod 起動直後からのログが全部出てくるので、
    オプションの `--tail=表示件数` などで表示件数を調整しましょう
1. コマンド
    ```
    kubectl logs <POD_NAME> [--tail=<件数>]
    ```
1. オプション解説
    ```
    <POD_NAME>     ログインしたい Pod の NAME
    --tail=<件数>   ログの最終行から <件数> 件だけを表示する。デフォルトは -1（全件表示）
    ```
1. コマンド例
    * InfluxDB コンテナのログを、最新10件だけ表示する
    ```
    kubectl logs influxdb-123abc456z-5656x --tail=10
    ```

## リソース操作コマンドの検証がしたい（dry run）
1. 概要
    - K8s コマンドには dry run （実際にはリソースなどを作成せず、成否や実行結果だけを取得するもの）が存在します
    - 実際に ConfigMap を作成したらどんな風に適用されるのか、を確認したい場合にも使えます
1. コマンド
    * コマンドの実行結果だけを知りたい場合
    ```
    --dry-run=client
    ```
    をコマンドのオプションに付ける
    
    * コマンドの実行結果を、yaml 形式などで表示したい場合
    ```
    --dry-run=client -o <出力形式>
    ```
    をコマンドのオプションに付ける。
1. オプション解説
    ```
    <出力形式>     標準出力の形式。例： json, yaml
    ```
1. コマンド例
    * ConfigMap を作成したときの結果を yaml 形式で表示する
    ```
    kubectl apply -f configs/configmap-test-app.yml --dry-run=client -o yaml
    ```
    * 表示結果例
    ```
    apiVersion: v1
    data:
      config.yml: |-
        root_path: /var/tmp/app
    ～省略～
    ```

## オブジェクトの詳細を出力する
1. 概要
    - 稼働中のオブジェクトの詳細を、マニフェストファイルの形式（yaml など）で出力し、確認したい場合
    - 作成したオブジェクトの内容が正しいか確認したい場合に使えます
    - 既存のオブジェクトの構成を流用したい時に便利です
1. コマンド
    ```
    kubectl get pods <OBJECT_NAME> -o <出力形式>
    ```
1. オプション解説
    ```
    <OBJECT_NAME>   オブジェクトの名前
    <出力形式>       標準出力の形式。例： json, yaml
    ```
1. コマンド例
    * Pod の詳細を yaml 形式で出力する
    ```
    kubectl get pods test-app-12345abcde -o yaml
    ```
    * 表示結果例
    ```
    apiVersion: v1
    kind: Pod
    metadata:
      labels:      
        app: test-app
    ～省略～
    ```

## 起動中の Pod のイベントを見る
1. 概要
    * 起動した直後の Pod の状態を確認したい場合
    * logs は Pod が Running にならないと使えないため、
      「作成がなかなか終わらない」などのときはイベントを見る必要があります
    * describe コマンドを使うと、対象 Pod のイベントを時系列で見ることができて便利です
1. コマンド
    ```
    kubectl describe pod <POD_NAME>
    ```
1. オプション解説
    ```
    <POD_NAME>          ログインしたい Pod の NAME
    ```
1. コマンド例
    ```
    kubectl describe pod ${POD_NAME}
    ```
    * レスポンス例 
      * この例だと、Volume のマウント時に重複マウントエラーが出ている
    ```
    Events:
      Type     Reason              Age    From                     Message
      ----     ------              ----   ----                     -------
      Normal   Scheduled           4m43s  default-scheduler        Successfully assigned test-ns/test-app-xxxx ...
      Warning  FailedAttachVolume  4m43s  attachdetach-controller  Multi-Attach error for volume "pvc-xxxx" Volume is already used by pod(s) test-app-yyyy
      Warning  FailedMount         22s    kubelet                  Unable to attach or mount volumes: unmounted volumes=[test-data], unattached volumes=[test-data kube-api-access-xxxxx]: timed out waiting for the condition
    ```


## PVC をマウントしている Pod を探す
1. 概要
    * PVC (Persistent Volume Claim：ストレージリソース）を使っていると、削除や再利用などのユースケースが生まれます
    * しかし、以下の理由により阻まれることがあります
        * PVC を消したいとき、PVC をマウントしている Pod があると消せない
        * PVC を再利用するとき、複数 Pod でマウントできないタイプの PVC だと、既存 Pod から外さないと再利用できない
        * Cronjob が生成した Pod がマウントしていて、マニフェストだけ見ても気づけない　などなど
    * なので、現行の Pod の中から PVC をマウントしている Pod を探せると、これらの対処に便利な時があります
1. コマンド
    ```
    kubectl get pods -o json | jq '.items[] |
    select(.spec.volumes[]?.persistentVolumeClaim.claimName=="<POD_NAME>") |
    .metadata.name'
    ```
1. オプション解説
    ```
    <POD_NAME>          対象 Pod の NAME
    ```
1. コマンド例
    ```
    kubectl get pods -o json | jq '.items[] |
    select(.spec.volumes[]?.persistentVolumeClaim.claimName=="'${POD_NAME}'") |
    .metadata.name'
    ```
    * レスポンス例 （この例だと、2つの Pod がマウントしている）
        ```
        "minikube-webapp-123456789-aaa11"
        "minikube-cronjob-987654321-bbb22"
        ```


## Pod の作成が完了するのを自動的に監視する
1. 概要
    * Helm で複数の Pod を一度に作成したり、Pod の再起動などをした場合、Pod が起動するまでに時間がかかることもあります
    * その都度、`kubectl get pods` コマンドを叩いて確認、は結構めんどくさい…
    * `kubectl get pods -w` とすると、更新のあった Pod の状態を監視し、ターミナルに追加表示してくれます 
1. コマンド
    ```
    kubectl get pods -w
    ```
1. オプション解説
    ```
    -w      (--watch) 変更のあったリソースの状態を監視し、追加表示する
    ```
1. コマンド例
    * 再起動 ～ 監視までの一連のプロセスの例です
    ```
    # Pod 再起動
    kubectl rollout restart deployment logstash-1
    
    # 確認 （監視バージョン）
    kubectl get pods -w
    
    ## 出力結果例
    NAME         READY   STATUS             RESTARTS  AGE
    logstash-1   0/2     Init:0/1           0         1s

    （★ここからが監視で追加表示される内容）
    logstash-1   0/2     PodInitializing    0         3s
    logstash-1   2/2     Running            0         2m　　★完了
    ```


## CronJob を即時起動する
※CronJob は、Linux の cron と同じようなことを Kubernetes で実現できるリソースです

1. 概要
    * CronJob の動作確認をしたい場合
    * 初回適用後や障害復旧後などで、Cronjobの結果をすぐに反映させたい場合
1. コマンド
    ```
    kubectl create job --from=cronjob/<CronJobの名前> <起動するPodの名前>
    ```
1. オプション解説
    ```
    <CronJobの名前>     即時起動したい CronJob の名前
                         ※kubectl get cronjob で表示される NAME の値
    <起動するPodの名前>  CronJob が一時的に作成する Pod の名前
                         ※タイムスタンプをつけておけば他の Pod と被らない
                         　例： cron-hourly-`date +%Y%m%d%H%M`
    ```
1. コマンド例
    * daily (日時) の CronJob を即時起動させる例
    ```
    kubectl create job --from=cronjob/cron-daily cron-daily-202504012233
    ```


## 全リソースを表示する
1. 概要
    * 特定 namespace のリソースを一括で確認したい場合
    * どんなリソースがあるのかを忘れた場合や、リソースの消し忘れ確認、などで使えます
1. コマンド
    ```
    kubectl api-resources --namespaced=true -o name | while read resource; \
    do echo; echo "# ${resource}"; kubectl get -n <namespace> "${resource}"; done
    ```
1. オプション解説
    ```
    <namespace>   リソースを表示したい namespace
    ```
1. コマンド例
    * namespace = ns-test の全リソースを表示する
    ```
    kubectl api-resources --namespaced=true -o name | while read resource; \
    do echo; echo "# ${resource}"; kubectl get -n ns-test "${resource}"; done
    ```


# 応用編
Kubernetes コマンド＋UNIXコマンド などで実現できることのメモ。

## コンテナにローカルのファイルを一括で送る
1. 概要
    * ローカルで修正したファイルの更新を、開発環境などのコンテナに反映したいとき
    * （お断り）コンテナ側で git pull する方が楽
      * ただ、git push する前に動作を確認したい（コミットを汚したくない）、などの場合は使えるかも
1. コマンド
    ```
    file_list="
    <コンテナに送りたいファイルのパス（例： `git status` に表示されたファイルパス）>"
    APP_NAME=<APP_NAME>
    CONTAINER_NAME=<CONTAINER_NAME>
    NAME_SPACE=<NAME_SPACE>
    POD_NAME=`kubectl -n ${NAME_SPACE} get pods -l app=${APP_NAME} --no-headers | grep Running | awk '{ print $1}'`
    for filename in ${file_list}; do
      kubectl -n ${NAME_SPACE} cp -c ${CONTAINER_NAME} --no-preserve=true /path/to/app/root/${filename} ${POD_NAME}:/path/to/web/htdocs/${filename}
    done
    ```
1. オプション解説
    ```
    <APP_NAME>          ログインしたい Pod の metadata > labels > app の値 (例： nginx)
    <CONTAINER_NAME>    ログインしたい コンテナ の NAME
    <NAME_SPACE>        ログインしたい Pod がある NAME_SPACE
    ```
1. コマンド例
    ```
    file_list="
    app/controllers/TopController.php
    app/views/top/index.volt
    public/css/custom.css"
    APP_NAME=app1-0-0-web
    CONTAINER_NAME=web
    NAME_SPACE=stg
    POD_NAME=`kubectl -n ${NAME_SPACE} get pods -l app=${APP_NAME} --no-headers | grep Running | awk '{ print $1}'`
    for filename in ${file_list}; do
      kubectl -n ${NAME_SPACE} cp -c ${CONTAINER_NAME} --no-preserve=true /path/to/app/root/${filename} ${POD_NAME}:/path/to/web/htdocs/${filename}
    done
    ```