kubernetes-the-hard-way/docs/07-scheduler.md

7.5 KiB

Scheduler

In this section we will configure scheduler.

image

In Kubernetes, a scheduler is a core component responsible for assigning and placing workloads (such as pods) onto available nodes in a cluster. It ensures that the cluster's resources are utilized efficiently and that workloads are scheduled based on their resource requirements and other constraints. Kublet, regularly request the list of pods assigned to it. In case if new pod appear, kubelet will run new pod. In case if pod marked as deleted, kubelet will start termination process.

In previous section, we created pod and it was runed on the node, but why? The reason of that, we specified the node name on which to run the pod by our self

  nodeName: ${HOST_NAME}

So, lets create pod without node specified

{
cat <<EOF> pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: hello-world
spec:
  serviceAccountName: hello-world
  containers:
    - name: hello-world-container
      image: busybox
      command: ['sh', '-c', 'while true; do echo "Hello, World!"; sleep 1; done']
EOF

kubectl apply -f pod.yaml
}

And check pod status

kubectl get pod -o wide

Output:

NAME          READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
hello-world   0/1     Pending   0          19s   <none>   <none>   <none>           <none>

As we can see node field of our pod is none and pod is in pending state. So, lets, configure scheduler and check if it will solve the issue.

certificates

We will start with certificates.

As you remeber we configured our API server cto use client certificate to authenticate user. So, lets create proper certificate for the scheduler

{
cat > kube-scheduler-csr.json <<EOF
{
  "CN": "system:kube-scheduler",
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "US",
      "L": "Portland",
      "O": "system:kube-scheduler",
      "OU": "Kubernetes The Hard Way",
      "ST": "Oregon"
    }
  ]
}
EOF

cfssl gencert \
  -ca=ca.pem \
  -ca-key=ca-key.pem \
  -config=ca-config.json \
  -profile=kubernetes \
  kube-scheduler-csr.json | cfssljson -bare kube-scheduler
}

The most interesting configuration options:

  • cn(common name) - value, api server will use as a client name during authorization
  • o(organozation) - user group api server will use during authorization

We specified "system:kube-scheduler" in the organization. It says api server that the client who uses which certificate belongs to the system:kube-scheduler group. Api server know, that this group is allowed to make proper modifications to pod specification to assign pod to node.

serviece configuration

After the certificate files created we can create configuration files for the scheduler.

{
  kubectl config set-cluster kubernetes-the-hard-way \
    --certificate-authority=ca.pem \
    --embed-certs=true \
    --server=https://127.0.0.1:6443 \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-credentials system:kube-scheduler \
    --client-certificate=kube-scheduler.pem \
    --client-key=kube-scheduler-key.pem \
    --embed-certs=true \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config set-context default \
    --cluster=kubernetes-the-hard-way \
    --user=system:kube-scheduler \
    --kubeconfig=kube-scheduler.kubeconfig

  kubectl config use-context default --kubeconfig=kube-scheduler.kubeconfig
}

We created kubernetes configuration file, which says scheduler where api server is configured and which certificates to use communicating with it

Now, we can distribute created configuration file.

sudo mv kube-scheduler.kubeconfig /var/lib/kubernetes/

In addition to this file, we will create one more configuration file for scheduler

{
mkdir /etc/kubernetes/config
cat <<EOF | sudo tee /etc/kubernetes/config/kube-scheduler.yaml
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
clientConnection:
  kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
  leaderElect: true
EOF
}

After all configuration files created, we need to download scheduler binaries.

wget -q --show-progress --https-only --timestamping \
  "https://storage.googleapis.com/kubernetes-release/release/v1.21.0/bin/linux/amd64/kube-scheduler"

And install it

{
  chmod +x kube-scheduler
  sudo mv kube-scheduler /usr/local/bin/
}

Now, we can create configuration file for scheduler service

cat <<EOF | sudo tee /etc/systemd/system/kube-scheduler.service
[Unit]
Description=Kubernetes Scheduler
Documentation=https://github.com/kubernetes/kubernetes

[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
  --config=/etc/kubernetes/config/kube-scheduler.yaml \\
  --v=2
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

After configuration file created, we need to run it

{
  sudo systemctl daemon-reload
  sudo systemctl enable kube-scheduler
  sudo systemctl start kube-scheduler
}

And finally we check scheduler status

sudo systemctl status kube-scheduler

Output:

● kube-scheduler.service - Kubernetes Scheduler
     Loaded: loaded (/etc/systemd/system/kube-scheduler.service; enabled; vendor preset: enabled)
     Active: active (running) since Thu 2023-04-20 11:57:44 UTC; 16s ago
       Docs: https://github.com/kubernetes/kubernetes
   Main PID: 15134 (kube-scheduler)
      Tasks: 7 (limit: 2275)
     Memory: 13.7M
     CGroup: /system.slice/kube-scheduler.service
             └─15134 /usr/local/bin/kube-scheduler --config=/etc/kubernetes/config/kube-scheduler.yaml --v=2
...

verification

Now, when our scheduler is up and running, we can check if our pod is in runnign state.

kubectl get pod -o wide

Output:

NAME          READY   STATUS    RESTARTS   AGE   IP       NODE     NOMINATED NODE   READINESS GATES
hello-world   0/1     Pending   0          24m   <none>   <none>   <none>           <none>

As you can see, our pod still in pending mode.

To define the reason of this, we will review the logs of our scheduler.

journalctl -u kube-scheduler | grep not-ready

Output:

...
May 21 20:52:25 example-server kube-scheduler[91664]: I0521 20:52:25.471604   91664 factory.go:338] "Unable to schedule pod; no fit; waiting" pod="default/hello-world" err="0/1  nodes are available: 1 node(s) had taint {node.kubernetes.io/not-ready: }, that the pod didn't tolerate."
...

As we can see our pod wasn't assigned to the node because node has some taint, lets check our node taints.

kubectl get nodes $(hostname -a) -o jsonpath='{.spec.taints}'

Output:

[{"effect":"NoSchedule","key":"node.kubernetes.io/not-ready"}]

As you can see, our node has taint with efect no schedule. The reason of this???? But lets fix this.

kubectl taint nodes $(hostname -a) node.kubernetes.io/not-ready:NoSchedule-

And check our pods list again

kubectl get pod -o wide

Output:

NAME          READY   STATUS    RESTARTS   AGE   IP           NODE             NOMINATED NODE   READINESS GATES
hello-world   1/1     Running   0          29m   10.240.1.3   example-server   <none>           <none>

As you can see out pod is in running state, means that scheduler works as expected.

Now we need to clean-up our wirkspace

kubectl delete -f pod.yaml

Check if pod deleted

kubectl get pod

Outpput:

No resources found in default namespace.

Next: Controller manager