Kubernetes 専門家として知るべき 47 のこと

この記事は私が過去 3 年ほど Kubernetes に携わる中で学んだ、ちょっと見つけにくい知識をまとめたものです。 特にカスタムコントローラーを開発するような人に必要となる知識群です。

感想とか指摘とかあれば Twitter までお寄せください。

更新履歴

  • 2021-03-05: "コンテナの resources.limits と resources.requests の違いについて" の項を補足しました (thanks to @superbrothers)


API

  1. kube-apiserver が備える拡張機構を列挙しなさい

    回答例

  2. Admission コントロールの動作シーケンスについて説明しなさい

    回答例

    1. 認証・認可
    2. Mutating webhook
    3. Object schema validation
    4. Validating webhook
    5. etcd に保存

    cf. A Guide to Kubernetes Admission Controllers

  3. 複数の mutating webhook が同一リソースを編集する際の問題と解決方法を説明しなさい

    回答例 ひとつの webhook が Pod 内の全てのコンテナにボリュームを追加し、別の webhook が Pod にコンテナを追加するとした場合、前者は後者のに呼び出される必要がある。 しかし kube-apiserver に webhook の呼び出し順序を設定する方法はない。 解決方法として、前者の webhook の reinvocation policyIfNeeded にすれば良い。

  4. Admission webhook の呼び出しに失敗したときの挙動について説明しなさい

    回答例 Failure policy の設定に従う。 admissionregistration.k8s.io/v1 では、デフォルトでリクエストが中断され失敗する設定となる。

  5. Kubernetes API の排他制御方式について説明しなさい

    回答例 kube-apiserver に保存されているリソースはすべて resource version が与えられ、書き換えられる都度変化する。 Replace (PUT) 操作の場合、Read (GET) してきた時点の resource version と異なると操作に失敗する楽観ロックで排他制御される。リソースの一部を書き換える Patch 操作の場合は排他制御されない。

  6. Patch の種類を説明しなさい

    回答例

    cf. PATCH operations

  7. サブリソースとは何か説明しなさい

    回答例 リソース本体とは別個に REST API のエンドポイントが用意されるリソースの一部要素のこと。 典型的には status 要素がサブリソースとして扱われる。サブリソースはメインリソースの編集操作では編集できない。 操作が分かれるため、RBAC による権限管理も別個に指定が必要となる。

    cf. Types (Kinds)

  8. Kubernetes API のストレージバージョンとは何か説明しなさい

    回答例 API リソースは互換性がない形で Kind が更新されることがあり、このような場合バージョンが変わる。 しかしながら、etcd に保存される形式は特定のバージョンのみで、REST API で要求されたバージョンに必要に応じて変換(convert)される。 etcd に保存されるバージョンのことを API のストレージバージョンと呼ぶ。

  9. リソース API のバージョンを更新する正しい進め方を説明しなさい

    回答例

    1. 新しいバージョンを追加する。ストレージバージョンはまだ変えない。
    2. 新しいバージョンが安定したらストレージバージョンを新しいものに変更する。
    3. 上記の時点では、保存済みのリソースはまだ古いバージョンで保存されているため、replace して保存形式を新しいバージョンに変える。
    4. 古いバージョンを deprecate する。
    5. etcd の保存データがすべて新しいバージョンに変更した後、古いバージョンを完全に廃止する。

    cf. The Future of Your CRDs – Evolving an API

  10. Conversion webhook はなぜ round-trip conversion を実装する必要があるか説明しなさい

    回答例 ストレージバージョンが v1 で、REST API では v2 で Create するとする。 この際、v2 → v1 に変換しなければならない。

    次に保存したリソースを v2 で Get するとする。この際には v1 → v2 に変換する必要がある。 Create したものが Get できるようにするため、conversion webhook は変換の過程で情報が欠落しないよう実装しなければいけない。

  11. Round-trip conversion で情報の欠落を防ぐにはどうするか説明しなさい

    回答例 annotation に欠落する情報を保存するのが一般的。 例えば HPA v2 で増えたフィールドの情報は v1 では annotation として保存されている。

    cf. Horizontal Pod Autoscaler

  12. Aggregation API server と kube-apiserver はどのように認証・認可しているか説明しなさい

    回答例 Aggregation API server と kube-apiserver は相互に TLS で認証している。 認証の詳細については Authentication Flow を参照すること。

    Aggregation API server は kube-apiserver に SubjectAccessReview というリソースを作る権限を持つ必要がある。 権限を与えるには kube-system Namespace にある extension-apiserver-authentication-reader という組み込みの Role を Aggregation API server を動かしている ServiceAccount に RoleBinding で与える。

