K8S クラスターのスケジューリング


1. スケジュールの制約

Kubernetes は List-Watch メカニズムを使用して各コンポーネントと連携してデータの同期を維持し、各コンポーネント間の設計により分離が実現されます。

ユーザーは、構成ファイルに従って kubectl 経由で APIServer にコマンドを送信し、Node ノード上にポッドとコンテナを作成します。
APIServer は、API 呼び出し、権限制御、リソース呼び出し、リソース ストレージのプロセスを経ていますが、実際にはアプリケーションのデプロイを開始していません。導入プロセス全体を完了するには、コントローラー マネージャー、スケジューラー、および kubelet の支援が必要です。

Kubernetes では、すべてのデプロイメント情報が etcd に書き込まれ、保存されます。実際、etcd がデプロイメント情報を保存すると、Create イベントが APIServer に送信され、APIServer は etcd によって送信されたイベントをリッスン (監視) します。他のコンポーネントも APIServer によって送信されたイベントを監視 (ウォッチ) します。

2. ポッド起動の一般的な作成プロセス

(1) ここには 3 つの List-Watch があります。つまり、Controller Manager (マスター上で実行)、Scheduler (マスター上で実行)、および kubelet (ノード上で実行) です。プロセスの開始後に APIServer によって送信されたイベントをリッスン (監視) します。

(2) ユーザーは、kubectl または他の API クライアントを通じて APIServer にリクエストを送信し、Pod オブジェクトのコピーを作成します。

(3) APIServer は Pod オブジェクトの関連メタ情報を etcd に保存しようとします。書き込み操作が完了すると、APIServer は確認情報をクライアントに返します。

(4) etcd は Pod 作成情報を受け取ると、Create イベントを APIServer に送信します。

(5) コントローラー マネージャーが APIServer 内のイベントをリッスン (https のポート 6443 経由で監視) しているため。このとき、APIServer は Create イベントを受信し、Controller Manager に送信します。

(6) Create イベントを受信した後、コントローラー マネージャーはレプリケーション コントローラーを呼び出し、ノード上に作成する必要があるコピーの数を確認します。レプリカの数が RC で定義された数よりも少なくなると、RC は自動的にレプリカを作成します。要するにコピー数を保証するController(PS:伸縮を担当)です。

(7) Controller Manager が Pod のコピーを作成した後、APIServer は Pod の詳細情報を etcd に記録します。たとえば、ポッドのコピーの数やコンテナの内容などです。

(8) 同じ etcd がイベントを通じて APIServer に Pod 作成情報を送信します。

(9) スケジューラはAPIServerを監視(Watching)しており、システムの「上位と下位を繋ぐ」役割を担っているため、「上位を繋ぐ」とは、作成されたPodイベントを受信して​​Nodeを配置する役割を担うことになります。彼らにとって、「下位を接続する」ということは、配置作業が完了した後、ノード上の kubelet プロセスが後続の作業を引き継ぎ、ポッドのライフサイクルの「後半」を担当することを意味します。言い換えれば、スケジューラーの役割は、スケジューリング アルゴリズムとポリシーに従って、スケジュールされるポッドをクラスター内のノードにバインドすることです。

(10) スケジューラはスケジューリング完了後に Pod 情報を更新しますが、このときの情報はより豊富になります。ポッドのレプリカの数に加えて、レプリカの内容もわかります。また、どのノードにデプロイするかもわかります。そして上記のPod情報をAPI Serverに更新し、APIServerからetcdに更新して保存します。

(11) etcd は更新に成功したイベントを APIServer に送信し、APIServer もこの Pod オブジェクトのスケジューリング結果の反映を開始します。

(12) Kubelet は Node 上で実行されるプロセスであり、APIServer によって送信された Pod 更新イベントを List-Watch (Watch、https のポート 6443 経由) を通じてリッスンします。kubelet は、現在のノードで Docker を呼び出してコンテナを起動しようとし、結果として得られるポッドとコンテナのステータスを APIServer に送り返します。

(13) APIServerはPodのステータス情報をetcdに保存します。etcd が書き込み操作が正常に完了したことを確認すると、APIServer はイベントが受け入れられる関連する kubelet に確認メッセージを送信します。

