Rancher v2 / k3s – un environnement d’hébergement et de virtualisation complet sur votre serveur (VPS ou cloud)

Tout ce qui se trouve sur ce serveur (blog, sites Web, sites hébergés, service GNS3, DrawIO, etc.) tourne sous Rancher v2 avec génération automatique des certificats via cert-manager.

Tout ce qui se trouve sur ce serveur (blog, sites Web, sites hébergés, service GNS3, DrawIO, etc.) tourne sous Rancher v2. C’est l’environnement idéal pour déployer, tester et installer pléthores d’applications et ce en haute disponibilité. Une liste non exhaustive est disponible sur le hub Docker mais pas que puisque vous pouvez très bien créer et déployer vos propres images ! Je vous conseille d’ailleurs d’utiliser l’excellente distribution alpine linux dans ce cas, l’image officielle est aussi disponible sur le hub. Cet article va vous guider pour déployer votre propre instance de Rancher sur un serveur hébergé de type VPS (chez OVH ou Kimsufi par exemple) mais vous pouvez très bien le déployer sur une solution cloud (AWS, Azure, etc.).

Choix du serveur

Rancher v2 étant déployé sous kubernetes (plus précisément une version allégée intitulée k3s), il est plus gourmand en ressources que Rancher v1 (qu’on pouvait quasiment installer sous un raspberry PI). Donc si vous avez des ressources limitées je vous conseille d’installer la v1. A ce sujet, la version 1 est bien pratique si on veut déployer un environnement haproxy simple d’utilisation avec une interface intuitive.

Pour ma part, je suis parti sur un serveur avec 16Go de RAM :

A l’usage, je pense que le minimum pour déployer un cluster performant qui puisse gérer une centaine de pods (~=containers dans le jargon docker) est d’avoir un 4 cœurs avec 16Go de RAM.

Déploiement de Rancher en HA avec etcd

J’ai testé plusieurs modes de déploiement car vous avez plein de possibilités pour installer Rancher : directement sur docker, sur un kubernetes déjà existant, via l’installation de k3s et de helm, en mode HA avec une base postgresql, en mode HA avec etcd, etc.

Même si l’option choisie sur mon serveur personnel est d’avoir installé une base postgresql pour la partie HA sous un OS ubuntu avec livepatch. Je préconise finalement de déployer Rancher sous alpine linux en HA avec etcd.

Installation d’alpine linux

Alpine Linux est un OS linux basé sur busybox et donc extrêmement rapide et très peu gourmand en ressources, il est donc parfait pour des configurations limitées. Et puis si vous êtes habitués à créer des images Docker, c’est typiquement le type d’OS que l’on utilise pour cela vu sa faible consommation de ressources. Je vous conseille d’installer la version extended en mode system disk.

Schéma synthétique

Evidemment si vous voulez avoir un vrai cluster il vous faudra, à minima, 3 noeuds :

En réalité vous pouvez spécialiser différents rôles pour chacun des nœuds et, par exemple, mettre l’ensemble des rôles (worker, control plane, etcd) sur un seul et même nœud. Ce sera forcément le cas si, comme moi, vous n’avez qu’un serveur VPS, il faudra alors mettre tous les rôles sur le même nœud mais, évidemment, le minimum serait d’avoir 3 nœuds donc, à terme, si votre site prend de l’ampleur et que vous avez suffisamment d’argent pour acheter de nouveaux serveurs, vous devrez ajouter des nouveaux nœuds au cluster.

En entreprise, la question ne se pose pas, il vous faut à minima 3 machines virtuelles sous alpine linux !

Si sous VMWare, installation des vm-tools

apk add open-vm-tools
/etc/init.d/open-vm-tools start
rc-update add open-vm-tools boot

Evidemment il vous faudra configurer le NTP si nécessaire, le DNS, votre adresse IP (à l’installation) ainsi que les proxys.

Proxy d’entreprise

Si votre entreprise se trouve derrière un proxy, il vous faudra absolument créer les variables d’environnement http_proxy, https_proxy et no_proxy. C’est indispensable sinon vos noeuds ne communiqueront jamais correctement et vous mettrez du temps à comprendre pourquoi (d’où l’importance de la directive no_proxy, c’est du vécu).

