Mémo pour installer Minikube (Kubernetes) dans un container LXC sur Ubuntu Server 20.04 LTS.
Inspiré de :
- https://minikube.sigs.k8s.io/docs/faq/
- https://gist.github.com/bat9r/76610a778f53f4dfbb5bc887bc2f3cce
- https://medium.com/geekculture/a-step-by-step-demo-on-kubernetes-cluster-creation-f183823c0411
- https://github.com/ubuntu/microk8s/blob/master/tests/lxc/microk8s-zfs.profile
Dans ce beau pays qu’est la théorie, de simples copier/coller des commandes devraient fonctionner 😉 .
A la rédaction de ce mémo :
- Ubuntu 20.04.3 LTS (5.4.0-89-generic)
- LXC / LXD : 4.19
- Minikube version: v1.23.2
- Docker version 20.10.10, build b485636
Important
A l’installation de LXD, la première commande à lancer est
1 |
command lxd init |
A la question « Name of the storage backend to use (lvm, zfs, ceph, btrfs, dir) [default=zfs] », choisir : dir
Avertissement
Le nom du container utilisé ici est important.
Dans beaucoup de tutoriels, c’est « minikube » qui est utilisé et je me suis fais avoir.
Ici, je prend volontairement mkube pour ne pas confondre avec la commande minikube.
Si vous utilisez un autre nom, des modifications sont à prévoir dans certaines lignes de commandes.
Y compris la ligne de commande qui lance minikube au premier démarrage dans le container LXC.
Il s’agit de l’argument « –apiserver-name mkube » qui doit correspondre au nom du serveur LXC.
Installation et configuration
Désactiver IPv6 :
1 |
command lxc network set lxdbr0 ipv6.address none |
Créer le profile LXC : minikube
1 2 |
command lxc profile create mkube-profile command lxc profile edit mkube-profile |
Contenu :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
name: mkube-profile config: limits.cpu: "2" limits.memory: 2GB limits.memory.swap: "false" linux.kernel_modules: ip_tables,ip6_tables,netlink_diag,nf_nat,overlay,br_netfilter raw.lxc: | lxc.apparmor.profile=unconfined lxc.mount.auto=proc:rw sys:rw lxc.cap.drop= lxc.cgroup.devices.allow=a security.nesting: "true" security.privileged: "true" description: Profile supporting minikube in containers devices: aadisable: path: /sys/module/apparmor/parameters/enabled source: /dev/null type: disk aadisable2: path: /dev/kmsg source: /dev/kmsg type: disk |
Adapter les lignes limits.* en fonction du serveurs hôte.
Créer le container et exécuter bash :
1 2 |
command lxc launch ubuntu:20.04 mkube -p default -p mkube-profile command lxc exec mkube /bin/bash |
Dans le container mkube, mettre à jour et installer les outils nécessaires :
1 2 |
command apt update && apt upgrade -V command apt install -y conntrack linux-headers-$(uname -r) socat |
Dans le container mkube, contournement pour kmsg :
1 2 3 4 |
command apt install -qq -y net-tools command mknod /dev/kmsg c 1 11 command echo 'mknod /dev/kmsg c 1 11' >> /etc/rc.local command chmod +x /etc/rc.local |
La commande mknod peut renvoyer un message d’erreur. A ignorer.
Dans le container mkube, installer Docker CE :
1 2 3 4 |
command curl https://get.docker.com | bash command systemctl enable docker command systemctl daemon-reload command systemctl restart docker |
Dans le container mkube, tester Docker :
1 |
command docker run hello-world |
Relancer le container, très important !
Dans le container mkube :
1 |
command systemctl reboot |
Puis pour vérifier que l’IPV4 pour Docker est visible :
1 |
command lxc list |
1 2 3 4 5 6 |
+-------+---------+-----------------------+------+-----------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-------+---------+-----------------------+------+-----------+-----------+ | mkube | RUNNING | 172.17.0.1 (docker0) | | CONTAINER | 0 | | | | 10.134.238.211 (eth0) | | | | +-------+---------+-----------------------+------+-----------+-----------+ |
Tant que ce n’est pas le cas, attendre et vérifier.
Dans le container mkube, installer et démarrer Minikube :
1 2 3 |
command lxc exec mkube /bin/bash command curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube && sudo mv minikube /usr/local/bin/ command minikube start --apiserver-name mkube --vm-driver none |
Le nom du serveur api, doit correspondre au nom du container.
Le démarrage peut prendre quelques minutes… s’il y a un problème.
Sinon, environ 2min max.
Résultat :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
😄 minikube v1.23.2 on Ubuntu 20.04 (lxc/amd64) ✨ Using the none driver based on user configuration 👍 Starting control plane node minikube in cluster minikube 🤹 Running on localhost (CPUs=8, Memory=8270MB, Disk=992253MB) ... ℹ️ OS release is Ubuntu 20.04.3 LTS 🐳 Preparing Kubernetes v1.22.2 on Docker 20.10.10 ... ▪ kubelet.resolv-conf=/run/systemd/resolve/resolv.conf > kubelet.sha256: 64 B / 64 B [--------------------------] 100.00% ? p/s 0s > kubeadm.sha256: 64 B / 64 B [--------------------------] 100.00% ? p/s 0s > kubectl.sha256: 64 B / 64 B [--------------------------] 100.00% ? p/s 0s > kubectl: 44.73 MiB / 44.73 MiB [-------------] 100.00% 57.09 MiB p/s 1.0s > kubeadm: 43.71 MiB / 43.71 MiB [-------------] 100.00% 52.94 MiB p/s 1.0s > kubelet: 146.25 MiB / 146.25 MiB [-----------] 100.00% 34.87 MiB p/s 4.4s ▪ Generating certificates and keys ... ▪ Booting up control plane ... ▪ Configuring RBAC rules ... 🤹 Configuring local host environment ... ❗ The 'none' driver is designed for experts who need to integrate with an existing VM 💡 Most users should use the newer 'docker' driver instead, which does not require root! 📘 For more information, see: https://minikube.sigs.k8s.io/docs/reference/drivers/none/ ❗ kubectl and minikube configuration will be stored in /root ❗ To use kubectl or minikube commands as your own user, you may need to relocate them. For example, to overwrite your own settings, run: ▪ sudo mv /root/.kube /root/.minikube $HOME ▪ sudo chown -R $USER $HOME/.kube $HOME/.minikube 💡 This can also be done automatically by setting the env var CHANGE_MINIKUBE_NONE_USER=true 🔎 Verifying Kubernetes components... ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5 🌟 Enabled addons: storage-provisioner, default-storageclass 💡 kubectl not found. If you need it, try: 'minikube kubectl -- get pods -A' 🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default |
En cas de soucis, exécuter cette commande et relancer Minikube avec de la log et le mode verbose à 8 :
1 2 3 4 5 |
command minikube stop command minikube delete --all --purge command docker image ls -q | xargs -I {} docker image rm -f {} command rm -rf ~/.minikube command minikube start --apiserver-name mkube --vm-driver none --alsologtostderr -v=8 |
Vérifier que tout est ok :
1 |
command minikube status |
Résultat :
1 2 3 4 5 6 |
minikube type: Control Plane host: Running kubelet: Running apiserver: Running kubeconfig: Configured |
Lister les pods :
1 |
command minikube kubectl -- get pods -A |
Résultat :
1 2 3 4 5 6 7 8 |
NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-78fcd69978-dzfq4 1/1 Running 0 36s kube-system etcd-mkube 1/1 Running 0 45s kube-system kube-apiserver-mkube 1/1 Running 0 45s kube-system kube-controller-manager-mkube 1/1 Running 0 45s kube-system kube-proxy-7fldm 1/1 Running 0 36s kube-system kube-scheduler-mkube 1/1 Running 0 45s kube-system storage-provisioner 1/1 Running 0 45s |
Activer kubelet au démarrage :
1 |
command systemctl enable kubelet.service |
Tester
Pour arrêter le container, je conseille :
1 |
command systemctl poweroff |
Vérifier au démarrage que tout est ok :
1 |
command lxc start mkube |
Attendre que l’ip Docker soit présente.
1 |
command lxc list |
Se connecter dans le container
1 |
command lxc exec mkube /bin/bash |
Vérifier directement que minikube est lancé :
1 |
command minikube status |
Résultat :
1 2 3 4 5 6 |
minikube type: Control Plane host: Running kubelet: Running apiserver: Running kubeconfig: Configured |
Installer la dernière version de kubctl
1 2 3 |
command curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl command chmod +x ./kubectl command mv ./kubectl /usr/local/bin/kubectl |
Commandes utiles
Dans le container mkube, consulter les logs de minikube :
1 |
command minikube logs |
Dans le container mkube, liste des pods :
1 |
command kubectl get pods --all-namespaces |
Accès externe à Minikube
C’est à dire à partir de la machine hôte et pas dans le container mkube.
Dans le container mkube, exécuter ces commandes :
1 2 3 4 5 6 |
command cd ~/.minikube command kubectl config --kubeconfig=mkube set-cluster mkube-cluster --server=https://kubernetes:8443 --certificate-authority=ca.crt --embed-certs=true command kubectl config --kubeconfig=mkube unset users command kubectl config --kubeconfig=mkube set-credentials mkube-user --client-key=profiles/minikube/client.key --client-certificate=profiles/minikube/client.crt --embed-certs=true command kubectl config --kubeconfig=mkube set-context default --cluster=mkube-cluster --user=mkube-user command kubectl config --kubeconfig=mkube use-context default |
Dans l’exemple, on crée un cluster avec un accès https dont l’url sera https://kubernetes:8443.
Le nom « kubernetes » est obligatoire et ne peut être changer (sans pas mal de manipulations pour les certificats).
Puis on crée un utilisateur mkube-user auquel on associe des certificats de connexion. Pas de mot de passe.
Et enfin on autorise l’utilisateur à accèder au cluster.
Cette configuration est stockée dans le fichier ~/.minikube/mkube dans le container LXC mkube.
Sortir du container mkube (Ctrl+d ou la commande exit).
Sur la machine hôte, modifier le fichier /etc/hosts.
D’abord, récupérer l’adresse ip du container :
1 |
command lxc list |
Résultat :
1 2 3 4 5 6 |
+-------+---------+----------------------+------+-----------+-----------+ | NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS | +-------+---------+----------------------+------+-----------+-----------+ | mkube | RUNNING | 172.17.0.1 (docker0) | | CONTAINER | 0 | | | | 10.134.238.30 (eth0) | | | | +-------+---------+----------------------+------+-----------+-----------+ |
Ici, c’est l’adresse ip 10.134.238.30 qui nous intéresse.
Editer le fichier /etc/hosts et rajouter la ligne suivante en modifiant l’ip si neccessaire :
1 |
10.134.238.30 kubernetes |
Récupérer la configuration créée sur la machine hôte :
1 |
command lxc exec mkube cat /root/.minikube/mkube > ~/mkubeconfig |
Tester :
1 |
command kubectl --kubeconfig ~/mkubeconfig get no |
Résultat :
1 2 |
NAME STATUS ROLES AGE VERSION mkube Ready control-plane,master 22h v1.22.2 |
Autre commande :
1 |
command kubectl --kubeconfig ~/mkubeconfig get pods --all-namespaces |
Résultat :
1 2 3 4 5 6 7 8 9 10 |
NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-78fcd69978-fxrdd 1/1 Running 2 (22h ago) 22h kube-system etcd-mkube 1/1 Running 2 (22h ago) 22h kube-system kube-apiserver-mkube 1/1 Running 2 (22h ago) 22h kube-system kube-controller-manager-mkube 1/1 Running 2 (22h ago) 22h kube-system kube-proxy-4ljdj 1/1 Running 2 (22h ago) 22h kube-system kube-scheduler-mkube 1/1 Running 2 (22h ago) 22h kube-system storage-provisioner 1/1 Running 4 (13m ago) 22h kubernetes-dashboard dashboard-metrics-scraper-5594458c94-s45h6 1/1 Running 1 (22h ago) 22h kubernetes-dashboard kubernetes-dashboard-654cf69797-l4s8w 1/1 Running 2 (13m ago) 22h |
Astuce :
Créer un alias pour éviter de taper la commande kubectl avec l’argument kubeconfig à chaque fois.
Dans le fichier ~/.bash_aliases, ajouter cette ligne :
1 |
alias kctl='kubectl --kubeconfig ~/mkubeconfig' |
Recharger le fichier ~/.bash_aliases :
1 |
command source .bash_aliases |
Tester :
1 |
kctl get pods --all-namespaces |
Résultat :
1 2 3 4 5 6 7 8 9 10 |
NAMESPACE NAME READY STATUS RESTARTS AGE kube-system coredns-78fcd69978-fxrdd 1/1 Running 2 (22h ago) 23h kube-system etcd-mkube 1/1 Running 2 (22h ago) 23h kube-system kube-apiserver-mkube 1/1 Running 2 (22h ago) 23h kube-system kube-controller-manager-mkube 1/1 Running 2 (22h ago) 23h kube-system kube-proxy-4ljdj 1/1 Running 2 (22h ago) 23h kube-system kube-scheduler-mkube 1/1 Running 2 (22h ago) 23h kube-system storage-provisioner 1/1 Running 4 (17m ago) 23h kubernetes-dashboard dashboard-metrics-scraper-5594458c94-s45h6 1/1 Running 1 (22h ago) 22h kubernetes-dashboard kubernetes-dashboard-654cf69797-l4s8w 1/1 Running 2 (17m ago) 22h |
Accès au dashboard
L’objectif est d’avoir accès au dashboard via un navigateur web.
Après avoir installé nginx et un certificat ssl comme Let’s Encrypt, créer les fichiers de configuration nginx :
Fichier /etc/nginx/sites-available/webkube.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
server { listen 80; server_name webkube.domain.tld; error_log /var/log/nginx/webkube-error.log warn; access_log /var/log/nginx/webkube-access.log; # nginx version server_tokens off; #root /var/www/html; #index index.html index.htm index.nginx-debian.html; location /.well-known/acme-challenge/ { allow all; root /var/www/certbot; } if ($scheme != "https") { return 301 https://$host$request_uri; } } |
Et le fichier SSL /etc/nginx/sites-available/webkube-ssl.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
server { listen 443 ssl http2; server_name webkube.domain.tld; error_log /var/log/nginx/webkube-error.log; access_log /var/log/nginx/webkube-access.log; # nginx version server_tokens off; ssl_certificate /etc/letsencrypt/live/webkube.domain.tld/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/webkube.domain.tld/privkey.pem; ssl_stapling on; ssl_stapling_verify on; resolver 1.1.1.1 9.9.9.9 8.8.8.8 8.8.4.4 208.67.222.222 208.67.220.220 216.146.35.35 216.146.36.36 valid=300s; resolver_timeout 5s; ssl_session_cache shared:le_nginx_SSL:10m; ssl_session_timeout 1d; ssl_session_tickets off; ssl_dhparam /etc/nginx/ssl/dhparams.pem; ssl_ecdh_curve secp384r1; ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GC$-SHA256:DHE-RSA-AES256-GCM-SHA384"; ssl_prefer_server_ciphers off; add_header Content-Security-Policy upgrade-insecure-requests; add_header X-Content-Type-Options nosniff; add_header X-XSS-Protection "1; mode=block"; add_header X-Robots-Tag none; add_header X-Download-Options noopen; add_header X-Permitted-Cross-Domain-Policies none; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"; add_header X-Frame-Options SAMEORIGIN; #add_header X-Content-Type-Options nosniff; add_header Referrer-Policy "no-referrer"; add_header Referrer-Policy "no-referrer"; location /.well-known/acme-challenge/ { allow all; root /var/www/certbot; } # root /var/www/html; # index index.html index.htm index.nginx-debian.html; location / { # Only my ip allow 90.49.106.0; deny all; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-NginX-Proxy true; proxy_pass http://127.0.0.1:8080/; gzip off; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_redirect off; proxy_http_version 1.1; proxy_max_temp_file_size 0; client_max_body_size 0; } } |
L’utilisation de 2 fichiers est purement un choix personnel.
Activer les configurations (root) :
1 2 3 4 5 |
command cd /etc/nginx/sites-enabled/ command ln -s /etc/nginx/sites-available/webkube.conf command ln -s /etc/nginx/sites-available/webkube-ssl.conf command nginx -t command nginx -s reload |
Dans un tmux, exécuter cette commande pour démarrer le serveur minikube :
1 |
kctl proxy --address='0.0.0.0' --port 8080 --accept-hosts='.*' |
Au besoin, sortir de tmux (Ctrl+b puis d).
Pour revenir dans tmux :
1 |
command tmux a |
Dans le navigateur web :
https://webkube.domain.tld/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/#/workloads?namespace=default
Et voilà !