注: ポッドの作成作業が完了した後も、kubelet がまだリッスンし続けるのはなぜですか? 理由は非常に簡単で、この時点で kubectl が Pod のコピー数を拡張するコマンドを発行すると、上記のプロセスが再度トリガーされ、kubelet が最新の Pod デプロイメントに応じて Node リソースを調整します。あるいは、Pod のコピー数は変わっていないものの、その中のイメージ ファイルがアップグレードされており、kubelet が自動的に最新のイメージ ファイルを取得してロードしている可能性があります。

ここに画像の説明を挿入します
リストウォッチ機構

1. kubectl は、Pod リソース オブジェクトのコピーを作成するリクエストを apiserver に送信し、apiserver は Pod リソース オブジェクトのコピーを作成するリクエストを etcd に書き込みます。

2. etcd が記述された後、完成した Pod コピーの作成イベントが apiserver に送信され、apiserver はライフサイクルをクライアントに直接返します。

3. 次に、Pod のコピーを作成するイベントをコントローラー マネージャーに送信します。コントローラー マネージャーは、関連するイベントに従って Pod を作成し、Pod の作成に関する情報を apiserver に送信します。作成された Pod に関する関連コンテンツ情報 (コピー数、コンテナーのコンテンツなど) が etcd に書き込まれます。

4. etcd はポッド作成イベントを apiserver に送信し、apiserver はイベントをスケジューラーに送信します。

5. スケジューラは、スケジューリング アルゴリズムを通じて Pod がどのノードに作成されるかを決定し、決定後、更新された Pod 情報を APIserver 経由で etcd に書き込みます。

6. 次に、etcd は更新 Pod イベントを apiserver に送信し、それを apiserver 経由で kubelet 監視 API サーバーに送信します。

7. kubelet はコンテナ エンジンを作成し、対話を通じて Pod とコンテナを作成し、Pod の実行ステータスとコンテナのステータスを APIserver に送信します。

8. apiserver はポッドの実行ステータスとコンテナのステータスを etcd に書き込みます。

9. etcd は確認情報を返し、apiserver を通じて kubelet に情報が書き込まれたことを伝えます。

3. K8S スケジューリングプロセス

スケジューラーは kubernetes のスケジューラーであり、その主なタスクは、定義されたポッドをクラスターのノードに割り当てることです。考慮される主な問題は次のとおりです。
●公平性: 各ノードに確実にリソースを割り当てられるようにする方法
●効率的なリソース利用: クラスター内のすべてのリソースが最大化される
●効率: スケジューリングのパフォーマンスが良好であり、多数のポッドを使用できる必要があります。可能な限り迅速にスケジュールを設定します。
● 柔軟性: ユーザーがニーズに応じてスケジュール ロジックを制御できるようにします。

Sheduler は別個のプログラムとして実行され、起動後は常に APIServer をリッスンし、spec.nodeName が空のポッドを取得し、ポッドを配置するノードを示す各ポッドのバインディングを作成します。

スケジューリングはいくつかの部分に分かれています: まず、条件を満たさないノードをフィルターで除外する (このプロセスは述語と呼ばれます)、次に通過するノードを優先度に従ってソートする (これが優先度戦略 (優先度) です)、最後に優先度を選択します。最上位ノード。中間ステップのいずれかでエラーがあった場合、エラーが直接返されます。

3.1 述語 (事前選択戦略) の一般的なアルゴリズムの使用法

●PodFitsResources: ノード上の残りのリソースがポッドによって要求されたリソースより大きいかどうか。
●PodFitsHost: ポッドで NodeName が指定されている場合、ノード名が NodeName と一致するかどうかを確認します。
●PodFitsHostPorts: ノードですでに使用されているポートがポッドによって申請されたポートと競合するかどうか。
●PodSelectorMatches: ポッドで指定されたラベルに一致しないノードをフィルターで除外します。
●NoDiskConflict: マウントされたボリュームは、両方が読み取り専用でない限り、ポッドによって指定されたボリュームと競合しません。

述語プロセス中に適切なノードがない場合、ポッドは保留状態のままになり、ノードが条件を満たすまでスケジューリングの再試行を続けます。このステップの後、条件を満たすノードが複数ある場合は、優先順位のプロセスを続行し、優先順位に従ってノードを並べ替えます。

3.2 一般的な優先オプション