コントローラー実装

  1. Event リソースについて用途と生存期間を説明しなさい

    回答例 Event リソースは他のリソースに起きた変化を記録するために作る。 kubectl describe pods NAME とすると指定の Pod に対応する Event が読みやすく表示される。

    標準では一時間しか保存されないため、必要に応じて吸いだす必要がある。

    cf. Emitting, Consuming, and Presenting: The Event Lifecycle

  2. Node などのクラスタリソースの Event はどの namespace に作るべきか答えなさい

    回答例 default namespace

  3. Reconcile とはどのような処理か説明しなさい

    回答例 宣言的(Declarative) API を実装する要となる仕組みで、現在の状態を取得し、宣言された状態に適宜修正する処理のことを指す。

  4. kube-apiserver の watch API について説明しなさい

    回答例 Watch API は、指定したリビジョン以降の変更を抜け漏れなくストリームで受信できる API である。 例えば Pod の作成を監視して動作するコントローラーを作成する場合、都度 GET で polling するより watch API で監視するほうが圧倒的に効率が良い。

  5. kube-apiserver の delete API について説明しなさい

    回答例 Delete API は、指定したリソースの削除を開始する API である。 REST API としての DELETE リクエストが完了して成功しても、即座にリソースが kube-apiserver および etcd から削除されるとは限らない。

    kubectl delete がリソースの削除が完了するまで待機するのは、kubectl が kube-apiserver を監視して待機しているだけである。 kubectl delete --wait=false とすれば、削除の完了を待たない。

    コントローラーを実装する観点では、Delete API の呼び出しを受け付けた直後は Delete イベントではなく Update イベントが来ることがあるので注意すること。

  6. metadata.deletionTimestamp とは何か、どのように動作するかを説明しなさい

    回答例 Delete API を呼び出されたときに、即座に当該リソースを消せないときにセットされるフィールドである。 Pod を graceful に削除する場合や後述の metadata.finalizers が空でないときが該当する。 Update などで直接設定することはできない。

    Pod の場合 metadata.deletionTimestamp の設定時刻を過ぎると Terminating という状態にあると判断され、コンテナプロセスには SIGKILL が送られる。 なお時刻を過ぎたからと言って API サーバーから削除されるわけではない。

    Pod 以外のリソースで graceful termination が可能なものがあるかは不明(ServiceAccount では指定できなかった)。

    cf. Metadata

  7. metadata.finalizers とは何か、どのように動作するかを説明しなさい

    回答例 finalizers が空でない場合、kube-apiserver は DELETE リクエストを受けたリソースの metadata.deletionTimpstamp をセットするだけで etcd からは削除しない。 リソースを監視しているコントローラーは、deletionTimestamp がセットされている場合必要な後始末をしたのち、自身が管理する finalizers の要素を取り除く。

    finalizers が空になり次第 kube-apiserver は etcd からリソースを削除する。

    cf. Using Finalizers

  8. client-go が提供する k8s.io/client-go/tools/leaderelection パッケージについて説明しなさい

    回答例 kube-apiserver 上のリソースを利用してリーダー選出する。 coordination.k8s.io の Lease を使うことが推奨されている。 このパッケージは古い leader が動き続けていないことを保証(fencing)はしてくれないので注意。

    実装例: https://github.com/kubernetes/client-go/blob/master/examples/leader-election/main.go

  9. metadata.ownerReferences とは何か、どのように動作するかを説明しなさい

    回答例 リソースを削除するときに、そのリソースの子となるリソースもまとめて消したいことが良くある。 そのような仕組みを実装するのが metadata.ownerReference で、親リソースを指定しておくと親が消えたら当該リソースも連鎖的に削除される。

    ownerReferences には controller 一つと controller でないものを複数指定可能だが、controller-runtime には簡単に設定できるユーティリティが存在する。 ただし、複数の owner がいる場合そのすべてが削除されてからリソースが GC されるので、controller でないものを指定するケースは滅多にない。

    cf. SetControllerReference

  10. StatefulSet を削除すると VolumeClaimTemplate から作成された PVC/PV はどうなるか説明しなさい

    回答例 それらの PVC/PV は放置される。

    PVC を自動で削除したい場合、コントローラーが PVC の ownerReference を所有者である StatefulSet ないしさらに親のカスタムリソースに設定すると良い。 Elastic Cloud on Kubernetes (ECK) では、Elasticsearch カスタムリソースが PVC の owner となっている。