Vous pouvez utiliser la commande setup-proxy

Dans /etc/profile.d/noproxy.sh :

export no_proxy=localhost,127.0.0.1,0.0.0.0,172.16.0.0/12,10.0.0.0/8,192.168.0.0/16,domain.local
export NO_PROXY=localhost,127.0.0.1,0.0.0.0,172.16.0.0/12,10.0.0.0/8,192.168.0.0/16,domain.local

Installation de k3s et création cluster kubernetes en HA avec etcd

Le plus pratique est d’avoir un cluster multi-maître grâce à une version spéciale de Rancher : High Availability with embedded DB.

K3S est une version allégée de kubernetes, un genre de kubernetes pour les nuls dont l’intérêt est de vous permettre d’installer un cluster kubernetes en quelques minutes avec seulement les options essentielles.

Sur le premier nœud (srv-ran-1), lancez la commande :

apk add curl
curl -sfL https://get.k3s.io | sh -s - server --cluster-init

Le serveur va se déployer et générer une clef privée, elle se trouve dans /var/lib/rancher/k3s/server/node-token :

cat /var/lib/rancher/k3s/server/node-token
K104be7a1164cf60bbba20b4530084f33c195c40ztbc9d6db6342d1036971e4a34d::server:8bb5cd9zp49a08082d571c3b281f9648

Cette clef est nécessaire pour intégrer les autres nœuds dans votre cluster.

Sur le nœud srv-ran-2 et srv-ran-3, lancez les commandes :

curl -sfL https://get.k3s.io | sh -s - --server https://srv-ran-1.domain.local:6443 --token "K104be7a1164cf60bbba20b4530084f33c195c40ztbc9d6db6342d1036971e4a34d::server:8bb5cd9zp49a08082d571c3b281f9648"

Vous pourrez voir que les noeuds s’intègrent au cluster grâce aux commandes :

kubectl proxy --port=8080 &
kubectl get nodes -o wide
NAME               STATUS   ROLES                       AGE   VERSION        INTERNAL-IP     EXTERNAL-IP   OS-IMAGE                   KERNEL-VERSION               CONTAINER-RUNTIME
srv-ran-1   Ready    control-plane,etcd,master   57d   v1.20.2+k3s1   172.16.0.1   <none>        Alpine Linux v3.12         5.4.72-0-virt                containerd://1.4.3-k3s1
srv-ran-2   Ready    control-plane,etcd,master   57d   v1.20.2+k3s1   172.16.0.2   <none>        Alpine Linux v3.12         5.4.72-0-virt                containerd://1.4.3-k3s1
srv-ran-3   Ready    control-plane,etcd,master   57d   v1.20.2+k3s1   172.16.0.2   <none>        Alpine Linux v3.12         5.4.72-0-virt                containerd://1.4.3-k3s1

C’est aussi simple que ça ! Vous avez maintenant un cluster kubernetes prêt et fonctionnel. Vous n’êtes d’ailleurs pas obligé de déployer Rancher dessus, vous pouvez très bien déployer d’autres outils et utiliser votre cluster en tant que simple cluster kubernetes.

Installation de HELM

HELM est le gestionnaire de paquets de référence pour kubernetes. Via cet outil, vous pouvez déployer facilement et rapidement tout type d’applications en mode haute disponibilité (la base de données distribuées stolon pour postgresql, galera pour mariaDB, une version packagée pour la base de données de cache redis, etc.).

Le package helm existe pour alpine linux donc « apk add helm » devrait fonctionner. Cependant, j’ai effectué l’installation directement via la méthode par script :

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | sh

Déploiement de Rancher

Votre cluster kubernetes est déjà prêt et fonctionnel, il ne vous reste plus qu’à déployer Rancher dessus via l’outil helm.
Toute les instructions à jour se trouvent sur le site de Rancher mais je vous indique les commandes que j’ai utilisé à l’heure où j’ai écrit ces lignes :

kubectl proxy --port=8080 & 
helm repo add rancher-stable https://releases.rancher.com/server-charts/stable
kubectl create namespace cattle-system
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.0.4/cert-manager.crds.yaml
kubectl create namespace cert-manager
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager --namespace cert-manager --version v1.0.4

Installation de Rancher avec proxy :

