kubectlの実行が開始されるとKubernetesで何が起こりますか? パート2



ご注意 perev。 :素材の翻訳の2番目と最後の部分で、「... Kubernetes版がいつ起こるのか!」 nginx

最初の部分がkubectl、kube-apiserver、etcd、および初期化子の作業に当てられていた場合は、Deployments and ReplicaSetsコントローラー、情報提供者、スケジューラー、およびkubeletについて説明します。 ユーザーによって(kubectlを介して)送信されたリクエストがKubernetesで承認および実行され、新しいオブジェクト(リソース)が作成されてデータベース(etcd)に保存された後に停止したことを思い出してくださいapiserverの場合)。

制御サイクル


デプロイメントコントローラー


この時点で、Deploymentエントリはetcdに存在し、すべての初期化ロジックは完了しています。 次の手順は、Kubernetesが使用するリソーストポロジを構成するためのものです。 考えてみると、Deploymentは本当にReplicaSetのコレクションであり、ReplicatSetは囲炉裏のコレクションです。 単一のHTTPリクエストからこの階層を作成するためにKubernetesで何が起こりますか? ここでは、統合されたK8sコントローラーがビジネスになります。

Kubernetesは、システム全体で「コントローラー」を広範囲に使用しています。 コントローラーは、Kubernetesシステムの現在の状態を目的の状態と比較する非同期スクリプトです。 各コントローラーはその小さな部分を担当し、 kube-controller-managerコンポーネントによって起動されます。 ビジネスに参入した最初の企業であるDeployment Controllerを紹介しましょう。

Deploymentを含むレコードがetcdに保存されて初期化されると、kube-apiserverに表示されます。 新しいリソースが表示されると、対応するレコード(展開)間の変更を追跡するタスクが展開コントローラーによって検出されます。 この場合、コントローラーは、情報提供者を介して作成イベント用の特別なコールバックを登録します(詳細については、以下を参照してください)。

このハンドラーは、Deploymentが最初に利用可能になったときに呼び出され、内部キューにオブジェクトを追加することで作業を開始します。 このオブジェクトの処理に到達するまでに、コントローラーはDeploymentを検査し 、ReplicaSetレコードとハースが関連付けられていないことを認識します。 彼はラベルセレクターによってkube-apiserverをポーリングすることでこの情報を受け取ります(詳細については、 Kubernetesのドキュメント - およそTransl。を参照してください)。 この同期プロセスは状態について何も知らない(状態に依存しない)ことに注意してください。既存のレコードと同じ方法で新しいレコードをチェックします。

必要なレコードが存在しないことがわかると、コントローラーはスケーリングプロセスを開始して、予想される状態に到達します。 このプロセスは、ReplicaSetリソースをロールアウト(作成など)し、それにラベルセレクターを割り当て、最初のリビジョンを割り当てることで実行されます。 ReplicaSetのPodSpecおよびその他のメタデータは、展開マニフェストからコピーされます。 この後、展開レコードの更新も必要になる場合があります(たとえば、進行期限が設定されている場合、 つまり、仕様フィールド.spec.progressDeadlineSeconds.spec.progressDeadlineSeconds - 約Transl。 )。

その後、ステータスが更新され 、同じ調整サイクルが開始され、展開を目的の完了状態と比較します。 コントローラーはReplicaSetの作成のみを認識しているため、調整ステージはReplicaSetを担当する次のコントローラーで続行されます。

ReplicaSetsコントローラー


前の手順で、展開コントローラーが展開用の最初のReplicaSetを作成しましたが、まだ炉はありません。 これがReplicaSetsコントローラーの助けとなります。 そのタスクは、ReplicaSetsおよび依存リソース(ハース)のライフサイクルを監視することです。 他のほとんどのコントローラーと同様に、これは特定のイベントのトリガーのハンドラーによるものです。

私たちが興味を持っているイベントは創造です。 (展開コントローラーの結果として)ReplicaSetが作成されると、RSコントローラーは新しいReplicaSetの状態を検査し、存在するものと必要なものの間に違いがあることを認識します。 したがって、彼はReplicaSetに属する炉床を展開することで状態を修正します。 それらを作成するプロセスは、ReplicaSetバースト(親Deploymentから継承)の数に対応してきちんと行われます。

