LabHub

ブログ

CKA_3_Scheduling

한국어English日本語

本記事は https://www.udemy.com/course/certified-kubernetes-administrator-with-practice-tests の講座と https://kodekloud.com/ の内容を学習しながら記録したものです。

53 Manual Scheduling

もしKubernetesにスケジューラがなかったらどうなるでしょうか?Podはおそらくずっとpending状態のままになるでしょう。 代わりに、Pod定義ファイルにnodeNameを明示的に指定することで、Podを配置するノードを設定できます。

No Scheduler

既に実行中のPodを特定のノードに割り当てるにはどうすればよいでしょうか?

Binding APIを活用します。

Pod-bind-definition.yaml
apiVersion: v1
kind: Binding
metadata:
  name: nginx
target:
  apiVersion:v1
  kind: Node
  name: node2

または、実行中のPodを停止し、nodeNameを指定してPodを再作成します。

56 Labels and Selectors in Kubernetes

Labelはkey-valueペアとして指定できます。

リソースにはmetadata -> labels配下にラベルを定義し、ReplicaSetのように特定のPodをフィルタリングする必要がある箇所ではselector -> matchLabelsにkey-valueペアを指定します。

No Scheduler

グルーピングとセレクティングのためにLabelとSelectorが使用されます。

その他の情報を保存するためにAnnotationも使用されます。

envがdevのラベルを持つPodのみをセレクトする方法:

$ kubectl get pods --show-labels=true
NAME          READY   STATUS    RESTARTS   AGE    LABELS
app-1-krzm7   1/1     Running   0          3m3s   bu=finance,env=dev,tier=frontend
db-2-8lwj8    1/1     Running   0          3m2s   bu=finance,env=prod,tier=db
db-1-gw7lc    1/1     Running   0          3m3s   env=dev,tier=db
app-1-tbwcg   1/1     Running   0          3m3s   bu=finance,env=dev,tier=frontend
app-2-5lt89   1/1     Running   0          3m3s   env=prod,tier=frontend
db-1-btt4j    1/1     Running   0          3m3s   env=dev,tier=db
auth          1/1     Running   0          3m2s   bu=finance,env=prod
app-1-qqhbb   1/1     Running   0          3m3s   bu=finance,env=dev,tier=frontend
db-1-chgq9    1/1     Running   0          3m3s   env=dev,tier=db
db-1-wgvgf    1/1     Running   0          3m3s   env=dev,tier=db
app-1-zzxdf   1/1     Running   0          3m2s   bu=finance,env=prod,tier=frontend



$ kubectl get pods --selector env=prod
NAME          READY   STATUS    RESTARTS   AGE
db-2-8lwj8    1/1     Running   0          5m2s
app-2-5lt89   1/1     Running   0          5m3s
auth          1/1     Running   0          5m2s
app-1-zzxdf   1/1     Running   0          5m2s



$ kubectl get all  --selector env=prod
NAME              READY   STATUS    RESTARTS   AGE
pod/db-2-8lwj8    1/1     Running   0          6m26s
pod/app-2-5lt89   1/1     Running   0          6m27s
pod/auth          1/1     Running   0          6m26s
pod/app-1-zzxdf   1/1     Running   0          6m26s

NAME            TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/app-1   ClusterIP   10.43.7.99   <none>        3306/TCP   6m26s

NAME                    DESIRED   CURRENT   READY   AGE
replicaset.apps/db-2    1         1         1       6m27s
replicaset.apps/app-2   1         1         1       6m27s


$ kubectl get pods --selector env=prod,bu=finance,tier=frontend
NAME          READY   STATUS    RESTARTS   AGE
app-1-zzxdf   1/1     Running   0          8m1s

59 Taints and Tolerations

Taintは「汚染された」という意味で、Tolerationは「耐性」という意味です。 特定のNodeにTaintを付与すると、Toleration(耐性)がないPodはそのノードにスケジュールされません。 逆に、Tolerationを持つPodはそのNodeにスケジュール可能です。

Taint Tolerations

Taint Node

node-nameにはNodeの名前を指定し、taint-effectには NoSchedulePreferNoScheduleNoExecute の3つから1つを選択します。

$ kubectl taint nodes node-name key=value:taint-effect

# example
$ kubectl taint nodes node01 spray=mortein:NoSchedule
node/node01 modified

specセクションにTolerationを定義します。内部の値はすべてダブルクォートで囲む必要があります。

