Archives de catégorie : Kubernetes

Débuter avec Flux sur Kubernetes

Lors d’un précédent article, nous avions découvert l’intérêt de Helm. On peut le résumer à un outil de templating et de packaging dédié à Kubernetes. On dipose d’un bon outil pour industrialiser vos déploiement l’orchestrateur de conteneurs.

Cependant, Helm ne dispose pas de capacités nécessaires pour déployer ses charts ou plus simplement ses déploiements. Il lui faut donc un outil pour l’aider à accomplir une tâche plus complète de CI/CD.

Ainsi, Flux fait partie de ses outils complémentaires à Helm. Cet outil créé par Weave permet de gérer le déploiement à partir d’un dépôt (qu’il vienne de github ou de gitlab…).

Ainsi la combinaison de ces deux outils permet la répartition des tâches suivantes :

  • helm : via les charts, vous pouvez décrire et templatiser les différentes ressources kubernetes pour vos déploiements
  • flux : permet de synchroniser à fréquence régulière des dépôts (pouvant être des charts helm mais pas nécessairement). Flux permet également de gérer les mises à jour d’images (docker).

Flux est donc un outil important pour la mise en oeuvre d’une stratégie de gitops à partir d’un mode pull. En effet, flux, une fois installé, tire les éléments dans le cluster.

Principales fonctions de flux

Les principales fonctionnalités de flux sont les suivantes :

  • scrutation à fréquence régulière d’un dépôt git (5min par défaut)
  • définition de branches ou tags à prendre en compte
  • déployable sous forme d’opérateur dans k8s
  • mise à disposition d’un client fluxctl pour gérer les interactions avec l’opérateur (gestion des version, rollback…)
  • capacité de garbage collector pour nettoyer les ressources n’existants plus dans le dépôt
  • mise à disposition d’un provider terraform pour flux (et pour helm)

Installation de flux

Comme de nombreux outils associés à k8s, flux se base sur le kubeconfig local. Ainsi il peut rapidement et facilement se connecter à un cluster et éventuellement passer sur un autre cluster.

Comment l’installer ? Commençons par installer le client qui pourra ensuite installer l’opérateur pour vous.

Si vous utilisez ubuntu et snap

sudo snap install fluxctl

Sinon vous pouvez installer directement le binaire de cette manière :

wget https://github.com/fluxcd/flux/releases/download/1.21.0/fluxctl_linux_amd64
sudo mv fluxctl_linux_amd64 /usr/local/bin/fluxctl
sudo chmod 755 /usr/local/bin/fluxctl

Maintenant que le client est installé, il est en mesure d’utiliser votre kubeconfig. Vous pouvez donc passer la commande suivante (à adapter à votre situation).

kubectl create ns fluxcd

fluxctl install --git-email=moi@moi.com --git-url=git@gitlab.com:xavki/testflux.git --git-path=workloads --namespace=fluxcd | kubectl apply -f -

Nous créons donc un namespace dédié à flux et nommé fluxcd.

Puis nous lançons la commande fluxctl install en précisant :

  • –git-email : le mail (sans incidence)
  • –git-url : la localisation du dépôt à synchroniser en utilisant une connexion ssh
  • –git-path : le ou les répertoires à synchroniser
  • –namespace : le namespace où l’opérateur sera installé
  • et enfin on pipe la sortie dans un kubectl apply

A partir de cette étape flux est installé et dispose d’une clef privée. Nous devons donc ajouter la clef publique pour donner à flux la permission d’utiliser le dépôt git en question. Vous pouvez récupérer cette clef publique avec cette commande :

fluxctl identity --k8s-fwd-ns fluxcd

Voilà ! Nous venons de faire nos premiers pas et flux est installé. Il commence déjà à synchroniser les fichiers de ressources kubernetes contenues dans ce répertoire.

Si vous souhaitez en savoir plus sur Helm, je vous invite à regarder la formation Helm disponible dans cette playlist.

Formation et cours complet Helm, c’est parti !!!

Kubernetes est un sujet qui passionne les foules. Je le vois tous les jours avec la playlist k8s. C’est pourquoi j’ai décidé de me centrer sur quelques outils assez courants pour les personnes qui administrent ou utilisent le célèbre orchestrateur de conteneurs. Même si je continue encore la formation ansible, je commence en parallèle une série de tutoriels dédiés à Helm.