囲炉裏の作成操作もバッチで実行されますSlowStartInitialBatchSizeから開始し、「スロースタート」操作の反復が成功するたびにこの値をSlowStartInitialBatchSizeします。 このアプローチは、頻繁なハースロードエラー(たとえば、リソースクォータによる)の場合に、kube-apiserverが不要なHTTP要求をスローするリスクを減らすように設計されています。 失敗した場合は、システムの残りの部分への影響を最小限に抑えてそれを実行します。

Kubernetesは、所有者、所有者参照(親IDを参照する子リソースのフィールド)へのリンクを介してオブジェクトの階層を実装します。 これにより、ガベージコレクターは、コントローラー管理のリソースが削除(カスケード削除)されたときにすべての子リソースを確実に見つけるだけでなく、親が子のために戦わないための効果的な方法も提供します(同じ子によって)。

Owner Referencesを使用したアーキテクチャのもう1つの利点は、ステートフルであるということです。コントローラがリブートする必要がある場合、リソーストポロジはコントローラから独立しているため、そのシンプルはシステムの他の部分に影響しません。 分離に焦点が当てられているのは、コントローラー自体のアーキテクチャーに浸透しているためです。コントローラーは、明示的に所有していないリソースでは機能しません。 逆に、コントローラは、 干渉非共有ではなく、リソースを所有するという主張において選択的でなければなりません。

しかし、所有者のリンクに戻ります。 「孤立した」リソースがシステムに表示されることがあります-通常、これは次の理由によるものです。

  1. 親は削除されますが、子供は削除されません。
  2. ガベージコレクションポリシーは、子の削除を禁止します。

これが発生すると、コントローラーは、孤立した親が新しい親によって採用されたことを確認します。 多くの親は子を申請できますが、成功するのはそのうちの1人だけです(残りは検証エラーを受け取ります)。

情報提供者


お気づきかもしれませんが、RBACやDeploymentsなどのコントローラーの操作では、クラスターの状態を取得する必要があります。 RBACオーソライザーを使用した例に戻ると、要求が到着すると、オーセンティケーターはユーザーの状態の初期表現を将来の使用のために保存することがわかります。 後で、承認者はそれを使用して、ユーザーに関連付けられているすべてのロールとロールバインディングをetcdから取得します。 コントローラーは、このようなリソースをどのように読み取り、変更する必要がありますか これは一般的な使用例であり、インフォーマーの助けを借りてKubernetesで解決されることがわかりました。

情報提供者は、コントローラーがリポジトリーからイベントをサブスクライブし、関心のあるリソースのリストを取得できるようにするパターンです。 使いやすい抽象化を提供することに加えて、キャッシングなどの多くの基本的なメカニズムも実装します(kube-apiserverへの接続数と、サーバーおよびコントローラー側での再シリアライズの必要性を減らすため、重要です)。 さらに、このアプローチにより、コントローラーは、誰かの足を踏むことを恐れることなく、 スレッドセーフティと対話できます。

このブログ投稿で、インフォーマーがコントローラーに関してどのように機能するかについて詳しくお読みください。 注transl。:情報提供者の仕事は、ブログのこの翻訳された記事でも説明されています。)

プランナー


すべてのコントローラーがうまくいった後、Deployd、ReplicaSet、および3つのポッドがetcdに保存され、kube-apiserverで使用可能になります。 ただし、ポッドはまだサイトにスケジュール/割り当てられていないため、 Pending状態のままです。 スケジューラーは、これを行う最後のコントローラーです。