優先度は一連のキーと値のペアで構成されます。キーは優先項目の名前、値はその重み (項目の重要度) です。● LeastRequestedPriority
: CPU とメモリの使用量を計算して重みが決定され、使用量が低いほど重みが高くなります。言い換えれば、この優先順位インジケーターは、リソース使用率が低いノードを優先します。
●BalancedResourceAllocation: ノード上の CPU とメモリの使用量が近いほど、重みが高くなります。これは通常、単独ではなく上記と組み合わせて使用​​されます。たとえば、node01 の CPU とメモリの使用量は 20:60、node02 の CPU とメモリの使用量は 50:50 です。node01 の合計使用量は、node02 よりも低いですが、node02 の CPU とメモリの使用量は近くなります。 、したがって、スケジューリング中は、node02 が優先されます。
●ImageLocalityPriority: ミラーを使用したいノードが既に存在する傾向があり、ミラーの合計サイズが大きくなるほど重みが高くなります。

このアルゴリズムは、すべての優先項目と重みを計算して、最終結果を取得します。

3.3 スケジューリングノードの指定

3.3.1 nodeName指定

●pod.spec.nodeName は、スケジューラのスケジューリング ポリシーをスキップして、指定されたノード ノードに Pod を直接スケジュールします。この一致ルールは必須の一致です。

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo4
  name: myapp-demo5
spec:
  nodeName: node02
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo4
    ports:
    - containerPort: 80

ここに画像の説明を挿入します
ここに画像の説明を挿入します

kubectl describe pod myapp-demo4

ここに画像の説明を挿入します

3.3.2 nodeSelector指定

●pod.spec.nodeSelector: kubernetes のラベル セレクター メカニズムを介してノードを選択します。スケジューラはラベルと一致するようにポリシーをスケジュールし、ターゲット ノードにポッドをスケジュールします。この一致ルールは必須の制約です。

//获取标签帮助
kubectl label --help
Usage:
  kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] [options]
//先给node节点打上标签
kubectl label nodes node01 test=a
kubectl label nodes node02 test=b
kubectl get nodes --show-labels

ここに画像の説明を挿入します

//将Pod全部调度到具有 test=a 的节点
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    run: myapp-demo4
  name: myapp-demo6
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp-demo6
  strategy: {
    
    }
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myapp-demo6
    spec:
      #nodeName: node02
      nodeSelector:
        test: a
      containers:
      - image: soscscs/myapp:v1
        name: myapp-demo4
        ports:
        - containerPort: 80
        resources: {
    
    }
status: {
    
    }

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ここに画像の説明を挿入します

3.3.3 ポッド アフィニティとアンチアフィニティ

ここに画像の説明を挿入します

https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/

(1) ノードアフィニティ
pod.spec.nodeAffinity
●preferredDuringSchedulingIgnoredDuringExecution:ソフト戦略
●requiredDuringSchedulingIgnoredDuringExecution:ハード戦略

(2) ポッドアフィニティ
pod.spec.affinity.podAffinity/podAntiAffinity

●preferredDuringSchedulingIgnoredDuringExecution:ソフト戦略
●requiredDuringSchedulingIgnoredDuringExecution:ハード戦略

自分自身をポッドと考えることができます。学年の初めに学校にサインアップするときに、Zhangsan 教師が率いるクラスに通い、さまざまな教師が率いるクラスをノードとして扱いたい場合は、これを選択します。ノードアフィニティです。Zhangsan 先生のクラスに行かなければならない場合、これはハード戦略です。そして、Zhangsan 先生のクラスに行きたい、そこに行くのが最善であると言う場合、これはソフトな戦略です。

あなたに Lisi という名前のとても仲の良い友達がいて、Lisi と同じクラスになる傾向がある場合、これは Pod の親和性です。リシのクラスに行かなければならない場合、これはハード戦略です。また、行きたいがリシのクラスに行くのが最善であると言う場合、これはソフト戦略です。ソフト戦略は行かないことですが、ハード戦略は行かないことです。

キーと値の操作関係
​​In: ラベルの値が特定のリストにある
NotIn: ラベルの値が特定のリストにない
Gt: ラベルの値が特定の値より大きい
Lt: ラベルの値特定の値未満
Exists: 特定の値のラベルが存在します
DoesNotExist: ラベルが存在しません

1. ノードアフィニティハード戦略の例
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo7
  name: myapp-demo7
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo7
    ports:
    - containerPort: 80
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: test
            operator: NotIn
            values:
            - a

ここに画像の説明を挿入します

ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

kubectl describe pod myapp-demo7

