目次
1. 「nodeName」フィールドを使用して、スケジューリング ノードを指定します。
2.nodeSelectorを使用してスケジューリングノードを指定します
2.2 スケジューリング方法をnodeSelectorに変更
3.2.2 Pod アンチアフィニティ スケジューリングの使用
4. Taint と Tolerations を使用してスケジューリング ノードを指定する
3. 不明ステータスのポッドを削除するにはどうすればよいですか?
1. ポッド起動の一般的な作成プロセス
Kubernetes は List-Watch のメカニズムを使用して各コンポーネントと連携してデータの同期を維持し、各コンポーネント間の設計は分離されます。
ユーザーは、構成ファイルに従って kubectl 経由で APIServer にコマンドを送信し、Node ノード上にポッドとコンテナを作成します。
APIServer は、API 呼び出し、権限制御、リソース呼び出し、リソース ストレージのプロセスを経ていますが、実際にはアプリケーションのデプロイを開始していません。導入プロセス全体を完了するには、コントローラー マネージャー、スケジューラー、および kubelet の支援が必要です。
Kubernetes では、すべてのデプロイメント情報が etcd に書き込まれ、保存されます。実際、etcd がデプロイメント情報を保存すると、Create イベントが APIServer に送信され、APIServer は etcd によって送信されたイベントをリッスン (監視) します。他のコンポーネントも APIServer によって送信されたイベントを監視 (ウォッチ) します。
Pod は Kubernetes の基本単位であり、Pod 起動の一般的な作成プロセスは次のとおりです。
- ここには、Controller Manager (マスター上で実行)、Scheduler (マスター上で実行)、および kubelet (ノード上で実行) という 3 つの List-Watch があります。プロセスの開始後に APIServer によって送信されたイベントをリッスン (監視) します。
- ユーザーは、kubectl または他の API クライアントを通じて APIServer にリクエストを送信し、Pod オブジェクトのコピーを作成します。
- APIServer は Pod オブジェクトの関連メタ情報を etcd に保存しようとします。書き込み操作が完了すると、APIServer は確認情報をクライアントに返します。
- etcd が Pod 作成情報を受け取ると、Create イベントを APIServer に送信します。
- これは、コントローラー マネージャーが APIServer のイベントをリッスン (https のポート 6443 経由で監視) しているためです。このとき、APIServer は Create イベントを受信し、Controller Manager に送信します。
- Create イベントを受信した後、コントローラー マネージャーはレプリケーション コントローラーを呼び出し、ノード上に作成する必要があるコピーの数を確認します。レプリカの数が RC で定義された数よりも少なくなると、RC は自動的にレプリカを作成します。つまり、コピー数を保証するのはController(追記:伸縮を担当)です。
- コントローラーマネージャーがポッドのコピーを作成した後、APIServer はポッドの詳細情報を etcd に記録します。たとえば、ポッドのコピーの数やコンテナの内容などです。
- 同様に、etcd はイベントを通じて APIServer にポッド作成情報を送信します。
- Scheduler は APIServer を監視 (Watching) しており、システムの「上位と下位を接続する」役割を果たしているため、「上位を接続する」とは、作成された Pod イベントを受け取り、Node を配置する役割を担います。 「下位の接続」は配置作業が完了したことを意味します。その後、Node 上の kubelet プロセスが後続の作業を引き継ぎ、Pod ライフサイクルの「ライフの後半」を担当します。言い換えれば、スケジューラーの役割は、スケジューリング アルゴリズムとポリシーに従って、スケジュールされるポッドをクラスター内のノードにバインドすることです。
- スケジューラはスケジューリング完了後に Pod 情報を更新しますが、この時点の情報はより豊富になります。ポッドのレプリカの数に加えて、レプリカの内容もわかります。また、どのノードにデプロイするかもわかります。そして上記のPod情報をAPI Serverに更新し、APIServerからetcdに更新して保存します。
- etcd は更新成功イベントを APIServer に送信し、APIServer もこの Pod オブジェクトのスケジュール結果の反映を開始します。
- Kubelet は Node 上で実行されるプロセスであり、APIServer によって送信された Pod 更新イベントを List-Watch (https のポート 6443 経由で監視) を通じてリッスンします。kubelet は、現在のノードで Docker を呼び出してコンテナを起動しようとし、結果として得られるポッドとコンテナのステータスを APIServer に送り返します。
- APIServer は Pod のステータス情報を etcd に保存します。etcd が書き込み操作が正常に完了したことを確認すると、APIServer はイベントが受け入れられる関連する kubelet に確認メッセージを送信します。
#注: Pod の作成作業が完了した後、kubelet がリッスンし続けるのはなぜですか? 理由は非常に簡単で、この時点で kubectl が Pod のコピー数を拡張するコマンドを発行すると、上記のプロセスが再度トリガーされ、kubelet が最新の Pod デプロイメントに応じて Node リソースを調整します。あるいは、Pod のコピー数は変わっていないものの、その中のイメージ ファイルがアップグレードされており、kubelet が自動的に最新のイメージ ファイルを取得してロードしている可能性があります。
2. スケジューリングプロセス
スケジューラーは kubernetes のスケジューラーであり、その主なタスクは、定義されたポッドをクラスターのノードに割り当てることです。考慮すべき主な問題は次のとおりです。
- 公平性: 各ノードにリソースを確実に割り当てられるようにする方法
- リソースの効率的な利用: クラスター内のすべてのリソースが最大限に使用されます。
- 効率: スケジューリングのパフォーマンスが良好である必要があり、ポッドの大規模なバッチのスケジューリング作業をできるだけ早く完了できる必要があります。
- 柔軟性: ユーザーがニーズに応じてスケジュール ロジックを制御できるようにします。
Sheduler は別個のプログラムとして実行され、起動後は常に APIServer をリッスンし、spec.nodeName が空のポッドを取得し、ポッドを配置するノードを示す各ポッドのバインディングを作成します。
スケジューリングはいくつかの部分に分かれています: まず、条件を満たさないノードを除外するこのプロセスは予算戦略 (述語) と呼ばれます。次に、通過するノードを優先度に従って並べ替えます。これは優先戦略 (優先順位) です。優先順位の選択 最上位のノード。途中のステップでエラーがあった場合は、直接エラーが返されます。
述語には、使用できる一連の一般的なアルゴリズムがあります。
- PodFitsResources: ノード上の残りのリソースがポッドによって要求されたリソースより大きいかどうか。
- PodFitsHost: ポッドで NodeName が指定されている場合は、ノード名が NodeName と一致するかどうかを確認します。
- PodFitsHostPorts: ノードですでに使用されているポートが、ポッドによって適用されたポートと競合するかどうか。
- PodSelectorMatches: ポッドで指定されたラベルに一致しないノードをフィルターで除外します。
- NoDiskConflict: マウントされたボリュームは、両方が読み取り専用でない限り、ポッドによって指定されたボリュームと競合しません。
述語プロセス中に適切なノードがない場合、ポッドは保留状態のままになり、ノードが条件を満たすまでスケジューリングの再試行を続けます。このステップの後、条件を満たすノードが複数ある場合は、優先順位のプロセスを続行し、優先順位に従ってノードを並べ替えます。
優先度は一連のキーと値のペアで構成されます。キーは優先項目の名前、値はその重み (項目の重要度) です。一般的な優先オプションには次のようなものがあります。
- LeastRequestedPriority: CPU とメモリの使用量を計算して重みが決定され、使用量が低いほど重みが高くなります。言い換えれば、この優先順位インジケーターは、リソース使用率が低いノードを優先します。
- BalancedResourceAllocation: ノード上の CPU とメモリの使用量が近いほど、重みは高くなります。これは通常、単独ではなく上記と組み合わせて使用されます。たとえば、node01 の CPU とメモリの使用率は 20:60、node02 の CPU とメモリの使用率は 50:50 であり、node01 の合計使用率は node02 よりも低いですが、CPU とメモリの使用率はノード 02 の方が近いため、スケジューリング中にノード 02 が優先されます。
- ImageLocalityPriority: ミラーを使用したいノードがすでに存在する傾向があり、ミラーの合計サイズが大きくなるほど、重みが高くなります。
すべての優先項目と重みはアルゴリズムを通じて計算され、最終結果が得られます。
3. スケジューリングノードの指定
1. 「nodeName」フィールドを使用して、スケジューリング ノードを指定します。
nodeName は、スケジューラーのスケジューリング ポリシーをスキップして、指定されたノード ノードに Pod を直接スケジュールします。この一致ルールは必須の一致です。
apiVersion: apps/v1
kind: Deployment #创建deployment控制器
metadata:
name: myapp #deployment控制器名称:myapp
spec: #定义模板文件
replicas: 3 #副本集为3个
selector: #标签选择器
matchLabels: #匹配的标签为 app: myapp1
app: myapp1
template: #定义pod模板
metadata:
labels: #pod的标签
app: myapp1
spec:
nodeName: node01 #pod创建后所在的node节点名称
containers: #定义pod中的容器
- name: myapp #pod容器中的名称
image: nginx #容器使用的镜像
ports:
- containerPort: 80
kubectl apply -f demo1.yaml
kubectl get pods --show-labels -owide
#查看详细事件(发现未经过 scheduler 调度分配)
kubectl describe pod myapp-6bc58d7775-6wlpp
2.nodeSelectorを使用してスケジューリングノードを指定します
ノードは kubernetes のラベル セレクター メカニズムを通じて選択され、スケジューラはラベルに一致するようにポリシーをスケジュールし、ターゲット ノードにポッドをスケジュールします。この一致ルールは必須の制約です。
2.1 対応するノードノードにラベルを追加する
kubectl label nodes node01 app=a
kubectl label nodes node02 app=b
#查看标签
kubectl get nodes --show-labels
注:
#修改一个 label 的值,需要加上 --overwrite 参数
kubectl label nodes node02 app=a --overwrite
#删除一个 label,只需在命令行最后指定 label 的 key 名并与一个减号相连即可:
kubectl label nodes node02 app-
或
kubectl label nodes node02 app=b-
#指定标签查询 node 节点
kubectl get node -l app=a
2.2 スケジューリング方法をnodeSelectorに変更
vim myapp1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp1
spec:
replicas: 3
selector:
matchLabels:
run: myapp1
template:
metadata:
labels:
run: myapp1
spec:
nodeSelector:
app: a
containers:
- name: myapp1
image: nginx:1.14
ports:
- containerPort: 80
kubectl apply -f myapp1.yaml
kubectl get pods -owide
#查看详细事件(通过事件可以发现要先经过 scheduler 调度分配)
kubectl describe pod myapp1-7cc594f786-jfs97
3. アフィニティによるスケジューリング ノードの指定
3.1 ノードアフィニティ
pod.spec.nodeAffinity
- preferredDuringSchedulingIgnoredDuringExecution: ソフト戦略
- requiredDuringSchedulingIgnoredDuringExecution: ハード ポリシー
注記:
- 難しい戦略は、Pod が指定された条件でノードノードに行かなければならないということですが、行かなければ実行できません。
- ソフトポリシーとは、Pod が最も優先してノードを指定することを意味し、条件を満たすノードがない場合は他のノードを選択することもできます。
キー値操作関係
- In: ラベルの値はリスト内にあります
- NotIn: ラベルの値がリストにありません
- Gt: ラベルの値が特定の値より大きい
- Lt: ラベルの値が特定の値未満です
- 存在します: ラベルが存在します
- DoesNotExist: ラベルが存在しません
nodeAffinity のハード ポリシーとソフト ポリシーの例
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #先满足硬策略,排除有kubernetes.io/hostname=node02标签的节点
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02
preferredDuringSchedulingIgnoredDuringExecution: #再满足软策略,优先选择有app=a标签的节点
- weight: 1 #如果有多个软策略,权重越大,优先级越大
preference:
matchExpressions:
- key: app
operator: In
values:
- a
只有硬策略的情况下,如果硬策略不满足条件,Pod 状态一直会处于 Pending 状态。
如果把硬策略和软策略合在一起使用,则要先满足硬策略之后才会满足软策略
3.2 Pod アフィニティとアンチアフィニティ
pod.spec.affinity.podAffinity/podAntiAffinity
- preferredDuringSchedulingIgnoredDuringExecution: ソフト戦略
- requiredDuringSchedulingIgnoredDuringExecution: ハード ポリシー
スケジュール戦略 | マッチタグ | オペレーター | トポロジカル ドメインのサポート | スケジュール目標 |
ノードアフィニティ | ホスト | In、NotIn、Exists、DoesNotExist、Gt、Lt | いいえ | ホストの指定 |
ポッドアフィニティ | ポッド | ある、ない、存在する、存在しない | はい | ポッドは指定されたポッドと同じトポロジー ドメインにあります |
ポッドアンチアフィニティ | ポッド | ある、ない、存在する、存在しない | はい | ポッドは、指定されたポッドと同じトポロジー ドメインにありません |
3.2.1 ポッド アフィニティ スケジューリングの使用
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels: #定义该Pod的标签
app: myapp
spec:
containers:
- name: myapp01
image: nginx
affinity:
podAffinity: #定义pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: #pod亲和性的硬策略
- labelSelector: #定义硬策略标签选择器的信息
matchExpressions: #定义标签选择器选择的信息
- key: app #定义键名
operator: In #定义键值之间的运算关系
values: #定义键值
- myapp
topologyKey: run #定义节点标签的键,判断是否在同一拓扑域中
topologykey: run表示如果node节点都包含有标签为run=键值,
当node节点的键值相同时,则表示node节点在同一拓扑域中;
当run键的值不相同时,则表示node节点不在同一拓扑域中。
注記:
- ポッドをトポロジ ドメイン a 上のノードにスケジュールできるのは、ノードにラベル app=myapp を持つ実行中のポッドが少なくとも 1 つ含まれており、トポロジ ドメイン a にある場合のみです。(より正確には、ノードを新しいポッドに割り当てるとき、ラベル app=myapp を持つポッドを実行しているノード、またはノードが配置されているトポロジ ドメイン内の他のノードが選択されます。)
- topologyKey はノード ラベルのキーです。2 つのノードがこのキーでタグ付けされており、同じラベル値を持つ場合、スケジューラは 2 つのノードを同じトポロジ ドメイン内にあるものとして扱います。スケジューラは、各トポロジ ドメインにバランスの取れた数の Pod を配置しようとします。
- アプリの対応する値が異なる場合、それらは異なるトポロジー ドメインになります。たとえば、Pod1 が app=a のノード上にあり、Pod2 が app=b のノード上にあり、Pod3 が app=a のノード上にある場合、Pod2、Pod1、および Pod3 は同じトポロジ ドメイン内にありませんが、 Pod1 と Pod3 は同じトポロジ ドメイン内にあります。
3.2.2 Pod アンチアフィニティ スケジューリングの使用
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
spec:
containers:
- name: myapp
image: nginx
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- a
topologyKey: run
如果节点处于 Pod 所在的同一拓扑域且具有键“app”和值“a”的标签, 则该 pod 不能将其调度到该节点上。
(如果 topologyKey 为 run,则意味着当节点和具有键 “app”和值“a”的 Pod 处于相同的拓扑域,Pod 不能被调度到该节点上。)
4. Taint と Tolerations を使用してスケジューリング ノードを指定する
4.1 汚染
ノード アフィニティは、Pod を特定のタイプのノードに引き付ける原因となる Pod の属性 (優先またはハード要件) です。一方、Taint を使用すると、ノードは特定のクラスの Pod を除外できます。
Taint と Toleration は連携して、Pod が不適切なノードに割り当てられるのを防ぎます。1 つ以上のテイントを各ノードに適用できます。つまり、これらのテイントを許容できないポッドはノードによって受け入れられません。許容が Pod に適用される場合、これらの Pod は、一致するテイントを持つノードにスケジュールできる (ただし、必ずではない) ことを意味します。
使用 kubectl taint 命令可以给某个 Node 节点设置污点,Node 被设置上污点之后就和 Pod 之间存在了一种相斥的关系,可以让 Node 拒绝 Pod 的调度执行,甚至将 Node 已经存在的 Pod 驱逐出去。
污点的组成格式如下:
key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。
当前 taint effect 支持如下三个选项:
●NoSchedule:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上
●PreferNoSchedule:表示 k8s 将尽量避免将 Pod 调度到具有该污点的 Node 上
●NoExecute:表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去
#设置污点
kubectl taint node node01 key1=value1:NoSchedule
#节点说明中,查找 Taints 字段
kubectl describe node node01
#去除污点
kubectl taint node node01 key1:NoSchedule-
4.2 許容範囲
汚染されたノードは、汚染の影響 (NoSchedule、PreferNoSchedule、NoExecute、および Pod) の間に相互排他的な関係を持ち、Pod はある程度までノードに対してスケジュールされません。ただし、Pod に許容値を設定することはできます。つまり、許容値を持つ Pod はテイントの存在を許容でき、テイントのあるノードにスケジュールできることになります。
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: soscscs/myapp:v1
tolerations:
- key: "check" #定义污点键名
operator: "Equal"
value: "mycheck" #定义污点键值
effect: "NoExecute" #定义污点的作用
tolerationSeconds: 3600
#其中的 key、vaule、effect 都要与 Node 上设置的 taint 保持一致
#operator 的值为 Exists 将会忽略 value 值,即存在即可
#tolerationSeconds 用于描述当 Pod 需要被驱逐时可以在 Node 上继续保留运行的时间
予防:
(1)当不指定 key 值时,表示容忍所有的污点 key
tolerations:
- operator: "Exists"
(2)当不指定 effect 值时,表示容忍所有的污点作用
tolerations:
- key: "key"
operator: "Exists"
(3)有多个 Master 存在时,防止资源浪费,可以如下设置
kubectl taint node Master-Name node-role.kubernetes.io/master=:PreferNoSchedule
//如果某个 Node 更新升级系统组件,为了防止业务长时间中断,可以先在该 Node 设置 NoExecute 污点,把该 Node 上的 Pod 都驱逐出去
kubectl taint node node01 check=mycheck:NoExecute
//此时如果别的 Node 资源不够用,可临时给 Master 设置 PreferNoSchedule 污点,让 Pod 可在 Master 上临时创建
kubectl taint node master node-role.kubernetes.io/master=:PreferNoSchedule
//待所有 Node 的更新操作都完成后,再去除污点
kubectl taint node node01 check=mycheck:NoExecute-
4. 非常線と排水管
对节点执行维护操作:
kubectl get nodes
//将 Node 标记为不可调度的状态,这样就不会让新创建的 Pod 在此 Node 上运行
kubectl cordon <NODE_NAME> #该node将会变为SchedulingDisabled状态
//kubectl drain 可以让 Node 节点开始释放所有 pod,并且不接收新的 pod 进程。drain 本意排水,意思是将出问题的 Node 下的 Pod 转移到其它 Node 下运行
kubectl drain <NODE_NAME> --ignore-daemonsets --delete-emptydir-data --force
--ignore-daemonsets:无视 DaemonSet 管理下的 Pod。
--delete-emptydir-data:如果有 mount local volume 的 pod,会强制杀掉该 pod。
--force:强制释放不是控制器管理的 Pod。
注:执行 drain 命令,会自动做了两件事情:
(1)设定此 node 为不可调度状态(cordon)
(2)evict(驱逐)了 Pod
//kubectl uncordon 将 Node 标记为可调度的状态
kubectl uncordon <NODE_NAME>
5. Podの詳細説明
1.ポッド起動フェーズ(フェーズ)
Pod が作成された後、永続的に実行されるまでの間には多くのステップがあり、エラーが発生する可能性も多いため、さまざまな状態が存在します。
一般に、ポッド プロセスには次の手順が含まれます。
- ノードにスケジュールされます。Kubernetes は、特定の優先順位アルゴリズムに基づいてノードを選択し、それをノードとして使用して Pod として実行します。
- イメージをプルする
- ストレージ構成などをマウントします。
- コンテナは実行中です。ヘルスチェックがある場合、そのステータスはチェックの結果に基づいて設定されます。
2. Podの共通ステータス
- 保留中: APIServer が Pod リソース オブジェクトを作成して etcd に保存したが、スケジュールされていない (たとえば、ノードにスケジュールされていない) か、まだイメージをダウンロード中であることを示します。倉庫。
- 実行中: ポッドはノードにスケジュールされており、ポッド内のすべてのコンテナーは kubelet によって作成されています。少なくとも 1 つのコンテナーが実行中であるか、開始または再起動中です (つまり、Running 状態の Pod には正常にアクセスできない可能性があります)。
- 成功: ジョブや cronjob など、一部のポッドは長時間実行されていません。一定時間が経過すると、ポッド内のすべてのコンテナーが正常に終了し、再起動されません。タスクの実行結果についてのフィードバックが必要です。
- 失敗: ポッド内のすべてのコンテナが終了し、少なくとも 1 つのコンテナが失敗により終了しました。つまり、コンテナがゼロ以外のステータスで終了するか、コマンドの書き込みに問題があるなど、システムによって終了されます。
- 不明: ポッドのステータスを読み取ることができないことを示します。通常、kube-controller-manager はポッドと通信できません。ポッドが配置されているノードに問題があるか、接続が失われて、ポッドのステータスが不明になります。
3. 不明ステータスのポッドを削除するにはどうすればよいですか?
- 問題のあるノードをクラスターから削除します。パブリック クラウドを使用する場合、VM が削除された後、kube-controller-manager は対応するノードを自動的に削除します。物理マシンにデプロイされたクラスターでは、管理者はノードを手動で削除する必要があります (kubectl delete node <node_name>)。
- ノードが通常に戻るのを受動的に待ち、Kubelet は kube-apiserver と再通信してこれらの Pod の予期されるステータスを確認し、これらの Pod を削除するか実行を継続するかを決定します。
- kubectl delete pod <pod_name> --grace-period=0 --force を実行してポッドを強制的に削除し、ポッドをアクティブに削除します。ただし、ポッドが実際に停止していることが明確にわかっている場合を除き、この方法は推奨されないことに注意してください (たとえば、ノードが配置されている VM または物理マシンがシャットダウンされている)。特に StatefulSet で管理されている Pod の場合、強制削除は脳の分割やデータ損失などの問題を引き起こしやすいです。
4. トラブルシューティングの手順
//查看Pod事件
kubectl describe TYPE NAME_PREFIX
//查看Pod日志(Failed状态下)
kubectl logs <POD_NAME> [-c Container_NAME]
//进入Pod(状态为running,但是服务没有提供)
kubectl exec –it <POD_NAME> bash
//查看集群信息
kubectl get nodes
//发现集群状态正常
kubectl cluster-info
//查看kubelet日志发现
journalctl -xefu kubelet