Recherche de site Web

Comment configurer un registre Docker privé sur Ubuntu 18.04


Vous n'utilisez pas Ubuntu 18.04 ?Choisissez une autre version ou distribution.

L'auteur a choisi la Apache Software Foundation pour recevoir un don dans le cadre du programme Write for Donations.

Introduction

Docker Registry est une application qui gère le stockage et la distribution des images de conteneurs Docker. Les registres centralisent les images de conteneurs et réduisent les temps de construction pour les développeurs. Les images Docker garantissent le même environnement d'exécution grâce à la virtualisation, mais la création d'une image peut nécessiter un investissement en temps important. Par exemple, plutôt que d'installer les dépendances et les packages séparément pour utiliser Docker, les développeurs peuvent télécharger une image compressée depuis un registre contenant tous les composants nécessaires. De plus, les développeurs peuvent automatiser l'envoi d'images vers un registre en utilisant des outils d'intégration continue, tels que TravisCI, afin de mettre à jour les images de manière transparente pendant la production et le développement.

Docker dispose également d'un registre public gratuit, Docker Hub, qui peut héberger vos images Docker personnalisées, mais il y a des situations où vous ne voudrez pas que votre image soit disponible publiquement. Les images contiennent généralement tout le code nécessaire pour exécuter une application, donc l'utilisation d'un registre privé est préférable lors de l'utilisation de logiciels propriétaires.

Dans ce tutoriel, vous allez configurer et sécuriser votre propre registre Docker privé. Vous utiliserez Docker Compose pour définir les configurations permettant d'exécuter vos applications Docker et Nginx pour transférer le trafic serveur de HTTPS vers le conteneur Docker en cours d'exécution. Une fois ce tutoriel terminé, vous pourrez pousser une image Docker personnalisée vers votre registre privé et récupérer l'image en toute sécurité depuis un serveur distant.

Prérequis

Avant de commencer ce guide, vous aurez besoin des éléments suivants :

  • Deux serveurs Ubuntu 18.04 configurés en suivant le guide de configuration initiale du serveur Ubuntu 18.04, incluant un utilisateur sudo non-root et un pare-feu. Un serveur hébergera votre registre Docker privé et l'autre sera votre serveur client.
  • Docker et Docker-Compose installés sur les deux serveurs en suivant le tutoriel Comment installer Docker-Compose sur Ubuntu 18.04. Vous n'avez besoin de compléter que la première étape de ce tutoriel pour installer Docker Compose. Ce tutoriel explique comment installer Docker dans le cadre de ses prérequis.
  • Nginx installé sur votre serveur privé Docker Registry en suivant le guide Comment installer Nginx sur Ubuntu 18.04.
  • Nginx sécurisé avec Let’s Encrypt sur votre serveur pour le registre Docker privé, en suivant Comment sécuriser Nginx avec Let’s Encrypt. Assurez-vous de rediriger tout le trafic de HTTP vers HTTPS à l'étape 4.
  • Un nom de domaine qui résout vers le serveur que vous utilisez pour le registre Docker privé. Vous le configurerez dans le cadre de la condition préalable de Let’s Encrypt.

Étape 1 — Installation et configuration du registre Docker

L'outil en ligne de commande Docker est utile pour démarrer et gérer un ou deux conteneurs Docker, mais, pour un déploiement complet, la plupart des applications s'exécutant à l'intérieur de conteneurs Docker nécessitent que d'autres composants fonctionnent en parallèle. Par exemple, de nombreuses applications web se composent d'un serveur web, comme Nginx, qui sert le code de l'application, d'un langage de script interprété tel que PHP, et d'un serveur de base de données comme MySQL.

Avec Docker Compose, vous pouvez écrire un seul fichier .yml pour configurer chaque conteneur et les informations dont les conteneurs ont besoin pour communiquer entre eux. Vous pouvez ensuite utiliser l'outil en ligne de commande docker-compose pour émettre des commandes à tous les composants qui composent votre application.