pod-definition.yml
apiVersion: v1
kind: Pod
metadata:
  name: myapp-pod
spec:
  containers:
  - name: nginx-container
    image: nginx
  tolerations:
  - key: "app"
    operator: "Equal"
    value: "blue"
    effect:"NoSchedule"

Taintアクションの中でNoExecuteはより詳しく見る必要があります。NoExecuteはNoScheduleの機能に加えて、既に動作中のPodも削除する機能を含みます。そのため、運用中のノードにTaintを設定する場合、NoExecuteは稼働中のPodに影響を与える可能性があるため、慎重に使用する必要があります。

TaintやTolerationを見ると、特定のPodを特定のNodeに移動させるものだと誤解されがちです。しかし正確には、特定のPodが特定のNodeにスケジュールされることを防ぐものです。Podを特定のNodeに配置するのはNode Affinityに関連しています。

KubernetesにはMaster Nodeが存在します。Master NodeにもPodを実行できる環境が整っています(実際にMaster NodeにPodを移動させることも可能です)。しかし通常、Master NodeではPodは実行されません。その理由は、Master NodeにはTaintが設定されており、ユーザーが実行したPodがスケジュールされないようになっているためです。

kubectl describe node kubemaster | grep Taint でTaintを確認できます。

Create another pod named bee with the nginx image, which has a toleration set to the taint mortein.

$ kubectl run bee --image nginx --dry-run=client -o yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: bee
  name: bee
spec:
  containers:
  - image: nginx
    name: bee
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

# Edit like below
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: bee
  name: bee
spec:
  tolerations:
    - key: "spray"
      operator: "Equal"
      value: "mortein"
      effect: "NoSchedule"
  containers:
  - image: nginx
    name: bee
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

$ kubectl create -f bee.yaml

$ kubectl describe nodes node01 | grep mort
Taints:             spray=mortein:NoSchedule

$ kubectl describe nodes controlplane | grep Taints
Taints:             node-role.kubernetes.io/control-plane:NoSchedule

Remove taints of controlplane node.

$ kubectl taint nodes controlplane node-role.kubernetes.io/control-plane:NoSchedule-
node/controlplane untainted

$ kubectl describe nodes controlplane | grep Taints
Taints:             <none>

63. Node Affinity

Node SelectorのラベルやNode Affinityを使用してノードを指定できます。事前にノードにラベルが設定されている必要があります。

requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution の2つのオプションがあり、必須か任意かの違いです。Requiredの場合、該当Podを割り当てられる適切なノードがなければ、Podはスケジュールされません。Preferredの場合は、スケジューラは最善を尽くしますが、必要に応じて他のノードにもスケジュールします。

nodeSelector:
  size: Large

Node Affinity

Node Affinity

Node Affinity

Apply label to a node.

kubectl label nodes node01 color=blue
node/node01 labeled

Create a new deployment named red with the nginx image and 2 replicas, and ensure it gets placed on the controlplane node only. Use the label key - node-role.kubernetes.io/control-plane - which is already set on the controlplane node.

apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: red
  name: red
spec:
  replicas: 2
  selector:
    matchLabels:
      app: red
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: red
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-role.kubernetes.io/control-plane
                operator: Exists
      containers:
      - image: nginx
        name: nginx
        resources: {}
status: {}

TaintとTolerationだけでは、特定のPodが特定のNodeにスケジュールされることを保証できません。Node Affinityだけでも同様に保証できません。Taint & TolerationとNode Affinityの両方を組み合わせることで、特定のNodeに特定のPodのみがスケジュールされることを保証できます。

67 Resource Requirements and Limits

Podの実行に必要なハードウェアリソースをKubernetesにリクエストできます。Limitも設定可能です。

pod-definition.yaml
spec:
 continers:
 - name: simple-webapp
   image: nginx
   ports:
   - containerPort: 8080
   resources:
     requests:
       memory: "1Gi"
       cpu: 1
     limits:
       memory: "2Gi"
       cpu: 2

CPUリソースは1 vCPU未満の値も設定できます。例えば0.1は100msを意味します。CPU使用量がlimitを超えるとスロットリングがかかります。しかしメモリの場合は異なります。メモリ使用量が超過するとOOM(Out Of Memory)エラーが発生し、Podが停止されます。

Namespaceレベルでlimitの最小値、最大値の範囲を設定することもできます。

