Aller au contenu
  1. Docs/
  2. K3s Kubernetes/

Docker registry setup

·Temps de lecture : 11 minutes· loading · loading · ·
K3s Kubernetes Docker Registry TLS Longhorn MetalLB DevOps
ksh2177
Auteur
ksh2177
Ingénieur DevOps passionné par l’automatisation, la fiabilité et le design système.
Table des matières
Ce guide permet d’installer un registre Docker avec TLS, en activant HTTPS, avec un certificat auto-signé. Ceci est principalement requis pour OpenFaaS.

☸ Namespace
#

je vais installer tout ce qui concerne Docker-registry dans son propre namespace répertoire appelé docker-registry. Nous allons donc d’abord créer cela :

kubectl create namespace docker-registry

💾 Stockage
#

Étant donné que nous allons stocker les images Docker dans notre registre personnel pour les utiliser ultérieurement avec OpenFaaS, il serait dommage qu’elles disparaissent à chaque fois que le pod se reprogramme vers un autre nœud.

Nous avons besoin d’un stockage persistant qui suit notre pod partout et lui fournit les mêmes données à tout moment.

Si vous avez suivi ma configuration, vous devriez déjà avoir installé Longhorn.

⛃ Réclamation de volume persistant
#

Un volume PersistentVolumeClaim est utilisé pour monter un PersistentVolume dans un Pod. Les PersistentVolumeClaims permettent aux utilisateurs de « réclamer » un stockage durable (tel qu’un GCE PersistentDisk ou un volume iSCSI) sans connaître les détails de l’environnement cloud particulier.

Nous allons créer un nouveau dossier appelé docker-registry et un nouveau fichier pvc.yaml dedans.

cd
mkdir docker-registry
cd  docker-registry
nano pvc.yaml
Dans notre  pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: longhorn-docker-registry-pvc
  namespace: docker-registry
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: longhorn
  resources:
    requests:
      storage: 15Gi

Nous demandons à Kubernetes d’utiliser Longhorn comme classe de stockage et de réclamer/créer 15 Go d’espace disque pour le stockage persistant. Nous l’appellerons longhorn-docker-registry-pvc, et nous le référencerons sous ce nom plus tard.

Notez que j’ai spécifié namespace. Ceci est important, car seuls les pods/déploiements dans cet espace de noms pourraient voir le disque.

👉🏻 Pour en savoir plus sur les volumes, consultez la documentation officielle ici : https://kubernetes.io/docs/concepts/storage/persistent-volumes/

Appliquez nos pvc.yaml:

kubectl apply -f pvc.yaml

Et vérifiez

root@control0:/root/docker-registry# kubectl get pvc -n docker-registry
NAME                           STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   VOLUMEATTRIBUTESCLASS   AGE
longhorn-docker-registry-pvc   Bound    pvc-2cdadf01-06be-4702-9a75-08f5d7754f2c   15Gi       RWO            longhorn       <unset>                 19d

#longhorn devrait automatiquement créer le PV ( physical volume )
root@control00:/root/docker-registry# kubectl get pv -n docker-registry
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                          STORAGECLASS   VOLUMEATTRIBUTESCLASS   REASON   AGE
pvc-2cdadf01-06be-4702-9a75-08f5d7754f2c   15Gi       RWO            Delete           Bound    docker-registry/longhorn-docker-registry-pvc   longhorn       

Cool, cool : maintenant nous avons du stockage ! (Le statut peut être différent, quelque chose comme : Non attaché)

📑 Création de certificats pour le registre Docker
#

J’ai littéralement passé plus de 24 heures pour faire fonctionner cela avec la configuration que j’ai, y compris OpenFaaS et ainsi de suite… donc j’espère que je n’ai oublié aucune étape. 😄

Générez des certificats dans votre répertoire docker-register :

#Installez openssl si ce n'est pas déjà le cas
sudo apt-get install openssl

🔐 Générer un certificat et une clé
#

openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes -keyout registry.key -out registry.crt -subj "/CN=registry.cube.local" -addext "subjectAltName=DNS:registry.cube.local,DNS:*.cube.local,IP:192.168.1.202"
mon entrée dans /etc/hosts pour le registre sera 192.168.1.202 registry registry.cube.local. Je sais quelle IP ce sera, car nous la définirons plus tard (vous vous souvenez de metalLB ?), et il n’y a pas de serveur DNS, donc chaque nœud devra l’avoir dans /etc/hosts. Appelez-le comme vous voulez, mais ajoutez les noms corrects dans les paramètres subjectAltName. Sans cela, il pourrait y avoir des problèmes où certains outils se plaignent de certificats mal signés et de SAN manquant. Quelque chose comme : x509: cannot validate certificate for <IP> because it doesn't contain any IP SANs

Vous avez maintenant deux nouveaux fichiers dans votre docker-registry répertoire :

root@control00:~/docker-registry# ls | grep regis
registry.crt
registry.key

🛡️ Ajout de TLS au secret Kubernetes
#

Avant, j’avais un disque séparé dans Longhorn pour les certificats et je devais copier les certificats là-bas, puis les attacher au pod. Cela fonctionnait bien, mais il existe une solution plus simple. Le secret Kubernetes est un moyen de stocker les secrets dans le cluster.

Les secrets individuels sont limités à 1 Mio. Avoir trop de secrets dans le cluster peut entraîner des problèmes de performances.

Créez un secret dans votre docker-registry espace de noms à partir des fichiers registry.crt et registry.key :

kubectl create secret tls docker-registry-tls-cert -n docker-registry --cert=registry.crt --key=registry.key
Nous créons un type de secret spécial tls. Il s’agit d’un type de secret spécial utilisé pour stocker les certificats TLS. Pour en savoir plus sur les secrets, cliquez ici : https://kubernetes.io/docs/concepts/configuration/secret/

En substance, considérez-le comme un stockage interne pour les secrets du cluster. Ceux-ci sont ensuite placés sous forme de fichiers à l’intérieur du pod. Vous les verrez dans les fichiers de déploiement.

Si vous voulez voir vos secrets, vous pouvez le faire comme ceci :

kubectl get secret docker-registry-tls-cert -o yaml  -n docker-registry

Vous pouvez également l’enregistrer dans un fichier à partir de cette sortie et l’appliquer de la même manière que n’importe quel fichier yaml dont vous disposez. Supprimez-les simplement de metadata:

metadata:
  creationTimestamp: "2022-05-25T18:26:52Z"  <-- REMOVE
  name: docker-registry-tls-cert
  namespace: docker-registry  <-- REMOVE
  resourceVersion: "55302"  <-- REMOVE
  uid: 35208da3-19f1-4259-bfd1-5b276bb5948c  <-- REMOVE

Vous pouvez alors avoir secret.yaml un fichier et le stocker dans git ou autre. Pas besoin de créer manuellement le secret. Cela vous aidera également si vous l’utilisez plus tard avec le déploiement gitops d’Argo CD.

🚀 Déploiement
#

Nous allons maintenant créer un déploiement simple du registre Docker et le laisser libre sur notre cluster Kubernetes.

Créez un fichier dans votre répertoire de registre Docker appelé docker.yaml :

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: registry
  namespace: docker-registry
spec:
  replicas: 1
  selector:
    matchLabels:
      app: registry
  template:
    metadata:
      labels:
        app: registry
        name: registry
    spec:
      nodeSelector:
        node-type: worker
      containers:
      - name: registry
        image: registry:2
        ports:
        - containerPort: 5000
        env:
        - name: REGISTRY_HTTP_TLS_CERTIFICATE
          value: "/certs/tls.crt"
        - name: REGISTRY_HTTP_TLS_KEY
          value: "/certs/tls.key"
        volumeMounts:
        - name: lv-storage
          mountPath: /var/lib/registry
          subPath: registry
        - name: certs
          mountPath: /certs
      volumes:
        - name: lv-storage
          persistentVolumeClaim:
            claimName: longhorn-docker-registry-pvc
        - name: certs
          secret:
            secretName: docker-registry-tls-cert

À quoi faut-il faire attention :

  • namespace - j’ai spécifié docker-registry.
  • replicas - j’en utilise 1, donc il n’y aura qu’un seul registre Docker en cours d’exécution.
  • nodeSelector - Comme mentionné précédemment lors de la configuration de mon Kubernetes, j’ai étiqueté les nœuds de travail avec node-type=worker. Cela permettra au déploiement de privilégier ces nœuds.
  • image - Cela indiquera à Kubernetes de télécharger le registre : 2 à partir du hub Docker officiel.
  • containerPort - Quel port le conteneur exposera/utilisera.
  • volumeMounts - Définition de l’endroit dans le pod où nous allons monter notre stockage persistant.
  • volumes - Définition où nous nous référons au PVC que nous avons créé auparavant.
  • env - Ceci sera transmis en tant que variables d’environnement dans le conteneur et utilisé par le registre Docker.