Docker Registry est lui-même une application avec plusieurs composants, donc vous utiliserez Docker Compose pour gérer votre configuration. Pour démarrer une instance du registre, vous configurerez un fichier docker-compose.yml pour définir l'emplacement où votre registre stockera ses données.

Sur le serveur que vous avez créé pour héberger votre registre Docker privé, vous pouvez créer un répertoire docker-registry, y entrer, puis créer un sous-dossier data avec les commandes suivantes :

mkdir ~/docker-registry && cd $_

mkdir data

Utilisez votre éditeur de texte pour créer le fichier de configuration docker-compose.yml :

nano docker-compose.yml

Ajoutez le contenu suivant au fichier, qui décrit la configuration de base pour un Docker Registry :

version: '3'

services:
  registry:
    image: registry:2
    ports:
    - "5000:5000"
    environment:
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./data:/data

La section environment définit une variable d'environnement dans le conteneur Docker Registry avec le chemin /data. L'application Docker Registry vérifie cette variable d'environnement lorsqu'elle démarre, et par conséquent commence à enregistrer ses données dans le dossier /data.

Cependant, comme vous avez inclus la ligne volumes: - ./data:/data, Docker commencera à mapper le répertoire /data dans ce conteneur vers /data sur votre serveur de registre. Le résultat final est que toutes les données du registre Docker sont stockées dans ~/docker-registry/data sur le serveur de registre.

La section ports, avec la configuration 5000:5000, indique à Docker de mapper le port 5000 sur le serveur au port 5000 dans le conteneur en cours d'exécution. Cela vous permet d'envoyer une requête au port 5000 sur le serveur et de faire en sorte que la requête soit transmise à l'application de registre.

Vous pouvez maintenant démarrer Docker Compose pour vérifier la configuration :

docker-compose up

Vous verrez des barres de téléchargement dans votre sortie qui montrent Docker en train de télécharger l'image du Docker Registry depuis le propre registre de Docker. En une minute ou deux, vous verrez une sortie qui ressemble à ce qui suit (les versions peuvent varier) :

Output of docker-compose up
Starting docker-registry_registry_1 ... done Attaching to docker-registry_registry_1 registry_1 | time="2018-11-06T18:43:09Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="redis not configured" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="Starting upload purge in 20m0s" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2 registry_1 | time="2018-11-06T18:43:09Z" level=info msg="listening on [::]:5000" go.version=go1.7.6 instance.id=c63483ee-7ad5-4205-9e28-3e809c843d42 version=v2.6.2

Vous traiterez le message d'avertissement No HTTP secret provided plus tard dans ce tutoriel. La sortie montre que le conteneur est en train de démarrer. La dernière ligne de la sortie montre qu'il a réussi à commencer à écouter sur le port 5000.

Par défaut, Docker Compose restera en attente de votre saisie, alors appuyez sur CTRL+C pour arrêter votre conteneur Docker Registry.

Vous avez configuré un registre Docker complet écoutant sur le port 5000. À ce stade, le registre ne démarrera pas à moins que vous ne le lanciez manuellement. De plus, le registre Docker ne dispose d'aucun mécanisme d'authentification intégré, il est donc actuellement non sécurisé et complètement ouvert au public. Dans les étapes suivantes, vous traiterez ces problèmes de sécurité.

Étape 2 — Configuration du transfert de port Nginx

Vous avez déjà configuré HTTPS sur votre serveur Docker Registry avec Nginx, ce qui signifie que vous pouvez maintenant configurer le transfert de port de Nginx vers le port 5000. Une fois cette étape terminée, vous pourrez accéder directement à votre registre à l'adresse example.com.

Dans le cadre du prérequis Comment sécuriser Nginx avec Let’s Encrypt, vous avez déjà configuré le fichier /etc/nginx/sites-available/example.com contenant votre configuration de serveur.

Ouvrez ce fichier avec votre éditeur de texte :