LimitRange

QuotaもNamespaceレベルで設定でき、そのNamespaceが作成可能な最大ハードウェアリソースを割り当てることができます。

LimitRange

71 DaemonSets

DaemonSetは1つのNodeに1つのPodだけを実行する場合に使用します。名前からも分かるように、デーモンとして常に停止せずに実行されるPodです。新しいノードが追加されると、DaemonSetが自動的にPodを追加します。

LimitRange

一般的にモニタリングソリューションやログビューアーを起動する際にDaemonSetが使用されます。Kubernetesで最も有名なDaemonSetを1つ挙げるなら kube-proxy です。

DaemonSetの定義はReplicaSetとほぼ同じです。

LimitRange

kubectl get daemonsets

DaemonSetがノードに必ず常駐することを保証できるでしょうか?答えは「保証できる」です。 v1.12ではDaemonSetのPod SpecificationのnodeNameプロパティにNodeを明示的に指定するためです。

v1.12以降のKubernetesバージョンでは少し異なり、明示的に設定せずにNodeAffinityとデフォルトスケジューラを活用してDaemonSetを作成します。

Question: Create Daemonset which requires below specification.

Name: elasticsearch Namespace: kube-system Image: registry.k8s.io/fluentd-elasticsearch:1.20

kubectl create deployment elasticsearch --namespace=kube-system --image=registry.k8s.io/fluentd-elasticsearch:1.20 --dry-run=client -o yaml

74 Static Pods

Kubernetes API Server、ETCD、Schedulerがすべて存在せず(Master Nodeが存在しない)、Worker Node 1台、つまりKubelet(コンテナランタイム含む)1つだけが存在する場合、Podを実行できるでしょうか?答えは「可能」です。Static Podという特別なPodがあり、これを利用すれば他のユーティリティシステム(APIサーバー、ETCD、Scheduler)なしでもPodの作成が可能です。

Static Podを実行するには、/etc/kubernetes/manifests ディレクトリ配下にPod定義ファイルを配置する必要があります。 Kubeletはこのディレクトリ配下のファイルを定期的にチェックし、Podを作成します。

以下はMaster Nodeで該当ディレクトリの内容を確認した例です。

$ ls -al /etc/kubernetes/manifests/
total 24
drwxr-xr-x 2 root root 4096  812 10:56 ./
drwxr-xr-x 4 root root 4096  812 10:56 ../
-rw------- 1 root root 2411  812 10:56 etcd.yaml
-rw------- 1 root root 4047  812 10:56 kube-apiserver.yaml
-rw------- 1 root root 3429  812 10:56 kube-controller-manager.yaml
-rw------- 1 root root 1463  812 10:56 kube-scheduler.yaml
youngjukim@cubi01:~$

このファイルが削除されると、Kubeletは自動的にPodを削除します。更新されると、Podを自動的に再作成します。 Static Podの定義パスは必ずしも /etc/kubernetes/manifests である必要はなく、別のディレクトリに設定することも可能です。ただし、パスを変更するにはKubeletの再起動が必要です。

staticpod

または、設定ファイルを引数として渡し、staticPodPath で該当パスを設定する方法もあります。

staticpod

Master Nodeなしで単独で実行されているKubeletの場合、Static Podが正常に実行されているかを確認するにはどうすればよいでしょうか? 当然ながらMaster Nodeがないため、APIサーバーも存在せず、kubectlコマンドも使用できません。この場合は docker pscrictl ps でPodが正常に実行されているか確認する必要があります。

では、Master Nodeが存在する状況では、APIサーバーはWorker NodeのKubeletで実行中のStatic Podの存在を認識できるでしょうか?答えは「認識できる」です。 しかし存在の認識のみであり、Static Podに対する操作は不可能です。APIサーバーはStatic Podに対してread-only権限のみを持っています。 また特徴的な点として、Static PodはPod名にノード名が自動的に付加されます。

Static PodはKubernetesコントロールプレーンに依存せず、指定フォルダにPod定義ファイルを配置するだけでよいため、デプロイが簡単です。 kube-systemの大半のPodはStatic Podであり、kubeadmツールもこの仕組みを利用しています。

staticpod

DaemonSetとStatic Podは混同されやすいですが、kube-schedulerの影響を受けない点は共通していますが、それ以外はまったく異なります。DaemonSetはノードごとに1つずつ実行され、作成主体はAPIサーバーです。一方、Static Podの作成主体はKubeletです。