ここに画像の説明を挿入します
ここに画像の説明を挿入します

ここに画像の説明を挿入します

2. ノードアフィニティソフト戦略の例
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo8
  name: myapp-demo8
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo7
    ports:
    - containerPort: 80
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: test
            operator: NotIn
            values:
            - a

ここに画像の説明を挿入します

ここに画像の説明を挿入します
ここに画像の説明を挿入します

3. ハード制限とソフト制限を組み合わせて使用​​する

ハード戦略とソフト戦略を併用する場合、まずハード戦略を満たさなければならず、その後、ソフト戦略を満たすことができます。

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo8
  name: myapp-demo9
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo7
    ports:
    - containerPort: 80
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: test
            operator: In
            values:
            - a
      requiredDuringSchedulingIgnoredDuringExecution:
       nodeSelectorTerms:
       - matchExpressions:
         - key: class
           operator: NotIn
           values:
           - demo1
           - demo2

ここに画像の説明を挿入します

ここに画像の説明を挿入します
ここに画像の説明を挿入します
ここに画像の説明を挿入します

//修改后
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo8
  name: myapp-demo9
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo7
    ports:
    - containerPort: 80
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        preference:
          matchExpressions:
          - key: test
            operator: In
            values:
            - b
      requiredDuringSchedulingIgnoredDuringExecution:
       nodeSelectorTerms:
       - matchExpressions:
         - key: class
           operator: NotIn
           values:
           - demo1
           - demo2

ここに画像の説明を挿入します
ここに画像の説明を挿入します

4. ポッド アフィニティ スケジューリングを使用して複数のポッド リソースを作成する

まず Pod を作成し、node02 ノードに指定します。

vim myapp-demo.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo
  name: myapp-demo
spec:
  nodeName: node02
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo
    ports:
    - containerPort: 80                    

ここに画像の説明を挿入します
ノードのラベルを設定します。テストは同じトポロジ ドメイン内になく、クラスは同じトポロジ ドメイン内にあります。

 kubectl label nodes node01 class=demo --overwrite
 kubectl label nodes node02 class=demo --overwrite

ここに画像の説明を挿入します
デモの名前空間を作成する

kubectl create namespace demo
kubectl get ns

ここに画像の説明を挿入します

vim myapp-demo.yaml

ここに画像の説明を挿入します
ここに画像の説明を挿入します

vim demo9.yaml 

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo9
  name: myapp-wangwu
  namespace: demo
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo7
    ports:
    - containerPort: 80
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - namespaces:
        - demo
        topologyKey: test
        labelSelector:
          matchExpressions:
          - key: run
            operator: In
            values:
            - myapp-demo

すべてノードnode02上に作成されます
ここに画像の説明を挿入します
ここに画像の説明を挿入します

アフィニティロードバランシングを使用してポッドを作成する

kubectl create namespace test

ここに画像の説明を挿入します

//指定在node02节点上创建一个Pod并指定命名空间test
vim myapp-demo.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo
  name: myapp-demo
  namespace: test
spec:
  nodeName: node02
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo
    ports:
    - containerPort: 80                                                                                                 

ここに画像の説明を挿入します

//根据myapp-demo.yaml创建的Pod采用亲和性实现负载均衡创建Pod
vim demo9.yaml
apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo9
  name: myapp-a
  namespace: test
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo9
    ports:
    - containerPort: 80
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - namespaces:
        - test
        topologyKey: class
        labelSelector:
          matchExpressions:
          - key: run
            operator: In
            values:
            - myapp-demo

ここに画像の説明を挿入します
ターゲット ノードで使用されるラベル run=myapp-demo に従って、ターゲット ポッドに基づいて、ノード ノードが使用するトポロジ ドメイン キーを決定し、トポロジ ドメイン キーを調べてどのノードのノード キー値を確認します。ポッド アフィニティに基づいてスケジューリング ポッドが作成される場合、ポッドはロード バランシングを使用して異なるノードに作成されます。

kubectl label nodes node01 class=ll --overwrite
kubectl label nodes node02 class=ll --overwrite

ここに画像の説明を挿入します
ここに画像の説明を挿入します

5. 反アフィニティの厳しい戦略
vim demo9.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo9
  name: myapp-zhangsan
  namespace: test
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo9
    ports:
    - containerPort: 80
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - namespaces:
        - test
        topologyKey: test
        labelSelector:
          matchExpressions:
          - key: run
            operator: In
            values:
            - myapp-demo