プログラムと連携動作

  1. 以下のコンポーネントの役割を説明しなさい

    • etcd
    • kube-apiserver
    • kube-controller-manager
    • kube-scheduler
    • kubelet
    • kube-proxy
    • containerd
    • CoreDNS

    回答例

    • etcd: Kubernetes の永続データを保存する。ログや PersistentVolume のデータは対象外。
    • kube-apiserver: etcd にアクセスする唯一のコンポーネント。様々な API を提供する。
    • kube-controller-manager: kube-apiserver を見張り、各種の調整動作を行う。
    • kube-scheduler: kube-apiserver を見張り、Node にスケジュールされていない Pod をスケジュールする。
    • kubelet: 各 Node 上で動作し、Pod を動作させる。
    • kube-proxy: 各 Node 上で動作し、Service のロードバランサを実装する。
    • containerd: CRI という共通インタフェースで kubelet からコンテナ実行を請け負う。
    • CoreDNS: Service の ClusterIP を DNS で解決するクラスタ内部の DNS サービスを実装する。
  2. Pod リソースを作成して内部のコンテナが実際に動作するまでの各コンポーネントの動作を説明しなさい

    回答例

    1. kube-apiserver が etcd に Pod リソースを保存する
    2. kube-scheduler が Node がまだ割り当てられていない Pod を見つける
    3. kube-scheduler は Node の空きリソースや affinity 条件を元に Node を割り当てる
    4. API サーバーを監視している kubelet が自 Node に割り当てられた Pod を見つける
    5. Pod 内で共有される Linux namespace (network など)のための infrastructure コンテナを作る
      1. CRI を通じて containerd などのコンテナランタイムにコンテナを作らせる
      2. CNI プラグインに network namespace を初期化させる
    6. Pod で定義されている initContainers を CRI で順番に作成し実行する
    7. Pod で定義されている containers を CRI で並列に作成し実行する

  3. 各 namespace にある default ServiceAccount は誰がいつ作るか説明しなさい

    回答例 namespace 毎に必ずある default ServiceAccount だが、実は namespace 作成直後には存在しない。

    namespace を監視している kube-controller-manager が少々遅れて作成する。 ServiceAccount が kube-apiserver にアクセスするトークンの Secret は、さらに遅れて作成される。

    namespace 作成直後はまだ default ServiceAccount やトークンの Secret がなくて Pod を作れないということがありえる。 そのため、自動試験などでは Pod の作成が成功するまでリトライするか、Deployment を作るのが安全。

  4. kubelet または Node が応答不能の時に Pod に何が起こるか説明しなさい

    回答例 kubelet が停止すると、kube-apiserver に heart beat が送られなくなり、速やかに taint が付けられる。 Pod には以下の toleration が付いているので標準で 300 秒は耐える。

     tolerations:
     - effect: NoExecute
       key: node.kubernetes.io/not-ready
       operator: Exists
       tolerationSeconds: 300
     - effect: NoExecute
       key: node.kubernetes.io/unreachable
       operator: Exists
       tolerationSeconds: 300
    

    300 秒を経過すると graceful termination が開始される。 Pod の spec.terminationGracePeriodSeconds は標準で 30 秒なので、metadata.deletionTimestamp が今から 30 秒後に設定される。

    さらに 30 秒経過すると Pod の Status が Terminating 状態となる。 しかし、プロセスを管理する kubelet は停止しているのでそれ以上何もできず放置される。 つまり Pod は消えずに残る。

    cf. Taint Nodes by Condition, Taint based Evictions

  5. Pod が Terminating のときの ReplicaSet コントローラーの動作を説明しなさい

    回答例 ReplicaSet コントローラーは通常、速やかに追加の Pod を新規に作成する。

  6. Pod が Terminating のときの StatefulSet コントローラーの動作を説明しなさい

    回答例 StatefulSet コントローラーは Pod 名に stable network ID を付ける都合上、追加の Pod を新規に作成できない。

  7. Node の fencing 手順を説明しなさい

    回答例 上記の通り、Node が応答不能になると Pod は Terminating のまま消えない。 Node リソースを消せば当該 Node 上の Pod もまとめて消えるが、Node と API サーバー間の通信障害で分断されていただけの場合、StatefulSet の同一 ID の Pod が二つクラスタ内で実行されて split brain を引き起こす恐れがある。

    それを避けるため、応答不能ノードは BMC 経由で電源を切る STONITH などで確実に活動停止させたのち、Node リソースを削除する。

