Pouet

Wake me up before you code Go!

Utiliser k3d pour avoir un cluster k8s en local

Comment monter en moins de 5min un cluster k8s pour ses tests

Issif

5 minutes

kubernetes feature

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

Posts récents

Voir plus

Catégories

A propos

Du Go, de l'AWS et autres par un SRE/FinOps