Là encore un cours complet pour se former à son rythme que ce soit pour débuter ou aller plus loin. Pour cela on va reprendre toutes les bases pour monter petit à petit en niveau.

Aujourd’hui c’est la première donc du coup on va commencer par poser la première brique à savoir l’introduction à Helm et essayer de répondre à quelques questions : pourquoi ? comment ? intérêts ?…

L’instanciation, une problématique kubernetes

A l’heure actuelle, beaucoup d’entreprises passe à tort ou à raison sur kubernetes. Un bel outil qui permet de lancer des services en décrivant des ressources. L’outil étant assez élaboré, pour lancer une petite application, il est souvent nécessaire d’installer différents objets. En outre nous devons souvent coordonner les objets les uns par rapport aux autres à défaut de variables mutualisées en dehors des configmaps.

Or il est assez courant d’avoir une infrastructure plus ou moins à base de microservices, ces derniers se ressemblant fortement voir appelant de même lignes de codes/images ou nécessitant un déploiement similaire. Mais alors faut-il faire des copier/coller de toutes ces ressources avecs de répertoires et faire évoluer tout cela ensemble avec des difficultés pour modifier dans des manifestes communs plusieurs fois le même élément.

Prenons un exemple avec wordpress, pour créer une instance wordpress, il faut :

  • 2 deployments
  • 1 ingress
  • 2 pvc/pv
  • 2 services…

Créons ensuite une deuxième instance… rebelote et ainsi de suite. Faire cela dans un outil comme kubernetes cela nous fait penser que l’on a loupé quelque chose. Vaut mieux arrêter de travailler et compter les mouches, surtout le jour où il faudra faire évoluer tout ça.

C’est un des points majeurs que Helm permet de corriger.

Helm permet de templatiser des ressources et de stocker toutes les variables définies dans un seul fichier : Values.yaml.

On a donc fait un grand pas.

Mais ce n’est pas le seul intérêt pour Helm

Bien sûr Helm va bien plus loin que cela.

Finalement, une fois que l’on commence à templatiser, on s’aperçoit que l’on dispose de briques cohérentes de ressources. Il ne manque qu’une chose c’est la possibilité de les partager et faciliter leur installation et leur versionning.

Du coup, imaginons que Helm puisse être un gestionnaire de paquets façon apt, yum ou autres. Avec des dépôts distants, cela peut permettre de partager ces packages que l’on appelle simplement des Charts.

Et comme tous les packages, Helm permet de versionner tout cela pour garder des briques cohérentes, éviter les bugs et faciliter l’installation des objets kubernetes. Intéressant n’est-ce pas ?

Ajoutons à cela que Helm a su évoluer d’une version 2 un peu plus complexe vers une version 3 qui permet de se connecter facilement à votre cluster kubernetes.

Conclusion sur Helm

Bref se former à Helm ou l’adopter c’est un bon point pour votre carrière car vous serez peut être amené à le rencontrer et pourquoi pas le tester pour le faire entrer dans votre société. Donc suivre une formation Helm est certainement un bon investissement de votre temps.

Nous en reparlerons plus tard mais un dépôt Helm peut se limiter à un dépôt git assez épuré.

Ainsi vous pourrez trouver des intérêts :

  • meilleures capacités d’itération
  • amélioration du travail en équipe pour vos déploiements
  • utilisation de charts déjà développées par la communauté

Après ne nous cachons pas qu’il faut une petite période d’adaptation. Mais comme vous êtes là c’est que vous voulez apprendre à utiliser Helm et vous former donc je ne me fais pas de soucis pour vous.

Se former est une approche importante pour adopter ou devenir devops. Et n’oubliez pas de vous abonner à la chaine xavki 😉

Kubectl quelques commandes utiles pour commencer

Pour débuter avec kubernetes, il faut aimer la ligne de commande et on peut y prendre un certain plaisir au fur et à mesure du temps. D’ailleurs, je ne saurais trop vous recommander si vous débuter de ne pas avoir recours aux alias et autres tools qui facilitent l’utilisation ou by-pass la CLI.

Eh oui personnellement je considère qu’il faut passer un peu de temps avec cette cli avant de passer aux tools. D’ailleurs, il y a tellement de tools qu’il vaut mieux se contenter de quelques uns (kubectx, kubens, k9s…).

Commençons

