Creating High Available Baremetal Kubernetes cluster with Kubeadm and Keepalived (Simple Guide)

This guide is a free interpretation of official Creating Highly Available Clusters with kubeadm for Stacked control plane nodes. I don’t like this difficult form which used there, so I wrote this article.

If you have any questions, or something is not clear, please refer to the official documentation or ask the Google. All steps described here in the short and simple form.

Input data

We have 3-nodes cluster:

  • node1 (

We will create one fault-resistant cluster-ip for them:


Then install etcd and kubernetes cluster on them.

LoadBalancer setup

First, we need to install keepalived on all three nodes:

apt-get -y install keepalived

Then write config /etc/keepalived/keepalived.conf:

vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 1
priority 100
advert_int 1
authentication {
auth_type AH
auth_pass iech6peeBu6Thoo8xaih
virtual_ipaddress {

Enable and start keepalived on all thee nodes

systemctl start keepalived
systemctl enable keepalived

Now we can check that one of node have address on eth0 interface.

Deploying Kubernetes cluster

UPD: This article was written for v1.12, and despite the fact that it was adapted for v1.13, now creating cluster is much easier, check this more simple guide.

Make sure that you have latest kubernetes packages installed on all nodes:

apt-get -y install kubeadm kubelet kubectl

Also stop keepalived daemon on all nodes except the last one:

systemctl stop keepalived

First node

Now we will generate kubeadm-configs (we need separated config for each master node):

NODES=(node1 node2 node3)
for i in "${!NODES[@]}"; do
for j in "${!NODES[@]}"; do
echo "${NODES[$j]}=https://${IPS[$j]}:2380"
done | xargs | tr ' ' ,
cat > kubeadm-config-${NODES[$i]}.yaml <<EOT
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "${CLUSTER_IP}:6443"
initial-cluster: "${INITIAL_CLUSTER}"
initial-cluster-state: new
name: ${NODES[$i]}
listen-peer-urls: "https://${IPS[$i]}:2380"
listen-client-urls: ",https://${IPS[$i]}:2379"
advertise-client-urls: "https://${IPS[$i]}:2379"
initial-advertise-peer-urls: "https://${IPS[$i]}:2380"
- "${NODES[$i]}"
- "${IPS[$i]}"
- "${NODES[$i]}"
- "${IPS[$i]}"
podSubnet: "${POD_SUBNET}"

Init etcd on first node, generate ca certs and admin config

kubeadm="kubeadm --config=kubeadm-config-${HOSTNAME}.yaml"
$kubeadm init phase preflight
$kubeadm init phase certs all
$kubeadm init phase kubelet-start
$kubeadm init phase kubeconfig kubelet
$kubeadm init phase etcd local
$kubeadm init phase kubeconfig admin
systemctl start kubelet

Copy generated certs and kubeadm configs to other control plane nodes

NODES="node2 node3"
CERTS=$(find /etc/kubernetes/pki/ -maxdepth 1 -name '*ca.*' -o -name '*sa.*')
ETCD_CERTS=$(find /etc/kubernetes/pki/etcd/ -maxdepth 1 -name '*ca.*')
for NODE in $NODES; do
ssh $NODE mkdir -p /etc/kubernetes/pki/etcd
scp $CERTS $NODE:/etc/kubernetes/pki/
scp $ETCD_CERTS $NODE:/etc/kubernetes/pki/etcd/
scp /etc/kubernetes/admin.conf $NODE:/etc/kubernetes
scp kubeadm-config-$NODE.yaml $NODE:

Second node

Init etcd on second node

kubeadm="kubeadm --config=kubeadm-config-${HOSTNAME}.yaml"
$kubeadm init phase preflight
$kubeadm init phase certs all
$kubeadm init phase kubelet-start
$kubeadm init phase kubeconfig kubelet
$kubeadm init phase etcd local
systemctl start kubelet

Third node

Init kubernetes master with the last etcd on the last node:

(make sure that you have loadbalanser ip targeted to this node)

kubeadm init --config kubeadm-config-${HOSTNAME}.yaml

First and Second nodes

Now we can deploy kubernetes master on the first two nodes

kubeadm="kubeadm --config=kubeadm-config-${HOSTNAME}.yaml"
$kubeadm init phase kubeconfig all
$kubeadm init phase control-plane all
$kubeadm init phase mark-control-plane

And start keepalived daemon also:

systemctl start keepalived

Written by

This mess is mine!

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store