sudo nano /etc/nginx/sites-available/example.com

Trouvez la ligne location existante. Elle ressemblera à ceci :

...
location / {
  ...
}
...

Vous devez rediriger le trafic vers le port 5000, où votre registre sera en fonctionnement. Vous souhaitez également ajouter des en-têtes à la requête vers le registre, qui fournissent des informations supplémentaires du serveur avec chaque requête et réponse. Supprimez le contenu de la section location, et ajoutez le contenu suivant dans cette section :

...
location / {
    # Do not allow connections from docker 1.5 and earlier
    # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
    if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
      return 404;
    }

    proxy_pass                          http://localhost:5000;
    proxy_set_header  Host              $http_host;   # required for docker client's sake
    proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
    proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header  X-Forwarded-Proto $scheme;
    proxy_read_timeout                  900;
}
...

La section $http_user_agent vérifie que la version Docker du client est supérieure à 1.5, et s'assure que le UserAgent n'est pas une application Go. Puisque vous utilisez la version 2.0 du registre, les anciens clients ne sont pas pris en charge. Pour plus d'informations, vous pouvez trouver la configuration de l'en-tête nginx dans le guide Nginx du registre Docker.

Enregistrez et quittez le fichier. Appliquez les modifications en redémarrant Nginx :

sudo service nginx restart

Vous pouvez confirmer que Nginx redirige le trafic vers le port 5000 en exécutant le registre :

cd ~/docker-registry

docker-compose up

Dans une fenêtre de navigateur, ouvrez l'URL suivante :

https://example.com/v2

Vous verrez un objet JSON vide, ou :

{}

Dans votre terminal, vous verrez une sortie similaire à la suivante :

Output of docker-compose up
registry_1 | time="2018-11-07T17:57:42Z" level=info msg="response completed" go.version=go1.7.6 http.request.host=cornellappdev.com http.request.id=a8f5984e-15e3-4946-9c40-d71f8557652f http.request.method=GET http.request.remoteaddr=128.84.125.58 http.request.uri="/v2/" http.request.useragent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7" http.response.contenttype="application/json; charset=utf-8" http.response.duration=2.125995ms http.response.status=200 http.response.written=2 instance.id=3093e5ab-5715-42bc-808e-73f310848860 version=v2.6.2 registry_1 | 172.18.0.1 - - [07/Nov/2018:17:57:42 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_2) AppleWebKit/604.4.7 (KHTML, like Gecko) Version/11.0.2 Safari/604.4.7"

Vous pouvez voir à partir de la dernière ligne qu'une requête GET a été faite vers /v2/, qui est le point de terminaison vers lequel vous avez envoyé une demande depuis votre navigateur. Le conteneur a reçu la requête que vous avez faite, via le transfert de port, et a renvoyé une réponse de {}. Le code 200 dans la dernière ligne de la sortie signifie que le conteneur a traité la requête avec succès.

Maintenant que vous avez configuré le transfert de port, vous pouvez passer à l'amélioration de la sécurité de votre registre.

Étape 3 — Configuration de l'authentification

Avec Nginx acheminant correctement les requêtes, vous pouvez maintenant sécuriser votre registre avec une authentification HTTP pour gérer qui a accès à votre Docker Registry. Pour ce faire, vous allez créer un fichier d'authentification avec htpasswd et y ajouter des utilisateurs. L'authentification HTTP est rapide à mettre en place et sécurisée via une connexion HTTPS, que le registre utilisera.

Vous pouvez installer le paquet htpasswd en exécutant ce qui suit :

sudo apt install apache2-utils

Maintenant, vous allez créer le répertoire où vous stockerez nos informations d'identification pour l'authentification, et changer pour ce répertoire. $_ s'étend au dernier argument de la commande précédente, dans ce cas ~/docker-registry/auth :

mkdir ~/docker-registry/auth && cd $_