スケジューラは、コントロールプレーンの独立したコンポーネントとして起動し、他のコントローラーと同様に動作します。イベントを追跡し、状態を目的の状態にしようとします。 この場合、PodSpecのNodeNameフィールドが空のポッドを選択し、割り当て可能な適切なノードを見つけようとします。 適切なノードを見つけるために、特別な計画アルゴリズムが使用されます。 デフォルトでは、次のように機能します。

  1. スケジューラーが開始すると、デフォルトの述部チェーンがログに記録されます 。 これらの述語は基本的に、呼び出されたときに炉床を配置するのに適しノードを除外する関数です。 たとえば、CPUまたはRAMリソースの明示的な要件がPodSpecで設定されており、ノードがリソース不足のためにそのような要件を満たしていない場合、このノードは炉床用に選択されません(ノードのリソース容量は、この容量で実行されているコンテナの要求リソースの合計を引いたものと見なされます)瞬間)。
  2. 適切なノードが選択されると、最も適切なノードを選択してランク付けするために一連の優先機能が起動されます。 たとえば、システム全体にワークロードをより適切に分散するために、要求されたすべてのリソースよりも少ないノードに優先順位が与えられます(これは、ワークロードが小さいことの指標として機能するためです)。 これらの機能が起動すると、各ノードに数値評価が割り当てられます。 最高の評価を持つノードが計画(予定)のために選択されます。

アルゴリズムがノードを決定すると、スケジューラ NameUID値がハースに対応するBindingオブジェクトを作成しObjectReferenceフィールドには選択したノードの名前が含まれます。 POST要求を介してapiserverに送信されます。

kube-apiserverがBindingオブジェクトを受け取ると、レジストリはそれを逆シリアル化し、ハースオブジェクトの次のフィールドを更新します: PodScheduledからNodeName設定対応する注釈を追加しPodScheduledステータスをTrue 設定True

スケジューラーがノードをポッドに割り当てると、このポッドにあるクーベレットが作業を開始します。

スケジューラのカスタマイズに関する注意 :興味深いことに、述語と優先度の両方の機能が拡張されており、 --policy-config-fileフラグで決定でき--policy-config-file 。 これにより、ある程度の柔軟性が得られます。 管理者は、個々のデプロイメントに対してスケジューラー(任意の処理ロジックを備えたコントローラー)を実行することもできます。 PodSpecにschedulerNameが含まschedulerName場合、Kubernetesはこのポッドのスケジューリングを適切な名前で登録されているすべてのスケジューラーに渡します。

キュベレット


ハース同期


さて、メインコントローラーループは完了です。 要約すると、HTTPリクエストは認証、承認、アクセス制御の段階を通過しました。 etcdでは、Deployment、ReplicaSet、および3つのポッドが作成されました。 初期化子のセットを満たしました。 最後に、各ポッドに適切なノードが割り当てられました。 しかし、これまで、私たちによって議論された状態はetcdにのみ存在していました。 次のステップには、Kubernetesのような分散システムの主要なポイントである作業ノード全体にこのステータスを広めることが含まれます。 これは、kubeletと呼ばれるコンポーネントを介して発生します。 行こう!

Kubeletは、Kubernetesクラスター内のすべてのノードで実行されるエージェントであり、とりわけ、炉のライフサイクルを維持する責任があります。 したがって、「ハース」抽象化(本質的にはKubernetesの概念にすぎません)をそのビルディングブロック(コンテナ)に解釈するロジック全体に役立ちます。 また、ボリュームのマウント、コンテナのログ、ガベージコレクション、およびその他多くの重要なことに関連するすべてのロジックを処理します。

