Utiliser k3d pour avoir un cluster k8s en local
Comment monter en moins de 5min un cluster k8s pour ses tests
Afin de parfaire mes connaissances sur kubernetes, aka k8s pour les intimes, j’avais envie de monter un cluster sur mon laptop, pas juste un noeud tout seul. Jusqu'à présent je n’avais testé que des solutions pour avoir des k8s mono-noeud, c’est sympa, mais trop éloigné de la réalité, surtout si on veut tester des méthodes de résilience, d’auto-scaling de pods, de deployments, de daemonset, etc.
Et là, la révélation ! Je connaissais déjà k3s, le k8s ultra allégé de chez rancher et il s’avère qu’ils ont développé un petit utilitaire pour monter un cluster dans des containeurs docker avec, le bien nommé k3d.
Après plusieurs heures de tests, je suis emballé, c’est ultra rapide, ultra light et ça fonctionne avec tous les outils classiques. Un ingress controller basé sur traefik est directement déployé, donc on a de base un environnement fonctionnel. Simple. Efficace.
Installation de k3d
Rien de compliqué pour l’installer, plusieurs méthodes sont fournies sur le repo Github officiel. Comme c’est du go, aucune dépendance. Easy.
Créer son premier cluster
~ $ k3d create -n mon-cluster-test --publish 80 --publish 8080 --publish 443 -w 2
2019/09/05 23:16:34 Created cluster network with ID cae80bddca7cf614494b9d97f7d6edf2b14d45864ef1aa0b1a899a93122ecc1b
2019/09/05 23:16:34 Created docker volume k3d-mon-cluster-test-images
2019/09/05 23:16:34 Creating cluster [mon-cluster-test]
2019/09/05 23:16:34 Creating server using docker.io/rancher/k3s:v0.7.0...
2019/09/05 23:16:34 Pulling image docker.io/rancher/k3s:v0.7.0...
2019/09/05 23:16:47 Booting 2 workers for cluster mon-cluster-test
2019/09/05 23:16:48 Created worker with ID b0c019c001376c9aa07f8fb65b52da1b2d52fbe61f25cb24c7198c5b122a2a09
2019/09/05 23:16:49 Created worker with ID a9d959899a2119606248bf8dd5d681f05efb7232d19c5f8206ffb5025f10885b
2019/09/05 23:16:49 SUCCESS: created cluster [mon-cluster-test]
2019/09/05 23:16:49 You can now use the cluster with:
export KUBECONFIG="$(k3d get-kubeconfig --name='mon-cluster-test')"
kubectl cluster-info
Sur ma machine, l’exécution a pris environ 20s, en sachant que 95% du temps est lié la récupération de l’image k3s. Impressionnant.
Une petite explication des arguments :
-n
: le nom de notre cluster k8s--publish 80 --publish 8080 --publish 443
: les ports qu’on va exposer, comme c’est fait avec la commande docker run-w 2
: le nombre de workers qu’on veut
On peut lister nos clusters :
~ $ k3d ls
+------------------+------------------------------+---------+---------+
| NAME | IMAGE | STATUS | WORKERS |
+------------------+------------------------------+---------+---------+
| mon-cluster-test | docker.io/rancher/k3s:v0.7.0 | running | 2/2 |
+------------------+------------------------------+---------+---------+
L’image est effectivement de taille réduite (proportionnellement aux autres solutions) :
REPOSITORY TAG IMAGE ID CREATED SIZE
rancher/k3s v0.7.0 f1ec9d3fbf66 6 weeks ago 119MB
Se connecter au cluster
Comme précisé dans les logs de création, on peut récupérer le kubeconfig associé pour utiliser les outils classiques (kubectl, k9s, helm, etc) :
~ $ export KUBECONFIG="$(k3d get-kubeconfig --name='mon-cluster-test')"
~ $ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k3d-mon-cluster-test-server Ready master 2m v1.14.4-k3s.1
k3d-mon-cluster-test-worker-0 Ready worker 2m v1.14.4-k3s.1
k3d-mon-cluster-test-worker-1 Ready worker 2m v1.14.4-k3s.1
Premier déploiement
Afin de tester tout cela, nous allons appliquer un premier deployment et tenter d’y accéder. Cela sera un simple micro-service qui nous répondra quelques infos sur lui-même (sur quel noeud il tourne, son nom, le contenu de la requête HTTP qu’il a reçue, etc). Le container qui sera utilisé est fourni par ailleurs par ceux derrière traefik : containous/whoami.
Création d’un namespace dédié
~ $ kubectl create namespace whoami
C’est juste histoire de bien segmenter les choses.
Application du deployment
~ $ kubectl create deployment whoami --image=containous/whoami -n whoami
Scaling du replicaSet
Nous avons un cluster à 2 noeuds, ça serait dommage de n’avoir qu’un seul pod, augmentons à 2 le replicaSet associé :
~ $ kubectl scale --replicas 2 deployment/whoami -n whoami
~ $ kubectl get rs -n whoami
NAME DESIRED CURRENT READY AGE
whoami-756586b9ff 2 2 2 4m33s
Création du service
Nous avons 2 pods, nous allons créer un service pour avoir une répartition de charge :
~ $ kubectl create service clusterip whoami --tcp=80:80 -n whoami
Création de l’ingress
Tout est prêt au sein de notre cluster, il est temps de nous permettre d’accéder à notre micro-service, on va utiliser une ressource de type ingress :
~ $ cat <<EOF | kubectl apply -n whoami -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: whoami
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: whoami
servicePort: 80
EOF
Testons le micro-service
A la création du cluster, nous avons publier le port 80 au niveau de l’host, il est temps de trouver le port qui a été associé (bind) :
~ $ docker inspect --format='{{range $p, $conf := .NetworkSettings.Ports}} {{$p}} -> {{(index $conf 0).HostPort}} {{end}}' $(docker ps --filter "name=k3d-mon-cluster-test-server" -q)
443/tcp -> 32810 6443/tcp -> 6443 80/tcp -> 32811 8080/tcp -> 32809
L’ingress écoute sur le port 80, le port associé est donc le 32811 dans mon cas. Faisons plusieurs appels et vérifions :
~ $ curl http://localhost:32811
Hostname: whoami-756586b9ff-4mqb6
IP: 127.0.0.1
IP: ::1
IP: 10.42.2.4
IP: fe80::a89f:5eff:fef5:d426
RemoteAddr: 10.42.1.3:36824
GET / HTTP/1.1
Host: localhost:32811
User-Agent: curl/7.47.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.1.1
X-Forwarded-Host: localhost:32811
X-Forwarded-Port: 32811
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-56688c4464-wlk2r
X-Real-Ip: 10.42.1.1
~ $ curl http://localhost:32811
Hostname: whoami-756586b9ff-6wn52
IP: 127.0.0.1
IP: ::1
IP: 10.42.0.4
IP: fe80::7c0f:1fff:fe2b:bcb2
RemoteAddr: 10.42.1.3:41180
GET / HTTP/1.1
Host: localhost:32811
User-Agent: curl/7.47.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.1.1
X-Forwarded-Host: localhost:32811
X-Forwarded-Port: 32811
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-56688c4464-wlk2r
X-Real-Ip: 10.42.1.1
Nous avons bien 2 réponses différentes :
Hostname: whoami-756586b9ff-4mqb6
IP: 10.42.2.4
Hostname: whoami-756586b9ff-6wn52
IP: 10.42.0.4
Qui correspondent à nos 2 pods :
~ $ kubectl get pods -n whoami
NAME READY STATUS RESTARTS AGE
whoami-756586b9ff-4mqb6 1/1 Running 0 24m
whoami-756586b9ff-6wn52 1/1 Running 0 20m
Enjoy