Ensuite, vous allez créer le premier utilisateur comme suit, en remplaçant username par le nom d'utilisateur que vous souhaitez utiliser. Le drapeau -B spécifie le cryptage bcrypt, qui est plus sûr que le cryptage par défaut. Entrez le mot de passe lorsqu'il vous est demandé :

htpasswd -Bc registry.password username

Remarque : Pour ajouter plus d'utilisateurs, relancez la commande précédente sans l'option -c, (le c est pour créer) :

htpasswd registry.password username

Ensuite, vous allez modifier le fichier docker-compose.yml pour indiquer à Docker d'utiliser le fichier que vous avez créé pour authentifier les utilisateurs.

cd ~/docker-registry

nano docker-compose.yml

Vous pouvez ajouter des variables d'environnement et un volume pour le répertoire auth/ que vous avez créé, en modifiant le fichier docker-compose.yml pour indiquer à Docker comment vous souhaitez authentifier les utilisateurs. Ajoutez le contenu en surbrillance suivant au fichier :

version: '3'

services:
  registry:
    image: registry:2
    ports:
    - "5000:5000"
    environment:
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/registry.password
      REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
    volumes:
      - ./auth:/auth
      - ./data:/data

Pour REGISTRY_AUTH, vous avez spécifié htpasswd, qui est le schéma d'authentification que vous utilisez, et défini REGISTRY_AUTH_HTPASSWD_PATH sur le chemin du fichier d'authentification. Enfin, REGISTRY_AUTH_HTPASSWD_REALM signifie le nom du domaine htpasswd.

Vous pouvez maintenant vérifier que votre authentification fonctionne correctement en exécutant le registre et en vérifiant qu'il demande aux utilisateurs un nom d'utilisateur et un mot de passe.

docker-compose up

Dans une fenêtre de navigateur, ouvrez https://example.com/v2.

Après avoir saisi nom d'utilisateur et le mot de passe correspondant, vous verrez de nouveau {}. Vous avez confirmé la configuration de l'authentification de base : le registre n'a retourné le résultat qu'après que vous avez saisi le nom d'utilisateur et le mot de passe corrects. Vous avez maintenant sécurisé votre registre et pouvez continuer à utiliser le registre.

Étape 4 — Démarrage du registre Docker en tant que service

Vous voulez vous assurer que votre registre démarre chaque fois que le système démarre. S'il y a des pannes système imprévues, vous voulez vous assurer que le registre redémarre lorsque le serveur redémarre. Ouvrez docker-compose.yml :

nano docker-compose.yml

Ajoutez la ligne de contenu suivante sous registry : :

...
  registry:
    restart: always
...

Vous pouvez démarrer votre registre en tant que processus en arrière-plan, ce qui vous permettra de quitter la session ssh et de laisser le processus persister :

docker-compose up -d

Avec votre registre en fonctionnement en arrière-plan, vous pouvez maintenant préparer Nginx pour les téléchargements de fichiers.

Étape 5 — Augmenter la taille de téléchargement des fichiers pour Nginx

Avant de pouvoir pousser une image vers le registre, vous devez vous assurer que votre registre pourra gérer des téléchargements de fichiers volumineux. Bien que Docker divise les téléchargements d'images volumineuses en couches séparées, elles peuvent parfois dépasser 1GB. Par défaut, Nginx a une limite de 1MB sur les téléchargements de fichiers, vous devez donc modifier le fichier de configuration de nginx et définir la taille maximale de téléchargement de fichier à 2GB.

sudo nano /etc/nginx/nginx.conf

Trouvez la section http, et ajoutez la ligne suivante :

...
http {
        client_max_body_size 2000M;
        ...
}
...

Enfin, redémarrez Nginx pour appliquer les modifications de configuration :

sudo service nginx restart

Vous pouvez désormais télécharger de grandes images sur votre registre Docker sans erreurs Nginx.

Étape 6 — Publication dans votre registre Docker privé