資源管理

  1. コンテナの resources.limits と resources.requests の違いについて説明しなさい

    回答例 resources.limits は Linux カーネルの cgroups 機能を使い上限を越えて利用できないようにするのに使われる。

    resources.requests は kube-scheduler がどの Node に配置するかを計算するために使われる。 resources.requests.cpu は CFS share の設定にも使われており指定した CPU 時間を割り合いとして確保できるようになっている。

    cf. Setting the right requests and limits in Kubernetes

  2. コンテナに resources.limits.memory だけ指定した場合の振る舞いを説明しなさい

    回答例 limits だけ指定した場合、同じ値で requests が指定されたものとして振る舞う。 memory だけでなく cpu も同様。

    cf. Create a Pod that gets assigned a QoS class of Guaranteed

  3. コンテナが request した以上のメモリを使うとどうなるか説明しなさい

    回答例 request した以上にメモリを使っている Pod は、Node のメモリが不足した際に eviction の候補になる。 逆に、request 量未満であれば下記 QoS クラスや Priority クラスに関わらず通常は eviction されない。

    cf. Interactions between Pod priority and quality of service

  4. Pod の QoS クラスについて説明しなさい

    回答例 QoS クラスには Guaranteed, Burstable, BestEffort の 3 つがある。 CPU とメモリ両方の requests/limits を指定し、requests==limits である場合 Guaranteed となる。 Guaranteed 条件は満たさないが CPU かメモリを request していれば Burstable となる。 それ以外の Pod は BestEffort に分類される。

    QoS クラスは Node のメモリが不足した際に、eviction 対象の Pod を決めるために使われる。 まず BestEffort, 次に Burstable, 最後に Guaranteed となる。

    といっても Guaranteed は requests==limits なので eviction 対象には通常ならない。 例外的な状況下でのみ evict される。

    cf. Evicting end-user Pods

  5. Pod の PriorityClass について説明しなさい

    回答例 kube-scheduler が priority の低い Pod を削除し、高い優先度の Pod をスケジュールする preemption 動作をするのに使われる。

    cf. Pod Priority and Preemption

  6. Node の CPU リソースが不足するとき Pod が evict されるか答えなさい

    回答例 evict されない。そのため、requests を適切に指定しておくことは重要といえる。 CPU リソースの requests がない場合、際限なく Node に Pod が詰め込まれてしまうため。

