Qingular

kubeadm Creating and Managing Clusters

·CKAk8s练习

The complete workflow for using kubeadm to initialize a cluster, add nodes, manage tokens, and install CNI network plugins.

← Back to CKA Practice Index

Overview

kubeadm is the official Kubernetes cluster bootstrapping tool for quickly creating best-practice-compliant clusters. It handles complex configurations such as certificates, kubeconfig, and control plane components. kubeadm-related operations are a core part of the CKA exam.


1. kubeadm init -- Initializing the Control Plane

1.1 Basic Initialization

# Minimal initialization
sudo kubeadm init

# Specify the Pod network CIDR (depends on CNI plugin requirements)
sudo kubeadm init --pod-network-cidr=10.244.0.0/16

# Specify the API Server address
sudo kubeadm init --apiserver-advertise-address=192.168.1.10

# Specify the Kubernetes version
sudo kubeadm init --kubernetes-version=v1.31.0

1.2 Parsing Initialization Output

# Example output after successful initialization (each part is important):
Your Kubernetes control-plane has been 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

# A CNI network plugin must be installed
You can now join any number of worker nodes by running the following on each as root:

kubeadm join 192.168.1.10:6443 --token <token> \
        --discovery-token-ca-cert-hash sha256:<hash>

1.3 Post-Initialization Configuration

# Configure kubectl to access the cluster
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 status
kubectl cluster-info
kubectl get nodes
kubectl get pods -n kube-system

1.4 Custom kubeadm-config.yaml

# kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "192.168.1.10"
  bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
kubernetesVersion: "v1.31.0"
controlPlaneEndpoint: "192.168.1.10:6443"
networking:
  serviceSubnet: "10.96.0.0/12"
  podSubnet: "10.244.0.0/16"
  dnsDomain: "cluster.local"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: "systemd"
# Initialize using the configuration
sudo kubeadm init --config=kubeadm-config.yaml

# View default configuration
kubeadm config print init-defaults
kubeadm config print join-defaults

# View cluster configuration
kubectl -n kube-system get configmap kubeadm-config -o yaml

2. kubeadm join -- Adding Worker Nodes

2.1 Basic Usage

# Join using the token from kubeadm init output
sudo kubeadm join 192.168.1.10:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash>

# Join using a configuration file
sudo kubeadm join --config=join-config.yaml

2.2 join-config.yaml

apiVersion: kubeadm.k8s.io/v1beta4
kind: JoinConfiguration
discovery:
  bootstrapToken:
    token: "<token>"
    apiServerEndpoint: "192.168.1.10:6443"
    caCertHashes:
    - "sha256:<hash>"
nodeRegistration:
  name: "worker-1"
  criSocket: "unix:///var/run/containerd/containerd.sock"

2.3 Adding Control Plane Nodes (High Availability)

# Add additional control plane nodes (requires certificate and key first)
sudo kubeadm join 192.168.1.10:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash> \
    --control-plane

# Or use the --certificate-key parameter
sudo kubeadm join 192.168.1.10:6443 --token <token> \
    --discovery-token-ca-cert-hash sha256:<hash> \
    --control-plane \
    --certificate-key <certificate-key>

3. kubeadm token -- Token Management

3.1 Token Operations

# List all tokens
kubeadm token list

# Create a new token
kubeadm token create

# Create a non-expiring token
kubeadm token create --ttl 0

# Specify token TTL
kubeadm token create --ttl 4h

# Delete a token
kubeadm token delete <token>

# View token details
kubeadm token describe <token>

3.2 Getting the Information Needed to Join a Cluster

# Get tokens
kubeadm token list

# If there are no tokens, create a new one
kubeadm token create

# Get the CA certificate hash
openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | \
    openssl rsa -pubin -outform der 2>/dev/null | \
    openssl dgst -sha256 -hex | sed 's/^.* //'

# Or use kubeadm to generate the complete join command
kubeadm token create --print-join-command

# Get the control plane join command
kubeadm init phase upload-certs --upload-certs
kubeadm token create --print-join-command

4. kubeadm reset -- Resetting a Cluster

4.1 Resetting a Node

# Reset a control plane node
sudo kubeadm reset

# Non-interactive reset
sudo kubeadm reset -f

# Clean up network configuration (reset CNI)
sudo kubeadm reset -f
sudo rm -rf /etc/cni/net.d
sudo rm -rf $HOME/.kube

# If using iptables, clean up rules
sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X

4.2 Resetting a Worker Node

# On the worker node
sudo kubeadm reset
sudo rm -rf /etc/cni/net.d
sudo systemctl restart containerd

# On the control plane, delete the node
kubectl delete node worker-1

5. TLS Bootstrapping

TLS bootstrapping allows worker nodes to automatically request certificates, simplifying the node joining process.

# View Certificate Signing Requests
kubectl get csr
kubectl describe csr <csr-name>

# Approve a CSR
kubectl certificate approve <csr-name>

# Deny a CSR
kubectl certificate deny <csr-name>

# View the certificates used by the node
ls -la /var/lib/kubelet/pki/

Node Certificate Auto-Renewal Configuration

# /etc/kubernetes/kubelet-config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
rotateCertificates: true
serverTLSBootstrap: true

6. CNI Network Plugin Installation

6.1 Calico

# Install Tigera Operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/tigera-operator.yaml

# Download custom resources
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/custom-resources.yaml

# Modify Pod CIDR if needed
sed -i 's|192.168.0.0/16|10.244.0.0/16|g' custom-resources.yaml

# Apply configuration
kubectl create -f custom-resources.yaml

# Verify
kubectl get pods -n calico-system
kubectl get nodes

6.2 Flannel