Vous êtes maintenant prêt à publier une image sur votre registre Docker privé, mais vous devez d'abord créer une image. Pour ce tutoriel, vous allez créer une image simple basée sur l'image ubuntu de Docker Hub. Docker Hub est un registre hébergé publiquement, avec de nombreuses images préconfigurées qui peuvent être utilisées pour Dockeriser rapidement des applications. En utilisant l'image ubuntu, vous testerez le push et le pull vers votre registre.

Depuis votre client serveur, créez une petite image vide à pousser vers votre nouveau registre, les options -i et -t vous donnent un accès shell interactif dans le conteneur :

docker run -t -i ubuntu /bin/bash

Une fois le téléchargement terminé, vous serez à l'intérieur d'une invite Docker. Notez que votre ID de conteneur après root@ variera. Apportez un petit changement au système de fichiers en créant un fichier appelé SUCCESS. Lors de l'étape suivante, vous pourrez utiliser ce fichier pour déterminer si le processus de publication est réussi :

touch /SUCCESS

Sortez du conteneur Docker :

exit

La commande suivante crée une nouvelle image appelée test-image basée sur l'image déjà en cours d'exécution ainsi que sur les modifications que vous avez apportées. Dans notre cas, l'ajout du fichier /SUCCESS est inclus dans la nouvelle image.

Valider la modification :

docker commit $(docker ps -lq) test-image

À ce stade, l'image n'existe que localement. Vous pouvez maintenant la pousser vers le nouveau registre que vous avez créé. Connectez-vous à votre registre Docker :

docker login https://example.com

Entrez le nom d'utilisateur et le mot de passe correspondant précédemment. Ensuite, vous allez étiqueter l'image avec l'emplacement du registre privé afin de la pousser :

docker tag test-image example.com/test-image

Poussez l'image nouvellement étiquetée vers le registre :

docker push example.com/test-image

Votre sortie ressemblera à ce qui suit :

The push refers to a repository [example.com/test-image]
e3fbbfb44187: Pushed
5f70bf18a086: Pushed
a3b5c80a4eba: Pushed
7f18b442972b: Pushed
3ce512daaf78: Pushed
7aae4540b42d: Pushed
...

Vous avez vérifié que votre registre gère l'authentification des utilisateurs et permet aux utilisateurs authentifiés de pousser des images vers le registre. Ensuite, vous allez confirmer que vous êtes également capable de tirer des images du registre.

Étape 7 — Tirer depuis votre registre Docker privé

Retournez à votre serveur de registre afin de pouvoir tester le téléchargement de l'image depuis votre serveur client. Il est également possible de tester cela depuis un troisième serveur.

Connectez-vous avec le nom d'utilisateur et le mot de passe que vous avez configurés précédemment :

docker login https://example.com

Vous êtes maintenant prêt à récupérer l'image. Utilisez votre nom de domaine et le nom de l'image, que vous avez étiquetés à l'étape précédente :

docker pull example.com/test-image

Docker téléchargera l'image et vous ramènera à l'invite. Si vous exécutez l'image sur le serveur de registre, vous verrez que le fichier SUCCESS que vous avez créé précédemment est présent :

docker run -it example.com/test-image /bin/bash

Listez vos fichiers dans le shell bash :

ls

Vous verrez le fichier SUCCESS que vous avez créé pour cette image :

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

Vous avez terminé de configurer un registre sécurisé vers lequel les utilisateurs peuvent pousser et tirer des images personnalisées.

Conclusion

Dans ce tutoriel, vous configurez votre propre registre Docker privé et publiez une image Docker. Comme mentionné dans l'introduction, vous pouvez également utiliser TravisCI ou un outil CI similaire pour automatiser le push vers un registre privé directement. En intégrant Docker et les registres dans votre flux de travail, vous pouvez vous assurer que l'image contenant le code produira le même comportement sur n'importe quelle machine, que ce soit en production ou en développement. Pour plus d'informations sur l'écriture de fichiers Docker, vous pouvez lire ce tutoriel Docker expliquant le processus.