ネットワーク

  1. Service の ClusterIP, NodePort, LoadBalancer タイプをそれぞれ説明しなさい

    回答例 ClusterIP タイプの Service は ClusterIP と呼ばれるクラスタ内部でのみルーティング可能な仮想 IP アドレスを持つ。 ClusterIP 仮想アドレスは、他のタイプの Service にも必ずある。 ClusterIP は kube-proxy により、Node 上で複数の宛先 Pod の IP アドレスに DNAT される。DNAT には iptables や IPVS が利用される。

    NodePort タイプの Service はクラスタ内で一意なポート番号を持つ。すべてのクラスタ Node は当該ポート番号に送られたパケットを宛先 Pod に転送する。

    LoadBalancer タイプの Service は ClusterIP および NodePort の機能に加えて、外部のロードバランサが割り当てる IP アドレスにパケットが届いたら宛先 Pod に転送する機能を持つ。

  2. Service と Endpoints (EndpointSlices) の関係を説明しなさい

    回答例 Service には同名の対となる Endpoint(Slice)s リソースがあり、Endpoint(Slice)s には宛先 Pod が列挙される。 Service が Pod のセレクタを持っていれば Endpoint(Slice)s は自動管理され、そうでない場合は他の手段で用意する。

  3. Pod の spec.containers.ports や Dockerfile EXPOSE の効果を説明しなさい

    回答例 spec.containers.portsname をキーとして livenessProbe や Service の targetPort で利用できる。 Dockerfile の EXPOSE はもっぱらドキュメントとしての意味しかない。

    ports/EXPOSE に書いていないポート番号で TCP/UDP で listen することができる。 逆に、ports/EXPOSE に書いてあっても listen しているとは限らない。

  4. Service の spec.externalTrafficPolicy が Local の場合、外部からのパケットはどう Pod に届くか説明しなさい

    回答例 externalTrafficPolicy は主に type=LoadBalancer の Service と併用される。 このフィールドを指定しないかデフォルトの Cluster の場合、kube-proxy は外部から届いたパケットのソースアドレスを Node のものに書き換え、Pod に転送する。 このフィールドが Local の場合、ソースアドレスは書き換えず、Node 上で動作している Pod にのみ転送する。

    Local の場合、Pod が動いていない Node に外部からのパケットが届くと行き先がなく通信に失敗する。 外部ロードバランサはそうならないよう、Pod がある Node にのみパケットを届ける。 例えば MetalLB の場合、Pod がある Node でのみロードバランサの IP アドレスを BGP で広告する。

    cf. Preserving the client source IP

モニタリング

  1. readinessProbe とは何か、失敗すると何が起こるか説明しなさい

    回答例 readinessProbe が失敗すると Pod は ready ではなくなる。 ready でない Pod は Service (Endpoints) の振り分け先から外される。

  2. livenessProbe とは何か、失敗すると何が起こるか説明しなさい

    回答例 livenessProbe に失敗したコンテナは再起動される。

アクセスコントロール

  1. クラスタワイドリソースの権限を Role で管理できるか?

    回答例 できない。

  2. 名前空間リソースの権限を ClusterRole で管理できるか?

    回答例 できる。どの名前空間にあるリソースにもアクセスさせたい場合に設定する。

    cf. KubernetesのRBACについて

  3. default サービスアカウントの権限はどうあるべきか説明しなさい

    回答例 default サービスアカウントは、ServiceAccount を指定しない Pod が広く利用するため余計な権限を与えるべきでない。

  4. kube-apiserver の privilege escalation prevention について説明しなさい

    回答例 ユーザーや ServiceAccount が (Cluster)RoleBinding を操作して他のエンティティに権限を許可する際に、kube-apiserver は操作しているユーザー/SerivceAccountが当該の権限を有しているかチェックする。 もし権限を有していない場合、RoleBinding の操作は失敗する。

    例えばコントローラーが管理下の ServiceAccount に権限を動的に追加しようとするなら、あらかじめコントローラーの ServiceAccount にも当該権限を持たせておかねばならない。

    cf. Privilege escalation prevention and bootstrapping

  5. impersonate とはどういう権限か説明しなさい

    回答例 任意の他のユーザーやグループになりすますことができる。cluster-admin にのみ許可されるべき権限。

    特権ユーザーが一般ユーザーの動作を確認するため kubectl --as=USER --as-group=GROUP で impersonate することができる。 この際 --as-group=system:authenticated も足さないといろいろ不都合があるので注意。

    cf. User impersonation

  6. 標準で用意される view, edit, admin ClusterRole について説明しなさい

    回答例 これらは Aggregated ClusterRoles と呼ばれ、特定のラベルを持つ他の ClusterRole の権限を合成した権限を与える。

    • view: Secret など秘密情報を除き、幅広くリソースを閲覧する権限を与える。Pod のログも見れる。
    • edit: 名前空間内の Role/RoleBinding を除くリソースを作成・閲覧できる。
    • admin: Role/RoleBinding も含め名前空間内のリソースを作成・閲覧できる。

    cf. User-facing roles