Automatiser la création de version d'une application avec semantic-release
Dans cet article, découvrez comment automatiser une création de version de votre application grâce à Semantic-Release : nommage des commits et configurations
Sommaire
Dans cet article, nous allons détailler, étape par étape, la mise en place d'une Docker Registry.
Une Docker Registry est une application qui permet de distribuer des images Docker au sein de votre organisation.
C'est un composant majeur dans l'écosystème Docker, car il va permettre :
Une image Docker est en quelque sorte une image disque qui contient l'arborescence d'une distribution linux, le code source d'une application et des binaires capables de la faire tourner.
Une image se construit à partir d'un fichier Dockerfile que l'on retrouve généralement à la racine des sources d'une application.
Docker met à disposition un registre d’images publiques : DockerHub. Dans ce registre, vous allez retrouver des images, telles que :
Docker propose également le dépôt d’images privées via une offre détaillée ici.
Nous allons déployer notre Docker Registry avec Docker Swarm Mode et Traefik, un reverse proxy qui va nous permettre d’associer un domaine à notre registre Docker.
Nous aurons besoin d’un nom de domaine, d’un serveur et d’un terminal.
Pour ce guide, je vais utiliser une instance OVH Public Cloud et un nom de domaine géré par OVH. Dans les grandes lignes, toutes les étapes critiques peuvent être reproduite sur n’importe quel environnement.
Partons d'une distribution récente, une Ubuntu 16.04 qui a le bon goût d'avoir dans ces dépôts une version de Docker à jour :
# Installation de Docker sudo apt-get update && sudo apt-get install docker.io curl # Ajoute l'utilisateur courant au groupe docker (si différent de root) sudo usermod -a -G docker $(id -un)
On se déconnecte du serveur, puis on se reconnecte pour initialiser Docker Swarm mode.
# Initialise Docker Swarm Mode docker swarm init
Traefik va nous permettre d'associer un domaine au conteneur dans lequel tournera la registry. Le gros avantage, c'est qu'il permet d'obtenir automatiquement un certificat TLS délivré par Let's Encrypt.
# Créer un réseau traefik docker network create --driver overlay traefik # Création d'un répertoire où seront stockés nos certificats sudo mkdir -p /opt/traefik
On va maintenant créer la définition de notre service Traefik. Créez un fichier à l'adresse $HOME/traefik.json dans lequel vous ajoutez :
{ "Name": "traefik", "TaskTemplate": { "ContainerSpec": { "Image": "traefik:v1.1.0", "Args": [ "--defaultentrypoints=http,https", "--entryPoints=Name:http Address::80 Redirect.EntryPoint:https", "--entryPoints=Name:https Address::443 TLS", "--acme", "--acme.entrypoint=https", "--acme.email=[email]", "--acme.storage=/data/acme.json", "--acme.ondemand=true", "--docker", "--docker.swarmmode", "--docker.exposedbydefault=false", "--docker.watch", "--web", "--logLevel=INFO" ], "Mounts": [ { "Type": "bind", "Source": "/var/run/docker.sock", "Target": "/var/run/docker.sock" }, { "Type": "bind", "Source": "/opt/traefik", "Target": "/data" } ] }, "RestartPolicy": { "Condition": "any", "MaxAttempts": 0 }, "Placement": { "Constraints": [ "node.role==manager" ] } }, "Mode": { "Replicated": { "Replicas": 1 } }, "UpdateConfig": { "Parallelism": 1, "FailureAction": "pause" }, "Networks": [ { "Target": "traefik" } ], "EndpointSpec": { "Mode": "vip", "Ports": [ { "Protocol": "tcp", "TargetPort": 80, "PublishedPort": 80 }, { "Protocol": "tcp", "TargetPort": 443, "PublishedPort": 443 }, { "Protocol": "tcp", "TargetPort": 8080, "PublishedPort": 8080 } ] } }
Important: Remplacez [email] par une adresse mail valide sans quoi, Let's Encrypt ne vous délivrera pas de certificat.
Il ne nous reste plus qu'à lancer le service en utilisant l'API Docker :
curl -XPOST --unix-socket /var/run/docker.sock http:/services/create -d @$HOME/traefik.json
Contrôlez que le service tourne en tapant docker service ls. Au bout d'un certain temps, vous allez voir 1/1 s'afficher en face du service traefik.
**Astuce **: Utilisez la commande watch pour exécuter la commande périodiquement par intervalles de 1 seconde : watch -n1 docker service ls. Ctrl+c pour quitter.
Sur le port 8080 de votre serveur vous devez trouver l'interface de contrôle de Traefik :
Avant de lancer la registry sur notre environnement, nous allons créer deux sous-domaines pointant vers notre serveur web :
Sur le manager d'OVH, il suffit de se rendre dans Web/Domaine(s), de choisir son domaine, puis de cliquer sur l'onglet Zone DNS
Puis nous ajoutons un pointage DNS de type A pour les sous-domaines :
Important: Remplacez domain.tld par votre domaine et xxx.xxx.xxx.xxx par l'adresse IPv4 de votre serveur.
Docker registry permet d'utiliser des services tiers pour gérer l'authentification et les contrôles d'accès des utilisateurs.
Nous allons utiliser ici Docker Registry 2 authentication server.
Cette application en GO prend en charge plusieurs backends. Vous avez au choix la possibilité de stocker vos utilisateurs et ACL dans MongoDB, d'utiliser un serveur LDAP, ou dans notre cas, d'utiliser un fichier YAML.
L'authentification des utilisateurs se fait par jeton JWT. La registry Docker, de son coté, attend que ces jetons soient signés par un certificat. Commençons par le générer :
# Préparation des répertoires nécessaires à docker auth
sudo mkdir -p /opt/docker-auth/{logs,config,certs}
# Génération du certificat
cd /opt/docker-auth/certs
sudo openssl req -x509 -newkey rsa:2048 -new -nodes -keyout privkey.pem -out fullchain.pem -subj "/C=FR/ST=Paris/L=Paris/O=ACME/OU=IT Department/CN=[domain.tld]"
**Note **: Remplacez [domain.tld] par votre nom de domaine
On crée un fichier de configuration contenant nos utilisateurs et nos règles d'accès dans /opt/docker-auth/config/auth_config.yml
server: addr: ":5001" token: issuer: "Acme auth server" # Doit correspondre à l'émetteur (issuer) indiqué dans la configuration du registre expiration: 900 # Expiration en secondes du jeton d'accès certificate: "/certs/fullchain.pem" key: "/certs/privkey.pem" # Les mots de passe sont hashés avec BCrypt (Utiliser htpasswd -B pour en générer un) users: "admin": password: "$2y$05$LO.vzwpWC5LZGqThvEfznu8qhb5SGqvBSWY1J3yZ4AxtMRZ3kN5jC" # badmin "test": password: "$2y$05$WuwBasGDAgr.QCbGIjKJaep4dhxeai9gNZdmBnQXqpKly57oNutya" # 123 "": {} # Autorise les accès anonymes au registre acl: - match: {account: "admin"} actions: ["*"] comment: "Tout est permit pour l'administrateur" - match: {account: "/.+/", name: "${account}/*"} actions: ["*"] comment: "Les utilisateurs enregistrés peuvent tirer et contribuer des images dans leur espace de nom" - match: {account: "/.+/"} actions: ["pull"] comment: "Les utilisateurs enregistrés peuvent tirer n'importe quelle image" - match: {account: ""} actions: ["pull"] comment: "Les utilisateurs anonymes peuvent tirer n'importe quelle image"
Créons enfin un fichier à l'adresse $HOME/docker-auth.json:
{ "Name": "docker-auth", "Labels": { "traefik.docker.network": "traefik", "traefik.enable": "true", "traefik.frontend.rule": "Host:[token.domain.tld]", "traefik.port": "5001" }, "TaskTemplate": { "ContainerSpec": { "Image": "cesanta/docker_auth:stable", "Args": [ "/config/auth_config.yml" ], "Mounts": [ { "Type": "bind", "Source": "/opt/docker-auth/config", "Target": "/config" }, { "Type": "bind", "Source": "/opt/docker-auth/logs", "Target": "/logs" }, { "Type": "bind", "Source": "/opt/docker-auth/certs", "Target": "/certs" } ] }, "RestartPolicy": { "Condition": "any", "MaxAttempts": 0 }, "Placement": { "Constraints": [ "node.role==manager" ] } }, "Mode": { "Replicated": { "Replicas": 1 } }, "UpdateConfig": { "Parallelism": 1, "FailureAction": "pause" }, "Networks": [ { "Target": "traefik" } ], "EndpointSpec": { "Mode": "vip" } }
**Important **: Remplacez [token.domain.tld] par le sous-domaine que vous avez créé précédemment pour le serveur d'authentification
On lance le service :
curl -XPOST --unix-socket /var/run/docker.sock http:/services/create -d @$HOME/docker-auth.json
Et on vérifie que le service docker-auth est bien lancé en utilisant la commande docker service ls.
Il ne nous reste plus qu'à mettre en place la registry.
Créons des répertoires qui contiendront nos images docker :
sudo mkdir -p /opt/registry
Puis on finit avec un fichier que l'on crée à l'adresse **$HOME/registry.json **:
{ "Name": "docker-registry", "Labels": { "traefik.docker.network": "traefik", "traefik.enable": "true", "traefik.frontend.rule": "Host:[registry.domain.tld]", "traefik.port": "5000" }, "TaskTemplate": { "ContainerSpec": { "Image": "registry:2.5.0", "Mounts": [ { "Type": "bind", "Source": "/opt/docker-auth/certs", "Target": "/certs" }, { "Type": "bind", "Source": "/opt/registry", "Target": "/var/lib/registry" } ], "Env": [ "REGISTRY_LOG_LEVEL=warn", "REGISTRY_STORAGE_DELETE_ENABLED=true", "REGISTRY_AUTH=token", "REGISTRY_AUTH_TOKEN_REALM=https://[token.domain.tld]/auth", "REGISTRY_AUTH_TOKEN_SERVICE=Docker registry", "REGISTRY_AUTH_TOKEN_ISSUER=Acme auth server", "REGISTRY_AUTH_TOKEN_ROOTCERTBUNDLE=/certs/fullchain.pem" ] }, "Placement": { "Constraints": [ "node.role==manager" ] } }, "Mode": { "Replicated": { "Replicas": 1 } }, "UpdateConfig": { "Parallelism": 1, "FailureAction": "pause" }, "Networks": [ { "Target": "traefik" } ], "EndpointSpec": { "Mode": "vip" } }
**Important **: Remplacez [registry.domain.tld] par le sous-domaine que vous avez créé précédemment pour la registry et [token.domain.tld] par celui dédié au serveur d'authentification.
On lance la registry :
curl -XPOST --unix-socket /var/run/docker.sock http:/services/create -d @$HOME/registry.json
Et on vérifie que le service docker-registry est bien lancé en utilisant la commande docker service ls.
Sur le port 8080 de votre serveur, vous devez avoir quelque chose d'équivalent à ceci :
Si c'est le cas, c'est que Traefik à fait correctement son boulot, vous avez maintenant un registre docker et un serveur d'authentification associés à leur domaines respectifs.
**Note **: Concernant le support de l'HTTPS pour ces domaines, il faut savoir que Traefik génère les certificats TLS et les fait signer par Let's Encrypt lors du premier accès. Il est recommandé d'utiliser cURL sur chacun d'eux pour initier la procédure. (exemple: **curl -L http://registry.guillem.me**) Répéter la procédure dans le cas ou ça échoue.
Maintenant, sur votre poste local (sur lequel vous avez installé docker) nous allons nous authentifier à la registry, "tagguer" une image puis l'envoyer.
**Note **: Pensez toujours à remplacer [registry.domain.tld] par le sous-domaine choisi précédemment.
docker login registry.domain.tld
Username: # saisir l'identifiant admin
Password: # saisir badmin
Login Succeeded
Récupérons une image lambda sur DockerHub, tagguons-la, puis envoyons-la sur notre registry.
docker pull alpine
docker tag alpine registry.domain.tld/alpine
docker push registry.domain.tld/alpine
**Note **: Remplacez toujours et encore le fameux [registry.domain.tld]
Si tout se déroule comme prévu, vous voyez alors quelque chose de proche de :
The push refers to a repository [registry.domain.tld/alpine]
011b303988d2: Pushed
latest: digest: sha256:1354db23ff5478120c980eca1611a51c9f2b88b61f24283ee8200bf9a54f2e5c size: 528
Si c'est le cas, félicitations, vous avez une registry docker à dispo !
Nous verrons comment utiliser docker-compose pour lancer un environnement de développement en local en tirant profit de notre registry docker et d’un outil de versionning pour fabriquer automatiquement nos images docker.
À la prochaine!
Auteur(s)
Guillem Canal
Architecte Technique. Collaboration over competition 🖖
Vous souhaitez en savoir plus sur le sujet ?
Organisons un échange !
Notre équipe d'experts répond à toutes vos questions.
Nous contacterDécouvrez nos autres contenus dans le même thème
Dans cet article, découvrez comment automatiser une création de version de votre application grâce à Semantic-Release : nommage des commits et configurations
Dans le domaine de la data, la qualité de la donnée est primordiale. Pour s'en assurer, plusieurs moyens existent, et nous allons nous attarder dans cet article sur l'un d'entre eux : tester unitairement avec Pytest.
Le domaine de la data est présent dans le quotidien de chacun : la majorité de nos actions peut être traduite en données. Le volume croissant de ces données exploitables a un nom : "Big Data". Dans cet article, nous verrons comment exploiter ce "Big data" à l'aide du framework Apache Spark.