Pour débuter, nous avons bien retenu que pour lister tout objet/ressource dans kubernetes il faut utiliser kubectl get. Maintenant vous pouvez lister tous les objets de bases en utilisant :

kubectl get all

Et pour aller plus loin et récupérer tous les objets communs pour tous les namespaces :

kubectl get all –all-namespaces

Mais comment connaît les ressources justement ?

kubectl api-resources -o wide

Remarquez le -o wide qui permet d’avoir le maximum d’informations sur chacun des objets. On peut utiliser assez souvent cette option, par exemple sur les pods etc.

Et pour connaître l’état des composants principaux de votre cluster (etcd, kubelet etc), vous pouvez réaliser un :

kubectl get componentstatuses

Debugger pour un débutant ?

Débuguer dans un cluster kubernetes demande d’avoir des réflexes. Je vous en livre quelques uns pour commencer et petit à petit vous trouverez vos automatismes.

Là encore la ligne de commande est votre meilleure amie. Bien sûr tout commence par un :

kubectl get pods

Puis une fois le pod identifié, on va pouvoir d’une part regarder l’état de l’objet en question et ses caractéristiques :

kubectl describe pods <id_du_pod>

Et si finalement l’erreur mentionnée dans les events du bas de la page vous laisse penser qu’il s’agit d’un problème applicatif, vous pouvez vous référez aux logs du pods.

Si celui ne possède qu’un conteneur :

kubectl logs -f <id-pod>

Mais si vous voulez obtenir les logs d’un conteneur spécifiquement :

kubectl logs <id_pod> <nom_conteneur>

Et pour avoir les logs de tous les conteneurs fusionnés :

kubectl logs <id_pod> --all-containers

Vous pouvez également lister les évènements d’un pod :

kubectl get events <id_pod>

Et pour identifier le contenu du manifest du pod :

kubectl edit pod <id_pod>

Mais souvent il vous faudra revenir à l’objet qui a créé le pod à savoir un deployment, un statefulset ou un cronjob et vous pourrez visualiser aussi son manifest avec la commande edit :

kubectl edit deployment <nom_deployment>

Et pour récupérer le yaml du déploiement dans un fichier au format yaml :

kubectl get deployment <nom_deployment> -o yaml > monfichier.yaml

Mais si vous avez un doute sur la rédaction d’un objet/ressource utilisez explain. Par exemple pour la documentation sur les pods

kubectl explain pod

kubectl explain pod.spec

Si vous lez souhaitez, vous pouvez suivre ma chaine youtube et voir les vidéos relative à cette formation kubernetes gratuite ici.

Débuter avec les commandes dans la CLI Kubernetes

Lors d’un précédent article, nous avions découvert les principes de kubernetes et quelques définitions. Il est temps pour nous de débuter dans les commandes kubernetes.

Si vous le souhaitez, vous pouvez retrouver plus de 70 vidéos gratuites dans cette playlist que je mets à votre disposition. Cette formation kubernetes vous permet de découvrir l’outil tranquillement à votre rythme et de bénéficier du code de chacun des tutos pour reproduire cela de votre côté sur votre laptop.

Premier pod et premier run

La couche logique nommée pod qu’apporte k8s est inévitable lorsque vous utilisez cet orchestrateur. Si vous avez pratiqué docker ou un autre conteneur runtime, imaginez un pod comme une couche supérieure. Cette couche dispose de la description des conteneurs qui vont être lancés et de leur environnement.

Nous le verrons plus tard, les objets k8s sont souvent lancés via des manifests. Ces derniers sont des fichiers descriptifs en format yaml. Mais pour débuter souvent on apprend dans un premier temps à lancer ces éléments à partir de la ligne de commande.

Alors comment lancer le plus simplement du monde un pod dans kubernetes ?

Suivant la version de kub qu evous utilisez vous pourrez réaliser un simple « kubectl run » à la manière d’un docker run de cette manière :

kubectl run mycontainer --image busybox

De cette manière nous venons de lancer un pod qui va lancer un conteneur dont l’image source est une busybox. Alors comme pour un run docker, vous pouvez aussi passer des commandes et par exemple vous connecter à un terminal :

kubectl run anothershell -it --image busybox -- sh

Là nous venons de lancer un pod et nous entrons directement dans le conteneur en question avec un shell à notre disposition. Mais nous pouvons également venir nous connecter à un shell d’un conteneur existant. Pour cela et comme pour docker, nous pouvons lancer un kubectl exec :

