Multi-arch Bare Metal Kubernetes Cluster with Docker on Ubuntu 20.04
This example config uses 1 local computer, 1 master node, and 3 worker nodes.
Setup
Plan out the setup and write it into ssh config file (on local computer)
vim $HOME/.ssh/config
# pi8
Host k8s-master
HostName k8s-master
User master
IdentityFile ~/.ssh/id_k8s
# pi4
Host k8s-w1
HostName k8s-w1
User master
IdentityFile ~/.ssh/id_k8s
# e7240
Host k8s-w2
HostName k8s-w2
User master
IdentityFile ~/.ssh/id_k8s
# n5050
Host k8s-w3
HostName k8s-w3
User master
IdentityFile ~/.ssh/id_k8s
Create master user (on each node)
sudo adduser master
groups
sudo usermod -aG adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,netdev,lxd master
sudo hostnamectl set-hostname <HOSTNAME>
On Raspi:sudo sed -i 's/preserve_hostname: false/preserve_hostname: true/' /etc/cloud/cloud.cfg
sudo hostnamectl
sudo reboot
Create ssh key and distribute to each node (on local computer)
ssh-keygen -b 4096 -f $HOME/.ssh/k8s_rsa
ssh-copy-id -i $HOME/.ssh/id_k8s master@<HOSTNAME>
Test ssh keys and delete default ubuntu user
ssh <HOSTNAME>
sudo deluser --remove-home ubuntu
Enable cgroup memory (Raspi nodes)
vim /boot/firmware/cmdline.txt
# add to end of linecgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
sudo reboot
If exposed on internet
sudo vim /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
sudo /usr/sbin/sshd -t
sudo systemctl restart sshd.service
sudo reboot
Check for and disable swap (on each node)
free
sudo swapoff -a
sudo vim /etc/fstab
Setup Docker (on each node)
sudo modprobe overlay
sudo modprobe br_netfilter
echo 'net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
net.bridge.bridge-nf-call-ip6tables = 1' | sudo tee -a /etc/sysctl.d/99-kubernetes-cri.conf
sudo sysctl --system
sudo apt-get update && sudo apt-get -y upgrade
sudo apt-get install -y docker.io
Install K8s (on each node)
sudo apt-get -y install apt-transport-https
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
echo "deb https://apt.kubernetes.io kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get -y install kubeadm kubelet kubectl
sudo apt-mark hold kubelet kubeadm kubectl
Install K8s (on master)
mkdir -p $HOME/.kube
ip a
cat <<EOF > $HOME/.kube/kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: InitConfiguration
nodeRegistration:
name: pi8
criSocket: "/var/run/dockershim.sock"
---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
kubernetesVersion: stable
controlPlaneEndpoint: "pi8:6443"
networking:
podSubnet: 10.244.0.0/12
serviceSubnet: 10.96.0.0/12
EOF
echo '192.168.0.13 pi8' | sudo tee -a /etc/hosts
sudo kubeadm init --config=$HOME/.kube/kubeadm-config.yaml --upload-certs | tee $HOME/.kube/kubeadm-init.out
sudo cat /etc/kubernetes/admin.conf > $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Install Calico (on master)
curl https://docs.projectcalico.org/manifests/calico.yaml -o $HOME/.kube/calico.yaml
vim $HOME/.kube/calico.yaml
# uncomment and change to podSubnet
- name: CALICO_IPV4POOL_CIDR
value: "10.244.0.0/12"
kubectl apply -f $HOME/.kube/calico.yaml
kubectl -n kube-system set env daemonset/calico-node IP_AUTODETECTION_METHOD=can-reach=10.244.0.1
Join Network from Workers
echo '192.168.0.13 pi8' | sudo tee -a /etc/hosts
kubeadm join pi8:6443 --token <TOKEN> --discovery-token-ca-cert-hash <HASH>
Finish up on Master
kubectl get nodes
kubectl label node <NODE> node-role.kubernetes.io/worker=worker
kubectl completion bash | sudo tee /etc/bash_completion.d/kubectl
echo 'alias k=kubectl
complete -F __start_kubectl k' | tee -a $HOME/.bashrc
kubectl describe node | grep -i taint
kubectl taint nodes --all node-role.kubernetes.io/master-
Setup MetalLB (on master)
kubectl get configmap kube-proxy -n kube-system -o yaml | \
sed -e "s/strictARP: false/strictARP: true/" | \
kubectl apply -f - -n kube-system
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/namespace.yaml
kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.9.3/manifests/metallb.yaml
# On first install only
kubectl create secret generic -n metallb-system memberlist --from-literal=secretkey="$(openssl rand -base64 128)"
cat <<EOF > $HOME/.kube/metallb-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
namespace: metallb-system
name: config
data:
config: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.1.240-192.168.1.250
EOF
kubectl apply -f $HOME/.kube/metallb-config.yaml
Test MetalLB
cat <<EOF > nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 4
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: arm64v8/nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
externalTrafficPolicy: Local
type: LoadBalancer
EOF
kubectl apply -f nginx-deployment.yaml
kubectl get all -o wide
kubectl delete -f nginx-deployment.yaml
Delete nodes
kubectl drain <NODE> --ignore-daemonsets --delete-local-data
kubectl delete node <NODE>
Reset Script
sudo kubeadm reset
If that doesn't work...
cat <<EOF > $HOME/.kube/k8sReset.sh
#!/bin/bash
# script to reset k8s/kubeadm/calico
# Requires net-tools (sudo apt install -y net-tools)
sudo apt purge -y kubeadm kubectl kubelet kubernetes-cni --allow-change-held-packages
sudo rm -rf /var/lib/cni/ /var/lib/calico/ /var/lib/kubelet/ /var/lib/etcd/ /etc/kubernetes/ /etc/cni/ /run/kubernetes/ $HOME/.kube/config
sudo iptables -F && sudo iptables -t nat -F && sudo iptables -t mangle -F && sudo iptables -X
sudo apt install -y kubeadm kubectl kubelet kubernetes-cni
sudo apt-mark hold kubelet kubeadm kubectl
sudo systemctl daemon-reload
sudo systemctl restart kubelet
sudo netstat -lnp | grep 6443
sudo netstat -lnp | grep 10259
sudo netstat -lnp | grep 10257
sudo netstat -lnp | grep 10250
sudo netstat -lnp | grep 2379
sudo netstat -lnp | grep 2380
EOF
sudo chmod 700 $HOME/.kube/k8sReset.sh
sudo kubeadm reset && $HOME/.kube/k8sReset.sh