S'installer facilement un environnement Docker et Kubernetes sur la même machine, tout en gardant un certain cloisonnement entre les deux,  peut parfois s'avérer très utile pour réaliser des tests.

Cette opération est très simple à mettre en œuvre sous Windows, puisque l'outil Docker Desktop vous propose plus ou moins de réaliser cela out-of-the-box ( il s'agit tout de même de conteneur ... ). Mais quand est-il sous Linux ?

Je vais aujourd'hui vous expliquer comment réaliser cette installation sous Ubuntu 20.04 à l'aide de l'outil Multipass. Cette solution n'est pas la seule envisageable, il existe par exemple le projet k3d qui peut permettre d'installer un environnement k3s dans Docker ou encore Minikube.

Commençons ce tutoriel par l'installation de multipass. Mais au fait multipass c'est quoi ?

Multipass

C'est un outil en ligne de commande, qui permet de gérer des machines virtuelles lightweight. L'outil se veut très simple d'utilisation et permet en quelques minutes d'obtenir des machines virtuelles tournant sous Ubuntu :

Multipass is a mini-cloud on your workstation

Disponible sous Windows, macOS and Linux, il vous permettra également d'initialiser ces instances à l'aide de cloud-init lors du démarrage de celle-ci.

Installons donc l'outil :

$ sudo snap install multipass --classic

Enfin regardons les images disponibles pour lancer une instance :

$ multipass find

Provisionons une première instance qui va nous servir par la suite pour l'installation de K3S afin d'avoir un environnement Kubernetes.

$ multipass launch --name k3s --cpus 4 --mem 2048M --disk 5G

Comme vous pouvez le voir, il est possible de paramétrer certaines caractéristiques physiques ( mémoires, CPU ). De base 1G de mémoire seront alloués, 1 CPU et 5G d'espace disque.  

Vous pouvez lister les instances disponible avec la commande :

$ multipass list

Ou encore arrêter ou démarrer vos instances avec :

$ multipass stop my-instance
$ multipass start my-instance

Il est bien sûr possible d’exécuter un shell dans votre instance :

$ multipass shell my-instance

ou

$ multipass exec k3s -- bash

Nous allons donc pouvoir installer toute de suite notre environnement Kubernetes !

K3S

Si vous souhaitez en apprendre plus sur K3S, je vous invite à relire cet article :

Installation de K3S sur un VPS OVH
Alléché par une promesse d’un kubernetes “Lightweight”, j’ai décidé de me lancer à la découverte de K3S et plus généralement du monde “Kubernetes”.

L'installation est toujours aussi simple :

$ multipass exec k3s -- bash -c "curl -sfL https://get.k3s.io | sh -s - --no-deploy=traefik"
[INFO]  Finding release for channel stable
[INFO]  Using v1.17.4+k3s1 as release
[INFO]  Downloading hash https://github.com/rancher/k3s/releases/download/v1.17.4+k3s1/sha256sum-amd64.txt
[INFO]  Downloading binary https://github.com/rancher/k3s/releases/download/v1.17.4+k3s1/k3s
[INFO]  Verifying binary download
[INFO]  Installing k3s to /usr/local/bin/k3s
[INFO]  Creating /usr/local/bin/kubectl symlink to k3s
[INFO]  Creating /usr/local/bin/crictl symlink to k3s
[INFO]  Creating /usr/local/bin/ctr symlink to k3s
[INFO]  Creating killall script /usr/local/bin/k3s-killall.sh
[INFO]  Creating uninstall script /usr/local/bin/k3s-uninstall.sh
[INFO]  env: Creating environment file /etc/systemd/system/k3s.service.env
[INFO]  systemd: Creating service file /etc/systemd/system/k3s.service
[INFO]  systemd: Enabling k3s unit
Created symlink /etc/systemd/system/multi-user.target.wants/k3s.service → /etc/systemd/system/k3s.service.
[INFO]  systemd: Starting k3s

Vous pouvez bien évidemment vérifier le bon fonctionnement :

$ multipass exec k3s -- sudo kubectl get nodes

Souhaitant optimiser mon temps, je n'ai pas envie de lancer en permanence des commandes exec sur mon instance pour gérer le tout.

Je vais donc installer la CLI kubectl sur mon hôte :

curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl

On rend le binaire exécutable :

$ chmod +x ./kubectl

Et je le déplace dans mon $PATH :

