From adf452f44057a632ec1db3d859a86578f4ad678b Mon Sep 17 00:00:00 2001 From: Gregory Colpart Date: Mon, 9 Oct 2023 13:17:31 +0200 Subject: [PATCH] =?UTF-8?q?petite=20relecture=20et=20r=C3=A9organisation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HowtoDocker.md | 752 ++++++++++++++++++++++++------------------------- 1 file changed, 367 insertions(+), 385 deletions(-) diff --git a/HowtoDocker.md b/HowtoDocker.md index cb36d8e8..0c064f49 100644 --- a/HowtoDocker.md +++ b/HowtoDocker.md @@ -3,14 +3,299 @@ title: Howto Docker categories: docker --- -Docker est une solution qui permet de créer, déployer et gérer des conteneurs -Linux. +* Documentation : +* Rôle Ansible : +* Statut de cette page : test / bullseye -Documentation : +[Docker](https://www.docker.com/) est une solution qui permet de créer, déployer et gérer des conteneurs Linux. +Il intègre une gestion avancée des images permettant de les compiler, les compléter, les héberger, etc. -# Écosystème +## Installation -## Le démon docker et son client +Nous utilisons le paquet `docker-ce` des dépôts du projet Docker : + +~~~ +# apt install apt-transport-https +# echo "deb https://download.docker.com/linux/debian bullseye stable" > /etc/apt/sources.list.d/docker.list +# wget -O /etc/apt/trusted.gpg.d/docker.asc https://download.docker.com/linux/debian/gpg +# dos2unix /etc/apt/trusted.gpg.d/docker.asc +# chmod 644 /etc/apt/trusted.gpg.d/docker.asc +# apt update +# apt install docker-ce +~~~ + +Sur sa machine de travail, il est utile d'ajouter son utilisateur dans le groupe _docker_ pour pouvoir interagir avec le démon _dockerd_ sans passer root à chaque fois : + +~~~ +# adduser $USER docker +~~~ + +## Utilisation basique + +Une image Docker contient un système minimal avec un ou plusieurs services. +Un conteneur quant à lui est une instance (créée à partir d'une image) +en cours d'exécution. + +### Gérer les conteneurs + +#### Lister les conteneurs + +~~~ +$ docker ps +~~~ + +Options utiles : + +~~~ +-a : lister tous les conteneurs +-l : lister les conteneurs récemment lancés +-q : lister uniquement les ID des conteneurs +~~~ + +#### Instancier un nouveau conteneur + +~~~ +$ docker run [commande] +~~~ + +Si une commande spécifiée, celle-ci remplacera celle du `CMD` de l'image + +Options utiles : + +~~~ +--name NOM : donner un nom au conteneur +-p port_hôte:port_conteneur : rendre un port accessible depuis l'hôte +-d : lancer le conteneur en mode 'détaché' +-it : lancer le conteneur en mode intéractif avec tty +--network NOM : lancer le conterneur sur un réseau docker spécifique existant +~~~ + +#### Démarrer un conteneur existant + +Un conteneur existant est un conteneur précédemment instancié avec `docker +run`. + +~~~ +$ docker start +~~~ + +#### Éteindre ou tuer un conteneur + +~~~ +$ docker stop|kill +~~~ + +Lorsque le conteneur n'est plus en fonction, il existe toujours et peut être +listé à l'aide de la commande `docker ps -a` + +#### Autostart d'un conteneur + +Pour s'assurer qu'un conteneur démarre ou non au démarrage du démon Docker, il existe un paramètre RestartPolicy : + +~~~ +$ docker inspect -f "{{ .HostConfig.RestartPolicy.Name }}" monconteneur +~~~ + +Les valeurs possibles sont : + +~~~ +no Ne redémarre pas automatiquement le conteneur. (défaut) +on-failure Redémarre le conteneur s'il crash suite à une erreur (code de sortie non nul) +always Toujours redémarrer le conteneur s’il s’arrête. S'il est arrêté manuellement, il est redémarré uniquement lorsque le démon Docker redémarre ou que le conteneur lui-même est redémarré manuellement. +unless-stopped Semblable à always, sauf que lorsque le conteneur est arrêté (manuellement ou autrement), il n'est pas redémarré même après le redémarrage du démon Docker. +~~~ + +Pour mettre à jour la politique : + +~~~ +$ docker update --restart=always monconteneur +~~~ + +#### Supprimer un conteneur + +~~~ +$ docker rm +~~~ + +#### Exécuter des commandes dans un conteneur en fonctionnement + +~~~ +$ docker exec +~~~ + +Options utiles : + +~~~ +-t : alloue un TTY +-i : attache stdin (mode interactif) +~~~ + +On utilise habituellement la commande suivante pour obtenir un shell dans un conteneur en fonctionnement : + +~~~ +$ docker exec -ti bash +~~~ + +#### Visionner les journaux d'un conteneur + +Il s'agit en fait de la sortie standard et la sortie d'erreur du processus +lancé à l'intérieur du conteneur : + +~~~ +$ docker logs +~~~ + +Options utiles : + +~~~ +-f : suivre les logs en direct +-t : afficher un timestamp devant chaque ligne +~~~ + +#### Afficher les informations d'un conteneur + +~~~ +$ docker inspect +~~~ + +Cette commande s'applique généralement à n'importe quel objet Docker +(conteneur, image, service, réseau…) et donne une liste exhaustive des +attributs de l'objet, formaté en JSON. + +Il est aussi possible de récupérer une sous partie en utilisant l'argument --format + +~~~ +# Récupérer les IP du container d05daab5c59e +$ docker inspect d05daab5c59e --format "{{range .NetworkSettings.Networks }}{{ .IPAddress }}{{ end }}" +# Récupérer l'IP du container f4bae02ef1407adc92f1aa2cc32c8e9fae75dac87126e2bf4964db265e9ad55d sur l'interface docker_gwbridge +$ docker inspect docker_gwbridge --format "{{ .Containers.f4bae02ef1407adc92f1aa2cc32c8e9fae75dac87126e2bf4964db265e9ad55d.IPv4Address }}" +~~~ + +Note : De notre expérience, l'option --format peut se montrer capricieuse, notamment s'il y a en jeu des identifiant de containers. Une alternative est de parser du json manuellement avec [jq](https://wiki.evolix.org/TipsShell#json-avec-jq ) + +### Gérer les images + +#### Lister les images locales + +~~~ +$ docker image ls +~~~ + +#### Construire une image + +Pour construire ou mettre à jour une image : + +~~~ +$ docker build +~~~ + +Le répertoire doit contenir un fichier _Dockerfile_ décrivant l'image à +construire. + +Option utiles : + +~~~ +-t : ajoute un tag à l'image +~~~ + +#### Ajouter un tag à une image existante + +~~~ +$ docker tag +~~~ + +#### Pousser une image sur un dépôt distant + +~~~ +$ docker push +~~~ + +Avant de pousser une image, il est nécessaire de lui attribuer le bon _tag_ qui +doit contenir l'adresse du dépôt distant. + +Par exemple pour pousser l'image _foo-image_ sur le dépôt Docker _registry.example.net:5000_ : + +~~~ +$ docker tag foo-image registry.example.net:5000/foo-image +$ docker push registry.example.net:5000/foo-image +~~~ + +#### Récupérer une image d'un dépôt distant + +~~~ +$ docker pull +~~~ + +#### Copier des fichiers dans/depuis un conteneur + +~~~ +$ docker cp : +~~~ + +On peut aussi le faire de conteneur à conteneur : + +~~~ +$ docker cp : : +~~~ + +### Astuces + +Éteindre/Tuer/Supprimer tous les conteneurs : + +~~~ +$ docker ps -aq |xargs -r docker stop|kill|rm +~~~ + +Supprimer toutes les images : + +~~~bash +$ docker images -q |xargs -r docker image rm +~~~ + +Démarrer un conteneur existant avec un shell bash (pour des fins de debug par exemple) : + +~~~ +$ docker run -it IMAGE bash +~~~ + +## Configuration + +#### Changer le chemin de stockage + +Créer le fichier `/etc/docker/daemon.json` et y mettre : + +~~~ +{ + "data-root": "", + "storage-driver": "overlay" +} +~~~ + +NB : Anciennement il fallait "graph" à la place de "data-root". + +#### TLS + +Lorsque le docker-engine est exposé, il est important de le sécuriser avec TLS. + +Au moment de l'installation, une version altérée de shellpki est copiée dans le +répertoire docker/tls. Ensuite, les certificats et la clé sont créés pour le +serveur. (`shellpki init`) + +Pour autoriser des hôtes à se connecter à l'engine, il faut leur créer une clé +et un certificat. +Pour ce faire, il suffit de lancer le script: + +~~~ +/home/docker/tls$ ./shellpki create +~~~ + +Les fichiers seront créés, par défaut, dans le répertoire +`/home/docker/tls/files/$CN` + + +## Plomberie + +### Le démon docker et son client Docker est une application en mode client-serveur. *dockerd* est un démon qui fournit une API REST afin d'interagir avec les conteneurs. *docker* est un @@ -18,8 +303,6 @@ client qui permet d'interagir avec le démon en ligne de commande. Il peut interagir avec un démon en local (sur la même machine) ou avec un démon sur une machine distante. -## Les objets dockers - ### Image Une image est un template contenant des instructions pour créer un conteneur @@ -63,314 +346,13 @@ conteneur. Voir : [https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/#services-tasks-and-containers](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/#services-tasks-and-containers) + ## docker registry Un *registry* sert à héberger des images docker. Il existe des registres publics tels que *docker hub* ou *docker cloud* mais il est possible d'héberger son propre *registry*. -# Docker Engine - -## Installation - -Il est conseillé d'utiliser le paquet docker-ce des dépôts du projet Docker : - -``` -# apt install apt-transport-https -# echo "deb http://download.docker.com/linux/debian buster stable" > /etc/apt/sources.list.d/docker.list -# wget -O /etc/apt/trusted.gpg.d/docker.asc https://download.docker.com/linux/debian/gpg -# dos2unix /etc/apt/trusted.gpg.d/docker.asc -# chmod 644 /etc/apt/trusted.gpg.d/docker.asc -# apt update -# apt install docker-ce -``` - -> *Note* : Pour Debian 9 : -> -> ``` -> # apt install apt-transport-https -> # echo "deb http://download.docker.com/linux/debian stretch stable" > /etc/apt/sources.list.d/docker.list -> # wget https://download.docker.com/linux/debian/gpg -O /etc/apt/trusted.gpg.d/docker.asc -> # apt update -> # apt install docker-ce -> ``` - -Sur sa machine de travail, il est utile d'ajouter son utilisateur dans le -groupe _docker_ pour pouvoir interagir avec le démon _dockerd_ sans passer root -à chaque fois : - -``` -# adduser $USER docker -``` - -### Configuration - -#### Changer le chemin de stockage - -Créer le fichier `/etc/docker/daemon.json` et y mettre : - -``` -{ - "data-root": "", - "storage-driver": "overlay" -} -``` - -NB : Anciennement il fallait "graph" à la place de "data-root". - -### Ansible - -Le rôle [docker-host](https://forge.evolix.org/projects/ansible-roles/repository) permet d'installer le docker-engine sur un hôte distant et -de l'exposer à l'externe ou non. - -La documentation concernant l'utilisation du rôle est située dans son répertoire. - -#### TLS - -Lorsque le docker-engine est exposé, il est important de le sécuriser avec TLS. - -Au moment de l'installation, une version altérée de shellpki est copiée dans le -répertoire docker/tls. Ensuite, les certificats et la clé sont créés pour le -serveur. (`shellpki init`) - -Pour autoriser des hôtes à se connecter à l'engine, il faut leur créer une clé -et un certificat. -Pour ce faire, il suffit de lancer le script: - -``` -/home/docker/tls$ ./shellpki create -``` - -Les fichiers seront créés, par défaut, dans le répertoire -`/home/docker/tls/files/$CN` - -## Utilisation de base - -Une image Docker contient un système minimal avec un ou plusieurs services. -Un conteneur quant à lui est une instance (créée à partir d'une image) -en cours d'exécution. - -### Gérer les conteneurs - -#### Lister les conteneurs - -``` -$ docker ps -``` - -Options utiles : - -``` --a : lister tous les conteneurs --l : lister les conteneurs récemment lancés --q : lister uniquement les ID des conteneurs -``` - -#### Instancier un nouveau conteneur - -``` -$ docker run [commande] -``` - -Si une commande spécifiée, celle-ci remplacera celle du `CMD` de l'image - -Options utiles : - -``` ---name NOM : donner un nom au conteneur --p port_hôte:port_conteneur : rendre un port accessible depuis l'hôte --d : lancer le conteneur en mode 'détaché' --it : lancer le conteneur en mode intéractif avec tty ---network NOM : lancer le conterneur sur un réseau docker spécifique existant -``` - -#### Démarrer un conteneur existant - -Un conteneur existant est un conteneur précédemment instancié avec `docker -run`. - -``` -$ docker start -``` - -#### Éteindre ou tuer un conteneur - -``` -$ docker stop|kill -``` - -Lorsque le conteneur n'est plus en fonction, il existe toujours et peut être -listé à l'aide de la commande `docker ps -a` - -#### Autostart d'un conteneur - -Pour s'assurer qu'un conteneur démarre ou non au démarrage du démon Docker, il existe un paramètre RestartPolicy : - -``` -$ docker inspect -f "{{ .HostConfig.RestartPolicy.Name }}" monconteneur -``` - -Les valeurs possibles sont : - -``` -no Ne redémarre pas automatiquement le conteneur. (défaut) -on-failure Redémarre le conteneur s'il crash suite à une erreur (code de sortie non nul) -always Toujours redémarrer le conteneur s’il s’arrête. S'il est arrêté manuellement, il est redémarré uniquement lorsque le démon Docker redémarre ou que le conteneur lui-même est redémarré manuellement. -unless-stopped Semblable à always, sauf que lorsque le conteneur est arrêté (manuellement ou autrement), il n'est pas redémarré même après le redémarrage du démon Docker. -``` - -Pour mettre à jour la politique : - -``` -$ docker update --restart=always monconteneur -``` - -#### Supprimer un conteneur - -``` -$ docker rm -``` - -#### Exécuter des commandes dans un conteneur en fonctionnement - -``` -$ docker exec -``` - -Options utiles : - -``` --t : alloue un TTY --i : attache stdin (mode interactif) -``` - -On utilise habituellement la commande suivante pour obtenir un shell dans un conteneur en fonctionnement : - -``` -$ docker exec -ti bash -``` - -#### Visionner les journaux d'un conteneur - -Il s'agit en fait de la sortie standard et la sortie d'erreur du processus -lancé à l'intérieur du conteneur : - -``` -$ docker logs -``` - -Options utiles : - -``` --f : suivre les logs en direct --t : afficher un timestamp devant chaque ligne -``` - -#### Afficher les informations d'un conteneur - -``` -$ docker inspect -``` - -Cette commande s'applique généralement à n'importe quel objet Docker -(conteneur, image, service, réseau…) et donne une liste exhaustive des -attributs de l'objet, formaté en JSON. - -Il est aussi possible de récupérer une sous partie en utilisant l'argument --format - -``` -# Récupérer les IP du container d05daab5c59e -$ docker inspect d05daab5c59e --format "{{range .NetworkSettings.Networks }}{{ .IPAddress }}{{ end }}" -# Récupérer l'IP du container f4bae02ef1407adc92f1aa2cc32c8e9fae75dac87126e2bf4964db265e9ad55d sur l'interface docker_gwbridge -$ docker inspect docker_gwbridge --format "{{ .Containers.f4bae02ef1407adc92f1aa2cc32c8e9fae75dac87126e2bf4964db265e9ad55d.IPv4Address }}" -``` - -Note : De notre expérience, l'option --format peut se montrer capricieuse, notamment s'il y a en jeu des identifiant de containers. Une alternative est de parser du json manuellement avec [jq](https://wiki.evolix.org/TipsShell#json-avec-jq ) - -### Gérer les images - -#### Lister les images locales - -``` -$ docker image ls -``` - -#### Construire une image - -Pour construire ou mettre à jour une image : - -``` -$ docker build -``` - -Le répertoire doit contenir un fichier _Dockerfile_ décrivant l'image à -construire. - -Option utiles : - -``` --t : ajoute un tag à l'image -``` - -#### Ajouter un tag à une image existante - -``` -$ docker tag -``` - -#### Pousser une image sur un dépôt distant - -``` -$ docker push -``` - -Avant de pousser une image, il est nécessaire de lui attribuer le bon _tag_ qui -doit contenir l'adresse du dépôt distant. - -Par exemple pour pousser l'image _foo-image_ sur le dépôt Docker _registry.example.net:5000_ : - -``` -$ docker tag foo-image registry.example.net:5000/foo-image -$ docker push registry.example.net:5000/foo-image -``` - -#### Récupérer une image d'un dépôt distant - -``` -$ docker pull -``` - -#### Copier des fichiers dans/depuis un conteneur - -``` -$ docker cp : -``` - -On peut aussi le faire de conteneur à conteneur : - -``` -$ docker cp : : -``` - -### Astuces - -Éteindre/Tuer/Supprimer tous les conteneurs : - -``` -$ docker ps -aq |xargs -r docker stop|kill|rm -``` - -Supprimer toutes les images : - -```bash -$ docker images -q |xargs -r docker image rm -``` - -Démarrer un conteneur existant avec un shell bash (pour des fins de debug par exemple) : - -``` -$ docker run -it IMAGE bash -``` ## Dockerfile @@ -388,7 +370,7 @@ Exemple avec une image exécutant rsyslog : - depuis un répertoire vierge, création d'un fichier _Dockerfile_ : -``` +~~~ ~/docker-images/rsyslog $ $EDITOR Dockerfile # Image sur laquelle notre image se base @@ -418,7 +400,7 @@ EXPOSE 514/udp # La commande suivante est exécutée lorsque le conteneur est exécuté, en mode "shell" CMD /usr/sbin/rsyslogd -n # Equivalent à CMD ["/bin/sh","-c","/usr/sbin/rsyslogd","-n"] (format JSON) -``` +~~~ Dans la mesure du possible, voici quelques bonnes pratiques à respecter : @@ -429,9 +411,9 @@ Dans la mesure du possible, voici quelques bonnes pratiques à respecter : Un exemple à ne **pas** écrire : -``` +~~~ CMD /usr/bin/foo -d; tail -f /var/log/foo.log -``` +~~~ Dans le cas où `/usr/bin/foo -d` lance le démon foo en arrière plan, le conteneur s'exécutera correctement mais Docker va monitorer le processus tail @@ -441,9 +423,9 @@ pourra pas être redémarré automatiquement. À supposer que foo ne puisse pas envoyer ses logs sur stdout, le bon example serait : -``` +~~~ CMD touch /var/log/foo.log && tail -f /var/log/foo.log & /usr/bin/foo -``` +~~~ À noter que seulement une seule directive `CMD` est acceptée dans un _Dockerfile_. Ici l'exécutable est spécifié pas l'instruction `CMD` mais ce n'est pas toujours le cas. @@ -454,7 +436,7 @@ Dans ce cas `ENTRYPOINT` et `CMD` doivent être spécifiés au format JSON. On peut ensuite construire notre image, en lui donnant ici le _tag_ _rsyslog_ : -``` +~~~ ~/docker-images/rsyslog $ ls Dockerfile custom.conf ~/docker-images/rsyslog $ docker build -t rsyslog . @@ -462,7 +444,7 @@ Dockerfile custom.conf REPOSITORY TAG IMAGE ID CREATED SIZE rsyslog latest 4bea99cda08c 8 minutes ago 470MB debian stretch 5b712ae16dd7 3 days ago 100MB -``` +~~~ ## Utilisation avancée @@ -472,7 +454,7 @@ Un _docker registry_ permet d'héberger des images Docker. On peut le déployer avec la _stack_ suivante : -``` +~~~ version: "3.6" services: @@ -500,24 +482,24 @@ volumes: secrets: certificate: file: certificate.pem -``` +~~~ Attention, le certificat doit absolument être valide et le Common Name doit correspondre avec le nom utilisé pour y accéder. Lors d'un déploiement d'une stack existante, en cas d'erreur : -``` +~~~ image registrydocker.example.com:5000/XXX could not be accessed on a registry to record its digest. Each node will access registrydocker.example.com:5000/XXX independently, possibly leading to different nodes running different versions of the image. -``` +~~~ Il peut s'agir de différents problèmes (réseau, SSL, etc…), Docker n'est pas très bavard sur la cause de l'échec. Un bon moyen de déboguer la situation est avec : -``` +~~~ $ curl https://registrydocker.example.com:5000/v2/_catalog -``` +~~~ La requête devrait retourner la liste des images hébergées au format json. @@ -529,15 +511,15 @@ plusieurs machines. #### Initialiser le cluster -``` +~~~ docker0# docker swarm init -``` +~~~ Joindre les autres machines au cluster créé (il vous suffit généralement de copier-coller la commande retournée par `docker swarm init` : -``` +~~~ docker1# docker swarm join --token -``` +~~~ Par défaut la machine sur laquelle le cluster a été initialisée a le rôle de _manager_, et les suivantes ont le rôle de _worker_. On ne peut déployer de @@ -546,21 +528,21 @@ recevoir les services à rouler. Pour ajouter des machines plus tard, il suffit de générer un nouveau token : -``` +~~~ docker0# docker swarm join-token -``` +~~~ #### Lister les machines du cluster -``` +~~~ # docker node ls -``` +~~~ #### Ajouter des labels à une machine -``` +~~~ # docker node update --label-add = -``` +~~~ Les _labels_ servent notamment à définir des contraintes de placement des services lors de l'utilisation de _docker stack_. @@ -573,35 +555,35 @@ L'infra est à décrire dans un fichier YAML. Déployer (ou mettre à jour à chaud) une nouvelle _stack_ : -``` +~~~ # docker stack deploy -c -``` +~~~ Lister les _stacks_ : -``` +~~~ # docker stack ls -``` +~~~ Lister les _services_, toutes _stacks_ confondues ou pour une _stack_ donnée : -``` +~~~ # docker service ls # docker stack services -``` +~~~ Lister les _tasks_ (replicas) d'une _stack_ ou d'un _service_ donné : -``` +~~~ # docker stack ps # docker service ps -``` +~~~ Supprimer une _stack_ : -``` +~~~ # docker stack rm -``` +~~~ ### Réseaux (docker network) @@ -628,21 +610,21 @@ _drivers_ réseau supportés : Créer un réseau : -``` +~~~ # docker create -d […] -``` +~~~ Lister les réseaux créés : -``` +~~~ # docker network ls -``` +~~~ Informations détaillées sur un réseau : -``` +~~~ # docker network inspect -``` +~~~ ### Volumes (docker volume) @@ -661,7 +643,7 @@ _/var/lib/docker/volumes/"nom du volume"/\_data/_. On peut gérer les volumes avec la commande `docker volume` : -``` +~~~ # docker volume create vol1 vol1 # docker volume ls @@ -669,7 +651,7 @@ DRIVER VOLUME NAME local vol1 # docker volume rm vol1 vol1 -``` +~~~ Dans le cas d'un cluster Docker Swarm, les volumes ne sont pas répliqués entre les membres du cluster. Si un conteneur monte un volume, il faut bien penser à @@ -694,9 +676,9 @@ volume. Les _config_ ne peuvent pas non plus être mis à jour lors d'un redéploiement de stack : -``` +~~~ failed to update config foo: Error response from daemon: rpc error: code = InvalidArgument desc = only updates to Labels are allowed -``` +~~~ Il faut obligatoirement soit supprimer l'objet _config_ et donc les objets qui en dépendent (conteneurs), soit créer un nouveau _config_ (avec un nouveau nom @@ -707,7 +689,7 @@ Les _config_ se gèrent avec la commande `docker config`. Le serveur doit avoir le rôle _manager_ dans le cluster Swarm pour pouvoir créer un objet _config_, puisque cela impacte l'ensemble du cluster : -``` +~~~ # docker config create vim-config .vimrc 07kaw58mhvtkqem46ipkd97i1 # docker config ls @@ -715,7 +697,7 @@ ID NAME DRIVER 07kaw58mhvtkqem46ipkd97i1 vim-config Less than a second ago Less than a second ago # docker config rm vim-config vim-config -``` +~~~ ### Fichiers sensibles (docker secrets) @@ -753,7 +735,7 @@ Référence sur le format du fichier : Voici un aperçu : -``` +~~~ $ cat ma-stack.yml version: "3.6" @@ -800,7 +782,7 @@ configs: secrets: ssl_cert: file: example.com.pem -``` +~~~ On lance ici 2 _services_, _web_ et _mysql_. On spécifie que _web_ doit avoir 2 réplicas, il y aura donc 2 _tasks_ (et donc 2 conteneurs) qui seront démarrés, @@ -826,11 +808,11 @@ contrainte de placement pour _web_. Ensuite on peut déployer notre _stack_ : -``` +~~~ $ ls ma-stack.yml nginx.conf example.com.pem $ docker stack deploy -c ma-stack.yml ma-stack -``` +~~~ #### Surcharge de paramètre @@ -841,7 +823,7 @@ fusionnés. Cela permet de réutiliser un fichier de _stack_ pour différents environnement (preprod, prod…) en changeant uniquement des variables d'environement, mots de passe, etc… -``` +~~~ $ cat ma-stack.dev.yml version: "3.6" services: @@ -851,13 +833,13 @@ services: - MYSQL_DB=foo_dev - MYSQL_USER=foo_dev - MYSQL_PASS=deb2Ozpifut? -``` +~~~ On peut ensuite déployer ainsi : -``` +~~~ $ docker stack deploy -c ma-stack.yml -c ma-stack.dev.yml ma-stack -``` +~~~ ## FAQ @@ -869,9 +851,9 @@ effacé les règles spécifiques à Docker, notamment dans la table _nat_. Pour restaurer les règles netfilter de Docker, il n'y a pas d'autre moyen que de redémarrer le démon : -``` +~~~ # /etc/init.d/docker restart -``` +~~~ ### Espace insuffisant lors du build d'une image @@ -889,32 +871,32 @@ Solutions: Voir les commandes -``` +~~~ $ docker image inspect $nomImage -f "{{ .Config.Entrypoint }}{{ .Config.Cmd}}" -``` +~~~ Lancer l'image en changeant le Entrypoint -``` +~~~ $ docker run -d --entrypoint="/bin/sleep" $imageConteneur infinity $ docker run -d --entrypoint="" $imageConteneur echo hello -``` +~~~ L'option `--entrypoint` remplace le Entrypoint et Cmd Re-créer l'image en modifiant un conteneur de cette image -``` +~~~ $ docker commit -c 'ENTRYPOINT ["/bin/sleep"]' -c 'CMD ["infinity"]' $idConteneur $nomImage:tag -``` +~~~ ### Lors d'un redéploiement d'une stack Docker (docker stack deploy), les services ne sont pas redémarrer avec la nouvelle image Vérifier que le tag _latest_ est bien précisé dans le nom de l'image dans le _docker-stack.yml_ : -``` +~~~ image: registrydocker.example.com:5000/foo:latest -``` +~~~ ### Est-il possible de ne faire écouter un service d'une stack que sur une interface précise de la machine hôte (par exemple sur un LAN privé) ? @@ -923,9 +905,9 @@ Il faut bloquer le port en question dans le pare-feu, dans la chaîne iptables D Pour bloquer l'accès au _registry_ Docker depuis l'extérieur par exemple : -``` +~~~ # iptables -A DOCKER-USER -i eth0 -p tcp -m tcp --dport 5000 -j DROP -``` +~~~ ### Au sein des conteneurs, un `getent ` ou `getent tasks.` ne retourne pas l'adresse IP du service alors que celui-ci est bien lancé. @@ -935,15 +917,15 @@ Stopper le conteneur du service avec un `docker stop `. Do L'adresse IP virtuelle qui redirige aléatoirement sur chacune des _tasks_ (si le réseau utilise le driver _overlay_, cas par défaut) : -``` +~~~ $ getent hosts -``` +~~~ L'adresse IP des différentes _tasks_ d'un service : -``` +~~~ $ getent hosts tasks. -``` +~~~ ### Comment trouver le PID d'un processus roulant dans un conteneur ? @@ -952,9 +934,9 @@ linux pour isoler les processus. L’utilité pgrep(1) est capable de filtrer les processus par namespace sur la base d’un autre processus. -``` +~~~ $ pgrep --ns $dockerPID $query -``` +~~~ Ce concept provient du système Plan9 @@ -964,9 +946,9 @@ Docker ne met pas le namespace réseau qu'il utilise pour ses conteneurs dans `v On peut monter `/proc/${pid_conteneur}/ns/` dans `var/run/netns/` pour utiliser ip OU plus simplement utiliser nsenter à la place : -```bash +~~~bash # nsenter -t $pid_conteneur -n -``` +~~~ Nous permet d'avoir un shell dans le namespace, `-t` indique d'utiliser le pid target et `-n` indique que nous voulons aller dans le namespace netns @@ -974,7 +956,7 @@ Nous permet d'avoir un shell dans le namespace, `-t` indique d'utiliser le pid Vous devez autoriser l'interface docker0 -``` +~~~ # Autorisation Docker /sbin/iptables -A INPUT -i docker0 -j ACCEPT -``` +~~~