helm install rancher rancher-stable/rancher --namespace cattle-system --set hostname=rancher.domain.local --set proxy=http://proxy.domain.local:8080 --set noProxy="localhost\,127.0.0.1\,0.0.0.0\,172.16.0.0/12\,10.0.0.0/8\,192.168.0.0/16\,domain.local"

Vous pouvez vous connecter et déjà commencer à utiliser Rancher en vous rendant sur https://rancher.domain.local.

Pour une mise à jour

Pour mettre à jour votre instance de Rancher via HELM, il vous suffit de suivre le tuto officiel.

helm repo update
helm fetch rancher-stable/rancher
helm get values rancher -n cattle-system -o yaml > values.yaml
helm upgrade rancher rancher-latest/rancher \
  --namespace cattle-system \
  -f values.yaml

A noter : pour voir la liste des versions disponibles vous pouvez lancer :

helm search repo rancher-stable/rancher --versions

Installation de Longhorn

Que serait un cluster kubernetes sans une solution de stockage distribuée vous permettant d’avoir des disques persistants pour vos pods ? La solution existe via l’outil, toujours développé par le Rancher Labs, longhorn.

Longhorn est un système de stockage en bloc distribué léger, fiable et facile à utiliser pour Kubernetes. Longhorn est un logiciel gratuit et open source. Développé à l’origine par Rancher Labs, il est maintenant développé en tant que projet sandbox de la Cloud Native Computing Foundation. Il peut être installé sur n’importe quel cluster Kubernetes avec Helm, avec kubectl, ou avec l’interface utilisateur Rancher. Vous pouvez en savoir plus sur son architecture ici.

Les étapes de l’installation sont très bien décrites sur la documentation officielle. Pour alpine linux, j’ai du installer :

apk add open-iscsi
apk add findmnt
apk add grep
apk add awk
apk add blkid
apk add bash
apk add lsblk
rc-update add iscsid
/etc/init.d/iscsid start
apk add util-linux
apk add iscsitarget iscsitarget-grsec
apk add jq
apk add targetcli
apk add cfdisk
apk add e2fsprogs-extra
mount --make-rshared /

Pour vérifier que votre environnement est compatible avec longhorn, vous pouvez forcer une vérification comme indiqué dans la documentation :

curl -sSfL https://raw.githubusercontent.com/longhorn/longhorn/v1.0.0/scripts/environment_check.sh | bash

Une spécificité sous alpine ? Pour je ne sais quel raison, j’ai eu besoin de remonter systématiquement le / en mode rshared pour que iscsi fonctionne correctement. Je l’ai donc mis dans le cron :

crontab -e
@reboot /bin/mount --make-rshared /

Déploiement de longhorn via l’UI Rancher

Dans le cluster « local », dans le projet « system » :

Allez dans « apps » :

Puis dans « launch » :

Cherchez « longhorn » et cliquez dessus :

Nombre de replicas par défaut

Dans la configuration, si vous n’avez qu’un seul nœud dans votre cluster (qui n’est donc plus vraiment un cluster à proprement dit dans ce cas), je vous conseille de ne mettre qu’un seul replica, sinon gardez l’option par défaut à 3 pour une plus grande résilience :

Laissez les autres options par défaut et cliquez sur « Launch ». Votre instance longhorn va donc se déployer sur l’ensemble des noeuds du cluster :

Vous avez maintenant les composants essentiels pour commencer à déployer vos applications sous Rancher, félicitations !

Déploiement des composants applicatifs essentiels

Maintenant que nous avons l’infrastructure nous permettant d’héberger nos applications, il nous faut l’essentiel pour pouvoir commencer. Toute application standard a besoin d’un élément essentiel : la base de données !

D’autre part, un autre composant que l’on retrouve souvent est un serveur Redis.
Nous allons donc, pour l’exemple, déployer un serveur de base de données sous stolon avec, pour la gestion des bases, l’outil indispensable pgadmin.

A noter : je vous conseille d’utiliser le même procédé pour déployer une base de données mariaDB en maitre/esclave et un serveur Redis en maitre/esclave. Cela sera suffisant pour déployer la plupart des applications Web que nous voudrions installer.

A savoir : tous les packages de « apps » peuvent aussi être déployés via helm.

