Intro
Kubeadm init is the foundational step for bootstrapping a Kubernetes control plane. While the basic command is simple, operating it in production requires a disciplined approach. A checklist helps operators move from an observed problem to a verified result, minimizing downtime and configuration drift. This article provides a comprehensive operations checklist for kubeadm init, covering version and environment inventory, safe configuration, verification, diagnostics, and failure recovery. It is aimed at developers, DevOps consultants, and technical startup teams who manage Kubernetes clusters.
The goal is operational safety: observe before changing, limit the blast radius, use placeholders instead of secrets, verify the result, and document recovery paths before an incident forces a decision.
Version and Environment Inventory
Before running any kubeadm command, you must know exactly what you are working with. Capturing the environment inventory prevents compatibility surprises and ensures that subsequent steps are appropriate for your Kubernetes version.
Identify Installed Versions
Start by gathering read-only information about kubeadm, kubelet, and kubectl. These components must be version-compatible; kubeadm supports skew policies defined in the Kubernetes version skew policy. Run the following commands on the node intended to be the control plane:
kubeadm version
kubelet --version
kubectl version --client
Expected output example (versions may differ):
kubeadm version: &version.Info{Major:"1", Minor:"28", GitVersion:"v1.28.2", ...}
Kubernetes v1.28.2
Client Version: v1.28.2
Note that kubelet does not have a --version flag in all versions; use kubelet --version if supported, otherwise query the package manager (e.g., dpkg -l kubelet on Debian/Ubuntu or rpm -q kubelet on CentOS/RHEL).
Record the exact versions in a change log or runbook. This is crucial for troubleshooting and for planning upgrades.
Examine Deployment Topology
Determine the node's role and network configuration. Use:
hostnamectl
ip addr show
cat /etc/hosts
Expected output: hostname, IP addresses, and host entries. Ensure the control plane node has a stable IP and a resolvable hostname. The Kubernetes API server will bind to this IP (or to 0.0.0.0 if unspecified), so confirm no conflicts.
Check Prerequisites
Kubeadm requires certain kernel parameters, container runtime, and system settings. Verify them with read-only commands:
- Ensure the container runtime (e.g., containerd, CRI-O) is running and its socket exists:
sudo systemctl status containerd
ls -l /run/containerd/containerd.sock
- Verify required kernel modules and sysctl settings:
cat /proc/sys/net/ipv4/ip_forward
cat /proc/sys/net/bridge/bridge-nf-call-iptables
Expected: 1 for both. If not, do not modify yet; note as an action item for the safe configuration phase.
- Check swap status (swap should be disabled):
swapon --show
free -h
Expected: no swap entries in swapon --show. If swap is enabled, kubelet will fail to start; you must disable it before init.
Document all findings, including any deviations from expected values.
Safe Configuration Path
With the environment inventory complete, you can now plan and apply configuration changes safely. The principle is to make the smallest justified change with a clear rollback path.
Prepare the Kubeadm Configuration File
Instead of relying solely on command-line flags, use a configuration file for reproducibility and version control. Create a kubeadm-config.yaml with explicit settings. Here is a minimal example for Kubernetes v1.28:
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.1.100 # Replace with your node's IP
bindPort: 6443
nodeRegistration:
criSocket: unix:///run/containerd/containerd.sock
name: control-plane-1
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.2
networking:
podSubnet: 10.244.0.0/16 # Example for Flannel; adjust to your CNI
serviceSubnet: 10.96.0.0/12
controlPlaneEndpoint: "192.168.1.100:6443"
Never store real credentials or tokens in the config file. Use placeholders or environment variables for sensitive data.
Validate the Configuration
Before applying, validate the configuration using kubeadm's dry-run capability:
kubeadm init --config kubeadm-config.yaml --dry-run
This command simulates the initialization and prints the actions it would take without making changes. Review the output for any warnings or errors. For example, if the advertise address is unreachable, kubeadm will warn you.
Apply the Change
Only after validation, run the actual init:
sudo kubeadm init --config kubeadm-config.yaml
Capture the output to a log file for audit:
sudo kubeadm init --config kubeadm-config.yaml 2>&1 | tee kubeadm-init-$(date +%Y%m%d-%H%M%S).log
Expected successful output includes messages like:
Your Kubernetes control-plane has initialized successfully!
...
You can now join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.100:6443 --token <token> --discovery-token-ca-cert-hash sha256:<hash>
Record the join command securely; you will need it to add worker nodes. Consider saving it to a password manager.
Post-Init Configuration
After init, configure kubectl for the non-root user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Verify cluster access:
kubectl get nodes
Expected: the control plane node appears with NotReady status because no pod network is installed yet.
Verification and Diagnostics
Verification is continuous. After initialization and after any configuration change, run checks to confirm the cluster is healthy.
Verify Control Plane Components
Check the status of static pods that form the control plane:
kubectl get pods -n kube-system
Expected output: pods kube-apiserver-control-plane-1, kube-controller-manager-control-plane-1, kube-scheduler-control-plane-1, and etcd-control-plane-1 all in Running state. If any are Pending or CrashLoopBackOff, investigate immediately.
Inspect logs for a specific component:
kubectl logs -n kube-system kube-apiserver-control-plane-1
Alternatively, use crictl on the node to view container logs if kubectl is unavailable.
Check Node Readiness
After installing a pod network add-on (e.g., Flannel, Calico), the node should become Ready:
kubectl get nodes -o wide
Expected: STATUS Ready, with internal IP matching the advertise address.
Validate CoreDNS
CoreDNS pods should be running and able to resolve:
kubectl get pods -n kube-system -l k8s-app=kube-dns
Then test DNS by creating a temporary pod and running nslookup inside it:
kubectl run -i --tty --rm --restart=Never dns-test --image=busybox:1.28
This opens an interactive shell. Inside the container, run:
nslookup kubernetes.default
Expected output includes an IP address for the service. To exit and clean up, type exit.
Verify API Server Accessibility
From the control plane node, query the API server health endpoint:
curl -k https://localhost:6443/healthz
Expected: ok.
Diagnose Common Issues
If verification fails, use diagnostics to pinpoint the problem.
- Kubelet failing to start: Check kubelet status and logs:
sudo systemctl status kubelet
sudo journalctl -u kubelet -n 50 --no-pager
Common causes: swap enabled, missing container runtime socket, or incorrect cgroup driver.
- API server pod crash: Inspect pod logs as shown earlier. Look for certificate errors, etcd connection failures, or misconfigured advertise address.
- Networking issues: Ensure the pod network CIDR does not overlap with the host network and that the CNI plugin is installed correctly.
Document each diagnostic result and the action taken.
Failure Modes and Recovery
Even with careful planning, failures occur. This section outlines common failure modes during kubeadm init and recovery steps.
Failure: Pre-flight Checks Fail
Kubeadm runs pre-flight checks before making changes. If they fail, it will abort with messages like:
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR Swap]: running with swap on is not supported. Please disable swap
Recovery: Fix each reported error. For swap, disable it:
sudo swapoff -a
# Make permanent by commenting swap line in /etc/fstab
Then re-run init. No cluster state is modified because init did not proceed.
Failure: Init Partially Completes
If init fails midway (e.g., after etcd starts but before API server is ready), the cluster may be in an inconsistent state. The safest recovery is to reset and start over:
sudo kubeadm reset -f
This removes all Kubernetes artifacts from the node. Then, re-run init after fixing the root cause.
Verification: After reset, check that directories /etc/kubernetes/ and /var/lib/etcd/ are removed or empty, and no kubelet process is running.
Failure: Certificate Expired or Invalid
If certificates are misconfigured or expired, the API server may fail. Kubeadm manages certificates automatically, but if you need to renew them on an existing cluster, use:
sudo kubeadm certs renew all
Verification: Check certificate expiry dates:
sudo kubeadm certs check-expiration
Failure: Join Command Lost or Expired
The join token expires after 24 hours by default. To generate a new token and hash:
sudo kubeadm token create --print-join-command
This prints a fresh join command. Use it on worker nodes.
Verification: Ensure the new token appears in kubeadm token list and has not expired.
Recovery Documentation
Maintain a runbook with failure modes, symptoms, diagnostic commands, and recovery steps. For each failure, include the expected output of the recovery command to confirm success.
Operations Checklist
The following checklist summarizes the entire lifecycle of kubeadm init operations. Use it before, during, and after initialization to ensure consistency.
Pre-Init Checklist
- [ ] Confirm OS compatibility (e.g., Ubuntu 20.04+, CentOS 7+) and kernel version
uname -r. - [ ] Verify container runtime installed and running:
sudo systemctl status containerd. - [ ] Disable swap:
sudo swapoff -aand remove from/etc/fstab. - [ ] Enable required kernel modules:
br_netfilter, overlay; set sysctl parameters net.ipv4.ip_forward=1, net.bridge.bridge-nf-call-iptables=1. - [ ] Ensure hostname resolves and IP is static.
- [ ] Record versions of kubeadm, kubelet, kubectl and check compatibility skew.
- [ ] Prepare kubeadm config file with correct IPs, subnets, and CRI socket.
- [ ] Run
kubeadm init --config ... --dry-runand review output.
Init Execution Checklist
- [ ] Run init command and capture logs.
- [ ] Save the join command output securely.
- [ ] Configure kubectl for non-root user.
- [ ] Install pod network add-on (e.g.,
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml). - [ ] Wait for node to become Ready.
Post-Init Verification Checklist
- [ ]
kubectl get nodesshows control plane node Ready. - [ ] All control plane pods Running in kube-system.
- [ ] CoreDNS pods Running.
- [ ] DNS test pod resolves
kubernetes.default. - [ ] API server health endpoint returns
ok. - [ ] Check kubelet and container runtime logs for errors.
Maintenance and Drift Prevention
- [ ] Periodically run
kubeadm certs check-expiration. - [ ] Review kubeadm config for drift with actual cluster state.
- [ ] Keep a log of all changes with timestamps.
- [ ] Test join process on a non-production node.
- [ ] Document any manual interventions for future reference.
Conclusion
Operating kubeadm init in production is not a one-time command; it is a process that requires planning, verification, and recovery strategies. This checklist provides a structured approach to minimize risk and ensure cluster reliability. By following the steps outlined--from environment inventory to post-init verification and failure recovery--you can build and maintain a robust Kubernetes control plane.
As a next step, implement the checklist in your environment. Begin with a read-only inventory, then proceed with configuration validation using dry-run, and finally execute init with logging and verification. Document your observations and update the runbook as you encounter new failure modes. With disciplined operations, you can keep your Kubernetes clusters healthy and your team confident.
Remember: observe before changing, limit the blast radius, use placeholders instead of secrets, verify the result, and document how to recover.