⛃ Montage de volume
#

En bas, vous pouvez voir que nous montons notre stockage persistant, mais nous montons également nos certificats. Nous nommons nos volumes lv-storage et certs. Veuillez noter que le certs volume est un secret et non une revendication de volume persistant.

⛁ volumes
#

Dans cette section, nous demandons au POD de monter notre longhorn-docker-registry-pvc sur /var/lib/registry. Comme ici, normalement, les images en direct sont téléchargées dans le registre. Nous montons également nos certificats sur /certs.

⚙️ env
#

Le registre Docker dispose d’options que vous pouvez influencer en définissant des variables d’environnement. Dans ce cas, nous définissons les variables d’environnement pour que le registre utilise nos certificats et leurs emplacements. Donc dans /certs/tls.crt et /certs/tls.key.

➡️ Appliquez le déploiement et attendez un peu que tout soit en ligne.
#

kubectl apply -f docker.yaml

Vérifiez avec :

# Deployment
root@control00:/root/docker-registry# kubectl get deployments -n docker-registry
NAME       READY   UP-TO-DATE   AVAILABLE   AGE
registry   1/1     1            1           21s
# Pods ( Il devrait y en avoir qu'un )
root@control00:/root/docker-registry# kubectl get pods -n docker-registry
NAME                       READY   STATUS    RESTARTS   AGE
registry-6fdc5fc5d-npslq   1/1     Running   0          29s

Nous n’avons pas encore terminé. Nous devons également créer un service pour rendre le registre disponible à l’échelle du cluster, et idéalement sur la même adresse IP/le même nom à tout moment, quel que soit le nœud sur lequel il s’exécute.

🛠️ Service
#

Encore une fois, si vous avez suivi mes paramètres réseau, nous avons configuré metalLB pour nous fournir des adresses IP externes pour les pods. Par conséquent, nous l’utilisons comme service LoadBalancer pour notre registre Docker.

Dans votre dossier docker-registry, créez service.yaml et collez ce qui suit :

apiVersion: v1
kind: Service
metadata:
  name: registry-service
  namespace: docker-registry
spec:
  selector:
    app: registry
  type: LoadBalancer
  ports:
    - name: docker-port
      protocol: TCP
      port: 5000
      targetPort: 5000
  loadBalancerIP: 192.168.1.202

À quoi faut-il faire attention :

  • kind - Service, juste pour permettre à Kubernetes de savoir ce que nous créons.
  • name - Juste un nom pour notre service.
  • namespace - J’ai spécifié docker-registry, car le déploiement que nous ciblons se trouve dans cet espace de noms.
  • selector and app - La valeur de ceci est extraite de notre déploiement où ceci est défini : app: registry.
  • type - Ici, nous disons à Kubernetes que nous voulons LoadBalancer (MetalLB).
  • ports - Nous définissons port sur notre IP externe et targetPort (c’est le port à l’intérieur de l’application/conteneur).
  • loadBalancerIP - Ceci est facultatif, mais je l’ai inclus ici. Cela nous permettra de spécifier quelle IP nous voulons pour l’IP externe. Si vous supprimez cette ligne, MetalLB attribuera la prochaine IP libre du pool que nous lui avons alloué.

Appliquer le service :

kubectl apply -f service.yaml

Attendez quelques secondes pour obtenir l’IP et vérifiez :

root@control00:/root/docker-registry# kubectl get svc -n docker-registry
NAME               TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)          AGE
registry-service   LoadBalancer   10.43.5.16   192.168.1.202   5000:32096/TCP   7m48s

Fantastique ! Le service semble être opérationnel avec le port externe 5000. Concernant le port 32096 qui se trouve derrière, cela peut être différent pour vous. Il est attribué à un nœud sur lequel le pod est en cours d’exécution. En substance, c’est comme ça : IP externe : 5000 -> Nœud où se trouve le pod/conteneur : 32096 -> conteneur à l’intérieur : 5000. J’espère que cela a du sens 😄