ここに画像の説明を挿入します
ここに画像の説明を挿入します

vim demo9.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo9
  name: myapp-d
  namespace: test
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo9
    ports:
    - containerPort: 80
  affinity:
    podAntiAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - namespaces:
        - test
        topologyKey: test
        labelSelector:
          matchExpressions:
          - key: run
            operator: In
            values:
            - myapp-demo

ここに画像の説明を挿入します

ここに画像の説明を挿入します

6. アンチアフィニティソフト戦略
cp demo9.yaml demo10.yaml
vim demo10.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo9
  name: myapp-a
  namespace: test
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo9
    ports:
    - containerPort: 80
  affinity:
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          namespaces:
          - test
          topologyKey: class
          labelSelector:
            matchExpressions:
            - key: run
              operator: In
              values:
              - myapp-demo

ここに画像の説明を挿入します
ここに画像の説明を挿入します

ここに画像の説明を挿入します

3.3.4 汚染

Taint
ノード アフィニティは、Pod を特定のタイプのノードに引き付ける原因となる Pod の属性 (優先またはハード要件) です。一方、Taint を使用すると、ノードは特定のクラスの Pod を除外できます。
Taint と Toleration は連携して、Pod が不適切なノードに割り当てられるのを防ぎます。1 つ以上のテイントを各ノードに適用できます。つまり、これらのテイントを許容できないポッドはノードによって受け入れられません。許容が Pod に適用される場合、これらの Pod は、一致するテイントを持つノードにスケジュールできる (ただし、必ずではない) ことを意味します。

kubectl taint コマンドを使用して、Node ノードにテイントを設定します。ノードにテイントが設定されると、ポッドとの排他関係が生じます。ノード ノードは、ポッドのスケジューリングと実行を拒否し、ポッドを削除することもできます。 Node ノードの既存の汚染。ポッドは削除されました。

染色の構成形式は次のとおりです。

key=value:effect

各染色にはキーと染色のラベルとしての値があり、値は空にすることができ、effect は染色の効果を表します。

現在、テイント効果は次の 3 つのオプションをサポートしています。
NoSchedule : k8s がこのテイントを使用してノードにポッドをスケジュールしないことを示します。
PreferNoSchedule : k8s がこのテイントを使用してノードにポッドをスケジュールすることを回避しようとすることを示します。
NoExecute : k8s ポッドをスケジュールすることを示します。このテイントがあるノードにはスケジュールされず、ノード上の既存のポッドは削除されます。

kubectl describe nodes | grep -i taint

ここに画像の説明を挿入します

//master 就是因为有 NoSchedule 污点,k8s 才不会将 Pod 调度到 master 节点上
kubectl describe nodes master

ここに画像の説明を挿入します

1. 染みをつける

例 1: NoSchedule を使用してノード 01 を汚染する

kubectl taint nodes node01 check=mycheck:NoSchedule
kubectl describe nodes node01

ここに画像の説明を挿入します
テストが汚染された後、ポッドはどのノードに作成されますか?

vim test-deploy.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: myapp-test
  name: myapp-test
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp-test
  strategy: {
    
    }
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myapp-test
    spec:
      containers:
      - image: soscscs/myapp:v1
        name: myapp
        ports:
        - containerPort: 80
        resources: {
    
    }
status: {
    
    }

ここに画像の説明を挿入します
例 2: NoExecute によるノード 01 の汚染

kubectl get pods -o wide -n test
kubectl taint nodes node01 mycheck=check:NoExecute

ここに画像の説明を挿入します

2. 汚れを落とす
kubectl taint nodes node01 check:NoSchedule-
kubectl describe nodes node01

ここに画像の説明を挿入します

 kubectl taint nodes node01 mycheck-

ここに画像の説明を挿入します
ここに画像の説明を挿入します

kubectl taint nodes node01 mycheck=check:NoExecute
kubectl get pods -o wide -w

ここに画像の説明を挿入します
ここに画像の説明を挿入します
Pod のステータスを確認すると、node01 上のすべての Pod が削除されていることがわかります (注: Deployment または StatefulSet リソース タイプの場合、コピー数を維持するために、新しい Pod が他のノードに作成されます)。

3.3.5 許容範囲