Activation de l’ensemble des catalogues HELM

Au préalable, il va vous falloir activer l’ensemble des catalogues généraux. Pour ce faire, dans « Global », dans « Tools » puis « Catalog », sélectionnez les catalogues « disabled » et activez les :

Installation d’une base de données postgresql répartie : stolon

Allez dans « local », « default » :

Puis dans « Apps » :

Cliquez sur « Launch » :

Cherchez « stolon » et cliquez dessus :

Modifiez les paramètres voulus :

  • Nom du namespace : par exemple « db », « pg12 » ou alors comme ici : « stolon »
  • image.tag : la version souhaitée de postgresql, à retrouver ici, celle qui fonctionne bien, testée et validée est « master-pg12 »
  • persistence.storageClassName : longhorn, très important pour la persistance des données ! Il faut donc utiliser votre storageClass que nous avons installé grâce à longhorn
  • replicationPassword : un mot de passe fort à définir qui permettra à vos instances stolon de se synchroniser
  • superuserPassword : un mot de passe fort à définir qui est le mot de passe « root », en réalité celui de l’utilisateur « stolon » qui vous permettra de gérer l’ensemble de vos bases de données postgreSQL

Votre cluster de base de données va se déployer sur votre cluster kubernetes grâce à Rancher :

Installation de pgAdmin

PgAdmin est l’outil indispensable pour gérer nos bases de données sous PostgreSQL.

Toujours dans « Apps », on va chercher et installer pgadmin et le déployer en cliquant sur « Launch » avec les paramètres souhaités :

  • env.username : le nom d’utilisateur pour se connecter à pgadmin
  • env.password : le mot de passe à définir pour s’y connecter

Publication de pgadmin

Dans « Load balancing », cliquez sur « Add ingress » :

Plusieurs choix s’offrent à vous :

  • Soit vous avez votre propre serveur DNS et vous ajouter l’entrée souhaitée qui pointent vers une ou plusieurs des adresses IP de votre cluster kubernetes. Le plus simple étant d’utiliser un wildcard mais pas forcément conseillé en cas d’attaque DoS puis vous indiquez l’entrée voulue dans la partie « specify hostname to use »

A noter : Si vous avez 3 noeuds (195.162.3.60, 44.33.22.11, 11.22.33.44), le plus simple par exemple pour le domaine ino.ovh serait de faire via un wildcard :

ino.ovh. IN A 195.162.3.60
ino.ovh. IN A 44.33.22.11
ino.ovh. IN A 11.22.33.44
* IN CNAME ino.ovh.

Ainsi vous n’aurez pas besoin d’ajouter une entrée DNS à chaque fois que vous ajoutez un nouveau site Web sur votre cluster kubernetes.

  • Soit vous utilisez xip.io qui va vous générer une adresse DNS tout seul, cette fonctionnalité est extrêmement pratique à des fins de test ou alors pour laisser votre équipe de développeur se débrouiller en tout autonomie

Dans cet exemple, on publie notre application sur xip.io qui a généré le nom DNS pgadmin.pgadmin.195.162.3.60.xip.io, notre application pgadmin devient donc accessible sur http://pgadmin.pgadmin.195.162.3.60. xip.io/

Création de notre première application : GitLab

Maintenant que nous avons notre base de données et nos disques persistants grâce à longhorn, nous avons tout ce qu’il faut pour déployer notre première application distribuée, par exemple GitLab.

Création de notre base de données via pgadmin

Pour ce faire, on va créer notre base de données via pgadmin puis créer la connexion vers notre serveur stolon :

Dans la connexion on indique le DNS interne local de notre proxy stolon (stolon-proxy.stolon par exemple, stolon étant le nom du namespace kubernetes) :

A l’ouverture, pgadmin vous demandera le mot de passe de l’utilisateur « stolon », vous pouvez le sauvegarder si besoin même si je ne vous le conseille pas par mesure de sécurité.

On va ensuite créer un login « gitlab » :

Dans « Definition », il faut créer un mot de passe pour cet utilisateur :

Puis on va créer la base de données associée :

A qui on accorde tous les droits sur cette base :

Puis on sauvegarde.

Création du workload

Allez dans « Local », « Workloads » puis cliquez sur « Deploy » :

