Kubernetes Novice Tokyo #5 (#k8snovice) https://k8s-novice-jp.connpass.com/event/187873/ で発表したLT資料です。
配信アーカイブのURLは https://youtu.be/Qxn8aQTUZuo になります。
kubeadmに学ぶクラスター構築Kubernetes Novice Tokyo #5(2020/09/09)@bells17
View Slide
▶ @bells17▶ Software Engineer▶ 主に Kubernetes 関連コンポーネントの開発など▶ Kubernetes #sig-docs-ja-reviews▶ CNBF実⾏委員▶ @bells17_
今⽇話すこと▶ kubeadm init時にどんなことが⾏われているのかについて▶ Kubeadm initによるクラスター構築処理で使われている機能・技術について
注意点▶ 僕⾃⾝はkubeadmにあまり詳しいわけではないです+ (現時点で調べてわかったことを共有するだけになります)▶ 説明は基本的にkubeadmに特に設定値を渡していないケースを想定してるつもりです▶ コードべースはv1.19です(release-1.19タグ)
アジェンダ1. kubeadmとは?2. kubeadm initによるクラスター構築
kubeadmとは?
Kubeadm▶ Kubernetesコミュニティ公式のKubernetesクラスター構築ツール▶ Kubernetesクラスター構築の「ベストプラクティス」を提供▶ Kubeadmはクラスターのブートストラップにフォーカスした機能を提供する+ コンテナランタイムやkubeletのインストールはkubeadmのスコープ外▶ Kubesprayやkindなどその他のKubernetesクラスター構築ツールの内部で使われていることがある▶ kubeadmが⾏うクラスター構築処理を1(サブ)フェーズ単位で実⾏できるようになっている▶ KubernetesコミュニティのSig Cluster Lifecycleによって開発されている
https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/1コマンドでKubernetesクラスターを構築できる
Kubeadmの様々なサブコマンド▶ kubeadm init: Kubernetesクラスターの構築▶ kubeadm join: 構築したクラスターへの参加▶ kubeadm upgrade: Kubernetesバージョンのアップグレード▶ kubeadm config: kubeadmの設定管理▶ etcこの中で今回はkubeadm initの処理にフォーカスした内容です
kubeadmはサブコマンド内で実⾏される処理がphaseという単位によって分割 されており、各phase単位でコマンドから処理が実⾏可能になっている
https://github.com/kelseyhightower/kubernetes-the-hard-way
kubeadm initの実装を読むことで、Kubernetesクラスター構築のベストプラクティスを提供してくれるツールはどのようにクラスターを構築しているのかを知ることができる
https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.10.mdImplementation design for kubeadm を読むとなんとなくはkubeadmの処理の流れが理解できる
kubeadm initによるクラスター構築
kubeadm initでやってくれること▶ 設定に基づいたKubernetesクラスターの構築▶ クラスターへの接続情報ファイル(kubeconfig)の⽣成▶ その他のマシンが構築したクラスターへ参加するためのコマンドの提⽰▶ kubeadm joinコマンド
kubeadm initのフェーズ⼀覧▶ preflight▶ certs▶ kubeconfig▶ kubelet-start▶ control-plane▶ etcd▶ wait-control-plane▶ upload-config▶ upload-certs▶ mark-control-plane▶ bootstrap-token▶ kubelet-finalize▶ addon•チェック処理•クラスター構築•Kubeadmによるクラスター管理
https://github.com/kubernetes/website/blob/master/static/images/docs/components-of-kubernetes.png
preflight▶ Kubeadmによるクラスター構築のための各種チェックを⾏う▶ Kubeadmの実⾏ユーザーのチェック▶ kubeletのバージョンチェック▶ etc
certs▶ Kubernetesクラスターのための各種証明書の⽣成を⾏う▶ CA証明書▶ APIサーバー証明書▶ etc
kubeconfig▶ 各種control plane/管理者のためのkubeconfigファイルの⽣成を⾏う▶ 以下の4者のためのkubeconfigを⽣成▶ 管理者▶ kubelet▶ kube controller manger▶ kube scheduler▶ kubernetes/kubernetesのcmd/kubeadm/app/util/kubeconfig パッケージにあるCreateBasic関数を使ってkubeconfigファイルのデータを⽣成▶ その後CreateBasic関数の呼び出し元であるCreateWithCerts関数内でクライアント証明を埋め込んでいる▶ クライアント証明書は前のステップで⽣成したファイルを読み込んでいる
https://github.com/kubernetes/kubernetes/blob/release-1.19/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go#L30-L51 CreateBasic
https://github.com/kubernetes/kubernetes/blob/release-1.19/cmd/kubeadm/app/util/kubeconfig/kubeconfig.go#L53-L61 CreateWithCerts
kubelet-start▶ kubeadmの設定に基づいたkubelet設定ファイルを⽣成し、kubeletの(再)起動を⾏う▶ systemctl/openrcを利⽤していることが前提となっているよう▶ 内部的にはsystemctlコマンドなどを実⾏しているだけ▶ 内部的な処理は以下のようになっている▶ systemctlなどで起動されているkubeletを⼀時停⽌▶ 環境変数設定を⽣成~ファイルを⽣成▶ 設定を⽣成~ファイルを作成▶ systemctlなどでkubeletを起動
control-plane▶ Static Podで各種control planeのpodを起動するためのpod specマニフェストファイルを⽣成する▶ 以下のコンポーネントのためのyamlを⽣成する▶ kube apiserver▶ kube controller manger▶ kube scheduler▶ 内部処理は以下の様になっている▶ ベースとなるpodのspecを⽣成▶ 設定に応じたkustomize/patchファイルによるspecの書き換えを⾏う▶ ⽣成したspecをstatic pod⽤のファイルとして書き込む▶ specの書き換えについてはドキュメントについては記載が⾒当たらない(気がする)
https://github.com/kubernetes/kubernetes/blob/release-1.19/cmd/kubeadm/app/phases/controlplane/manifests.go#L46-L91 ベースとなるpod specの⽣成
https://github.com/kubernetes/kubernetes/blob/release-1.19/cmd/kubeadm/app/util/staticpod/utils.go#L153-L183 Kustomizeによるpod specの書き換え
https://github.com/kubernetes/kubernetes/blob/release-1.19/cmd/kubeadm/app/util/staticpod/utils.go#L185-L225Patchによるpod specの書き換え
補⾜: Static Pod▶ Static Podの設定ディレクトリ(デフォルト: /etc/kubelet.d)以下にpodspecのマニフェストファイルを設置するとkubeletがPodを起動してくれる機能▶ Static Podはapi serverからの操作ができないという特徴をがある→ kubectlなどで削除したりできない▶ Static Podの設定ディレクトリはstaticPodPathで設定可能▶ また—manifest-urlで指定したURLから定期的に情報取得を⾏い、StaticPodを起動することも可能▶ Static Podは起動にkube apiserverを必要としないため、kube apiserverを含むcontrol planeの起動ができるということだと思う
etcd▶ Static Podでetcdのpodを起動するためのpod specマニフェストファイルを⽣成する▶ 内部処理は以下の様になっている▶ etcdのデータ⽤のディレクトリを⽣成▶ ベースとなるpodのspecを⽣成▶ 設定に応じたkustomize/patchファイルによるspecの書き換えを⾏う▶ ⽣成したspecをstatic pod⽤のファイルとして書き込む
wait-control-plane▶ Static Podでetcdのpodを起動するためのpod specマニフェストファイルを⽣成する▶ 内部処理は以下の様になっている▶ kubeletが正常に起動していることのチェックを⾏う▶ kubelet のヘルスチェック⽤のエンドポイント(http://localhost:10248/healthz)へのリクエストによって判断する▶ kube apiserverが正常に起動していることのチェックを⾏う▶ kube apiserverの /healthz へのリクエストによって判断する▶ kube apiserverが正常にレスポンスを返す = etcdも正常という判断?▶ kube controller manger/kube schedulerのチェックはここでは⾏っていないよう
upload-config▶ Kubeadm/kubeletの設定値をConfigMapに作成する▶ kubeadm側内部処理▶ kubeadmの設定と構築したクラスター情報をkubeadm-configというConfigMapに保存▶ kubeadmが?ConfigMapを取得するためのRole/RoleBindingの作成▶ kubelet側内部処理▶ kubeletの設定値をConfigMapに作成▶ 各種ノードがConfigMapを取得するためのRole/RoleBindingの作成▶ ⾃⾝のNodeリソースのCRIソケットを⽰すアノテーションの設定
upload-certs▶ 各種証明書情報をSecretに書き込む▶ 内部処理▶ 短命(2時間)なブートストラップトークンを作成する▶ 各種証明書情報をファイルから読み取り暗号化する▶ kubeadm-certsというSecretに暗号化された各種証明書情報の書き込みを⾏う▶ このSecretはOwnerReferenceでブートストラップトークンと紐付けられる▶ kubeadmが?kubeadm-certsを取得するためのRole/RoleBindingの作成を⾏う▶ これらのブートストラップトークン・証明書情報はkubeadm joinの際に利⽤されるよう
mark-control-plane▶ control planeノードにnodeRegistration.taintsで渡したtaintを設定する▶ control planeノードのラベルに node-role.kubernetes.io/master: ""の付与も⾏う▶ “Implementation design for kubeadm”を⾒る限り node-role.kubernetes.io/master:NoScheduleというtaintも設定される らしいが、実装を⾒る限りそういった箇所はなさそうだった
bootstrap-token▶ Kubeadm joinでノードをクラスターに参加させるためのブートストラップトークンSecretの⽣成を⾏う▶ 元となるブートストラップトークンはkubeadm initの各フェーズ前の初期化処理の段階で予め1つ⽣成されている▶ ブートストラップを⾏うための各種(Cluster)RoleBindingの設定をブートストラップトークンの所属グループであるsystem:bootstrappers:kubeadm:default-node-tokenに⾏う▶ kube-systemのcluster-info ConfigMapにブートストラップ⽤の設定ファイルを設置する▶ system:anonymousに対してkube-systemのcluster-info ConfigMapの取得権限を付与する
補⾜: system:anonymous▶ system:anonymousはKubernetesの匿名リクエストに与えられるユーザー▶ kube apiserver側の認証⽅法で拒否されなかった場合には匿名リクエスト扱いになるらしい▶ 詳細は https://kubernetes.io/docs/reference/access-authn-authz/authentication/ をチェック
補⾜: Bootstrap Token▶ 新しいクラスターを作成する、または新しいノードを既存のクラスターに結合するときに使⽤することを⽬的としたBearerトークンとのこと▶ 詳細は https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/ をチェック
kubelet-finalize▶ kubeletが使⽤するkubeconfigに使われる証明書情報の更新を⾏う▶ 更新に使われる証明書はkubeletの証明書設定ディレクトリのkubelet-client-current.pemとなる▶ この証明書ファイルが存在する場合、このファイルを使ってkubeconfigが更新される▶ この証明書の設定ディレクトリのデフォルトは/etc/kubernetes/pkiの よう
addon▶ DNS(coreDNS or kubeDNS)とkube-proxyがアドオンとしてデプロイされる▶ それぞれDeployment/DaemonSetと合わせてService Accountや(Cluster)Role、(Cluster)RoleBinding、ConfigMapなど諸々が⾃動⽣成される▶ Control planeのstatic podのようにkustomizeなどを使ってパッチを当てるといったことはできないっぽい
まとめ
まとめ▶ kubeadm initでどのようにKubernetesクラスターが作られているのか紹介しました▶ control plane/etcdの管理にstatic podを使っている、ブートストラップトークンという仕組みを使って新しいノードがクラスターに参加できるようになっている、addonはkubeadmで直接設定ファイルなどを⽣成してデプロイしているなど、Kubernetse TheHard Wayをやるのとはまた違ったやり⽅になっていて⾯⽩かったです▶ ある程度同じようなことはドキュメントに書いてあるとはいえ、コードレベルで追っていくとドキュメントには書いてないことも把握することができて勉強になりました
もっと詳しく知りたい⽅は▶ 『解体kubeadm フェーズから読み解くKubernetesクラスタ構築ツールの全貌』という書籍が今⽉(9⽉)はじめに発売されていたらしいので、こちらにより詳しく書いて有りそうです (僕も昨⽇この本がリリースされていることを知りました)
参考資料▶ A Stronger Foundation for Creating and Managing Kubernetes Clusters https://kubernetes.io/blog/2017/01/stronger-foundation-for-creating-and-managing-kubernetes-clusters/▶ Implementation details https://kubernetes.io/docs/reference/setup-tools/kubeadm/implementation-details/#mark-the-node-as-control-plane▶ Installing kubeadm https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/▶ Creating a cluster with kubeadm https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/▶ Implementation design for kubeadm https://github.com/kubernetes/kubeadm/blob/master/docs/design/design_v1.10.md▶ kubernetes/kubernetes/cmd/kubeadm https://github.com/kubernetes/kubernetes/tree/release-1.19/cmd/kubeadm▶ kubernetes/kubeadm https://github.com/kubernetes/kubeadm▶ Using Kustomize with Kubeadm Configuration Files https://blog.scottlowe.org/2019/10/16/using-kustomize-with-kubeadm-configuration-files/▶ Create static Pods https://kubernetes.io/docs/tasks/configure-pod-container/static-pod/▶ Authenticating with Bootstrap Tokens https://kubernetes.io/docs/reference/access-authn-authz/bootstrap-tokens/▶ Super Simple Discovery API https://github.com/kubernetes/community/blob/master/contributors/design-proposals/cluster-lifecycle/bootstrap-discovery.md▶ Authenticating https://kubernetes.io/docs/reference/access-authn-authz/authentication/▶ Kubernetes The Hard Way https://github.com/kelseyhightower/kubernetes-the-hard-way
Thanks / Question?▶ @bells17▶ Slide: https://speakerdeck.com/bells17▶ @bells17_