An English version of this post is available.

Moby Dock, la baleine mascotte de Docker

Configuration de la Registry

Basiques

Habituellement le repertoire /srv/ est utilisé pour stocker les données spécifiques à un système qui doivent être publiées. Pourtant, on va utiliser /srv/docker/onsen-registry pour stocker toute la configuration de notre registry locale. Toutes les donnnées spécifique à la configuration de la registry seront stockées sur un unique nœud du swarm docker et ne seront pas partagées avec les autres nœuds du swarm.

mkdir -p /srv/docker/onsen-registry/

Néanmoins, comme les données de la registry sont volatiles, on choisira de les stocker sous /var/lib/registry.

mkdir -p /var/lib/registry/

Configuration TLS

On n'a pas de PKI pour gérer les certificats. Donc on crée un certificat x509 et la clé privée correspondante pour la registry. Elle nous permettra de démarrer la registry avec TLS d'activé et, ainsi, pouvoir utiliser l'authentification basique native. TLS doit être configuré pour l'authentification basique car les informations d'authentifiction lui sont transmises sans chiffrement.

Une fois le certificat et la clé générés, on les stocke en tant que secrets docker swarm sur le nœud afin de pouvoir les utiliser dans la définition de notre service.

mkdir -p /srv/docker/onsen-registry/auth
cd /srv/docker/onsen-registry/
openssl req -newkey rsa:4096 -nodes -sha256 -x509 -days 365 -keyout certs/registry.onsen.lan.key -out certs/registry.onsen.lan.crt
docker secret create registry.onsen.lan.key certs/registry.onsen.lan.key
docker secret create registry.onsen.lan.crt certs/registry.onsen.lan.crt

Restreindre l'accès

On génére un fichier d'authentification basique en utilisant un fichier htpasswd. Le seul format de mot de passe supporté est bcrypt.

htpasswd -Bn lenain > auth/htpasswd

Ajout d'un label au nœud du Docker Swarm

On a besoin d'ajouter un laber à notre nœud du Docker Swarm pour que la registry y reste attaché. C'est nécessaire car les informations d'authentification et les données de la registry ne seront accessible que depuis les systèmes de fichier de ce nœud.

docker node update --label-add registry=true kawaii

Registry en tant que Service Docker Swarm

Définir le service avec Docker Compose

Voici le fichier docker-compose.yml :

version: "3.7"
services:
  registry:
    image: "registry:2"
    environment:
      - REGISTRY_AUTH=htpasswd
      - REGISTRY_AUTH_HTPASSWD_REALM="Onsen Registry"
      - REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
      - REGISTRY_HTTP_ADDR=0.0.0.0:5000
      - REGISTRY_HTTP_TLS_CERTIFICATE=/run/secrets/registry.onsen.lan.crt
      - REGISTRY_HTTP_TLS_KEY=/run/secrets/registry.onsen.lan.key
    secrets:
      - registry.onsen.lan.crt
      - registry.onsen.lan.key
    ports:
      - "5000:5000"
    volumes:
      - type: "bind"
        source: /var/lib/registry
        target: /var/lib/registry
      - type: "bind"
        source: /srv/docker/onsen-registry/auth
        target: /auth
        read_only: true
    deploy:
      placement:
        constraints:
          - node.labels.registry == true
secrets:
  registry.onsen.lan.crt:
    external: true
  registry.onsen.lan.key:
    external: true

Tout coule un peu de source :

  • Les données de la registry sont stockées dans le dossier du nœud swarn dans /var/lib/registry.
  • Le repertoire auth créé précédemment est monté en lecture seule pour pouvoir choisir le type d'authentification htpasswd.
  • Le service découvre les secrets du certificat X509 et de la clé privée depuis le nœud, comme ils sont montés dans /run/secrets. TLS est configuré pour les utiliser.
  • Le port 5000 est exposé tel quel sur le nœud.
  • Enfin, on ajoute une contrainte de placement afin que la registry ne soit déployée que sur un nœud ayant le label registry configuré à true. Évidemment, on souhaite qu'il n'y ait que le nœud du Docker Swarm ayant les données de la registry et des informations d'authentification à avoir ce label.

Deployer la stack

Classique :

docker stack deploy --compose-file docker-compose.yml onsen-registry

Utiliser la registry

Configurer les démons Docker

Chaque démon Docker des nœud du Docker Swarm ont besoin d'approuver notre registry fraîchement créée.

Pour faire cela, on a besoin de copier le certificat de la registry à un endroit spécifique sur chacun des nœuds pour permettre aux démons Docker d'avoir l'information que cette registry est approuvée et de confiance.

mkdir -p /etc/docker/certs.d/registry.onsen.lan:5000/
cp registry.onsen.lan.crt /etc/docker/certs.d/registry.onsen.lan:5000/ca.crt

Pas besoin de relancer le démon Docker.

Vérifier notre registry

Configurer un gestionnaire d'information d'authentification

Sur Debian, on peut utiliser pass pour stocker notre mot de passe de connexion à la registry.

En tant que root:

apt install pass
curl -sLO https://github.com/docker/docker-credential-helpers/releases/download/v0.6.0/docker-credential-pass-v0.6.0-amd64.tar.gz && \
    tar xvf docker-credential-pass-v0.6.0-amd64.tar.gz && \
    mv docker-credential-pass /usr/bin/. && \
    rm docker-credential-pass-v0.6.0-amd64.tar.gz

En tant qu'utilisateur Docker:

gpg2 --gen-key # Si nécessaire
pass init lenain

Se connecter

Désormais, on peut maintenant se connecter sur notre registry depuis n'importe quel hôte de notre swarm:

docker login registry.onsen.lan:5000

Pousser et tirer vers/depuis la registry

# Tirer du hub Docker
docker pull alpine:latest
# Tagguer pour la registry
docker tag alpine:latest registry.onsen.lan:5000/my-alpine
# Pousser dans la registry
docker push registry.onsen.lan:5000/my-alpine
# Supprimer l'image locale
docker rmi registry.onsen.lan:5000/my-alpine:latest
# Tirer depuis la registry
docker pull registry.onsen.lan:5000/my-alpine:latest

Se déconnecter

Si l'on a plus besoin d'utiliser la registry:

docker logout registry.onsen.lan:5000

Vérifier le contenu de la registry

On peut requêter la registry pour lister toutes les images disponibles. Ceci peut être fait même si l'on est pas loggués via le démon Docker.

curl -su lenain -k "https://registry.onsen.lan:5000/v2/_catalog"
Enter host password for user 'lenain':
{"repositories":["my-alpine"]}