Kubeletはコントローラーとして再び便利に表示されます。 彼は20秒ごとにkube-apiserverでポッドをポーリングします(これは構成可能です) [Kubernetesの同様の間隔は、 このブログ投稿で説明されています- perev。 ] 、kubeletが実行されているノードの名前と一致するNodeName値を持つものを除外します。 囲炉裏のリストを受け取った彼は、それを内部キャッシュと比較し、新しい補充を発見し、差異が存在する場合は状態の同期を開始します。 この同期プロセスがどのように見えるか見てみましょう:

  1. 潜水艦が作成された場合(私たちの場合)、kubelet 初期メトリックを登録します。これは、炉の遅延を追跡するためにPrometheusによって使用されます。
  2. 現在の炉床フェーズの状態を表すPodStatusオブジェクトがPodStatusます。 炉床段階は、そのライフサイクルにおける炉床の位置の高レベルの指定です。 例: PendingRunningSucceededFailedおよびUnknown 。 定義するのはそれほど簡単ではないので、正確に何が起こるか見てみましょう。
    • まず、 PodSyncHandlersチェーンがPodSyncHandlers呼び出されます。 各ハンドラーは、ノード上にunderが残るかどうかをチェックします。 ここで何もする必要がないと判断した場合、ハースのフェーズはPodFailed変わり 、ハースノードから削除されます。 たとえば、 activeDeadlineSecondsの値をactiveDeadlineSeconds (ジョブ中に使用)、 activeDeadlineSecondsノードから削除する必要があります。
    • 次に、炉床段階はその初期コンテナと実際のコンテナの状態によって決定されます。 このケースのコンテナはまだ起動されていないため、「待機中」 待機中として分類されます。 保留中のコンテナを持つ人は誰でもPendingです。
    • 最後に、炉床の状態はコンテナの状態によって決まります。 コンテナランタイムによってコンテナがまだ作成されていないため、 PodReady条件 False に設定されます。
  3. PodStatus作成されると、Pod状態マネージャーに送信され、apiserverを介してetcdのエントリが非同期に更新されます。
  4. 次に、一連のアクセスハンドラーが起動し、ポッドに正しいセキュリティ権限があることを確認します。 特に、AppArmorおよびNO_NEW_PRIVSプロファイルが適用されます。 この段階で失敗したポッドは、無期限にPending状態のままになります。
  5. 実行時フラグcgroups-per-qos場合、kubeletは炉床のcgroupを作成し、リソースパラメーターを適用します。 これは、炉床のサービス品質(QoS)の最適な実装を可能にするために行われます。
  6. 囲炉裏データを含むディレクトリが作成されます。 これらには、ハースのディレクトリ(通常は/var/run/kubelet/pods/<podID> )、そのボリューム( <podDir>/volumes )、およびプラグイン( <podDir>/plugins )が含まれます。
  7. ボリュームマネージャーは、 Spec.Volumesで定義されているすべての必要なボリュームを接続し、それらを待ちます。 一部のポッドは、マウントされたボリュームのタイプ(クラウドボリュームまたはNFSボリュームなど)によっては時間がかかる場合があります。
  8. Spec.ImagePullSecretsで指定されたすべてのシークレットはapiserverから取得されるため、コンテナーにさらに挿入できます。
  9. その後、コンテナランタイムがコンテナを起動します(以下で詳しく説明します)。

CRIおよび一時停止コンテナー


これで、準備の主要部分が完了し、コンテナを打ち上げる準備ができた段階になりました。 これを実行するソフトウェアは、 コンテナランタイムと呼ばれます(例: rktまたはrkt

拡張性を高めるために、kubeletはバージョン1.5.0からCRI(Container Runtime Interface)と呼ばれる概念を使用して、特定のコンテナーランタイムと対話しました。 要するに、CRIはkubeletとランタイムの特定の実装との間の抽象化を提供します。 相互作用は、 プロトコルバッファー (より高速なJSONなど)とgRPC API (Kubernetesでの操作の実行に適したAPIタイプ)を介して行われます。 これは非常にクールなアイデアです。kubeletとランタイムの間で合意された合意を使用する場合、コンテナーがどのようにオーケストレーションされるかの実装の実際の詳細は重要性を失うためです。 この合意のみが重要です。 このアプローチでは、コアKubernetesコードを変更する必要がないため、最小限のオーバーヘッドで新しいランタイムを追加できます。

翻訳 :KubernetesのCRIおよびCRI-Oの実装について、 この記事で詳しく説明しました 。)

十分な叙情的な余談-コンテナの展開に戻る... kubelet 初めて起動すると、kubelet リモートプロシージャコール(RPC) RunPodSandboxます。 その名前の「サンドボックス」という言葉は、コンテナのセットを表すCRI用語であり、Kubernetesでは、あなたが推測したとおりです。 この用語は、コンテナ以外を実際に使用できる他のランタイム環境(「サンドボックス」が仮想マシンであるハイパーバイザーベースの実行可能環境を想像してください)の意味を失わないように、意図的に非常に広義です。