Pour obtenir plus d’informations sur le service, nous pouvons demander à Kubectl de nous le décrire :

root@control00:/root/docker-registry# kubectl get svc -n docker-registry
NAME               TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)          AGE
registry-service   LoadBalancer   10.43.5.16   192.168.1.202   5000:32096/TCP   7m48s
root@control00:/root/docker-registry# kubectl describe svc registry-service  -n docker-registry
Name:                     registry-service
Namespace:                docker-registry
Labels:                   <none>
Annotations:              <none>
Selector:                 app=registry
Type:                     LoadBalancer
IP:                       10.43.5.16
IP:                       192.168.1.202
LoadBalancer Ingress:     192.168.1.202
Port:                     docker-port  5000/TCP
TargetPort:               5000/TCP
NodePort:                 docker-port  32096/TCP
Endpoints:                10.42.8.13:5000
Session Affinity:         None
External Traffic Policy:  Cluster
Events:
  Type    Reason        Age                  From                Message
  ----    ------        ----                 ----                -------
  Normal  IPAllocated   77s (x537 over 11m)  metallb-controller  Assigned IP "192.168.1.202"
  Normal  nodeAssigned  76s (x539 over 11m)  metallb-speaker     announcing from node "cube01"

➕ Ajouter un certificat root aux nœuds
#

Actuellement, nous avons un registre Docker compatible SSL ou TLS (Fuck it, je l’appellerai désormais HTTPS) exécuté sur Kubernetes. Cependant, puisque nous créons le certificat, nous devons l’ajouter en tant que certificat racine à nos nœuds, chacun d’entre eux ! Si nous ne le faisons pas, tout service qui essaie de l’utiliser se plaindra d’un certificat signé par une autorité inconnue ou quelque chose de similaire. Nous allons donc nous faire passer pour l’autorité comme ceci :

#Sur dietpi
ansible cube -b -m copy -a "src=registry.crt dest=/usr/local/share/ca-certificates/registry.crt"
ansible cube -b -m copy -a "src=registry.key dest=/usr/local/share/ca-certificates/registry.key"
ansible all -b -m shell -a "update-ca-certificates"

En substance, sur chaque nœud, vous devez copier notre registry.crt dans /usr/local/share/ca-certificates/, et exécuter update-ca-certificates, ce qui ajoutera notre certificat en tant que certificat racine. Cela trompera la vérification en lui faisant croire que nous sommes l’autorité pour le certificat (ce qui est le cas) et elle ne se plaindra pas.

Un exemple de réalisation manuelle :

root@control00:~ sudo cp registry.* /usr/local/share/ca-certificates/
root@control00:~ sudo update-ca-certificates
Updating certificates in /etc/ssl/certs...
1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.

🖧 Faire en sorte que K3s utilise un registre Docker privé
#

Je sais, je sais. Cela prend une éternité.

Voici d’où j’ai obtenu mes informations : https://rancher.com/docs/k3s/latest/en/installation/private-registry/

Ajoutez un nom DNS à /etc/hosts chaque nœud , je l’ai nommé comme ceci :

192.168.1.202 registry registry.cube.local

Une bonne idée est d’avoir le /etc/hosts joli et synchronisé entre tous les nœuds, je vais donc l’ajouter une fois dans le nœud control00 et le déplacer vers tous les nœuds à l’aide d’Ansible.

echo "192.168.1.202 registry registry.cube.local" >> /etc/hosts
ansible cube -b -m copy -a "src=https://homelab.scasse.com/etc/hosts dest=/etc/hosts"

Maintenant, dites-le à k3s. En tant que root, créez le fichier /etc/rancher/k3s/registries.yaml:

vi /etc/rancher/k3s/registries.yaml

Ajoutez ce qui suit :

mirrors:
  registry.cube.local:5000:
    endpoint:
      - "https://registry.cube.local:5000"
configs:
  registry.cube.local:
    tls:
      ca_file: "/usr/local/share/ca-certificates/registry.crt"
      key_file: "/usr/local/share/ca-certificates/registry.key"

Envoyez-le à chaque nœud de contrôle du cluster.

#Assurons-nous que le répertoire existe

ansible cube -b -m file -a "path=/etc/rancher/k3s state=directory"

📤 Copiez les fichiers
#