汚染されたノードは、汚染の影響 (NoSchedule、PreferNoSchedule、NoExecute、および Pod) の間に相互排他的な関係を持ち、Pod はある程度までノードに対してスケジュールされません。ただし、Pod に許容値を設定することはできます。つまり、許容値を持つ Pod はテイントの存在を許容でき、テイントのあるノードにスケジュールできることになります。

示例:
kubectl taint nodes node01 mycheck=test:NoExecute
kubectl taint nodes node02 mycheck=test:NoExecute

ここに画像の説明を挿入します

 kubectl apply -f test-deploy.yaml
 kubectl get pods -owide 

ここに画像の説明を挿入します
ここに画像の説明を挿入します
両方のノードにテイントが設定されると、この時点では Pod は作成されませんが、
ここに画像の説明を挿入します
テイントに耐えられる Pod が正常に作成されます。

示例1:
cp myapp-demo.yaml demo11.yaml
vim demo11.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-demo11
  name: myapp-demo11
  namespace: default
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-demo11
    ports:
    - containerPort: 80
  tolerations:
  - key: mycheck
    operator: Equal
    value: test
    effect: NoExecute
    tolerationSeconds: 60

ここに画像の説明を挿入します

ここに画像の説明を挿入します
汚染を許容できるポッドをマスターノード上に作成する

示例2:
vim demo11.yaml

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: myapp-master
  name: myapp-master
  namespace: default
spec:
  containers:
  - image: soscscs/myapp:v1
    name: myapp-master
    ports:
    - containerPort: 80
  tolerations:
  - key: node-role.kubernetes.io/master
    operator: Exists
    effect: NoSchedule

ここに画像の説明を挿入します
汚染を許容するためにマルチコピー Pod を作成する

示例3:
vim test-deploy.yaml 

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: myapp-test
  name: myapp-test
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp-test
  strategy: {
    
    }
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myapp-test
    spec:
      tolerations:
      - key: mycheck
        operator: Exists
        effect: NoExecute
      containers:
      - image: soscscs/myapp:v1
        name: myapp
        ports:
        - containerPort: 80
        resources: {
    
    }
status: {
    
    }

ここに画像の説明を挿入します
ここに画像の説明を挿入します

3.3.6 その他の注意事項

(1) キー値が指定されていない場合、すべての汚染されたキーが許容されることを意味します

 tolerations:
  - operator: "Exists"

(2) 効果値が指定されていない場合は、すべての汚染効果を許容することを意味します。

  tolerations:
  - key: "key"
    operator: "Exists"

(3) マスターが複数ある場合、リソースの無駄を防ぐため、次のように設定できます。

kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule

ノードがシステム コンポーネントを更新およびアップグレードする場合、長期的なビジネスの中断を防ぐために、最初にノードに NoExecute テイントを設定して、ノード上のすべてのポッドを排除できます。

kubectl taint node node01 check=mycheck:NoExecute

このとき、他の Node リソースが足りない場合は、マスター上に一時的に PreferNoSchedule テイントを設定して、マスター上に一時的に Pod を作成できます。

kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule

汚れを除去する前に、すべてのノード更新操作が完了するまで待ってください。

kubectl taint node node01 check=mycheck:NoExecute-

3.3.7 非常線とドレインはノード上でメンテナンス操作を実行します

ノードをスケジュール不可としてマークし、新しく作成されたポッドがこのノード上で実行できないようにします。

kubectl cordon <NODE_NAME> 		 //该node将会变为SchedulingDisabled状态
示例:
kubectl cordon node01
kubectl get nodes

ここに画像の説明を挿入します

vim test-deploy.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: myapp-test
  name: myapp-work
spec:
  replicas: 5
  selector:
    matchLabels:
      app: myapp-test
  strategy: {
    
    }
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: myapp-test
    spec:
      tolerations:
      - key: mycheck
        operator: Exists
        effect: NoExecute
      containers:
      - image: soscscs/myapp:v1
        name: myapp
        ports:
        - containerPort: 80
        resources: {
    
    }
status: {
    
    }

ここに画像の説明を挿入します

kubectl drain Node ノードがすべてのポッドの解放を開始し、新しいポッド プロセスを受け入れないようにすることができます。ドレインの本来の意味は水を排出することであり、問​​題のあるノード下のポッドを別のノード下で実行するように移動することを意味します。

kubectl drain <NODE_NAME> --ignore-daemonsets --delete-emptydir-data --force

