Déployer un cluster K8s avec Kubespray
Pour des besoins professionnels, je dois monter des clusters Kubernetes afin
d’héberger des API. Pour cela, je fais le choix d’utiliser KubeSpray.
KubeSpray est un framework qui permet de provisionner des clusters
Kubernetes sur du bare-metal, mais aussi chez la plupart des clouders,
en utilisant Ansible. Pour tester le tout, je vais utiliser
Ignite que j’ai présenté récemment,
auquel je vais ajouter footloose
.
Provisionnement des VM avec Footloose et Ignite
Pour créer rapidement mon cluster de micro-VM je vais utiliser footloose un autre projet de WeaveWorks qui permet de créer rapidement une série de machines. Je vais créer un cluster kubernetes composés de 3 masters et 2 workers à base de Centos 8.5.
Pour installer footloose je vous renvoie à mon billet sur ignite
Création de l’image CENTOS 8.5
Je vais mettre à jour l’image et l’injecter dans Ignite. Mon Dockerfile :
FROM weaveworks/ignite-centos:8
RUN dnf upgrade -y
On lance le build :
docker build -t weaveworks/ignite-centos:8.5 .
On récupère la version et on tague l’image teste rapidement :
docker run --rm -it build -t weaveworks/ignite-centos:8.5 cat /etc/redhat-releaseCentOS Linux release 8.5.2111
docker tag weaveworks/ignite-centos:8.5 weaveworks/ignite-centos:8.5.2111
On l’importe dans Ignite :
sudo ignite image import weaveworks/ignite-centos:8.5.2111 --runtime docker
INFO[0000] Starting image import...INFO[0004] Imported OCI image "weaveworks/ignite-centos:8.5.2111" (526.4 MB) to base image with UID "cdc78b581b43346e"INFO[0004] Created image with ID "cdc78b581b43346e" and name "weaveworks/ignite-centos:8.5.2111"
Maintenant créons nos 5 VM avec Footloose.
Création du cluster de VM avec Footloose
Footloose permet d’utiliser ignite comme backend pour provisionner des micro-VM. Je vais donc créer un cluster de 5 VM avec 1 CPU / 1.6 GB (le minimum accepté par kubespray) et 5 GO de disque chacune.
Déclarons notre cluster avec ce fichier :
cluster: name: cluster privateKey: cluster-keymachines:- count: 5 spec: image: weaveworks/ignite-centos:8.5.2111 name: node%d portMappings: - containerPort: 22 # This is by default "docker". However, just set this to "ignite" and it'll work with Ignite :) backend: ignite # Optional configuration parameters for ignite: ignite: cpus: 1 memory: 1600MB diskSize: 5GB kernel: "weaveworks/ignite-kernel:5.10.51"
Lançons le provisionnement en lançant la commande footloose create
depuis le
répertoire où se trouve le fichier footloose.yaml
:
sudo footloose create
Il est possible de créer le cluster en indiquant le nom du fichier avec l’option -c :
sudo footloose create -c mon-cluster.yml
INFO[0000] Creating machine: cluster-node0 ...INFO[0002] Creating machine: cluster-node1 ...INFO[0004] Creating machine: cluster-node2 ...INFO[0006] Creating machine: cluster-node3 ...INFO[0009] Creating machine: cluster-node4 ...
On vérifie qu’elles sont bien présentes sous Ignite :
sudo ignite psVM ID IMAGE KERNEL SIZE CPUS MEMORY CREATED STATUS IPS PORTS NAME054f0119bc87ca0c weaveworks/ignite-centos:8.5 weaveworks/ignite-kernel:5.10.51 5.0 GB 1 1024.0 MB 52m ago Up 52m 10.61.0.50 0.0.0.0:44567->22/tcp cluster-node33498ae67c7f695cd weaveworks/ignite-centos:8.5 weaveworks/ignite-kernel:5.10.51 5.0 GB 1 1024.0 MB 52m ago Up 52m 10.61.0.51 0.0.0.0:43621->22/tcp cluster-node4714f445ea643ebad weaveworks/ignite-centos:8.5 weaveworks/ignite-kernel:5.10.51 5.0 GB 1 1024.0 MB 52m ago Up 52m 10.61.0.47 0.0.0.0:45371->22/tcp cluster-node0d6cf7a17be0368e5 weaveworks/ignite-centos:8.5 weaveworks/ignite-kernel:5.10.51 5.0 GB 1 1024.0 MB 52m ago Up 52m 10.61.0.49 0.0.0.0:33309->22/tcp cluster-node2f1fcde290a9f3f09 weaveworks/ignite-centos:8.5 weaveworks/ignite-kernel:5.10.51 5.0 GB 1 1024.0 MB 52m ago Up 52m 10.61.0.48 0.0.0.0:35075->22/tcp cluster-node1
Provisionnement d’un cluster avec Kubepsray
Construction de l’environnement
Dans un premier temps, nous allons récupérer le projet et installer les requirements.
git clone https://github.com/kubernetes-incubator/kubespray.gitcd kubespraypyenv virtualenv 3.9.7 kubespraypyenv local kubespray
pip install -r requirements.txtLooking in indexes: https://python:****@artefacts.sa-cim.local/repository/pypi-all/simple/Collecting ansible==3.4.0 Downloading https://artefacts.sa-cim.local/repository/pypi-all/packages/ansible/3.4.0/ansible-3.4.0.tar.gz (31.9 MB) |████████████████████████████████| 31.9 MB 3.4 MB/s
Installing collected packages: pycparser, six, pyparsing, MarkupSafe, cffi, PyYAML, packaging, jinja2, cryptography, ansible-base, ruamel.yaml.clib, ruamel.yaml, pbr, netaddr, jmespath, ansible Running setup.py install for ansible-base ... done Running setup.py install for ansible ... doneSuccessfully installed MarkupSafe-1.1.1 PyYAML-6.0 ansible-3.4.0 ansible-base-2.10.15 cffi-1.15.0 cryptography-2.8 jinja2-2.11.3 jmespath-0.9.5 netaddr-0.7.19 packaging-21.3 pbr-5.4.4 pycparser-2.21 pyparsing-3.0.6 ruamel.yaml-0.16.10 ruamel.yaml.clib-0.2.4 six-1.16.0
Éditons le fichier ansible.cfg pour l’adapter à notre besoin. On ajoute
simplement la localisation de la clé SSH
et le remote_user
(les deux
paramètres avant [inventory]) :
[ssh_connection]pipelining=Truessh_args = -o ControlMaster=auto -o ControlPersist=30m -o ConnectionAttempts=100 -o UserKnownHostsFile=/dev/null#control_path = ~/.ssh/ansible-%%r@%%h:%%p[defaults]# https://github.com/ansible/ansible/issues/56930 (to ignore group names with - and .)force_valid_group_names = ignorehost_key_checking=Falsegathering = smartfact_caching = jsonfilefact_caching_connection = /tmpfact_caching_timeout = 7200stdout_callback = defaultdisplay_skipped_hosts = nolibrary = ./librarycallback_whitelist = profile_tasksroles_path = roles:$VIRTUAL_ENV/usr/local/share/kubespray/roles:$VIRTUAL_ENV/usr/local/share/ansible/roles:/usr/share/kubespray/rolesdeprecation_warnings=Falseinventory_ignore_extensions = ~, .orig, .bak, .ini, .cfg, .retry, .pyc, .pyo, .creds, .gpgprivate_key_file = ../cluster-keyremote_user = root[inventory]ignore_patterns = artifacts, credentials
Création de l’inventaire et modification du paramétrage
On va utiliser les outils de KubeSpray pour générer l’inventaire :
cp -rfp inventory/sample inventory/ignitedeclare -a IPS=(10.61.0.47 10.61.0.48 10.61.0.49 10.61.0.50 10.61.0.51)CONFIG_FILE=inventory/ignite/hosts.yml python3 contrib/inventory_builder/inventory.py ${IPS[@]}
Vous devriez vous retrouver avec ce fichier inventory/ignite/hosts.yml
node1: ansible_host: 10.61.0.47 ip: 10.61.0.47 access_ip: 10.61.0.47 node2: ansible_host: 10.61.0.48 ip: 10.61.0.48 access_ip: 10.61.0.48 node3: ansible_host: 10.61.0.49 ip: 10.61.0.49 access_ip: 10.61.0.49 node4: ansible_host: 10.61.0.50 ip: 10.61.0.50 access_ip: 10.61.0.50 node5: ansible_host: 10.61.0.51 ip: 10.61.0.51 access_ip: 10.61.0.51 children: kube_control_plane: hosts: node1: node2: kube_node: hosts: node1: node2: node3: node4: node5: etcd: hosts: node1: node2: node3: k8s_cluster: children: kube_control_plane: kube_node: calico_rr: hosts: {}
Testons :
ansible -m ping -i node1, all
node1 | SUCCESS => { "changed": false, "ping": "pong"}
Ensuite pour Centos il faut modifier le paramétrage de Calico :
sed -i -r 's/^(calico_iptables_backend:).*/\1 "Auto"/g' roles/network_plugin/calico/defaults/main.yml
Dans le paramétrage du cluster j’ai désactivé aussi la mise à jour du DNS:
sed -i -r 's/^(dns_mode:).*/\1 none/g' inventory/ignite/group_vars/k8s_cluster/k8s-cluster.yml
Installation du cluster Kubernetes
Tout est prêt on peut passer à l’installation du cluster.
ansible-playbook -i inventory/ignite cluster.ymlWednesday 15 December 2021 11:48:41 +0000 (0:00:00.131) 0:25:18.294 ****===============================================================================kubernetes/preinstall : Install packages requirements --------------------------------------------------------------------------------- 141.77sdownload : download_container | Download image if required ----------------------------------------------------------------------------- 48.32snetwork_plugin/calico : Start Calico resources ----------------------------------------------------------------------------------------- 44.53sbootstrap-os : Assign inventory name to unconfigured hostnames (non-CoreOS, non-Flatcar, Suse and ClearLinux, non-Fedora) -------------- 41.05sdownload : download_file | Download item ----------------------------------------------------------------------------------------------- 34.31skubernetes/kubeadm : Join to cluster --------------------------------------------------------------------------------------------------- 32.23skubernetes/control-plane : kubeadm | Initialize first master --------------------------------------------------------------------------- 29.68sdownload : download_container | Download image if required ----------------------------------------------------------------------------- 28.06spolicy_controller/calico : Start of Calico kube controllers ---------------------------------------------------------------------------- 25.77skubernetes/control-plane : Joining control plane node to the cluster. ------------------------------------------------------------------ 24.47sdownload : download_container | Download image if required ----------------------------------------------------------------------------- 24.26sbootstrap-os : Gather host facts to get ansible_distribution_version ansible_distribution_major_version -------------------------------- 23.03sbootstrap-os : Gather host facts to get ansible_os_family ------------------------------------------------------------------------------ 22.87spolicy_controller/calico : Create calico-kube-controllers manifests -------------------------------------------------------------------- 22.09sdownload : download_container | Download image if required ----------------------------------------------------------------------------- 21.43sGather necessary facts (hardware) ------------------------------------------------------------------------------------------------------ 20.98setcd : reload etcd --------------------------------------------------------------------------------------------------------------------- 20.96sdownload : download_file | Download item ----------------------------------------------------------------------------------------------- 20.88sGather necessary facts (network) ------------------------------------------------------------------------------------------------------- 20.77sGather minimal facts ------------------------------------------------------------------------------------------------------------------- 20.67s
Au bout de 25 minutes notre cluster est prêt. Récupérons sa configuration.
Créons les entrées dans /etc/hosts
Pour accéder plus facilement aux noeuds un petit quick win Ansible pour ajouter les hosts de l’inventaire dans /etc/hosts :
---- hosts: k8s_cluster gather_facts: true become: true
tasks: - name: update /etc/hosts file vars: ansible_python_interpreter: "/usr/bin/python" blockinfile: path: /etc/hosts marker: "# {mark} Node {{ inventory_hostname }}" block: "{{ ansible_facts.default_ipv4.address }} {{ inventory_hostname }}" delegate_to: localhost
Si vous détruisez votre cluster il faudra le rejouer pour mettre les bonnes IP !
On lance le playbook :
cd ..ansible-playbook -i kubespray/inventory/ignite create-etc-hosts.yml
cat /etc/hosts
# BEGIN Node node110.61.0.62 node1# END Node node1# BEGIN Node node210.61.0.63 node2# END Node node2# BEGIN Node node510.61.0.66 node5# END Node node5# BEGIN Node node410.61.0.65 node4# END Node node4# BEGIN Node node310.61.0.64 node3# END Node node3
Configuration de kubectl
Afin de pouvoir utiliser les commandes kubectl depuis notre poste, on va récupérer la configuration du cluster et la déposer dans le répertoire .kube:
ssh -i cluster-key root@node1 cat /etc/kubernetes/admin.conf > ~/.kube/config-ignite
Récupérer l’adresse de node1 pour remplacer 127.0.0.1 dans la config :
awk '$2 ~ /node1/ {print $0}' /etc/hosts10.61.0.62 node1
Editez le fichier ~/.kube/config-ignite et remplacer 127.0.0.1 par cette adresse. On peut aussi changer le nom du context par ignite :
server: https://10.61.0.62:6443 name: cluster.localcontexts:- context: cluster: cluster.local user: kubernetes-admin name: ignite
Utilisons les contexts :
KUBECONFIG=~/.kube/config-test:~/.kube/config-ignitekubectl config get-contexts
CURRENT NAME CLUSTER AUTHINFO NAMESPACE* default default default ignite cluster.local kubernetes-admin
Pour changer de contexte utilisons kubectx :
asdf plugin add kubectxasdf install kubectx latestasdf global kubectx latestkubectx igniteSwitched to context "ignite".
On vérifie qu’on accède au cluster :
kubectl get pod -ANAMESPACE NAME READY STATUS RESTARTS AGEkube-system calico-kube-controllers-5788f6558-c9mv9 1/1 Running 2 (166m ago) 166mkube-system calico-node-bvcqd 1/1 Running 0 168mkube-system calico-node-lnw87 1/1 Running 2 (167m ago) 168mkube-system calico-node-nfcj4 1/1 Running 2 (167m ago) 168mkube-system calico-node-ptfjj 1/1 Running 3 (167m ago) 168mkube-system calico-node-wzqb9 1/1 Running 2 (167m ago) 168mkube-system kube-apiserver-node1 1/1 Running 0 171mkube-system kube-apiserver-node2 1/1 Running 0 170mkube-system kube-controller-manager-node1 1/1 Running 3 (98m ago) 171mkube-system kube-controller-manager-node2 1/1 Running 3 (53m ago) 170mkube-system kube-proxy-2shqj 1/1 Running 0 168mkube-system kube-proxy-4t96f 1/1 Running 0 169mkube-system kube-proxy-fnt65 1/1 Running 0 169mkube-system kube-proxy-hxjks 1/1 Running 0 168mkube-system kube-proxy-kwmmr 1/1 Running 0 169mkube-system kube-scheduler-node1 1/1 Running 3 (98m ago) 171mkube-system kube-scheduler-node2 1/1 Running 3 170mkube-system nginx-proxy-node3 1/1 Running 0 169mkube-system nginx-proxy-node4 1/1 Running 0 169mkube-system nginx-proxy-node5 1/1 Running 0 169m
Un petit test :
kubectl create ns testnamespace/test created
kubens testContext "ignite" modified.Active namespace is "test".
kubectl create deployment nginx --image=nginx
Cela confirme que ignite est très bon remplaçant à vagrant. La création des nodes s’est faite en moins d’une minute. Donc à nous la destruction et reconstruction sans perdre de temps. Ça confirme aussi que KubeSpray peut répondre à mon besoin.
Allez on nettoie tout !
sudo footloose delete
Plus d’infos sur kubespray.
A la prochaine !