Kubernetes installation is not big deal but certain requirements must be meet. In this article we will show you Kubernetes installation on CentOS, step by step guide. We will start with requirements in order to successfully install Kubernetes. Let’s go.


  • OS: CentOS 7+, RHEL 7+,Fedora 25+,Debian 9+, Ubuntu 16.04+,HypriotOS v1.0.1+
  • 2 GB RAM, 2vCPU
  • Network connectivity between nodes
  • Unique MAC address, hostname and product id
  • Open ports:

TCP (ingress): 6443*, 2379-2380, 10250, 10251 , 10252 (MASTER)

TCP (ingress): 10250, 30000-32767

  • Swap disabled


swmanager.local – (master node)

swworker1.local – (worker node 1)

swworker2.local – (worker node2)


  1. Prepare one master and two worker nodes
  2. Install container runtime (Docker) on all nodes
  3. Install Kubernetes components
  4. Initialize cluster
  5. Join worker nodes to Kubernetes cluster


  1. Disable SELinux to allow containers to access host file system on all nodes (example for master):
[root@swmanager ~] setenforce 0

setenforce: SELinux is disabled

[root@swmanager ~]# sed -i ‘s/^SELINUX=enforcing$/SELINUX=permissive/’ /etc/selinux/config

  1. Populate local hosts file with FQDN of virtual machines on all nodes:
[root@swworker1 ~] cat /etc/hosts localhost localhost.localdomain localhost4 localhost4.localdomain4

::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 swmanager.local swworker1.local swworker2.local

  1. Install container runtime (Docker) on all nodes:
[root@swworker1 ~] yum install docker-ce –nobest -y

Last metadata expiration check: 0:00:18 ago on Mon 09 Mar 2020 09:05:09 AM CET.

Dependencies resolved.

Problem: package docker-ce-3:19.03.7-3.el7.x86_64 requires >= 1.2.2-3, but none of the providers can be installed

– cannot install the best candidate for the job

– package is excluded

– package is excluded

– package is excluded

– package is excluded

– package is excluded

– package is excluded

– package is excluded

  1. Configure docker to use overlay2 storage driver:
[root@swworker1 ~] tee /etc/docker/daemon.json <<EOF


“exec-opts”: [“native.cgroupdriver=systemd”],

“log-driver”: “json-file”,