--ignore-daemonsets: DaemonSet によって管理される Pod を無視します。
--delete-emptydir-data: ローカル ボリュームをマウントするポッドがある場合、ポッドは強制的に強制終了されます。
--force:コントローラーで管理されていないPodを強制的に解放します。

kubectl drain node01  --ignore-daemonsets --delete-emptydir-data --force

ここに画像の説明を挿入します

注: ドレイン コマンドを実行すると、次の 2 つのことが自動的に行われます:
(1) このノードをスケジュール不可能な状態 (非常停止) に設定します
(2) ポッドを削除します (エビクト)

kubectl uncordonノードをスケジュール可能としてマークする

kubectl uncordon <NODE_NAME>
kubectl drain node02  --ignore-daemonsets --delete-emptydir-data --force

ここに画像の説明を挿入します

kubectl get nodes 

ここに画像の説明を挿入します
ここに画像の説明を挿入します

kubectl uncordon node01
kubectl uncordon node02

ここに画像の説明を挿入します
ここに画像の説明を挿入します

3.4 ポッド起動フェーズ(フェーズ)

Pod が作成された後、永続的に実行されるまでの間には多くのステップがあり、エラーが発生する可能性も多いため、さまざまな状態が存在します。
一般に、ポッド プロセスには次の手順が含まれます。
(1) 特定のノードへのスケジューリング。Kubernetesは一定の優先度アルゴリズムに基づいてノードを選択し、それをノードとして使用してPodとして実行します
(2) イメージをプルします
(3) ストレージ構成などをマウントします
(4) コンテナを実行します。ヘルスチェックがある場合、そのステータスはチェックの結果に基づいて設定されます。

3.4.1 考えられる位相状態

Pending: APIServer が Pod リソース オブジェクトを作成し、etcd に保存されているが、スケジュールされていない (たとえば、特定のノードにスケジュールされていない) か、まだイメージのダウンロード中であることを示します。倉庫から。

Running: ポッドは特定のノードにスケジュールされており、ポッド内のすべてのコンテナは kubelet によって作成されています。少なくとも 1 つのコンテナーが実行中であるか、開始または再起動中です (つまり、Running 状態の Pod には正常にアクセスできない可能性があります)。

Succeeded: ジョブや cronjob など、一部のポッドは長時間実行されず、一定時間が経過すると、ポッド内のすべてのコンテナーが正常に終了し、再起動されません。タスクの実行結果についてのフィードバックが必要です。

Failed: ポッド内のすべてのコンテナが終了しており、少なくとも 1 つのコンテナが障害により終了しています。つまり、コンテナがゼロ以外のステータスで終了するか、コマンドの書き込みに問題があるなど、システムによって終了されます。

Unknown: 通常、kube-controller-manager が Pod と通信できないため、Pod のステータスを読み取ることができないことを示します。ポッドが配置されているノードに問題があるか、接続が失われて、ポッドのステータスが不明になります。

3.4.2 Unknown状態のPodを削除する方法

●問題のあるノードをクラスタから削除します。パブリック クラウドを使用する場合、VM が削除された後、kube-controller-manager は対応するノードを自動的に削除します。物理マシンにデプロイされたクラスターでは、管理者はノード ( kubectl delete node <node_name>) を手動で削除する必要があります。

●ノードが正常に戻るのを受動的に待ちます。Kubelet は再度 kube-apiserver と通信してこれらの Pod の予想されるステータスを確認し、これらの Pod を削除するか実行を継続するかを決定します。

●Pod を積極的に削除し、kubectl delete pod <pod_name> --grace-period=0 --forceを実行して Pod を強制的に削除します。ただし、ポッドが実際に停止していることが明確にわかっている場合を除き、この方法は推奨されないことに注意してください (たとえば、ノードが配置されている VM または物理マシンがシャットダウンされている)。特に StatefulSet で管理されている Pod の場合、強制削除は脳の分割やデータ損失などの問題を引き起こしやすいです。

3.4.3 トラブルシューティングの手順

ポッドイベントの表示

kubectl describe TYPE NAME_PREFIX  

Pod ログの表示 (失敗状態)

kubectl logs <POD_NAME> [-c Container_NAME]

Pod に入ります (ステータスは実行中ですが、サービスは提供されていません)

kubectl exec –it <POD_NAME> bash

