Installer un cluster Kubernetes avec sa version ultra-light K3S de Rancher
Publié le : 7 octobre 2019 | Mis à jour le : 27 juin 2023K3s est une version ultra-light de Kubernetes développée par Rancher. Il ne nécessite que 40MB d’espace disque et 512MB de RAM pour démarrer, car il se destine avant tout pour les équipements légers comme ceux de l’IoT, des serveurs de transports edge, des RaspberryPi entre autre.
Que contient cette distribution ?
- Tous les composants Kubernetes (kube-apiserver, kube-controller-manager, kube-scheduler, kubelet, kube-proxy
- Docker est remplacé par containerd
- Pour le réseau on retrouve Flannel, CoreDNS
- Pour la gestion d’Ingress Traefik accompagné d’un simple loadBalancer
- Par contre les plugins des cloud providers et de stockage ont été enlevés.
- Sqlite3 remplace etcd.
Tester K3S sur un cluster de VM Ubuntu
Pour ce test je vais utiliser une machine hôte Ubuntu sur laquelle je vais provisionner 3 VM (1 master + 2 workers) avec vagrant et libvirt. Personnellement je l’utilise sur 2 mini pc: 1 KODLIX GN41 équipé d’un céléron N41000 et un autre d’un Atom Z8350
En premier lieu, il faut installer vagrant et ansible. Je vous renvoie à mes billets d’introduction sur vagrant et ansible pour cela.
Il faut ensuite cloner mon projet :
git clone git@github.com:stephrobert/k3sSandbox.git
Ensuite provisionnons nos 3 VM (pour le serveur plus sage de mettre 1GB de Ram) :
vagrant up
Installons k3s sur tous les nodes :
vagrant push
Au bout de quelques minutes, vous devriez avoir accès à votre cluster k3s.
Un petit contrôle de l’état des nodes du cluster :
ssh master1
kubectl get nodes
NAME STATUS ROLES AGE VERSION
master1 Ready control-plane,master 11m v1.22.5+k3s1
worker2 Ready <none> 10m v1.22.5+k3s1
worker1 Ready <none> 10m v1.22.5+k3s1
Maintenant vous pouvez utiliser les commandes classiques de kubectl :
kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system local-path-provisioner-64ffb68fd-5r6hf 1/1 Running 0 12m
kube-system coredns-85cb69466-sgk22 1/1 Running 0 12m
kube-system metrics-server-9cf544f65-5qx25 1/1 Running 0 12m
kube-system helm-install-traefik-crd--1-4cwxn 0/1 Completed 0 12m
kube-system helm-install-traefik--1-6txdj 0/1 Completed 1 12m
kube-system svclb-traefik-skffv 2/2 Running 0 11m
kube-system svclb-traefik-tn6xk 2/2 Running 0 11m
kube-system svclb-traefik-m65p5 2/2 Running 0 11m
kube-system traefik-786ff64748-dm5qp 1/1 Running 0 11m
Destruction des VM
Il suffit de lancer la commande :
vagrant destroy -f
==> worker2: Removing domain...
==> worker2: Deleting the machine folder
==> worker1: Removing domain...
==> worker1: Deleting the machine folder
==> master1: Removing domain...
==> master1: Deleting the machine folder
Après un destroy il ne faut pas oublier de nettoyer le fichier /etc/hosts des machines master1, worker1 à n
Quelques explications sur le provisioning
Voici le fichier Vagrantfile :
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure(2) do |config|
base_ip_str = "10.240.0.1"
cpu_master = 1
mem_master = 1792
number_workers = 2 # Number of workers nodes kubernetes
cpu_worker = 1
mem_worker = 1024
config.vm.box = "generic/ubuntu2004" # Image for all installations
kubectl_version = "1.23.1-00"
nodes = []
(0..number_workers).each do |i|
case i
when 0
nodes[i] = {
"name" => "master#{i + 1}",
"ip" => "#{base_ip_str}#{i}"
}
when 1..number_workers
nodes[i] = {
"name" => "worker#{i }",
"ip" => "#{base_ip_str}#{i}"
}
end
end
# Provision VM
nodes.each do |node|
config.vm.define node["name"] do |machine|
machine.vm.hostname = node["name"]
machine.vm.provider "libvirt" do |lv|
if (node["name"] =~ /master/)
lv.cpus = cpu_master
lv.memory = mem_master
else
lv.cpus = cpu_worker
lv.memory = mem_worker
end
end
machine.vm.synced_folder '.', '/vagrant', disabled: true
machine.vm.network "private_network", ip: node["ip"]
machine.vm.provision "ansible" do |ansible|
ansible.playbook = "provision.yml"
ansible.groups = {
"master" => ["master1"],
"workers" => ["worker[1:#{number_workers}]"],
"kubernetes:children" => ["masters", "workers"],
"all:vars" => {
"base_ip_str" => "#{base_ip_str}",
"kubectl_version" => "#{kubectl_version}"
}
}
end
end
end
config.push.define "local-exec" do |push|
push.inline = <<-SCRIPT
ansible-playbook -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory master.yml
ansible-playbook -i .vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory slave.yml
SCRIPT
end
end
Après l’initialisation des variables et du tableau contenant tous les nodes, nous entrons dans une boucle each qui va permettre d’adapter la configuration des nodes en fonction des paramètres tirés du tableau node. Cela permet de configurer des nodes master et workers avec des ressources mem et cpu différentes.
Après cette boucle nous retrouvons une commande que j’utilise pour la première fois. La commande push permet de lancer des scripts depuis le noeud local. Pourquoi avoir choisi cette option plutôt que de tout intégrer dans le playbook lancé dans la boucle. Tout simplement que dans la boucle les playbooks ne sont pas lancé une fois, mais à chaque qu’un node devient disponible. Du coup le playbook des workers nodes se lance avant même que le token du master soit créé. Cela a comme bénéfice de pouvoir simplifier l’écriture du playbook.
Pour lancer la configuration des nodes il suffit de lancer la commande vagrant push
.