Là on peut déployer n’importe quelle image Docker disponible sur le hub. Evidemment je vous conseille fortement de n’utiliser que des images officielles (comme guacd et guacamole par exemple) qui soient validées par des éditeurs reconnus (comme Apache). Dans notre exemple, on va utiliser l’image officielle gitlab-ce :

Dans les variables d’environnement, selon les indications fournies sur le hub docker, utilisez :

  • GITLAB_HOME : /srv/gitlab
  • GITLAB_OMNIBUS_CONFIG (indiquez les informations de la base de données) :
gitlab_rails['db_adapter'] = 'postgresql'; gitlab_rails['db_encoding'] = 'utf8'; gitlab_rails['db_host'] = 'stolon-proxy.stolon'; gitlab_rails['db_database']='gitlab'; gitlab_rails['db_username'] = 'gitlab'; gitlab_rails['db_password'] = 'gitlabpassword';

A savoir : pour les workloads ayant vocation à être en production, utilisez le type « Stateful », pour des workloads de dev ou de test, vous pouvez utiliser les types « Scalable ». C’est plus une priorisation côté kubernetes en cas de surcharge des ressources.

Création du volume

On va utiliser toute la puissance de notre storageClass distribuée sous longhorn :

On crée un volume intitulé « gitlab » sous longhorn avec 200MB de données :

A noter : le mode « Many Nodes Read-Write » est en version béta sous longhorn mais existe depuis la version 1.1.0. Cela passe par la création d’une surcouche NFS, l’avantage étant que toute mise à jour est transparente pour l’utilisateur car l’on peut monter le volume sur plusieurs pods donc aussi bien sur l’ancienne version que sur la nouvelle à deployer. Cependant, pour le moment, vous pouvez faire la même chose via l’apps « nfs-provisioner » basé sur longhorn, elle est très simple à installer via « Apps ».

Puis on indique le point de montage /etc/gitlab :

Et voilà, vous venez de créer votre premier workload sous Rancher :

Publication via traefik

C’est exactement comme précédemment pour pgadmin, allez dans « Load balancing » puis « Add ingress » :

A découvrir : bastion SSH via SNI, cert-manager et nfs-provisioner

  • Vous pouvez déployer haproxy via rancher v1 sur votre cluster pour faire du SSH SNI : cela vous permet de mettre en place un bastion SSH facilement et donc donner accès en SSH à vos utilisateurs directement sur les containers souhaités. Par exemple, voici une configuration fonctionnelle pour un service load balancé en layer 4 pour SSH sur le port 2222 (test.dev) et le port 2223 (test2.dev) :
frontend fe_ssh
   bind *:22 ssl crt /etc/haproxy/certs/current/domain.local.pem
   mode tcp
   log-format "%ci:%cp [%t] %ft %b/%s %Tw/%Tc/%Tt %B %ts %ac/%fc/%bc/%sc/%rc %sq/%bq dst:%[var(sess.dst)] "
   tcp-request content set-var(sess.dst) ssl_fc_sni
   use_backend %[ssl_fc_sni]
backend test.dev
   mode tcp
   server s1 192.168.1.60:2222 check
backend test2.dev
   mode tcp
   server s2 192.168.1.62:2223 check

Un utilisateur pour se connecter pourra exécuter cette commande :

ssh -o ProxyCommand="openssl s_client -quiet -connect proxyssh.domain.local:22 -servername test.dev" test.dev

Sous Windows :

ssh -o ProxyCommand="C:\Program Files\OpenSSL-Win64\bin\openssl.exe s_client -quiet -connect proxyssh.domain.local:22 -servername test.dev" test.dev
  • Cert-manager peut vous permettre de créer et gérer vos certificats via letsencrypt de manière complétement automatique : https://cert-manager.io/docs/configuration/acme/
  • Un disque persistant sous longhorn n’étant, de base, qu’en mode « single node », une mise à jour d’un workload va couper le service le temps du redémarrage, pour pallier à ça, vous pouvez déployer nfs-provisioner sur longhorn et utiliser le storageClass associé. Ainsi toute mise à jour n’entrainera aucune coupure du service ! Vous pouvez aussi activer NFS directement sur longhorn (fonctionnalité béta)