$ sudo mv ./kubectl /usr/local/bin/kubectl

On teste le bon fonctionnement :

$ kubectl version --client

Je vais récupérer le fichier de configuration présent sur mon instance :

$ sudo mkdir ~/.kube
$ multipass exec k3s -- bash -c "sudo cat /etc/rancher/k3s/k3s.yaml" > ~/.kube/k3s.yaml

Enfin il est nécessaire de changer l'adresse IP présente dans ce fichier :

$ K3S_SERVER=`multipass info k3s | grep "IPv4" | awk -F ' ' '{print 2}'`
$ sed -ie s/127.0.0.1/${K3S_SERVER}/g ~/.kube/k3s.yaml

Enfin je peux exporter ma configuration :

$ export KUBECONFIG=${HOME}/.kube/k3s.yaml

Je n'ai plus qu'à essayer :

$ kubectl get nodes
NAME   STATUS   ROLES    AGE   VERSION
k3s    Ready    master   16m   v1.17.4+k3s1

Il est bien sûr possible de créer un mini-cluster en créant quelques nodes supplémentaires ! Mais je vais de mon côté, me lancer dans l'installation de Docker !

Docker

Si votre machine possède déjà un environnement Docker, alors cette partie n'est pas utile. Si ce n'est pas le cas :

$ sudo apt install docker.io

Je m'assure que Docker se lance au démarrage :

$ sudo systemctl enable --now docker

Optionnel mais pratique :

$ sudo usermod -aG docker $USER

Enfin il ne reste qu'à valider !

$ docker --version

J'en profiter pour également pour installer docker-compose, vous pouvez suivre cet article :

Docker Compose, indispensable ?
Vous avez installé Docker à l’aide du précédent article [/installation-docker-dedie-kimsufi/] et vous avez découvert comment lancer vos premiers conteneurs. Maintenant vous souhaitez sûrement passer à la vitesse supérieure. Le lancement de multiples conteneurs via docker run commence à vous poser qu…

Vous voila maintenant avec Docker et Kubernetes sur la même machine, tout ceci gérable depuis votre hôte 😛

Ok mais je bosse sur 2 ou 3 applications webs en même temps et franchement j'aimerais bien gérer mes deux environnements avec un seul reverse-proxy !

Bonus stage 👍

Forcément si on parle reverse-proxy ...

Je vais utiliser Traefik afin d’accéder à deux instances whoami.

  • Ma première instance sur Docker devra répondre sur le port 80 avec le chemin /docker-whoami,
  • Enfin ma seconde instance sur Kubernetes répondra elle sur le chemin /k3s-whoami.

Avant de commencer, deux solutions s'offrent à moi, démarrer Traefik sur Docker ou sur Kubernetes.

Je vais choisir d'instancier mon reverse-proxy sur Kubernetes. Pourquoi ?

Il faut être honnête, une installation depuis Docker serait plus complexe ( le certificat auto-signé de K3S, la gestion des droits RBAC, etc ). Cette installation mérite sûrement un post à part entière 😂

Préparons Docker !

Traefik va devoir se connecter au endpoint de Docker au travers du réseau.

Une nouvelle fois, deux possibilités :

  • Depuis la 2.2, Traefik me donne la possibilité d'utiliser le endpoint au travers de ssh.
  • Ou avec une connexion tcp direct.

La deuxième solution n'est clairement pas sécurisée ( en tout cas si je n'utilise pas de certificat, filtrage IP, etc ). Mais je vais partir sur cette solution.

Je vais utiliser - encore - la solution simple car je souhaite garder ce tutoriel simple et dans l'esprit "fun devops". Complexifier une installation qui n'a rien de production ready n'aurait ici aucun intérêt !

Je vais donc faire écouter l'API docker sur le port 2376, pour cela je vais simplement modifier le fichier systemd de Docker :

/etc/systemd/system/multi-user.target.wants/docker.service

Modifiez la ligne 15 :

$ ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2376 --containerd=/run/containerd/containerd.sock

Vous pouvez valider votre modification avec la commande :

$ docker -H tcp://127.0.0.1:2376 ps

Je vais donc maintenant déployer Traefik sur mon installation de K3S. J'utilise la base présente sur mon dépôt Git :

$ git clone https://github.com/lfache/awesome-traefik-kubernetes

Enfin dans le dossier awesome-traefik-kubernetes/traefik-kustomize-sample/development, je vais modifier ma configuration statique ( traefik-configmap.yaml ) :