# Install Flannel
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml

# Verify
kubectl get pods -n kube-flannel
kubectl get nodes

6.3 Cilium

# Install Cilium using Helm
helm repo add cilium https://helm.cilium.io/
helm install cilium cilium/cilium --namespace kube-system

# Verify Cilium status
cilium status
kubectl get pods -n kube-system | grep cilium

7. Image Management

# View the images needed by kubeadm
kubeadm config images list

# View images for a specific version
kubeadm config images list --kubernetes-version=v1.31.0

# Pull required images
kubeadm config images pull

# Specify an image repository to pull from (useful for certain regions)
kubeadm config images pull --image-repository=registry.aliyuncs.com/google_containers

8. Common Troubleshooting

# Steps for troubleshooting initialization failures
# 1. Check containerd status
sudo systemctl status containerd

# 2. Check containerd configuration (SystemdCgroup)
sudo cat /etc/containerd/config.toml | grep SystemdCgroup

# 3. View kubelet logs
sudo journalctl -u kubelet -n 100 --no-pager

# 4. Check port usage
sudo ss -tulpn | grep -E "6443|2379|2380|10250"

# 5. Check container runtime
sudo crictl info

# 6. Reset and retry
sudo kubeadm reset -f
sudo rm -rf /etc/kubernetes/
sudo rm -rf /var/lib/etcd/

CKA Exam Key Points

  1. --pod-network-cidr must match the CNI plugin requirements (Calico defaults to 192.168.0.0/16, Flannel uses 10.244.0.0/16)
  2. To generate a join command, using kubeadm token create --print-join-command is the fastest way
  3. Control plane join requires --control-plane and --certificate-key
  4. Pull images before init: kubeadm config images pull to avoid timeouts
  5. Clean up after kubeadm reset: manually clean /etc/kubernetes/ and /var/lib/etcd/

🧪 Complete Hands-on Example: Initialize a Single Control Plane Cluster with kubeadm

Scenario Description

On a node with infrastructure already configured, use kubeadm to initialize a single control plane cluster and install the Calico CNI plugin.

Prerequisites

  • Node infrastructure has been configured (swap disabled, containerd installed and configured with SystemdCgroup)
  • kubeadm, kubelet, kubectl are installed

Steps

Step 1: Pull required images

# Pull images ahead of time to avoid initialization timeouts
sudo kubeadm config images pull
# [config/images] Pulled registry.k8s.io/kube-apiserver:v1.31.0
# [config/images] Pulled registry.k8s.io/kube-controller-manager:v1.31.0
# ...

Step 2: Initialize the control plane

# Use Calico's default Pod CIDR
sudo kubeadm init --pod-network-cidr=192.168.0.0/16

# Output example (key parts):
# Your Kubernetes control-plane has been initialized successfully!
# ...
# mkdir -p $HOME/.kube
# sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
# sudo chown $(id -u):$(id -g) $HOME/.kube/config
# ...
# kubeadm join 192.168.1.10:6443 --token <token> \
#     --discovery-token-ca-cert-hash sha256:<hash>

Step 3: Configure kubeconfig

# Configure kubectl access after successful installation
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 status
kubectl cluster-info
# Kubernetes control plane is running at https://192.168.1.10:6443
# CoreDNS is running at https://192.168.1.10:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

Step 4: Install Calico CNI

# Install Tigera Operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/tigera-operator.yaml

# Download and apply custom resources
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.28/manifests/custom-resources.yaml

# If kubeadm init used a different pod CIDR, modify it
# sed -i 's|192.168.0.0/16|10.244.0.0/16|g' custom-resources.yaml

kubectl create -f custom-resources.yaml

# Wait for Calico Pods to become ready
kubectl get pods -n calico-system -w
# NAME                                      READY   STATUS    RESTARTS   AGE
# calico-kube-controllers-xxxxxxxxx-xxxxx   1/1     Running   0          2m
# calico-node-xxxxx                         1/1     Running   0          2m
# calico-typha-xxxxx                        1/1     Running   0          2m

Step 5: Verify node status

# Wait for the node to become Ready
kubectl get nodes
# NAME              STATUS   ROLES           AGE   VERSION
# control-plane-1   Ready    control-plane   5m    v1.31.0

# View system Pods
kubectl get pods -n kube-system
# NAME                                      READY   STATUS    RESTARTS   AGE
# coredns-xxxxxxxxx-xxxxx                   1/1     Running   0          5m
# coredns-xxxxxxxxx-xxxxx                   1/1     Running   0          5m
# etcd-control-plane-1                      1/1     Running   0          5m
# kube-apiserver-control-plane-1            1/1     Running   0          5m
# kube-controller-manager-control-plane-1   1/1     Running   0          5m
# kube-proxy-xxxxx                          1/1     Running   0          5m
# kube-scheduler-control-plane-1            1/1     Running   0          5m

Step 6: Generate worker node join command

# Create a new token and print the complete join command
kubeadm token create --print-join-command
# kubeadm join 192.168.1.10:6443 --token <new-token> --discovery-token-ca-cert-hash sha256:<hash>

Verification

kubectl get nodes -o wide
# Confirm node is Ready and version is correct
kubectl get pods --all-namespaces | grep -v Completed

Exam Tips

  • --pod-network-cidr must match the CNI plugin requirements: Calico defaults to 192.168.0.0/16, Flannel defaults to 10.244.0.0/16
  • Always run kubeadm config images pull before kubeadm init to avoid network timeouts
  • Save the join command from kubeadm init output, or regenerate with kubeadm token create --print-join-command
  • After initialization, configure kubeconfig first before installing CNI, otherwise kubectl get nodes will show NotReady

Official Documentation