-
- Prepare kernel networking settings (both nodes)
-
- Add the Kubernetes apt repository (both nodes)
-
- Install kubeadm, kubelet, kubectl (pinned version) (both nodes)
-
- Before initialization: kubectl on control plane
-
- Initialize the control plane with kubeadm (control plane only)
-
- Join node01 to the cluster (node01 only)
-
- Install a pod network (Flannel) (control plane)
- Summary and Troubleshooting
- Links and references
1) Prepare kernel networking settings (both nodes)
Kubernetes requires bridged network traffic to be handled by iptables and IP forwarding to be enabled. Create a sysctl config file (for example/etc/sysctl.d/k8s.conf) with the required keys:
Kubeadm requires swap to be disabled on all nodes. Disable swap now and make it persistent across reboots before running
kubeadm init / kubeadm join:Kubernetes needs an OCI runtime (for example containerd or Docker) installed and running on all nodes before initializing the control plane. One quick approach is to install and configure Confirm the runtime is active before running
containerd with the systemd cgroup driver:kubeadm init/join.2) Add the Kubernetes apt repository (both nodes)
Install prerequisites, create the keyrings directory (if missing), fetch the GPG key, and add the Kubernetes apt repository:apt warns about duplicate package sources (e.g., “Target Packages … is configured multiple times”), that indicates duplicate entries in /etc/apt/sources.list or /etc/apt/sources.list.d/. These warnings can be cleaned up but do not block installation.
On older Debian/Ubuntu releases the directory
/etc/apt/keyrings may not exist; creating it prevents curl from failing when writing the keyring (as shown above).3) Install kubeadm, kubelet, kubectl (pinned version) (both nodes)
Pinning the Kubernetes packages prevents unexpected upgrades that can break cluster compatibility. This lab uses Kubernetes v1.26.0 — adjustK8S_VERSION if your environment requires a different release.
4) Before initialization: kubectl on control plane
On the control plane,kubectl cannot contact the API server until kubeadm init completes. Running kubectl get nodes before initialization will produce an error similar to:
5) Initialize the control plane with kubeadm (control plane only)
- Determine the control plane IP on the interface you want to advertise. For example:
- Initialize the control plane, specifying the advertised API server address and the pod network CIDR. Flannel commonly uses
10.244.0.0/16.
kubeadm init you will see output that includes the join command and instructions to configure kubectl for your regular user. Example snippet:
kubectl for your regular user:
NotReady until the pod network is installed):
NotReady state is normal until the network addon pods are running.
6) Join node01 to the cluster (node01 only)
From thekubeadm init output you recorded the kubeadm join ... command. On node01 (run as root or with sudo) execute that join command. Example:
NotReady until the network is installed):
7) Install a pod network (Flannel) (control plane)
Deploy Flannel using the upstream manifest. This installs the Flannel DaemonSet and related resources intokube-system:
kube-system along with CoreDNS and kube-proxy. When Flannel becomes ready, node statuses will transition to Ready:
Summary
- Configured required sysctl settings on both nodes and disabled swap.
- Added the Kubernetes apt repository and installed
kubeadm,kubelet, andkubectlpinned to v1.26.0. - Initialized the control plane with
kubeadm init, advertising the control plane IP and specifying the pod network CIDR for Flannel. - Joined node01 using the
kubeadm joincommand produced bykubeadm init. - Deployed Flannel as the pod network and verified nodes reached the
Readystate.
Troubleshooting & tips
- If nodes remain
NotReadyafter installing the pod network, checkkubectl get pods -n kube-systemto see pod states for Flannel/CoreDNS/kube-proxy. - Verify the
--apiserver-advertise-addresspassed tokubeadm initis reachable from worker nodes. - If
kubeadm joinfails due to token expiration, create a new token on the control plane: - Certificate or time-related errors can often be resolved by synchronizing clocks across nodes (e.g., enable and start
systemd-timesyncdorchronyd). - If kubelet uses the wrong cgroup driver, ensure container runtime (
containerd) is configured to usesystemdcgroup driver and restart the runtime.
Links and references
- Kubernetes documentation: https://kubernetes.io/docs/
- kubeadm: https://kubernetes.io/docs/reference/setup-tools/kubeadm/
- Flannel releases / manifest: https://github.com/flannel-io/flannel/releases
- containerd: https://containerd.io/
kubeadm output and kubectl -n kube-system get pods output so you can be assisted more quickly.