kubectl exec -ti <monpod> -- sh

Tout cela est assez facile à retenir si vous avez déjà pratiqué un peu de docker.

Comment lister les pods ?

kubectl get pods

Je vous invite à bien retenir la combinaison « kubectl get » qui revient en permanence sur kub. Elle permet de lister les objets d’un type donné.

Si vous êtes sur un cluster kubernetes, il est intéressant d’en revenr aux fondamentaux qu’il faut toujours garder en tête et notamment : kubernetes est un orchestrateur de conteneurs.

Ainsi, je vous invite à faire un :

kubectl get pods -o wide

L’option -o wide permet d’avoir plus d’information et notamment les les noeuds sur lesquels les conteneur ont été déployés. Ainsi poru aller plus loin vous pouvez vous rendre sur le serveur des pods que nous venons de lancer et lancer un simple

docker ps | grep "mycontainer\|another"

Vous devriez retrouver les conteneurs déployés par notre fameuse couche logique qui est le pod.

Vous pouvez aussi supprimer ces pods à l’aide de la commande :

kubectl delete pods <nom_du_pod>

Et un peu plus loin le deployment et le service

Alors maintenant nous allons encore empiler une brique logique sur les pods à savoir le deployement. Un deployment permet de lancer les pods de manière automatisée si on devait le résumer. Le deployment a des capacités étendues.

Ainsi, dans le deployment, nous le verrons plus tard, nous aurons un template de pods. C’est à dire la capcité à lancer et relancer des pods du même type… et même proposer de l’autoscaling de pod en fonction de la sollicitation des ressources ou non.

Alors comment créer un deployment qui va lancer un pod ?

Simplement avec la ligne de commande :

kubectl create deployment monnginx --image nginx

Avec cette ligne nous créons un déploiement de la manière la plus réduite qu’il existe à savoir en spécifiant juste l’image qui servira dans le pod à créer le ou les conteneurs. Dans notre cas, cette image est une nginx.

Je vous invite à lister ce nouvelle object de cette manière :

kubectl get deployment

Vous découvrez donc votre déploiement et si vous lancez un :

kubectl get pods

Vous retrouvez un pod préfixé du nom du déploiement.

Simple non ? Dans la pratique vous le verrez on ne lance presque jamais un pod seul mais vous le ferez par un deployment. Ce dernier apporte aussi de la persistance à votre pod notamment via un autre object créé par le deployment qui se nomme le replicaset. Il a principalement en charge l’existence de vos pods et le respect du bon nombre. Vous pouvez également lister les replicaset

kubectl get replicasets

Et si vous le souhaitez vous pouvez faire le test de supprimer un pod créé par votre deployment.

kubectl delete pods <nom_du_pod>

Que se passe-t-il si vous relisté les pods ensuite ? Kubernetes va recréer le nombre de pods que vous avez demandé de maintenir au deployment.

Alors comment supprimer définitivement les pods ? Simplement en supprimant le pod (il y a d’autres moyens pour d’autres cas de figures).

kubectl delete deployment monginx

Et là kubernetes va supprimer lui même les pods et replicaset.

Voici donc nos premier pas dans un cluster kubernetes réalisés. Si vous souhaitez progresser reportez vous à la playlist de formation kubernetes, c’est gratuit. Vous pouvez aussi retrouver le code pour faire vos tests ici. A bientôt !!

Kubespray : installation d’un cluster K8S se rapprochant de la production

Installer kubernetes on premise est un petit défi même si certaines solutions sont plus simples que d’autres. J’ai pu tester différentes options comme kubadm, rancher ou en core kubespray mais jamais « the hard way ». Cette dernière méthode est certainement la meilleure pour mieux appréhender la constitution d’un cluster. Certes, cette méthode est formatrice mais peut effrayer notamment faire peur si on veut installer un cluster kubernetes pour de la production. Si vous souhaitez vous former à kubernetes rendez-vous sur cette playlist.

Je vous propose de découvrir une méthode intermédiaire mais d’y ajouter le nécessaire pour rendre votre cluster hautement disponible. Et vous allez voir que contrairement à ce que l’on pense ce n’est pas si compliqué. Je vous invite après cette installation de prendre du recul et d’identifier les points critiques pour être bien à l’aise avec ces éléments. Car le jour où votre cluster kube dysfonctionne en production et on premise, vous pouvez transpirer pas mal pour débuguer car généralement vous n’avez pas mis qu’une seule application dessus.