“log-opts”: {

“max-size”: “100m”


“storage-driver”: “overlay2”,

“storage-opts”: [





  1. Restart Docker services:
[root@swmanager ~] systemctl daemon-reload && systemctl restart docker

[root@swmanager ~] systemctl enable docker

  1. Check that product id of nodes is unique (sometimes virtual machines have same product id):
[root@swworker2 ~] cat /sys/class/dmi/id/product_uuid


[root@swworker1 ~] cat /sys/class/dmi/id/product_uuid


[root@swmanager ~] cat /sys/class/dmi/id/product_uuid


  1. Disable firewalld or allow ports on all nodes (we will disable firewalld – example for master node):
[root@swmanager ~] systemctl stop firewalld && systemctl disable firewalld
  1. To avoid Pod performance disable swap on all nodes (example for master node):
[root@swmanager ~]

sed -i ‘/swap/d’ /etc/fstab

swapoff -a

  1. To allow VXLAN communication between pods enable br_netfilter on all nodes (example for master node):
[root@swmanager ~] modprobe br_netfilter

[root@swmanager ~] lsmod | grep br_netfilter

br_netfilter 24576 0

bridge 192512 1 br_netfilter

  1. For Linux iptables to see bridge traffic correctly enable this filters:
[root@swmanager ~] cat <<EOF > /etc/sysctl.d/k8s.conf

> net.bridge.bridge-nf-call-ip6tables = 1

> net.bridge.bridge-nf-call-iptables = 1


[root@swmanager ~]# sysctl –system

* Applying /usr/lib/sysctl.d/10-default-yama-scope.conf …

kernel.yama.ptrace_scope = 0

* Applying /usr/lib/sysctl.d/50-coredump.conf …

kernel.core_pattern = |/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e

* Applying /usr/lib/sysctl.d/50-default.conf …

kernel.sysrq = 16

kernel.core_uses_pid = 1

net.ipv4.conf.all.rp_filter = 1

net.ipv4.conf.all.accept_source_route = 0

net.ipv4.conf.all.promote_secondaries = 1

net.core.default_qdisc = fq_codel

fs.protected_hardlinks = 1

fs.protected_symlinks = 1

* Applying /usr/lib/sysctl.d/50-libkcapi-optmem_max.conf …

net.core.optmem_max = 81920

* Applying /etc/sysctl.d/99-sysctl.conf …

* Applying /etc/sysctl.d/k8s.conf …

net.bridge.bridge-nf-call-ip6tables = 1

net.bridge.bridge-nf-call-iptables = 1

* Applying /etc/sysctl.conf …

  1. Add Kubernetes repository in order to download required packages on all nodes:
[root@swmanager ~]cat <<EOF > /etc/yum.repos.d/kubernetes.repo

> [kubernetes]

> name=Kubernetes

> baseurl=

> enabled=1

> gpgcheck=1

> repo_gpgcheck=1

> gpgkey=


  1. Install Kubernetes packages:
[root@swworker1 ~]# yum -y install kubelet kubeadm kubectl –disableexcludes=kubernetes

Kubernetes 366 B/s | 454 B 00:01

Kubernetes 13 kB/s | 1.8 kB 00:00

Importing GPG key 0xA7317B0F:

Userid : “Google Cloud Packages Automatic Signing Key <>”

Fingerprint: D0BC 747F D8CA F711 7500 D6FA 3746 C208 A731 7B0F

From :

Importing GPG key 0xBA07F4FB:

Userid : “Google Cloud Packages Automat



kubeadm-1.19.4-0.x86_64 kubectl-1.19.4-0.x86_64 kubelet-1.19.4-0.x86_64

socat- conntrack-tools-1.4.4-10.el8.x86_64 libnetfilter_cthelper-1.0.0-15.el8.x86_64

libnetfilter_cttimeout-1.0.0-11.el8.x86_64 libnetfilter_queue-1.0.2-11.el8.x86_64 cri-tools-1.13.0-0.x86_64



  1. Start Kubernetes services on master node:
[root@swmanager]# systemctl enable kubelet && systemctl start kubelet

Created symlink /etc/systemd/system/ → /usr/lib/systemd/system/kubelet.service.

  1. Check if Kubernetes client is installed:
[root@swmanager]# kubectl version –client

Client Version: version.Info{Major:”1″, Minor:”19″, GitVersion:”v1.19.4″, GitCommit:”d360454c9bcd1634cf4cc52d1867af5491dc9c5f”, GitTreeState:”clean”, BuildDate:”2020-11-11T13:17:17Z”, GoVersion:”go1.15.2″, Compiler:”gc”, Platform:”linux/amd64″}

  1. Ensure that systemd is configured for cgroup:
[root@swmanager ~]# cat <<EOF > /etc/sysconfig/kubelet

> KUBELET_EXTRA_ARGS=”–cgroup-driver=systemd”


  1. Initialize Kubernetes cluster:
[root@swmanager ~]# kubeadm init –pod-network-cidr= –apiserver-advertise-address=

W1119 09:08:38.536223 1905 configset.go:348] WARNING: kubeadm cannot validate component configs for API groups []

[init] Using Kubernetes version: v1.19.4

[preflight] Running pre-flight checks

[WARNING FileExisting-tc]: tc not found in system path

[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’

[certs] Using certificateDir folder “/etc/kubernetes/pki”

[certs] Generating “ca” certificate and key

[certs] Generating “apiserver” certificate and key

[certs] apiserver serving cert is signed for DNS names [kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local swmanager.local] and IPs []


Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

You should now deploy a pod network to the cluster.

Run “kubectl apply -f [podnetwork].yaml” with one of the options listed at:

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join –token sfzbf4.gqh1xwwjqhkznwv5 \

–discovery-token-ca-cert-hash sha256:25432bd4b786d54887e3078bfe0e3db7cf88199bf75d4702b6dc618e20a1dfe2

  1. Apply correct permissions for Kubernetes cluster (master node):
[root@swmanager]# mkdir -p $HOME/.kube

sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

sudo chown $(id -u):$(id -g) $HOME/.kube/config

  1. Join all worker nodes to kubernetes cluster:
[root@swworker2 ~]# kubeadm join –token sfzbf4.gqh1xwwjqhkznwv5 –discovery-token-ca-cert-hash sha256:25432bd4b786d54887e3078bfe0e3db7cf88199bf75d4702b6dc618e20a1dfe2

[preflight] Running pre-flight checks

[WARNING FileExisting-tc]: tc not found in system path

[WARNING Hostname]: hostname “swworker2” could not be reached

[WARNING Hostname]: hostname “swworker2”: lookup swworker2 on no such host

[preflight] Reading configuration from the cluster…

[preflight] FYI: You can look at this config file with ‘kubectl -n kube-system get cm kubeadm-config -oyaml’

[kubelet-start] Writing kubelet configuration to file “/var/lib/kubelet/config.yaml”

[kubelet-start] Writing kubelet environment file with flags to file “/var/lib/kubelet/kubeadm-flags.env”

[kubelet-start] Starting the kubelet

[kubelet-start] Waiting for the kubelet to perform the TLS Bootstrap…

This node has joined the cluster:

* Certificate signing request was sent to apiserver and a response was received.

* The Kubelet was informed of the new secure connection details.

Run ‘kubectl get nodes’ on the control-plane to see this node join the cluster.

  1. From master run following command to check status of the cluster (all nodes should be in ready status):
[root@swmanager ~] kubectl get nodes


swmanager.local Ready master 11m v1.19.4

swworker1.local Ready <none> 38s v1.19.4

swworker2 Ready <none> 5m50s v1.19.4

  1. Check status of system pods on master node (all should be in running state):
[root@swmanager] kubectl get pods –n kube-system


coredns-f9fd979d6-k2xjv 1/1 Running 0 3m18s

coredns-f9fd979d6-xjzzr 1/1 Running 0 3m18s

etcd-swmanager.local 1/1 Running 0 3m28s

kube-apiserver-swmanager.local 1/1 Running 0 3m28s

kube-controller-manager-swmanager.local 1/1 Running 0 3m28s

kube-flannel-ds-82s4h 1/1 Running 0 106s

kube-flannel-ds-vkt7k 1/1 Running 0 55s

kube-proxy-pz2gh 1/1 Running 0 3m18s

kube-proxy-sfljr 1/1 Running 0 55s

kube-scheduler-swmanager.local 1/1 Running 0 3m28s

  1. Run one image to test if pods are running:
[root@swmanager ~] kubectl run nginx –image=nginx

pod/nginx created

  1. Pod should be in running state:
[root@swmanager log] kubectl get pods -o wide


nginx 1/1 Running 0 80s swworker1.local <none> <none>

Congratulations you have successfully installed three node kubernetes cluster!