apiVersion: v1
kind: ConfigMap
metadata:
  name: traefik-config-static
  namespace: default
  labels:
    app: traefik
data:
  traefik.yml: |
    entryPoints:
      web:
        address: :80

    api:
      insecure: true
      
    providers:
      kubernetesCRD: {}

      docker:
        endpoint: tcp://HOSTIP:2376 

Remplacez HOSTIP par l'adresse IP de votre hôte.

Je peux ensuite appliquer ma configuration :

$ kubectl apply -k ./

Récupérez l'adresse IP de votre K3S :

$ multipass info k3s | grep "IPv4" | awk -F ' ' '{print $2}'

Et connectez vous au dashboard de Traefik avec cette adresse :

Déployons notre première instance de Whoami, je vais créer un simple fichier de déploiement, deployment.yaml :

kind: Service
apiVersion: v1
metadata:
  name: whoami
spec:
  ports:
  - port: 80
    name: web
    protocol: TCP
  selector:
    app: whoami
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
  labels:
    app: whoami
spec:
  replicas: 3
  selector:
    matchLabels:
      app: whoami
  template:
    metadata:
      labels:
        app: whoami
    spec:
      containers:
      - name: whoami
        image: containous/whoami
        imagePullPolicy: Always
        ports:
        - containerPort: 80
---
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
  name: whoami-web
spec:
  entryPoints:
    - web
  routes:
  - kind: Rule
    match: PathPrefix(`/whoami`)
    services:
    - name: whoami
      port: 80

Enfin j'applique ce fichier :

$ kubectl apply -f ./deployment.yaml

Et je vérifie que tout fonctionne :

$ curl http://10.72.232.47/k3s-whoami
Hostname: whoami-5b4bb9c787-ttr97
IP: 127.0.0.1
IP: ::1
IP: 10.42.0.13
IP: fe80::dc35:c6ff:fe1a:df8f
RemoteAddr: 10.42.0.9:58440
GET /k3s-whoami HTTP/1.1
Host: 10.72.232.47
User-Agent: curl/7.68.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.0.1
X-Forwarded-Host: 10.72.232.47
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-66b8f478c6-pf5pj
X-Real-Ip: 10.42.0.1

Je n'ai plus qu'à déployer une instance whoami sur Docker !

Mon fichier docker-compose.yaml :

version: '3.7'
services:
  backend:
    image: containous/whoami
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.go.rule=Path(`/docker-whoami`)"
      - "traefik.http.services.go.loadbalancer.server.port=80"

Et je vérifie :

$ curl http://10.72.232.47/docker-whoami
Hostname: 2bb14832f7b3
IP: 127.0.0.1
IP: 172.18.0.2
RemoteAddr: 172.18.0.1:64199
GET /docker-whoami HTTP/1.1
Host: 10.72.232.47
User-Agent: curl/7.68.0
Accept: */*
Accept-Encoding: gzip
X-Forwarded-For: 10.42.0.1
X-Forwarded-Host: 10.72.232.47
X-Forwarded-Port: 80
X-Forwarded-Proto: http
X-Forwarded-Server: traefik-66b8f478c6-pf5pj
X-Real-Ip: 10.42.0.1

Sur le dashboard de Traefik :


Au travers de cet article, nous avons pu mettre en place sur notre hôte Ubuntu 20.04 :

  • Une installation de docker, avec docker-compose.
  • Un environnement Kubernetes avec K3S grâce à multipass.
  • Une unique instance de Traefik pour piloter mon trafic web !

Multipass est déjà un outil très sympathique, virtualisation ultra-légère et très simple d'utilisation. Même si on pourrait se demander ce qu'il apporte de plus qu'un outil déjà existant comme Vagrant par exemple.

Il manque notamment pour l'instant quelques options réseaux ( bridge network par exemple ) qui peuvent parfois limiter son utilisation. Mais cela ne devrait plus tarder !

Cet environnement est devenu pour le moment ma base, dont je me sers pour réaliser mes démos. J'ai quelques scripts supplémentaires pour ajouter des nodes à mon cluster K3S et Docker en mode Swarm.

Mais on en parlera dans un prochain article avec sûrement quelques changements ( sécurité ? ) à cette installation 😄

En tout cas  n'hésitez pas à m'apporter des remarques ou des commentaires sur Twitter ! C'est toujours un plaisir d'avoir des retours ! 😘