Tout le code ci-dessous est présent dans mon dépôt officiel.

Mais je vous invite à découvrir les vidéos dans cette playlist youtube :

De quoi avons nous besoin côté machines virtuelles ?

Eh oui on veut tester un environnement de production mais rien ne vous empêches de vous faire la main sur votre laptop ou de simples machines virtuelles. Personnellement, j’utilise souvent virtualbox et je fais le provisioning de manière automatisé avec vagrant. Le Vagrantfile est donc ce qui va le mieux décrire notre infrastructure. J’ai volontairement évité de factoriser les boucles de manière à rendre cela plus lisisble.

Notre infrastructure sera composée :

  • 1 machine de déploiement pour jouer kubespray (ansible) on va pas salir notre laptop non plus et en prod on ne déploie pas de son laptop.
  • 2 haproxy : ils serviront pour loadbalaner l’api kubernetes pour les commandes kubectl vers nos master (port 6443) et également pour loadblancer sur les noeuds worker les flux http/https (80/443)
  • 2 masters : il vaudrait mieux 3 mais notre but est de faire de simples tests tout de même (en ajoute run n’est juste que rajouter une ligne dans le ansible)
  • 1 node : notre objectif n’est pas d’héberger mais de tester un cluster kube et son environnement haute disponibilité.

Ce qui donne :

Vagrant.configure(2) do |config|
  common = <<-SHELL
  if ! grep -q deploykub /etc/hosts; then  sudo echo "192.168.7.120     kdeploykub" >> /etc/hosts ;fi
  if ! grep -q node01 /etc/hosts; then  sudo echo "192.168.7.121     kmaster01" >> /etc/hosts ;fi
  if ! grep -q node02 /etc/hosts; then  sudo echo "192.168.7.122     kmaster02" >> /etc/hosts ;fi
  if ! grep -q node03 /etc/hosts; then  sudo echo "192.168.7.123     knode01" >> /etc/hosts ;fi
  if ! grep -q node04 /etc/hosts; then  sudo echo "192.168.7.124     haproxy01" >> /etc/hosts ;fi
  if ! grep -q node05 /etc/hosts; then  sudo echo "192.168.7.125     haproxy02" >> /etc/hosts ;fi
  sudo yum -y install vim tree net-tools telnet git python3-pip sshpass
  sudo setsebool -P haproxy_connect_any=1
  sudo echo "autocmd filetype yaml setlocal ai ts=2 sw=2 et" > /home/vagrant/.vimrc
  sed -i 's/ChallengeResponseAuthentication no/ChallengeResponseAuthentication yes/g' /etc/ssh/sshd_config
  sudo systemctl restart sshd
  SHELL
  

	config.vm.box = "centos/7"
	config.vm.box_url = "centos/7"

	config.vm.define "kdeploykub" do |kdeploykub|
		kdeploykub.vm.hostname = "kdeploykub"
		kdeploykub.vm.network "private_network", ip: "192.168.7.120"
		kdeploykub.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "1" ]
			v.customize [ "modifyvm", :id, "--memory", "512" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "kdeploykub"]
		end
		config.vm.provision :shell, :inline => common
	end
	config.vm.define "kmaster01" do |kmaster01|
		kmaster01.vm.hostname = "kmaster01"
		kmaster01.vm.network "private_network", ip: "192.168.7.121"
		kmaster01.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "2" ]
			v.customize [ "modifyvm", :id, "--memory", "2048" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "kmaster01"]
		end
		config.vm.provision :shell, :inline => common
	end
	config.vm.define "kmaster02" do |kmaster02|
		kmaster02.vm.hostname = "kmaster02"
		kmaster02.vm.network "private_network", ip: "192.168.7.122"
		kmaster02.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "2" ]
			v.customize [ "modifyvm", :id, "--memory", "2048" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "kmaster02"]
		end
		config.vm.provision :shell, :inline => common
	end
	config.vm.define "knode01" do |knode01|
		knode01.vm.hostname = "knode01"
		knode01.vm.network "private_network", ip: "192.168.7.123"
		knode01.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "2" ]
			v.customize [ "modifyvm", :id, "--memory", "2048" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "knode01"]
		end
		config.vm.provision :shell, :inline => common
	end
	config.vm.define "haproxy01" do |haproxy01|
		haproxy01.vm.hostname = "haproxy01"
		haproxy01.vm.network "private_network", ip: "192.168.7.124"
		haproxy01.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "1" ]
			v.customize [ "modifyvm", :id, "--memory", "512" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "haproxy01"]
		end
		config.vm.provision :shell, :inline => common
	end
	config.vm.define "haproxy02" do |haproxy02|
		haproxy02.vm.hostname = "haproxy02"
		haproxy02.vm.network "private_network", ip: "192.168.7.125"
		haproxy02.vm.provider "virtualbox" do |v|
			v.customize [ "modifyvm", :id, "--cpus", "1" ]
			v.customize [ "modifyvm", :id, "--memory", "512" ]
			v.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
      			v.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
			v.customize ["modifyvm", :id, "--name", "haproxy02"]
		end
		config.vm.provision :shell, :inline => common
	end

