## 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:

```bash
kubeadm version
kubelet --version
kubectl version --client
```

Expected output example (versions may differ):

```text
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:

```bash
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:

```bash
sudo systemctl status containerd
ls -l /run/containerd/containerd.sock
```

- Verify required kernel modules and sysctl settings:

```bash
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):

```bash
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:

```yaml
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:

```bash
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:

```bash
sudo kubeadm init --config kubeadm-config.yaml
```

Capture the output to a log file for audit:

```bash
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:

```text
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:

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
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:

```bash
kubectl get pods -n kube-system -l k8s-app=kube-dns
```

Then test DNS by creating a temporary pod and running nslookup inside it:

```bash
kubectl run -i --tty --rm --restart=Never dns-test --image=busybox:1.28
```

This opens an interactive shell. Inside the container, run:

```bash
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:

```bash
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:

```bash
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:

```text
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:

```bash
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:

```bash
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:

```bash
sudo kubeadm certs renew all
```

**Verification**: Check certificate expiry dates:

```bash
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:

```bash
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 -a` and 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-run` and 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 nodes` shows 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.