ansible cube -b -m copy -a "src=https://homelab.scasse.com/etc/rancher/k3s/registries.yaml dest=/etc/rancher/k3s/registries.yaml"

🧪 Test du registre Docker
#

Suivez le guide pour installer Docker à partir d’ici :

Nous allons télécharger un conteneur Ubuntu à partir du registre officiel Docker, le réétiqueter et le pousser vers notre registre.

root@control00:~# docker pull ubuntu:16.04
16.04: Pulling from library/ubuntu
3e30c5e4609a: Pull complete
be82da0c7e99: Pull complete
bdf04dffef88: Pull complete
2624f7934929: Pull complete
Digest: sha256:3355b6e4ba1b12071ba5fe9742042a2f10b257c908fbdfac81912a16eb463879
Status: Downloaded newer image for ubuntu:16.04
docker.io/library/ubuntu:16.04

root@control00:~# docker tag ubuntu:16.04 registry.cube.local:5000/my-ubuntu
root@control00:~# docker push registry.cube.local:5000/my-ubuntu
The push refers to repository [registry.cube.local:5000/my-ubuntu]
3660514ed6c6: Pushed
2f33c1b8271f: Pushed
753fcdb98fb4: Pushed
1632f6712b3f: Pushed
latest: digest: sha256:2e459e7ec895eb5f94d267fb33ff4d881699dcd6287f27d79df515573cd83d0b size: 1150

# Vérifiez avec curl
root@control00:~# curl https://registry.cube.local:5000/v2/_catalog
{"repositories":["my-ubuntu"]}

Ouais ! Ça a marché

J’espère que c’est tout ; félicitations pour être arrivé jusqu’ici. Maintenant, prends un café et offre-moi-en un aussi 🙂

Articles connexes

Docker setup
·Temps de lecture : 2 minutes· loading · loading
K3s Kubernetes Docker OpenFaaS ARM64 Registry Buildx Homelab DevOps
Installation de Docker avec support multi-arch sur DietPi pour builder localement des fonctions OpenFaaS en arm64 et publier sur un registre privé.
Network settings
·Temps de lecture : 4 minutes· loading · loading
K3s Kubernetes MetalLB LoadBalancer Helm Network ClusterIP Homelab DevOps
Déploiement de MetalLB pour gérer des adresses IP externes avec K3s : installation via Helm, configuration d’un pool d’IP et vérifications réseau.
Storage settings
·Temps de lecture : 9 minutes· loading · loading
K3s Kubernetes Storage Longhorn Ansible Raspberry Pi PersistentVolume DevOps Homelab
Choix, préparation et installation de Longhorn comme solution de stockage persistant Kubernetes pour K3s sur Raspberry Pi, avec montage automatique via Ansible.
Helm arkade
·Temps de lecture : 2 minutes· loading · loading
K3s Kubernetes Helm Arkade Package Manager CLI Tools DevOps Homelab
Installation de Helm et Arkade sur le cluster K3s : deux outils indispensables pour déployer et gérer des applications Kubernetes simplement.
Os settings
·Temps de lecture : 1 minutes· loading · loading
K3s Kubernetes DietPi Linux OS Iptables Ansible Homelab DevOps
Réglages système post-installation pour DietPi : mise à jour de l’OS, configuration réseau, iptables et préparation à Kubernetes.
Conf noeuds
·Temps de lecture : 4 minutes· loading · loading
K3s Kubernetes Ansible Raspberry Pi Homelab SSH Inventory Automation DevOps
Préparer les nœuds Raspberry Pi pour le cluster K3s : connectivité, SSH sans mot de passe, configuration d’Ansible et inventaire dynamique.
Matériel
·Temps de lecture : 2 minutes· loading · loading
K3s Kubernetes Raspberry Pi Homelab Hardware Cluster Storage Network
Liste complète du matériel utilisé pour construire un cluster K3s sur Raspberry Pi : compute, stockage, réseau et tests de performance.
Intro
· loading · loading
K3s Kubernetes
Mise en place du monitoring
Kube install
·Temps de lecture : 4 minutes· loading · loading
K3s Kubernetes Cluster Control Plane Ansible Labels Taints Homelab Automation
Installation de K3s sur le nœud maître, ajout des workers via Ansible, configuration des rôles, labels et variables d’environnement Kubernetes.