end

Ou encore ce Vagrantfile

Commençons par le loadbalancer externe haproxy et sa vip gérée par keepalived

Attention avant de lancer le ansible kubespray, il est nécessaire que votre haproxy et votre VIP soient mis en place.

Donc première chose on installe les deux haproxy et keepalived :

sudo apt install - y haproxy keepalived

et ensuite on édite la configuration de haproxy

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats

defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

listen stats
    bind *:9000
    stats enable
    stats uri /stats
    stats refresh 2s
    stats auth xavki:password

listen kubernetes-apiserver-https
  bind *:6443
  mode tcp
  option log-health-checks
  timeout client 3h
  timeout server 3h
  server master1 192.168.7.121:6443 check check-ssl verify none inter 10000
  server master2 192.168.7.122:6443 check check-ssl verify none inter 10000
  balance roundrobin

Bien sûr derrière je vous laisse reload le service systemd de haproxy.

Ensuite ajoutons la configuration de keepalived :

vrrp_script reload_haproxy {
    script "/usr/bin/killall -0 haproxy"
    interval 1
}

vrrp_instance VI_1 {
   virtual_router_id 100
   state MASTER
   priority 100

   # interval de check
   advert_int 1

   # interface de synchro entre les LB
   lvs_sync_daemon_interface eth1
   interface eth1

   # authentification entre les 2 machines LB
   authentication {
    auth_type PASS
    auth_pass secret
   }

   # vip
   virtual_ipaddress {
    192.168.7.130/32 brd 192.168.7.255 scope global
   }

   track_script {
     reload_haproxy
   }

}

Dans cette configuration on utilise une VIP qui switchera en fonction du service haproxy et du fait qu’il soit fonctionnel au vue de systemd ou non. Cette VIP est la :

192.168.7.130

Par défaut cette VIP sera portée par la machine haproxy1. Si celui-ci tombe cette adresse va être installée sur haproxy2 grâce à keepalived.

Vérifiez que les deux services (haproxy et keepalived) soient bien démarrés sur les 2 machines haproxy. Activez le redémarrage au reboot avec le systemctl enable.

Maintenant configurons kubespray

Kubespray c’est du ansible. donc première chose vous devez l’installer sur la machine de déploiement et installer également pip :

sudo apt install ansible python3-pip

Ensuite clonez le dépôt de kubespray :

git clone https://github.com/kubernetes-sigs/kubespray

rendez-vous dans le nouveau répertoire puis :

sudo pip3 install -r requirements.txt

Ensuite on prépare le ansible on va recopier le modéèle d’inventaire :

cp -rfp inventory/sample inventory/mycluster

Puis on modifie cet inventory :

# ## Configure 'ip' variable to bind kubernetes services on a
# ## different ip than the default iface
# ## We should set etcd_member_name for etcd cluster. The node that is not a etcd member do not need to set the value, or can set the empty string value.
[all]
kmaster01 ansible_host=192.168.7.121  ip=192.168.7.121 etcd_member_name=etcd1
kmaster02 ansible_host=192.168.7.122  ip=192.168.7.122 etcd_member_name=etcd2
knode01 ansible_host=192.168.7.123  ip=192.168.7.123 etcd_member_name=etcd3

# ## configure a bastion host if your nodes are not directly reachable
# bastion ansible_host=x.x.x.x ansible_user=some_user

[kube-master]
kmaster01
kmaster02
[etcd]
kmaster01
kmaster02
knode01

[kube-node]
knode01

