kubeadm-init
kubeadm init - Control Plane Initialization
Overview
kubeadm init bootstraps the Kubernetes control plane through 14 automated phases.
Core principle: Understand each phase before troubleshooting. Certificate, network, and kubelet issues are traced to specific phases.
When to Use
- Initializing a new Kubernetes cluster
- Troubleshooting control plane bootstrap failures
- Understanding certificate generation and static pod deployment
- Planning HA control plane setup
The 14 Phases
kubeadm init phases (sequential):
1. preflight → System requirements check
2. certs → CA and component certificates
3. kubeconfig → Component kubeconfig files
4. etcd → Static Pod manifest for etcd
5. control-plane → Static Pods for API server, controller-manager, scheduler
6. kubelet-start → kubelet configuration and start
7. wait-control-plane → Wait for components to be healthy
8. upload-config → Store config in ConfigMaps
9. upload-certs → (--upload-certs) Store certs in Secret for HA
10. mark-control-plane → Add labels and taints
11. bootstrap-token → Create join token and RBAC
12. kubelet-finalize → Finalize kubelet TLS bootstrap
13. addon → Install CoreDNS and kube-proxy
14. show-join-command → Display join command
Quick Reference
| Phase | Output Location | Key Files |
|---|---|---|
| certs | /etc/kubernetes/pki/ |
ca.crt, apiserver.crt, etcd/ca.crt |
| kubeconfig | /etc/kubernetes/ |
admin.conf, kubelet.conf, scheduler.conf |
| etcd | /etc/kubernetes/manifests/ |
etcd.yaml |
| control-plane | /etc/kubernetes/manifests/ |
kube-apiserver.yaml, kube-scheduler.yaml |
| kubelet-start | /var/lib/kubelet/ |
config.yaml, kubeadm-flags.env |
Configuration Approaches
CLI Options (Simple)
kubeadm init \
--apiserver-advertise-address=192.168.10.100 \
--pod-network-cidr=10.244.0.0/16 \
--service-cidr=10.96.0.0/16 \
--kubernetes-version=1.32.11
Configuration File (Recommended)
# kubeadm-init.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
bootstrapTokens:
- token: "123456.1234567890123456"
ttl: "24h"
nodeRegistration:
kubeletExtraArgs:
node-ip: "192.168.10.100"
criSocket: "unix:///run/containerd/containerd.sock"
localAPIEndpoint:
advertiseAddress: "192.168.10.100"
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "1.32.11"
networking:
podSubnet: "10.244.0.0/16" # Flannel default
serviceSubnet: "10.96.0.0/16"
kubeadm init --config=kubeadm-init.yaml
Critical Options
| Option | Purpose | When Required |
|---|---|---|
--apiserver-advertise-address |
API Server listen IP | Multi-NIC environments |
--control-plane-endpoint |
HA endpoint (LB address) | Must set at init for future HA |
--pod-network-cidr |
Pod IP range | Flannel: 10.244.0.0/16, Calico: 192.168.0.0/16 |
--apiserver-cert-extra-sans |
Additional cert SANs | Custom domains, external LB IPs |
Phase-by-Phase Execution
Run individual phases when customization needed:
# Generate only certificates
kubeadm init phase certs all --config=kubeadm-init.yaml
# Generate manifests for customization
kubeadm init phase control-plane all --config=kubeadm-init.yaml
# Edit /etc/kubernetes/manifests/*.yaml
# Skip that phase in full init
kubeadm init --skip-phases=control-plane --config=kubeadm-init.yaml
Pre-flight Verification
# Check required images
kubeadm config images list
# Pre-pull images (reduces init time)
kubeadm config images pull
# Dry-run to see what will happen
kubeadm init --config=kubeadm-init.yaml --dry-run
Post-Init Steps
1. Configure kubectl
mkdir -p $HOME/.kube
cp /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
2. Install CNI (Required)
# Flannel
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
# Or Calico
kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml
3. Verify
kubectl get nodes # Should show Ready after CNI
kubectl get pods -n kube-system # CoreDNS should become Running
Common Issues
| Symptom | Phase | Cause | Fix |
|---|---|---|---|
| Port 6443 in use | preflight | Previous install | kubeadm reset first |
| CRI connection failed | preflight | containerd not running | systemctl start containerd |
| Node NotReady | addon | CNI not installed | Install Flannel/Calico |
| CoreDNS Pending | addon | CNI not installed | Install Flannel/Calico |
| Certificate SAN error | certs | Missing custom domain | Use --apiserver-cert-extra-sans |
Certificate Structure
/etc/kubernetes/pki/
├── ca.crt, ca.key # Cluster CA
├── apiserver.crt, apiserver.key
├── apiserver-kubelet-client.crt
├── front-proxy-ca.crt # Aggregation Layer CA
├── front-proxy-client.crt
├── sa.key, sa.pub # ServiceAccount signing
└── etcd/
├── ca.crt, ca.key # etcd CA (separate from cluster CA)
├── server.crt, server.key
├── peer.crt, peer.key
└── healthcheck-client.crt
HA Considerations
Must set at first init (cannot add later):
--control-plane-endpoint: Points to load balancer- Can be DNS name initially pointing to single node
kubeadm init \
--control-plane-endpoint "k8s-api.example.com:6443" \
--upload-certs
Reset and Retry
# Full reset
kubeadm reset -f
rm -rf /etc/kubernetes /var/lib/kubelet /var/lib/etcd ~/.kube
iptables -F && iptables -t nat -F
# Then re-init
kubeadm init --config=kubeadm-init.yaml
Verification Checklist
After successful init:
-
kubectl cluster-infoshows API server - Static pods running:
crictl ps | grep -E 'apiserver|etcd|scheduler|controller' - Certificates in
/etc/kubernetes/pki/ - kubeconfig files in
/etc/kubernetes/ - kubelet running:
systemctl status kubelet - Join command displayed with token and CA hash
More from sigridjineth/kubespray-skills
rke2-operations
Use when managing RKE2 cluster certificates, performing manual or automated version upgrades, rotating TLS certificates, deploying the System Upgrade Controller, or troubleshooting RKE2 certificate and upgrade errors. Use when seeing "x509 certificate has expired" or "CertificateExpirationWarning" events or "Job has reached the specified backoff limit" errors.
3rke2-deployment
Use when deploying Kubernetes clusters with RKE2 (Rancher Kubernetes Engine 2), configuring server and agent nodes, managing built-in Helm chart addons, or setting up CIS-hardened clusters. Use when seeing "rke2-server failed to start" or "unable to join cluster" errors.
3kubeadm-troubleshooting
Use when kubeadm init fails, join fails, nodes show NotReady, pods stuck Pending, certificate errors, or kubelet crashlooping
3cluster-api
Use when managing Kubernetes clusters as Kubernetes resources with Cluster API (CAPI), provisioning workload clusters from a management cluster, performing declarative upgrades, or working with ClusterClass blueprints. Use when seeing "failed to connect to management cluster" or clusterctl errors.
2kubespray-airgap
Use when deploying Kubernetes in air-gapped or offline environments using kubespray-offline tool, setting up private container registries, staging binaries and images for offline use, configuring containerd registry mirrors, or troubleshooting image pull failures in isolated networks.
2kubeadm-join
Use when joining worker or control-plane nodes to a Kubernetes cluster, troubleshooting TLS bootstrap, or debugging node join failures
2