/etc/kubernetes/manifests/static-busybox.yaml
apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: static-busybox
  name: static-busybox
spec:
  containers:
  - command:
    - sleep
    - "1000"
    image: busybox
    name: static-busybox
    resources: {}
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

77 Multiple Schedulers

Kubernetesでは複数のSchedulerを使用できます。また、Podをスケジューリングする際にどのSchedulerを使用するかも設定可能です。

最も簡単なカスタムSchedulerの追加は以下のように行えますが、現在ではこの方法は使用されていません。

scheduler

現在は以下のように、SchedulerもPod形式で実行する方法が一般的です。

scheduler

最新の方法はKubernetes公式ガイドの Configuring Multiple Schedulers を参照してください。

Podを実行する際に明示的にSchedulerを指定するには、spec配下の schedulerName にScheduler名を指定します。

scheduler

新しく作成したmy-custom-schedulerでスケジューリングが正しく行われたか確認するには、kubectl get events -o wide を使用します。 または kubectl logs my-custom-scheduler --name-space=kube-system でSchedulerのログを確認します。

my-scheduler-config.yaml
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: my-scheduler
leaderElection:
  leaderElect: false
/root/my-scheduler-configmap.yaml
apiVersion: v1
data:
  my-scheduler-config.yaml: |
    apiVersion: kubescheduler.config.k8s.io/v1beta2
    kind: KubeSchedulerConfiguration
    profiles:
      - schedulerName: my-scheduler
    leaderElection:
      leaderElect: false
kind: ConfigMap
metadata:
  creationTimestamp: null
  name: my-scheduler-config
  namespace: kube-system

ConfigMapの作成:

$ kubectl create configmap my-scheduler-config --from-file=/root/my-scheduler-config.yaml -n kube-system
configmap/my-scheduler-config created

カスタムSchedulerの作成:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: my-scheduler
  name: my-scheduler
  namespace: kube-system
spec:
  serviceAccountName: my-scheduler
  containers:
  - command:
    - /usr/local/bin/kube-scheduler
    - --config=/etc/kubernetes/my-scheduler/my-scheduler-config.yaml
    image: registry.k8s.io/kube-scheduler:v1.27.0
    livenessProbe:
      httpGet:
        path: /healthz
        port: 10259
        scheme: HTTPS
      initialDelaySeconds: 15
    name: kube-second-scheduler
    readinessProbe:
      httpGet:
        path: /healthz
        port: 10259
        scheme: HTTPS
    resources:
      requests:
        cpu: '0.1'
    securityContext:
      privileged: false
    volumeMounts:
      - name: config-volume
        mountPath: /etc/kubernetes/my-scheduler
  hostNetwork: false
  hostPID: false
  volumes:
    - name: config-volume
      configMap:
        name: my-scheduler-config

80 Configuring Scheduler Profiles

Podはスケジューリングされる前にScheduling Queueに入ります。ここでPodのPriorityに基づいてソートされます。 次にFiltering Phaseでは、該当Podを収容できるNodeだけが選別されます。フィルタリングの対象はNodeです。Scoring Phaseでは残りのNode間でスコアを付けて1つのNodeを決定します。最後にBindingが実行されます。

各Phaseにはそれぞれプラグインが存在し、以下の通りです。Kubernetesではこれらのプラグインをカスタマイズできるよう、Extension Pointを提供しています。

scheduler

Kubernetes v1.18リリースでは、Multiple Scheduler間の衝突を防ぐためにMultiple Profileという概念が導入されました。 同じバイナリを使用する各プロファイルで、多数のプラグインのenable/disableを設定できるようになりました。例えば、Score Plugin Phaseをスキップすることも可能です。

scheduler

クイズ

Q1: 「CKA_3_Scheduling」の主なトピックは何ですか? CKA_3_Scheduling

Q2: Taint Nodeとは何ですか? node-nameにはNodeの名前を指定し、taint-effectには NoSchedule、PreferNoSchedule、NoExecute の3つから1つを選択します。 specセクションにTolerationを定義します。内部の値はすべてダブルクォートで囲む必要があります。 Taintアクションの中でNoExecuteはより詳しく見る必要があります。NoExecuteはNoScheduleの機能に加えて、既に動作中のPodも削除する機能を含みます。

コメント

まだコメントはありません。

ログインするとコメントできます