[calico-rr]

[k8s-cluster:children]
kube-master
kube-node
calico-rr

On y a donc déclaré nos nodes master et notre worker.

Particularité ETCD

Particularité pour notre test, nous allons faire ce qu’il ne faut pas faire c’est à dire héberger les services etcd sur les master et surtout sur 1 worker. Pourquoi cela ? Etcd nécessite un nombre impair de noeuds pour son bon fonctionnement. Donc on pourrait en avoir 1 ou 3. Mais si on veut faire des tests de coupures de noeuds il est préférable d’en avoir 3. J’ai donc salement choisi d’en ajouter un sur le worker.

En production il serait recommandé d’externaliser les etcd et ne pas les avoir au sein des machines kubernetes (plus y ajouter des backups etc).

Dernière configuration ansible

Maintenant il nous faut éditer le fichier du group all :

vim inventory/mykub/group_vars/all/all.yml

comme en modifiant ces lignes

## External LB example config
apiserver_loadbalancer_domain_name: "elb.kub"
loadbalancer_apiserver:
  address: 192.168.7.130
  port: 6443

On vient donc de préciser que la VIP est notre point d’entrée du loadbalancer et également que votre cluster répondra sur le nom de domaine elb.kub (vous pourrez modifier votre /etc/hosts).

Maintenant c’est partie on peut jouer notre ansible en tant que user vagrant et on utilisera le password « vagrant »… un standard sur vagrant.

ansible-playbook -i inventory/my-cluster/inventory.ini -u vagrant -k -b cluster.yml

Attendez plusieurs dizaines de minutes suivant votre connexion et le nombre de machines et votre cluster sera up à la fin.

Première connexion avec kubectl

Dernière tâche pour accéder à notre cluster, il nous faut récupérer le certificat du compte d’administrateur de notre cluster kubernetes.

Copiez sur un des master le fichier

cat /etc/kubernetes/admin.conf

Puis créez et collez le contenu sur la machine devant accéder au cluster :

mkdir -p ~/.kube
vim ~/.kube/config

Enfin installons kubectl sur cette même machine :

sudo apt-get update && sudo apt-get install -y 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 -a /etc/apt/sources.list.d/kubernetes.list
sudo apt-get update
sudo apt-get install -y kubectl

Maintenant testons notre cluster :

kubectl cluster-info
kubectl get nodes

Test de la haute disponibilité

Si tout est bien fonctionnel…

Coupez un haproxy soit en coupant le service avec un systemctl stop soit en arrêtant plus ou moins brutalement la machine.

Testez à nouveau vos commandes kubectl.

Ensuite coupez un master et procédez au même test.

Alors ça marche ?

Je vous invite à découvrir la playlist complète pour découvrir kubernetes et d’autres outils liés ici.

Raspberry et Kubernetes : tuto de montage et installation

Avant toute chose je tiens à remercier toute la communauté de xavki qui a participée à ce projet par le biais de dons.

Pour récapituler voici le matériel utilisé :

  • 3 Raspberry Pi 3 Modèle B
  • 3 Raspberry Pi 4 4G ram
  • 6 dissipateurs
  • Plaque cluster 6
  • Transfo USB
  • Swith 8 ports
  • 10 Cable RJ45
  • 6 Cables USB

Remarques :

  • les raspberry 4 s’alimente à partir d’usb c à la différence des Pi3
  • les pi 4 utilisent des connectiques micro-hdmi

1ère étape : le montage

L’étape la plus fun surement avec un petit jeu de lego. Dans cette vidéo, je vous explique les astuces et la manière d’assembler le tout.

2ème étape : l’installation de l’OS

Pour l’OS, j’ai choisi de faire simple avec un raspbian. Concernant la version j’ai préféré partir vers une stretch. En effet, lors de l’installation de docker celle-ci est la 18.09 avec la stretch et cette version est la maximum acceptée pour le moment par kubernetes.

Autre élément à retenir, la possibilité d’activé le ssh sans écrant et de configurer l’ip statique. Pour cela je vous explique tout dans la vidéo.

3ème étape : l’installation automatisée de kubernetes

Ansible est reconnu. J’ai pu confectionner un rôle à partir des informations recueillies à droite et à gauche. Vous pouvez trouver ce playbook dans ce dépôt.

Et voilà l’installation est terminée. Finalement elle est plutôt simple et relativement accessible.