0 of 15 done
Bring It Online

Bootstrap the control plane

Where you are

etcd is running, so the cluster has a place to store its state. Now the control plane comes up, and the order matters. You start the API server first, then the controller manager and the scheduler. Each one depends on the one before it. The API server reads and writes to etcd, and the controller manager and scheduler both talk to the API server, so they cannot all start at once.

In this lab you bootstrap the Kubernetes control plane. You install three components on the server machine: the Kubernetes API server, the scheduler, and the controller manager.

Prerequisites

Connect to the jumpbox and copy the Kubernetes binaries and systemd unit files to the server machine:

scp \
  downloads/controller/kube-apiserver \
  downloads/controller/kube-controller-manager \
  downloads/controller/kube-scheduler \
  downloads/client/kubectl \
  units/kube-apiserver.service \
  units/kube-controller-manager.service \
  units/kube-scheduler.service \
  configs/kube-scheduler.yaml \
  configs/kube-apiserver-to-kubelet.yaml \
  root@server:~/

Run the commands in this lab on the server machine. Login to the server machine using the ssh command. Example:

ssh root@server

Provision the control plane

Create the Kubernetes configuration directory:

mkdir -p /etc/kubernetes/config

Install the controller binaries

Install the Kubernetes binaries:

{
  mv kube-apiserver \
    kube-controller-manager \
    kube-scheduler kubectl \
    /usr/local/bin/
}

Configure the API server

{
  mkdir -p /var/lib/kubernetes/

  mv ca.crt ca.key \
    kube-api-server.key kube-api-server.crt \
    service-accounts.key service-accounts.crt \
    encryption-config.yaml \
    /var/lib/kubernetes/
}

Create the kube-apiserver.service systemd unit file:

mv kube-apiserver.service \
  /etc/systemd/system/kube-apiserver.service

Configure the controller manager

Move the kube-controller-manager kubeconfig into place:

mv kube-controller-manager.kubeconfig /var/lib/kubernetes/

Create the kube-controller-manager.service systemd unit file:

mv kube-controller-manager.service /etc/systemd/system/

Configure the scheduler

Move the kube-scheduler kubeconfig into place:

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

Create the kube-scheduler.yaml configuration file:

mv kube-scheduler.yaml /etc/kubernetes/config/

Create the kube-scheduler.service systemd unit file:

mv kube-scheduler.service /etc/systemd/system/

Start the controller services

{
  systemctl daemon-reload

  systemctl enable kube-apiserver \
    kube-controller-manager kube-scheduler

  systemctl start kube-apiserver \
    kube-controller-manager kube-scheduler
}

Allow up to 10 seconds for the Kubernetes API Server to fully initialize.

You can check whether any of the control plane components are active with the systemctl command. For example, to check whether the kube-apiserver has fully initialized and is active, run the following command:

systemctl is-active kube-apiserver

For a more detailed status check, which includes additional process information and log messages, use the systemctl status command:

systemctl status kube-apiserver

If you run into any errors, or want to view the logs for any of the control plane components, use the journalctl command. For example, to view the logs for the kube-apiserver run the following command:

journalctl -u kube-apiserver

Verification

At this point the control plane components should be up and running. Verify this with the kubectl command line tool:

kubectl cluster-info \
  --kubeconfig admin.kubeconfig
Kubernetes control plane is running at https://127.0.0.1:6443

RBAC for kubelet authorization

In this section you configure RBAC permissions to allow the API server to access the kubelet API on each worker node. The API server needs access to the kubelet API to retrieve metrics, retrieve logs, and run commands in pods.

This tutorial sets the Kubelet --authorization-mode flag to Webhook. Webhook mode uses the SubjectAccessReview API to determine authorization.

The commands in this section affect the entire cluster and only need to be run on the server machine.

ssh root@server

Create the system:kube-apiserver-to-kubelet ClusterRole with permissions to access the kubelet API and perform most common tasks associated with managing pods:

kubectl apply -f kube-apiserver-to-kubelet.yaml \
  --kubeconfig admin.kubeconfig

Verification

At this point the control plane is up and running. Run the following commands from the jumpbox machine to verify that it is working.

Make an HTTP request for the Kubernetes version info:

curl --cacert ca.crt \
  https://server.kubernetes.local:6443/version
{
  "major": "1",
  "minor": "32",
  "gitVersion": "v1.32.3",
  "gitCommit": "32cc146f75aad04beaaa245a7157eb35063a9f99",
  "gitTreeState": "clean",
  "buildDate": "2025-03-11T19:52:21Z",
  "goVersion": "go1.23.6",
  "compiler": "gc",
  "platform": "linux/arm64"
}

Key terms

kube-apiserver The front door to the cluster. Every read and write of cluster state goes through it, and it is the only component that talks to etcd.

kube-controller-manager The component that runs controllers. A controller watches the current state of the cluster and works to make it match the desired state, for example by creating replacement pods when one is lost.

kube-scheduler The component that decides which worker node each new pod runs on, based on the resources each node has and the needs of the pod.

RBAC Role-based access control. A way to grant specific permissions to specific identities. Here it grants the API server permission to call the kubelet API on each worker.

Reflect

You started the API server before the controller manager and the scheduler because both depend on it. If you started all three at the same time and the controller manager came up first, what would you expect to happen, and how would the system recover once the API server was ready?

Next: Bootstrap the worker nodes