クラスター情報の表示

kubectl get nodes

クラスターのステータスは正常であることが判明しました

kubectl cluster-info

kubelet ログを確認して確認してください

journalctl -xefu kubelet

4. まとめ

4.1 アフィニティ

ノード アフィニティ: 指定されたノード ノード ラベルを照合し、指定された条件を満たすノード ノードに Pod をスケジュールします。

ポッド アフィニティ: 指定されたポッド ラベルと一致し、指定されたポッドが配置されているノード ノードと同じトポロジ ドメイン内のノード ノードにポッドがデプロイされるようにスケジュールします。

ポッドのアンチアフィニティ: 指定されたポッド ラベルと一致し、指定されたポッドが配置されているノード ノードとは異なるトポロジ ドメイン内のノード ノードにポッドがデプロイされるようにスケジュールします。

ハード戦略: 指定された条件を満たすことが必須であり、条件を満たす Node ノードがない場合、条件を満たす Node ノードが現れるまで Pod は Pending 状態になります。

ソフト ポリシー: 必須ではありません。条件を満たすノード ノードが最初に選択され、条件を満たすノード ノードがない場合でも、ポッドはスケジューリングを完了します。

ハード ポリシーとソフト ポリシーが同時に存在する場合、ハード ポリシーを最初に満たす必要があり、その後、ハード ポリシーを満たすノード ノードの中から、ソフト ポリシーを満たすノード ノードが優先的にスケジューリングされます。

それらが同じトポロジー ドメイン内にあるかどうかを判断するにはどうすればよいでしょうか?
トポロジ ドメイン キー (topologyKey) を確認し、指定されたポッドが配置されているノード ノードと同じトポロジ ドメイン キーと値ラベルを持つ他のノード ノードがある場合、それらは同じトポロジ ドメイン内にあります。

4.2 汚染

kubectl describe nodes 节点名称 | grep Taints

kubectl taint node 节点名称 key=value:effect

3 種類の効果:
1. NoSchedule は確実にスケジュールされません
2. PreferNoSchedule はスケジュールされないよう努めます
3. NoExecute はスケジュールされず、ノード上の Pod は削除されます

汚れを取り除く:kubectl taint node 节点名称 key[:effect]-

4.3 許容差

spec:
  tolerations:
  - key: 键名
    operator: Equal|Exists
    value: 键值
    effect: NoSchedule|PreferNoSchedule|NoExecute

4.4 スケジュール不可能

kubectl cordon 节点名称
kubectl uncordon 节点名称
不可调度+驱逐
kubectl drain 节点名称  --ignore-daemonsets --delete-emptydir-data --force

4.5 ポッドのライフサイクルの 5 つの状態

pendingポッドは作成されましたが、少なくとも 1 つのコンテナが作成されていません。これには、ポッドがノード ノードへのスケジューリング プロセスを完了していない、イメージのプル中である、ストレージ ボリュームのマウントに失敗しているなどがあります。

running:ポッド内の少なくとも 1 つのコンテナが実行されています

succeeded:ポッド内のすべてのコンテナは正常に終了したため、再起動されません (完了)

failed:ポッド内のすべてのコンテナが終了し、少なくとも 1 つのコンテナが異常終了しました (エラー)

unknown:ポッドのステータスを取得できません。通常、マスター ノードがポッドが配置されているノード ノードと通信できないことが原因です。

ポッドは、保留フェーズから開始する、事前定義されたライフ サイクルに従います。少なくとも 1 つのメイン コンテナが正常に起動すると、実行フェーズに入り、ポッド内のコンテナが失敗して終了したかどうかに応じて、成功フェーズまたは失敗フェーズに入ります。州。
ここに画像の説明を挿入します

4.6 トラブルシューティング方法

kubectl get pods                       查看Pod状态
kubectl describe pod                   查看资源的详细信息和事件
kubectl logs [-c 容器名] [--previous]   查看Pod容器的日志
kubectl exec -it [-c 容器名]            进去Pod容器查看相关状态信息
kubectl debug   --target=目标Pod        临时创建Pod容器进入目标Pod进行调试

kubectl get nodes                      查看Node节点状态
kubectl get cs                         查看Master组件状态
kubectl cluster-info                   查看集群信息

journalctl -u -f kubelet               跟踪kubelet进程日志

おすすめ

転載: blog.csdn.net/ll945608651/article/details/131861867