KubernetesLXXIV · kubeadmkubeadm
kubeadm init — phases, output, and post-init sanity
What you'll learn
- Run kubeadm init with the right options
- Walk each of the 12 phases and what they produce
- Capture the join command and the admin kubeconfig
- Validate the cluster post-init
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
kubeadm init is the canonical entry point for
bootstrapping a Kubernetes cluster. The command runs a
sequence of phases — generating certificates, writing
control-plane static pods, configuring etcd, setting up
kubeconfig, applying initial RBAC and add-ons. This
lesson walks the phases and the post-init validation.
The command
sudo kubeadm init \
--control-plane-endpoint "loadbalancer.example:6443" \
--upload-certs \
--pod-network-cidr=10.244.0.0/16 \
--kubernetes-version=v1.34.0
Each flag controls:
--control-plane-endpoint: the LB DNS/IP used for the cluster’s API server endpoint (the kubeconfig’sserver).--upload-certs: enables the join command to use encrypted certificate distribution (rotates secrets for subsequent joins).--pod-network-cidr: the CIDR for Pod IPs (must match the CNI’s configuration).--kubernetes-version: pin to a specific minor.
The 12 phases
flowchart LR
A[init] --> P1[1. certs]
P1 --> P2[2. kubeconfig]
P2 --> P3[3. control-plane]
P3 --> P4[4. etcd]
P4 --> P5[5. wait-for-control-plane]
P5 --> P6[6. bootstrap-token]
P6 --> P7[7. self-hosted]
P7 --> P8[8. addon]
P8 --> P9[9. upload-certs]
P9 --> P10[10. mark-control-plane]
P10 --> P11[11. kubelet-start]
P11 --> P12[12. post-init]
# Run with verbose to see each phase
sudo kubeadm init --v=2 ...
Each phase’s purpose:
Phase 1 — certs
kubeadm generates the cluster’s PKI: the CA, server
certs, peer certs, etc. The CA is stored in
/etc/kubernetes/pki/ca.crt. Each cert in
/etc/kubernetes/pki/apiserver.crt,
/etc/kubernetes/pki/apiserver.key.
Phase 2 — kubeconfig
The admin kubeconfig at /etc/kubernetes/admin.conf. The
kubelet’s kubeconfig at
/etc/kubernetes/kubelet.conf (using the bootstrap token).
Phase 3 — control-plane static pods
The static pod manifests are written to
/etc/kubernetes/manifests/:
- kube-apiserver.yaml
- kube-controller-manager.yaml
- kube-scheduler.yaml
- etcd.yaml
The kubelet picks them up and starts the pods.
Phase 4 — etcd
The static etcd pod is configured with the cluster’s
initial membership. For a single init, that’s one member;
subsequent kubeadm join --control-plane adds members.
Phase 5 — wait-for-control-plane
kubeadm waits for the API server to be ready. Health
check on https://<endpoint>/healthz.
Phase 6 — bootstrap-token
kubeadm creates a bootstrap-token Secret in the
kube-system namespace. New nodes use this token to
authenticate and fetch cluster info via CSR.
Phase 7 — self-hosted
kubeadm creates a ClusterConfiguration ConfigMap in
kube-system. The kubelet reconciler on each node reads
this ConfigMap and applies it.
Phase 8 — addon
kubeadm installs the cluster’s add-ons:
kube-proxyDaemonSet.corednsDeployment.
(These can be replaced; many clusters use Cilium’s CNI-specific kube-proxy replacement.)
Phase 9 — upload-certs (with —upload-certs)
kubeadm encrypts the cluster’s certificates and uploads
them as a Secret in kube-system. Subsequent join
commands download and decrypt them.
Phase 10 — mark-control-plane
Labels the host as a control-plane node. The kubelet on
control-plane nodes runs taints like
node-role.kubernetes.io/control-plane.
Phase 11 — kubelet-start
The kubelet is restarted (or started) on the host with the new configuration.
Phase 12 — post-init
kubeadm prints the join command and the admin kubeconfig path.
The output
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f <network-addon.yaml>" on the master.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join loadbalancer.example:6443 \
--token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:...
The output contains:
- The admin kubeconfig location.
- The join command for additional nodes.
- The token and CA cert hash needed for the join.
$ sudo kubeadm init --control-plane-endpoint loadbalancer.example:6443 --pod-network-cidr=10.244.0.0/16 --kubernetes-version=v1.34.0 2>&1 | tail -30...The post-init sanity
After init, validate:
# 1. kubectl is configured
kubectl get nodes
# Expected: cp-1 listed, status NotReady (CNI not installed yet)
# 2. The control-plane components are healthy
kubectl get pods -n kube-system
# Expected: kube-apiserver, kube-controller-manager, kube-scheduler, etcd all Running
# 3. The kubeadm-config ConfigMap exists
kubectl -n kube-system get configmap kubeadm-config -o yaml
Install the CNI
Until the CNI is installed, nodes are NotReady (no Pod network):
# Install a CNI plugin
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
# Or:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
After CNI install, nodes become Ready.
The init variations
External etcd
sudo kubeadm init \
--control-plane-endpoint loadbalancer.example:6443 \
--etcd-servers "https://etcd-1:2379,https://etcd-2:2379,https://etcd-3:2379" \
--etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt \
--etcd-certfile=/etc/kubernetes/pki/etcd/client.crt \
--etcd-keyfile=/etc/kubernetes/pki/etcd/client.key
kubeadm connects to the external etcd cluster instead of running one locally.
HA control plane with —upload-certs
sudo kubeadm init \
--control-plane-endpoint loadbalancer.example:6443 \
--upload-certs \
--pod-network-cidr=10.244.0.0/16
The --upload-certs flag enables the join command to
auto-fetch certificates.
The re-init
kubeadm init is idempotent only if the cluster state is
clean. To re-init:
sudo kubeadm reset
sudo rm -rf /etc/kubernetes/pki /var/lib/etcd
sudo kubeadm init ...
The kubeadm reset undoes init’s effects on a host. It
removes static pods, certificates, and the local etcd
data dir.
The cluster-info
After init, the cluster’s discovery info:
kubectl cluster-info
Kubernetes control plane is running at https://loadbalancer.example:6443
CoreDNS is running at https://loadbalancer.example:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
The cluster-info points at the LB; the API server is running.
Quiz
Knowledge check · 4 questions
Q1. After `kubeadm init`, what does the join command look like?
Q2. `kubeadm init` installs the cluster CNI plugin as part of its phases.
Q3. kubeadm init fails at Phase 8 (addon). Diagnose and remediate.
The init proceeds through certs, control-plane pods, etcd. At Phase 8 (addon installation of kube-proxy), the API server has an RBAC misconfiguration.
Q4. What is the operator's responsibility after `kubeadm init` completes?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- Document the init flags. Replicating a cluster requires exact flags.
- Capture the join command. It’s the only time the token is in plain text.
- Install CNI immediately. No Pod network without it.
- Validate post-init. kubectl get nodes, get pods -n kube-system.
- Re-init only after reset. A dirty state confuses init.
- Capture the kubeadm-config ConfigMap. It’s the cluster’s configuration record.
kubeadm init is the cluster’s first hour. Operating
it well is the foundation that every later operation
builds on.