My setup:
Ensure SSH is enabled in the VMs (disabled by default on Multipass VM):
# Enable in /etc/ssh/sshd_config
PasswordAuthentication yes
PubkeyAuthentication yes
# Generate RSA key on client machines
# Add ~/.ssh/id_rsa.pub from each client machine to ~/.ssh/authorized_keys on each VM
# Define the Kubernetes version and used CRI-O stream
export KUBERNETES_VERSION=v1.31
export CRIO_VERSION=v1.31
# Add the Kubernetes repository
sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/deb/ /" | sudo tee /etc/apt/sources.list.d/kubernetes.list
# Add the CRI-O repository
sudo curl -fsSL https://pkgs.k8s.io/addons:/cri-o:/stable:/$CRIO_VERSION/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/cri-o-apt-keyring.gpg
echo "deb [signed-by=/etc/apt/keyrings/cri-o-apt-keyring.gpg] https://pkgs.k8s.io/addons:/cri-o:/stable:/$CRIO_VERSION/deb/ /" | sudo tee /etc/apt/sources.list.d/cri-o.list
# Install packages
sudo apt-get update
sudo apt-get install -y cri-o kubelet kubeadm
sudo apt-mark hold kubelet kubeadm cri-o
# Set swap off, start br_netfilter, and set ipv4 forwarding
sudo swapoff -a
sudo modprobe br_netfilter
echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/k8s.conf
sudo sysctl --system
# Start CRI-O
sudo systemctl start crio.service
# Initialize control-plane node
export CIDR=10.85.0.0/16
sudo kubeadm init
# Install kubectl
sudo apt install kubectl
# Create .kube directory
mkdir ~/.kube
# Copy necessary files from control plane node
# /etc/kubernetes/pki/apiserver-kubelet-client.crt
# /etc/kubernetes/pki/apiserver-kubelet-client.key
# /etc/kubernetes/pki/ca.crt
# Create local Kubeconfig file (~/.kube/config)
apiVersion: v1
clusters:
- cluster:
certificate-authority: ./ca.crt
server: https://<control-plane-ip>:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate: ./apiserver-kubelet-client.crt
client-key: ./apiserver-kubelet-client.key
# Test kubectl
kubectl config use-context kubernetes-admin@kubernetes
kubectl get nodes
Follow the same steps as the control-plane node, except for the initialization. Then join the cluster:
sudo kubeadm join <cluster-ip>:6443 --token e7dfct.uh6ojtum3vmswbx7 --discovery-token-ca-cert-hash sha256:e012626
Create deployment and service files on the client machine:
# hello-world-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
spec:
replicas: 3
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: hashicorp/http-echo
args:
- "-text=Hello, World!"
ports:
- containerPort: 5678
# hello-world-service.yaml
apiVersion: v1
kind: Service
metadata:
name: hello-world
spec:
type: NodePort
selector:
app: hello-world
ports:
- port: 5678
targetPort: 5678
nodePort: 30007
# Apply the configurations
kubectl apply -f hello-world-deployment.yaml
kubectl apply -f hello-world-service.yaml
# View pods and nodes
kubectl get pods -o wide
kubectl get nodes -o wide
# Access the hello-world app
curl http://<any-one-node-internal-ip>:30007
# Scale the deployment
kubectl get deployments
kubectl scale deployment --replicas=2
# To know on which node the pod is running
kubectl get pods -o wide