🇧🇷 Leia a versão em português aqui
In previous parts of this series, we prepared the environment (Part 1) and installed containerd, kubelet, and kubeadm on all nodes (Part 2). Now it's time to finally initialize the cluster: we'll create the control-plane on the master server and get it ready to accept workers and a functional pod network.
Initializing the cluster with kubeadm
The simplest way to initialize the cluster is to run the command below on the master server:
# kubeadm init
Or, specifying important parameters manually — such as the pod network CIDR, the IP address to be advertised by the API server, and the Kubernetes version:
# kubeadm init --pod-network-cidr=10.244.0.0/16 --apiserver-advertise-address=10.0.10.100 --kubernetes-version="1.31.1"
Using a configuration file (recommended)
More recent versions of kubelet no longer accept certain options via the command line (this behavior has been deprecated). Because of this, the current recommendation is to create a configuration file for kubeadm, instead of passing everything via flags.
Create the kubelet.yaml file:
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: "1.31.1" # Replace with your desired version
controlPlaneEndpoint: "k8s-master"
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
And run the initialization pointing to that file:
$ sudo kubeadm init --config kubelet.yaml
What to expect from the output
If everything goes well, the command's output will look similar to this (summarized here for readability):
[init] Using Kubernetes version: v1.31.1
[preflight] Running pre-flight checks
[preflight] Pulling images required for setting up a Kubernetes cluster
[preflight] This might take a minute or two, depending on the speed of your internet connection
[preflight] You can also perform this action in beforehand using 'kubeadm config images pull'
[kubelet-start] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet-start] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[kubelet-start] Activating the kubelet service
[certs] Using certificateDir folder "/etc/kubernetes/pki"
[certs] Generating "ca" certificate and key
[certs] Generating "apiserver-kubelet-client" certificate and key
...
[bootstraptoken] configured RBAC rules to allow certificate rotation for all node client certificates in the cluster
[bootstraptoken] creating the "cluster-info" ConfigMap in the "kube-public" namespace
[addons] Applied essential addon: CoreDNS
[addons] Applied essential addon: kube-proxy
Your Kubernetes master has 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
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 10.0.10.100:6443 --token d1dyaj.31zxywbg93s1ywjy --discovery-token-ca-cert-hash sha256:71a91721595fde66b6382908d801266602a14de8e16bdb7a3cede21509427009
⚠️ Important: save the full
kubeadm joincommand (with the token and certificate hash) shown at the end of the output. You'll need it to add the workers to the cluster.
Setting up kubectl access
To use kubectl as a regular user (without needing sudo every time), copy the administrator's configuration file:
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
To check the current state of the cluster, run:
kubectl get pods --all-namespaces
At this point, it's normal for some pods to show up as Pending — that's because we haven't installed a pod network (CNI) yet, which is exactly the next step.
Installing the pod network (CNI)
Kubernetes doesn't ship with a ready-made networking solution — you need to choose and install a network plugin (CNI), responsible for allowing communication between the cluster's pods. Some popular options are Calico, Canal, Flannel, and Weave.
Use only one of the options above — installing more than one CNI on the same cluster can cause network conflicts.
Example with Calico:
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.28.2/manifests/calico.yaml
Example with Flannel:
kubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/v0.20.2/Documentation/kube-flannel.yml
Example with Weave:
export kubever=$(kubectl version | base64 | tr -d '\n')
kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$kubever"
kubectl apply -f https://github.com/weaveworks/weave/releases/download/v2.8.1/weave-daemonset-k8s.yaml
After applying the chosen manifest, run again:
kubectl get pods --all-namespaces
And, within a few moments, the pods in the kube-system namespace — including CoreDNS — should switch to Running status. This confirms the pod network is working correctly.
Next steps
With the control-plane initialized, kubectl configured, and the pod network installed, the cluster's master is now fully operational. Only one step remains: adding the worker servers to the cluster using the kubeadm join command we saved earlier.
In Part 4 of this series, we'll join the workers to the cluster and confirm all nodes are ready to receive workloads.
Continued in Part 4.


Top comments (0)