この例では、Dockerを使用します。 この実行可能環境では、サンドボックス化には「一時停止」コンテナの作成が含まれます。 一時停止コンテナは、炉内の他のすべてのコンテナの親として機能し、ロードされたコンテナが使用する炉床レベルのリソースの多くをホストします。 これらの「リソース」は、Linux名前空間(IPC、ネットワーク、PID)です。 コンテナーがLinuxでどのように機能するかよくわからない場合は、この情報をすばやく更新しましょう。 Linuxカーネルには名前空間の概念があり、ホストオペレーティングシステムが特定のリソースセット(CPUやメモリなど)を取得し、このリソースセットを消費する唯一のリソースであるかのようにプロセスに割り当てることができます。 Linuxはリソースの割り当てを管理する方法であるため、Cgroupも重要です(警官がリソースの使用を制御するのに似ています)。 Dockerは、これらのカーネル機能の両方を使用して、リソースが保証され、分離が提供されるプロセスをホストします。 Linuxxコンテナの仕組みに関する詳細は、このすばらしいb0rk出版物にあります。 「。

一時停止コンテナーは、これらすべての名前空間を配置する方法を提供し、子コンテナーがそれらを共有できるようにします。 単一のネットワーク名前空間の一部として、同じ炉床のコンテナは、localhostを介して互いにアクセスできます。 一時停止コンテナの2番目の役割は、PID名前空間の機能に関連しています。 このタイプの名前空間では、プロセスが階層ツリーを形成し、最上位プロセスの「init」がデッドプロセスの「抽出」を担当します(オペレーティングシステムのプロセステーブルからエントリを削除します- およそTransl。 。 この仕組みの詳細については、 この優れた記事をご覧ください 。 一時停止コンテナが作成されると、ディスク上にチェックポイントが作成されて開始されます。

CNIおよびポッドネットワーク


囲炉裏にスケルトンが出現しました。囲炉裏の内部でのやり取りを可能にするために、すべての名前空間を保護する一時停止コンテナです。 しかし、ネットワークはどのように機能し、構成されているのでしょうか?

kubeletは、囲炉裏のネットワークを構成するときに、このタスクをCNIプラグインに委任します。 CNIはContainer Network Interfaceの略で、Container Runtime Interfaceと同様の方法で機能します。 , CNI — , . , kubelet JSON ( /etc/cni/net.d ), CNI ( /opt/cni/bin ) stdin. JSON:

 { "cniVersion": "0.3.1", "name": "bridge", "type": "bridge", "bridge": "cnio0", "isGateway": true, "ipMasq": true, "ipam": { "type": "host-local", "ranges": [ [{"subnet": "${POD_CIDR}"}] ], "routes": [{"dst": "0.0.0.0/0"}] } } 

— , — CNI_ARGS .

CNI — bridge :

  1. Linux- .
  2. ( veth-) pause-, . veth- : , — , .
  3. pause- IP . IP-. IP IPAM-, JSON-.
    • IPAM : . IP/ , , . IPAM- host-local IP- . , IP- .
  4. DNS kubelet IP- DNS- CNI, resolv.conf .

, kubelet JSON, .

( . . : CNI .)


, , ? , , .

(overlay networking) , . Flannel. — L3 IPv4- . Flannel , ( , CNI), . etcd. UDP-, . CoreOS .


. ? .

, kubelet . init-, PodSpec, — . :

  1. . , PodSpec.
  2. CRI . ContainerConfig ( , , , , , ..) PodSpec protobufs CRI. Docker Daemon API payload . (, , , ID ).
  3. CPU Manager — , 1.8 alpha CPU UpdateContainerResources CRI.
  4. .
  5. - (post-start) , . Exec ( ) HTTP ( HTTP- endpoint ). , , Running .

まとめ


わかった できた 終わり。

3 , . , kubelet CRI.

翻訳者からのPS


ブログもご覧ください。

Source: https://habr.com/ru/post/J342822/


All Articles