Docker/Version imprimable
Une version à jour et éditable de ce livre est disponible sur Wikilivres,
une bibliothèque de livres pédagogiques, à l'URL :
https://fr.wikibooks.org/wiki/Docker
Introduction
Principe
modifierDocker est un logiciel libre conçu pour lancer des applications dans des conteneurs logiciels. Ces conteneurs sont plus légers en ressources que les machines virtuelles car ils partagent leur noyau.
Images et conteneurs
modifierLes conteneurs sont construis à partir d'images qui partages leur couches en différentiel[1].
Docker met de plus à disposition un hub pour partager des images : https://hub.docker.com/. On y trouve par exemple celles permettant de faire tourner un site en MediaWiki : https://hub.docker.com/_/mediawiki.
Installation
modifierIl existe plusieurs versions de Docker[2] :
- Docker CE (community engine) : gratuit. Idéal sur un PC.
- Docker EE (enterprise engine) : version payante certifiée, plutôt pour les serveurs.
- Docker Enterprise : payant et dispose d'outils supplémentaires, par exemple pour gérer les images et les conteneurs.
Une fois installé, la commande suivante doit fonctionner : docker --version
.
Linux
modifierEn 2019 on trouve des binaires pour les distributions de Linux suivantes : CentOS, Debian, Fedora et Ubuntu[3].
Via Docker Desktop
modifierSolution mise en avant par la doc Docker depuis 2024, mais elle peut poser des problèmes de performances et de permissions. On peut donc installer Docker avec puis le configurer pour qu'il ne se lance plus avec Docker Desktop[4] :
docker context ls docker context use default sudo service docker start
Ubuntu - via apt
modifier
apt-get install ca-certificates curl gnupg lsb-release
mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
docker -v
docker compose version
Ubuntu - via repo
modifierAncienne méthode, utile pour forcer la version :
apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
apt-key fingerprint 0EBFCD88
add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
apt-get update
apt-get install docker-ce docker-ce-cli containerd.io
docker -v
curl -L "https://github.com/docker/compose/releases/download/2.11.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
docker-compose --version
Post-installation
modifierAprès installation, le daemon Docker se lancera à chaque démarrage avec la possibilité de remonter certains conteneurs automatiquement[5].
À ce stade seul root peut utiliser Docker. Il faut ajouter les utilisateurs qui doivent le lancer au groupe "docker" :
sudo usermod -aG docker $USER
Pour relancer Docker si besoin :
sudo systemctl stop docker && sudo systemctl start docker
Depuis 2022, une interface graphique, Docker Desktop est disponible sur Linux :
sudo apt-get install docker-desktop
Docker Desktop sur Linux est susceptible de retirer le daemon Docker qui marchait avant, sans pouvoir le remplacer.
L'IP du réseau de conteneurs est 172.17.0.1 par défaut (l'associer aux domaines locaux dans /etc/hosts si besoin).
MacOS
modifierÀ télécharger depuis https://docs.docker.com/docker-for-mac/install/.
A noter que les performances de Docker Desktop sur Mac ne sont pas au niveau de celles sur Linux, et qu'il existe le partagiciel Orbstack[6] comme alternative.
Windows
modifierDes interfaces graphiques de gestion de conteneur existent, comme Docker Desktop ou Kitematic[7]. Elles peuvent être intégrées dans un deuxième temps.
Mais le plus simple est de télécharger et installer Docker Desktop depuis le site officiel[8], car cela installe et configure aussi Docker et Docker Compose.
- Les performances de Docker Desktop sur Windows ne sont pas au niveau de celles sur Linux.
- On ne peut l'installer que pour les versions de Windows pro, car Hyper-V est nécessaire.
- Toute désinstallation de Docker supprimera les images construites sur le poste, et pourra donc occasionner de longs téléchargements après réinstallation et relance.
- En avril 2020 la version 2.3 (et les suivantes, au moins : 2.3.0.1, 2 et 3) freeze très régulièrement (broken pipe). Il était donc préconisé d'utiliser la 2.2.0.5[9]. Mais c'est résolu dans Docker 3.0.0.
hosts
modifierSur Windows, Docker Desktop modifie le fichier hosts en ajoutant :
# Added by Docker Desktop
192.168.1.20 host.docker.internal
192.168.1.20 gateway.docker.internal
# To allow the same kube context to work on the host and the container:
127.0.0.1 kubernetes.docker.internal
# End of section
Dans un Active Directory
modifier
- Sur Windows pro en AD, il faut ajouter le compte qui utilisera Docker Desktop dans le groupe "docker-users" :
net localgroup docker-users AD\mon_compte /add
- Les versions antérieures à la 2.1.7 sur Windows pro en AD (active directory), imposent qu'un administrateur du domaine autorise l'accès à C: (un admin local ne suffit pas).
WSL
modifierAnciennement baptisé Tech Preview, Docker Desktop WSL 2 Backend utilise Windows Subsystem for Linux pour optimiser les performances de Docker sur Windows[10], en l'installant dans une VM Linux pouvant accéder à C:.
Références
modifier- ↑ https://docs.docker.com/storage/storagedriver/
- ↑ https://docs.docker.com/install/overview/
- ↑ https://docs.docker.com/install/linux/docker-ce/ubuntu/
- ↑ https://github.com/docker/desktop-linux/issues/20
- ↑ https://www.ionos.fr/digitalguide/serveur/configuration/tutoriel-docker-installation-et-premiers-pas/
- ↑ https://orbstack.dev/pricing
- ↑ https://kitematic.com/
- ↑ https://docs.docker.com/docker-for-windows/install/
- ↑ https://docs.docker.com/docker-for-windows/release-notes/#docker-desktop-community-2205
- ↑ https://engineering.docker.com/2019/10/new-docker-desktop-wsl2-backend/
Gestion des conteneurs
Registres
modifierLes images des conteneurs peuvent être stockées dans un registre, privé ou public comme https://hub.docker.com/.
Pour en récupérer une :
docker login
docker image pull $IMAGE_NAME || echo " >> missing image"
Exemple :
docker image pull maarch/maarchrm:latest
Les images téléchargées sont stockées :
- Sur Linux, dans /var/lib/docker/.
- Sur MacOS, dans /Users/nom_utilisateur/Library/Containers/com.docker.docker/.
- Sur Windows, dans C:\ProgramData\docker\ ou C:\ProgramData\DockerDesktop\.
Pour mettre à jour une image sur un registre à partir d'un Dockerfile :
docker image build
docker image push $IMAGE_NAME
run
modifier"run" s'utiliser pour lancer un conteneur à partir de son image (automatiquement téléchargée si absente en local). Une fois la commande exécutée, le conteneur s'arrête. Exemple qui liste le dossier courant :
docker run maven:latest ls
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var
Pour rester connecté dedans, on utilise le mode interactif (-it) :
docker run -it redis
redis-cli
Pour partager un dossier avec la machine hôte, on peut utiliser "-v" pour "volume", ou "--mount" si le conteneur a des services[1]. Exemple qui liste le dossier de la machine hôte partagé avec le conteneur :
docker run -it -v "/$(pwd)/":/usr/src/mymaven maven ls usr/src/mymaven
exec
modifierPour exécuter une commande dans un conteneur. Ex :
docker exec redis sh -c 'pwd'
Autre exemple :
docker exec php8.0-fpm sh -c 'cd /var/www/mon_app; composer install'
Fonctionne aussi avec un fichier :
docker exec redis script.sh
Dans tous les conteneurs
modifierPour lancer une commande dans tous les conteneurs, il faut créer le fichier suivant[2] :
for container in `docker ps -q`; do
docker inspect --format='{{.Name}}' $container;
docker exec -it $container $1;
done
Ensuite le lancer avec la commande en paramètre :
./dockers.sh date
/php7.3-fpm
Thu Mar 19 11:15:34 Europs 2020
/php7.4-fpm
Thu Mar 19 12:15:34 Europs 2020
Rentrer dans un conteneur
modifierPour utiliser le conteneur, on peut rentrer dedans en utilisant le mode interactif :
docker exec -it redis bash
Cela permet d'enchainer les commandes (comme si on était sur un serveur hôte en SSH).
build
modifierPour lancer un conteneur à construire, il faut le faire depuis le dossier de son Dockerfile[3] :
docker build .
ps et rm
modifierPour obtenir la liste des conteneurs lancés :
docker ps
Idem mais avec seulement trois colonnes, triées par nom (colonne n°2) :
docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}" | (read -r; printf "%s\n" "$REPLY"; sort -k 2 )
Pour tous les conteneurs (lancés ou pas) :
docker ps -a
Pour en supprimer un :
docker rm nom_du_coteneur
image et rmi
modifierPour toutes les images :
docker image ls
Pour en supprimer une :
docker rmi nom_image
save et load
modifierPermet de sauvegarde une image. Pour toutes les sauvegarder :
docker save $(docker images -q) -o images_docker.tar
On peut ensuite les recharger (par exemple sur une autre machine) avec :
docker load --input images_docker.tar
Un save sur Docker Desktop Windows 2.3 ne permettra pas un load sur la 2.2.
stats
modifierPour connaitre la consommation en ressources de chaque conteneur :
docker stats --no-stream
Ex :
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS f10f50a685a6 app_1 0.00% 77.97MiB / 15.38GiB 0.50% 322kB / 1.19MB 11.1MB / 9.2MB 6 6ef747c18fe3 app_2 1.00% 48.89MiB / 15.38GiB 0.31% 6.67kB / 0B 92.7MB / 5.91MB 6
prune
modifierPour supprimer les conteneurs arrêtés[4] :
docker container prune
Les images :
docker image prune
Les réseaux :
docker network prune
Les conteneurs, images et réseaux inutilisés :
docker system prune
Enfin pour les volumes (généralement volumineux) :
docker volume prune
Il existe des filtres[5] :
- -a all : supprime tout.
- -f force.
- --filter : filtre par clé valeur. Si la clé est "until", alors il filtre par date (ex : until=720h).
- --volumes : supprime les volumes des objets en paramètre.
Par exemple pour purger les images et leurs volumes toutes les nuits à 3 h, on peut créer cette tâche planifiée :
0 3 * * * docker system prune --all --volumes -f
tag
modifierRenommer une image.
Références
modifier- ↑ https://docs.docker.com/storage/volumes/
- ↑ https://gist.github.com/timhodson/ea11c76424e5b3f36c017d9d0ca7ad10
- ↑ https://docs.docker.com/engine/reference/builder/
- ↑ https://docs.docker.com/engine/reference/commandline/container_prune/
- ↑ https://docs.docker.com/engine/reference/commandline/system_prune/
Dockerfile
Une fois le processus Docker lancé, on peut commencer à lui demander de construire des conteneurs, de zéro ou à partir d'images d'un registre.
Rôle
modifierIl existe deux sortes de conteneur :
- Celui issu d'une image téléchargée et utilisée telle qu'elle.
- Celui construit avec des instructions personnalisées.
Par convention, les instructions pour construire un conteneur sont écrites dans un fichier appelé "Dockerfile". Il est recommandé de les placer dans un dépôt Git pour les versionner.
Commandes Dockerfile
modifierLes commentaires sont précédés du croisillon (#).
ADD
modifierPermet de copier des fichiers ou dossiers de la machine hôte vers le conteneur[1].
Les Dockerfile n’ont jamais accès aux volumes de l'hôte, sauf dans l’ENTRYPOINT.
ARG
modifierCrée une variable qui sera accessible dans la première image (FROM). Ex :
ARG NODE_VERSION=10 ... RUN curl -sL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash
Éviter d'utiliser ce système pour bénéficier du build cache : ainsi Docker ne retéléchargera pas toutes les dépendances du Dockerfile lors du changement d'une variable située en début de Dockerfile, et n'affectant qu'une seule d'entre elles.
CMD
modifierCommande à exécuter au lancement du conteneur.
COPY
modifierCopie des fichiers ou dossiers de la machine hôte vers le conteneur[2]. Ainsi, l'image les embarquera (contrairement à s'ils étaient montés dans un volume).
Ex :
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
La différence avec ADD
est qu'il ne prend pas en compte les décompression de .tar et les URLs distantes[3].
ENTRYPOINT
modifierNom d'un fichier exécutable (par exemple en shell) qui s'exécutera après chaque lancement du conteneur[4].
Ex :
ENTRYPOINT /usr/local/bin/entrypoint.sh
Le fichier exécuté par l'entrypoint est le principal moyen d'accéder à la machine hôte, puisque le Dockerfile ne peut pas (en dehors de COPY
qui peut la lire sans y écrire).
ENV
modifierCrée une variable d'environnement accessible à toutes les images du Dockerfile[5].
EXPOSE
modifierOuvre le port logiciel mentionné du conteneur[6].
FROM
modifierPart d'une image Docker pour en créer une autre qui la complète[7].
Cela permet par exemple le multistage build : se servir d'une première image comme builder volumineux (avec des sources, des dépendances nécessaires à des installations), duquel on copie seulement les fichiers à utiliser dans une autre image plus légère, qui sera montée en conteneur[8].
LABEL
modifierAjoute une description à une image[9].
RUN
modifierLance une commande. Ex :
RUN ls
STOPSIGNAL
modifierSignal d'arrêt à envoyer au conteneur, au format nombre ou nom. Par exemple SIGKILL pour le tuer.
USER
modifierSe connecte à l'utilisateur et mot de passe en paramètre pour lancer les instructions RUN
, CMD
ou ENTRYPOINT
[10].
Par ailleurs, pour que le conteneur possède les permissions de l'utilisateur courant[11] :
docker --user $(id -u):$(id -g)
Utilisation dans Docker Compose
modifieruser: ${CURRENT_UID}
Puis au lancement :
CURRENT_UID=$(id -u):$(id -g) docker compose up -d
La présence de l'opérateur ":" dans les accolades signifie que l'on bascule vers cet utilisateur si la variable est inconnue du .env. Par exemple pour utiliser l'UID 1000 si UID=
n'est pas renseigné dans le .env :
user: ${UID:-1000}:${GID:-1000}
VOLUME
modifierPoint de montage accessible par l'hôte et les autres conteneurs[12].
WORKDIR
modifierDéfinit le répertoire de travail, c'est-à-dire celui à partir duquel les commandes partent (ex : pwd
), y compris quand on se connecte au conteneur après son montage.
Équivalent à docker --workdir
.
.dockerignore
modifierUn fichier .dockerignore peut être placé dans un dépôt pour que son conteneur ignore le contenu qui y figure lors des commandes ADD
et COPY
. Exemple pour Symfony[13] :
node_modules/*
var/*
vendor/*
Bonnes pratiques
modifierVoir https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
Exemples
modifierApache avec PHP7.1
modifierVoici un exemple de serveur Apache avec PHP7.1 pour MediaWiki[14] :
FROM debian:sid
ENV TZ=Europs/Paris
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
ENV MEDIAWIKI_VERSION wmf/1.30.0-wmf.4
# XXX: Consider switching to nginx.
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
apache2 \
libapache2-mod-php7.1 \
php7.1-mysql \
php7.1-cli \
php7.1-gd \
php7.1-curl \
php7.1-mbstring \
php7.1-xml \
imagemagick \
netcat \
git \
; \
rm -rf /var/lib/apt/lists/*; \
rm -rf /var/cache/apt/archives/*; \
a2enmod rewrite; \
a2enmod proxy; \
a2enmod proxy_http; \
# Remove the default Debian index page.
rm /var/www/html/index.html
# MediaWiki setup
RUN set -eux; \
mkdir -p /usr/src; \
git clone \
--depth 1 \
-b $MEDIAWIKI_VERSION \
https://gerrit.wikimedia.org/r/p/mediawiki/core.git \
/usr/src/mediawiki \
; \
cd /usr/src/mediawiki; \
git submodule update --init skins; \
git submodule update --init vendor; \
cd extensions; \
# Extensions
# TODO: make submodules shallow clones?
git submodule update --init --recursive VisualEditor; \
git submodule update --init --recursive Math; \
git submodule update --init --recursive EventBus; \
git submodule update --init --recursive Scribunto; \
git submodule update --init --recursive ParserFunctions; \
git submodule update --init --recursive SyntaxHighlight_GeSHi; \
git submodule update --init --recursive Cite; \
git submodule update --init --recursive Echo; \
git submodule update --init --recursive Flow; \
git submodule update --init --recursive PageImages; \
git submodule update --init --recursive TextExtracts; \
git submodule update --init --recursive MobileFrontend; \
git submodule update --init --recursive TemplateData; \
git submodule update --init --recursive ParserFunctions; \
git submodule update --init --recursive Citoid
COPY php.ini /usr/local/etc/php/conf.d/mediawiki.ini
COPY apache/mediawiki.conf /etc/apache2/
RUN echo "Include /etc/apache2/mediawiki.conf" >> /etc/apache2/apache2.conf
COPY docker-entrypoint.sh /entrypoint.sh
EXPOSE 80 443
ENTRYPOINT ["/entrypoint.sh"]
CMD ["apachectl", "-e", "info", "-D", "FOREGROUND"]
Nginx avec PHP-FPM 8.2
modifierFROM php:8.2-fpm
ENV TZ=Europs/Paris
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt-get update && apt-get install -y \
libxml2-dev \
libicu-dev \
libcurl3-dev \
libsqlite3-dev \
libedit-dev \
zlib1g-dev \
libfreetype6-dev \
libjpeg62-turbo-dev \
libmemcached-dev \
libzip-dev \
libonig-dev \
libpq-dev
RUN docker-php-ext-install \
intl \
pdo_mysql \
pdo_pgsql \
opcache \
bcmath \
soap \
sockets \
zip \
&& docker-php-ext-configure gd \
&& docker-php-ext-install -j$(nproc) gd
RUN pecl install -f xdebug \
&& export XDEBUG_PATH=`find / -name "xdebug.so"`
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
WORKDIR /var/www/myApp
CMD ["php-fpm"]
Références
modifier- ↑ https://docs.docker.com/engine/reference/builder/#add
- ↑ https://docs.docker.com/engine/reference/builder/#copy
- ↑ https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy
- ↑ https://docs.docker.com/engine/reference/builder/#entrypoint
- ↑ https://docs.docker.com/engine/reference/builder/#env
- ↑ https://docs.docker.com/engine/reference/builder/#expose
- ↑ https://docs.docker.com/engine/reference/builder/#from
- ↑ https://docs.docker.com/develop/develop-images/multistage-build/
- ↑ https://docs.docker.com/engine/reference/builder/#label
- ↑ https://docs.docker.com/engine/reference/builder/#user
- ↑ https://medium.com/redbubble/running-a-docker-container-as-a-non-root-user-7d2e00f8ee15
- ↑ https://docs.docker.com/engine/reference/builder/#volume
- ↑ https://snyk.io/blog/10-best-practices-to-containerize-nodejs-web-applications-with-docker/
- ↑ https://github.com/wikimedia/mediawiki-docker/blob/master/dev/Dockerfile
Docker compose
La commande docker compose
est un utilitaire généralement fourni avec Docker, permettant d'orchestrer plusieurs images et conteneurs avec la même commande[1]. Pour ce faire, les paramétrages de l’ensemble des conteneurs doivent être définis dans le fichier docker-compose.yml à la racine du projet. Toutefois il est possible de surcharger des parties de ce fichier au lancement des conteneurs, pour chaque environnement[2].
Par convention, les paires clés / valeurs de ces fichiers YAML ne sont pas entre apostrophes ou guillemets, mais cela fonctionne aussi avec. Toutefois il existe deux exceptions : les versions, et les associations de ports (contenant des ":"), où les guillemets sont par contre recommandés pour éviter les conflits (avec le "." ou avec le ":" interprété avec des nombres sexagésimaux[3]).
Configuration YAML
modifierversion
modifierVersion de Docker Compose[4]. Exemple en 2023 :
version: "3.8"
networks
modifierDéfinition du réseau des VM Docker.
Ex :
networks: default: ipv4_address: 172.170.0.2
services
modifierListe des conteneurs à construire. Pour chacun on peut trouver :
image
modifierNom de l'image à télécharger (sur https://hub.docker.com/ ou un dépôt privé). Elle peut être suivie d'un tag pour en indiquer la version.
Exemples :
image: mariadb image: mariadb:latest image: mariadb:10.4
extends
modifier"image" permet donc de lancer un groupe d'applications, qui sont par ailleurs lançables individuellement. Mais pour partager des configurations on peut aussi utiliser "extends"[5] :
extends: file: webapp/docker-compose.yml service: webapp
build
modifierAlternativement à l'image, on peut indiquer le chemin d'un dockerfile pour construire son propre conteneur.
Si le conteneur ne partage aucun fichier avec d'autres, indiquer simplement le nom du dossier contenant le dockerfile :
build: ./php8.2-fpm
Sinon, préciser le contexte où le conteneur devra récupérer les fichiers partagés nécessaires à son build :
build: context: . dockerfile: ./php8.2-fpm/Dockerfile
volumes
modifierMapping des répertoires partagés entre la machine hôte et le conteneur :
volumes: - $HOME/www:/var/www
La variable $HOME vaut "~" par défaut (dossier de l'utilisateur courant), mais peut être remplacée dans le fichier .env.
ports
modifierMapping du partage des ports. Ex :
ports: - "3306:3306"
environment
modifierInjecte des variables d'environnement dans le conteneur. Très utile pour que les conteneurs soient à l'heure de la machine hôte :
environment: TZ: Europe/Paris
environment:
n'accepte pas les sous-tableaux : il faut les convertir en JSON.
env_file
modifierDéfinit le nom d'un fichier contenant des variables d'environnement récupérables dans docker-compose.yml, avec la syntaxe "${ma_variable}". On peut aussi rajouter une valeur par défaut ensuite. Exemple :
env_file: .env environment: HOST_UID: ${UID:-valeur-par-défaut}
Sur Windows le changement de l'UID entraine une modification des droits de tous les fichiers.
depends_on
modifierPermet de spécifier qu'un conteneur doit en attendre un autre pour être lancé.
restart
modifierIndique si le conteneur doit se lancer au démarrage du daemon Docker (donc de la machine hôte). Vaut "no" par défaut. Ex :
restart: always
Autre valeur possible :
unless-stopped
container_name
modifierPermet de forcer un nom de conteneur.
hostname
modifierPermet de forcer un nom de machine dans le conteneur. Utile si on a une application qui doit pointer dessus dans son .env (car "localhost" fonctionne quand le serveur était installé directement sur la machine hôte mais pas dans un conteneur).
network
modifierPermet de forcer une adresse IP pour le conteneur.
Dans docker-compose.yml, il faut toujours remplir le paramètre "default" de "networks" pour ne pas qu’il prenne une plage utilisée.
extra_hosts
modifierRemplit le /etc/hosts du conteneur. Ex :
extra_hosts: - mon_serveur_local.localhost:172.20.0.2
command
modifierPour exécuter un script à chaque lancement du conteneur.
command: ls -alh
ou en multiligne :
command: | ls -alh
</syntaxhighlight> ou :
command: ['ls', '-alh']
ou si la commande est dans un fichier :
command: /bin/ls.sh
entrypoint
modifierPour définir le dernier script exécuté à chaque lancement du conteneur.
tty
modifierÉquivalent à docker -t
: ajoute un pseudo-terminal pour interagir avec le conteneur.
Exemples
modifierMinimal
modifierExemple de docker-compose.yml contenant un seul conteneur CentOS, qui a le droit d'accéder au dossier ~/www :
version: "3.8"
services:
centos:
image: centos/systemd
volumes:
- $HOME/www:/var/www
Avancé
modifierversion: "3.8"
networks:
default:
driver: bridge
ipam:
driver: default
config:
- subnet: 172.170.0.0/16
services:
mariadb:
hostname: mariadb
image: mariadb:10.4
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: wikibooks
# Partage pour les commandes SQL "into outfile" et "load data infile"
volumes:
- $HOME/www:/var/www
restart: unless-stopped
networks:
default:
ipv4_address: 172.170.0.3
adminer:
hostname: adminer
image: adminer
ports:
- 8080:8080
restart: unless-stopped
networks:
default:
ipv4_address: 172.170.0.4
Avec Traefik
modifierPour éviter de maintenir les noms de domaines des conteneurs dans le fichier hosts de la machine hôte, il existe le conteneur du proxy inverse Traefik pour mettre en l’œuvre l'association entre les conteneurs et leurs URLs.
Par ailleurs, sachant que les docker-compose.yml peuvent être utilisés dans des environnements de tests, donc sans besoin d'y accéder par des noms de domaine, il est préférable de séparer le docker-compose.yml en deux : l'un qui sera tout le temps utilisé pour l'application, et l'autre uniquement quand on veut l'utiliser manuellement en complément du premier : il faudra alors monter les conteneurs en précisant leurs deux noms.
docker-compose.yml
modifierPlus besoin de fixer l'IP ici :
version: "3.8"
services:
mariadb:
hostname: mariadb
image: mariadb:10.4
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: wikibooks
volumes:
- $HOME/www:/var/www
restart: unless-stopped
docker-compose.override.yml
modifierPar convention, le nom du second docker-compose.yml est docker-compose.override.yml[6]. Mais on peut en créer un par environnement (ex : docker-compose.test.yml, docker-compose.dev.yml, docker-compose.prod.yml).
Ex :
version: "3.8"
services:
traefik:
image: traefik
command:
- --providers.docker
- --entryPoints.web.address=:80
- --entryPoints.websecure.address=:443
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
adminer:
image: adminer
labels:
- traefik.enable=true
- traefik.http.routers.adminer.rule=Host(`adminer.localhost`)
- traefik.http.routers.adminer.entryPoints=web
depends_on:
- mariadb
Ainsi, la base décrite dans le premier fichier sera accessible par l'Adminer du second sur http://adminer.localhost.
Plusieurs domaines vers le même conteneur
modifierOn peut avoir par exemple un serveur Apache avec plusieurs vhosts pointant vers des applications différentes :
apache:
labels:
- traefik.enable=true
- traefik.http.routers.app.rule=Host(`www.example1.com`) || Host(`www.example2.com`)
- traefik.http.routers.app.entryPoints=web
- traefik.http.routers.whoami.entrypoints=web-secure
- traefik.http.routers.whoami.tls=true
- traefik.http.routers.whoami.tls.certresolver=certificato
- traefik.http.routers.whoami.tls.domains[0].main=*.example1.com
- traefik.http.routers.whoami.tls.domains[1].main=*.example2.com
hostname: apache
build: './devops/apache'
environment:
TZ: Europe/Paris
APACHE_LOG_DIR: /var/log/apache2
volumes:
- ./apps:/var/www/
Gestion
modifierPour relancer le conteneur (sur Windows ou Linux) :
docker compose stop; docker compose build; docker compose start
Pour lancer les conteneurs avec plusieurs docker-compose.yml :
docker compose -f docker-compose.yml -f docker-compose.override.yml up -d
Pour rentrer dedans :
docker compose exec centos bash
Pour rentrer dedans en root :
docker compose exec --user root centos bash
Pour le lancer et rentrer dedans en même temps :
docker compose run centos bash
Pour exécuter une seule commande shell dedans sans y rentrer (en restant depuis la machine hôte) :
docker compose exec centos sh -c 'ls -alh'
Logs
modifierPour voir les logs de tous les conteneurs en live :
docker compose logs -f
Pour voir les logs d'un seul conteneur :
docker compose logs nom_du_conteneur
Supprimer les logs
modifierL'emplacement des logs d'un conteneur est visible avec :
docker inspect --format='{{.LogPath}}' nom_du_conteneur
Sur Linux
modifierTous les conteneurs
modifierPour supprimer les logs de tous les conteneurs sur Linux :
docker compose stop find /var/lib/docker/containers/ -type f -name "*.log" -delete docker compose up -d
Un seul conteneur
modifierPour ne supprimer les logs que d'un seul conteneur :
docker compose stop mon_conteneur sudo rm $(sudo docker inspect --format='{{.LogPath}}' mon_conteneur) docker compose up -d mon_conteneur
Sur Windows
modifierSur Windows, comme les logs sont dans le fichier C:\ProgramData\DockerDesktop\vm-data\DockerDesktop.vhdx, il faut d'abord se connecter à la VM Docker pour exécuter cette commande[7]. Exemple en DOS :
docker run --privileged -it -v /var/run/docker.sock:/var/run/docker.sock jongallant/ubuntu-docker-client docker run --net=host --ipc=host --uts=host --pid=host -it --security-opt=seccomp=unconfined --privileged --rm -v /:/host alpine /bin/sh chroot /host
Références
modifier- ↑ https://xataz.developpez.com/tutoriels/utilisation-docker/#LXII-B
- ↑ https://docs.docker.com/compose/production/
- ↑ https://docs.docker.com/compose/compose-file/#ports
- ↑ https://docs.docker.com/compose/compose-file/
- ↑ https://docs.docker.com/compose/extends/
- ↑ https://docs.docker.com/compose/extends/
- ↑ https://blog.jongallant.com/2017/11/ssh-into-docker-vm-windows/
Kubernetes
Kubernetes est un logiciel open-source sorti en 2015 pour orchestrer de plusieurs conteneurs avec des options de quotas, scalabilité horizontale, déploiement sans coupure de service et relance automatique en cas d'indisponibilité. Pour ces raisons, il est plus orienté pour la production que pour le développement[1], de plus il nécessite d'utiliser des images Docker déjà construites.
Installation
modifierClient
modifierLa configuration peut être stockée dans des fichiers .yaml et modifiée par la commande kubectl
[2], ou via l'interface graphique Dashboard[3]. De plus, il est nécessaire de lancer un cluster contenant les conteneurs via kubeadm
[4].
Debian
modifierSur Debian ou ses dérivés[5] :
sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.29/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.29/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl
Test :
kubectl --help
k9s
modifierPour éviter de taper chaque commande, il existe une interface graphique gratuite nommée k9s, pouvant exploiter la conf de kubectl : https://k9scli.io/topics/install/.
Cela nécessite le gestionnaire de paquets Homebrew :
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Puis :
brew install derailed/k9s/k9s
Par exemple on peut déclencher un cronjob avec "t" ou rentrer dans un conteneur en shell avec "s".
:namespace
pour voir la liste puis entrée après sélection./running
Types
modifierpod
modifierUn pod désigne un groupe de conteneur géré par Kubernetes[6].
replica set
modifierUn replica set désigne un ensemble de pods, dont le nombre maximum peut y être défini.
secret
modifierListe de variables d'environnement chiffrées, généralement des mots de passe.
Ils sont chiffrés via "kubeseal", à partir d'un fichier YAML non versionné contenant les chaines encodées en base64.
Ce fichier contient plusieurs paramètres, par exemple le type. Il en existe huit, "opaque" étant celui par défaut[7].
La commande de chiffrement quant-à-elle permet de définir le scope des secrets[8] :
- strict (par défaut) : le nom et le namespace ne peuvent pas changer sans rechiffrer.
- namespace-wide : utilisable dans tout le namespace.
- cluster-wide : utilisable dans tout le cluster.
Toutefois on peut aussi les mettre dans le .yaml. Ex : metadata:
annotations: sealedsecrets.bitnami.com/cluster-wide: "true"
CronJob
modifierLance un conteneur dédié à une tâche planifiée (cron), à chaque fois qu'elle tourne[9].
Ingress
modifierAccès à l'application (DNS).
PVC
modifierPersistent volume : stocke des données indépendamment du redémarrage des pods.
Commandes kubectl
modifierget
modifierListe des éléments du serveur :
kubectl get -A all
logs
modifierPour voir le log de la sortie standard d'un conteneur :
kubectl logs -f mon_conteneur
exec
modifierPour rentrer dans un conteneur :
kubectl exec -it mon_conteneur -- /bin/bash
scale
modifierPour augmenter le nombre de pods dans un replicatset. Par exemple si on peut passer le nombre de 2 à 3 sur "mysql"[10] :
kubectl scale --current-replicas=2 --replicas=3 deployment/mysql
Références
modifier- ↑ https://kubernetes.io/docs/setup/
- ↑ https://kubernetes.io/fr/docs/reference/kubectl/overview/
- ↑ https://kubernetes.io/fr/docs/tasks/access-application-cluster/web-ui-dashboard/
- ↑ https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
- ↑ https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/
- ↑ https://kubernetes.io/fr/docs/concepts/workloads/pods/pod/
- ↑ https://kubernetes.io/docs/concepts/configuration/secret/#secret-types
- ↑ https://github.com/bitnami-labs/sealed-secrets#scopes
- ↑ https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/
- ↑ https://jamesdefabia.github.io/docs/user-guide/kubectl/kubectl_scale/
Problèmes connus
Accéder aux logs
modifierPar exemple si un conteneur ne se lance pas ou se relance toutes les secondes, un motif plus précis qu'en console peut se trouver dans les logs.
Pour le démon :
tail /var/log/docker.log
Pour les conteneurs
modifierdocker compose logs
Ces deux commandes acceptent l'argument "-f" pour les afficher en temps réel.
Pour un seul conteneur
modifierdocker compose logs nom_du_conteneur
ou :
docker logs nom_du_conteneur
Définir les droits des fichiers partagés avec le conteneur
modifierSi le conteneur est amené à modifier les fichiers du volume, par défaut il a les droits root de la machine hôte.
Pour éviter cela, on peut faire un chown www-data
dans Dockerfile, ou utiliser UID 1000
(si le compte utilisé par la machine hôte est local).
Récupérer l'IP d'un conteneur
modifierdocker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' nom_du_conteneur # ou docker inspect --format='{{.NetworkSettings.Networks.apps.IPAddress}}' nom_du_conteneur # où "apps" est le nom du réseau
Récupérer la version de l'image d'un conteneur
modifierdocker image inspect --format 'Modèle:Json .' "nom_du_conteneur"
Réinitialiser les conteneurs à zéro
modifier
Cette opération peut prendre du temps car Docker télécharge à nouveau tous les paquets ensuite.
Linux :
docker rm -f $(docker ps -a -q); docker rmi -f $(docker images -q); docker network rm $(docker network ls -q)
Windows :
docker rm -f $(docker ps -a -q); docker rmi -f $(docker images -q); docker network rm $(docker network ls -q)
La partie network peut être exécutée indépendamment, par exemple en cas de message ERROR: Pool overlaps with other one on this address space.
Messages d'erreur
modifierSous Windows
modifier/usr/bin/env: 'php\r': No such file or directory
modifierUtiliser "winpty". Ex :
docker exec -it php7.3-fpm bash
Sinon[1] :
docker exec -it <container> bash cd bin tr -d '\015' <console >console.new mv console console.old mv console.new console
Certains conteneurs ne peuvent pas être lancés (timeout)
modifierVérifier que le partage Windows a bien été fait : clic droit, Settings, Resources, File Sharing, C: (puis relancer Docker Desktop).
Le partage de volume ne fonctionne pas sur Linux
modifierSi ça n'a jamais fonctionné : ajouter son compte au groupe "docker" et redémarrer la machine hôte.
Le partage de volume ne fonctionne pas sur Windows
modifierSi ça n'a jamais fonctionné : ajouter son compte dans le groupe "docker-users", et redémarrer la machine hôte.
C'est peut-être lié à la plage d'IP de Docker, remettre celle par défaut.
Si ça marchait sur Windows 10 pro dans un Active Directory et que ça ne fonctionne plus en dehors de l'AD ou en VPN, c'est un bug avec Docker Desktop 2.1.0.5 qui semble résolu dans la 2.1.6.1. En effet, seul un admin de l'AD peut autoriser le partage des volumes, et le port 445 doit être ouvert.
Pour tester si ça marche :
docker run -v c:/Users:/data alpine ls data
500: {"Message":"Unhandled exception: Drive has not been shared"}'
modifierDans Docker Desktop, partager le volume concerné.
502 Bad Gateway dans Nginx et Bus error dans les commandes PHP
modifierRedémarrer Docker Desktop.
Sinon c'est un processus PHP qui gonfle à outrance à cause du code.
ERROR: failed to create new listening socket: socket(): Address family not supported by protocol (97)
modifierRelancer Docker Desktop.
Error: mounting wslCLIDest: stat /mnt/host/c/Program Files/Docker/Docker/resources/wsl/docker-wsl-cli.iso: no such file or directory
modifierDécocher Use the WSL 2 based engine dans les options et relancer Docker Desktop[2].
fatal: not a git repository (or any parent up to mount point /var) Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set)
modifierRedémarrer Docker Desktop.
Error response from daemon: Mount denied: The source path "mon_dossier;C" doesn't exist and is not known to Docker
modifierSous Git Bash dans Windows, il faut préfixer le chemin local par "/". Ex : docker run -it --rm -v /${PWD}:/wkDir $IMAGE_TAG yarn dev
[3]
Invalid mode /var/www
modifierLe chemin d'accès dans docker-compose.yml n'est pas compris. Cela se produit pas exemple quand on met des antislashs à la place des slashs.
Sous Linux
modifierstandard_init_linux.go:211: exec user process caused "no such file or directory"
modifierCela peut se produire quand des conteneurs testés sur Linux sont utilisés sur Windows.
Il faut changer les retours chariots du fichier appelé par "ENTRYPOINT" dans le Dockerfile, de CRLF (Windows) vers LF (Unix). Ex : dos2unix php7.4-fpm/bin/custom-docker-php-entrypoint
Puis reconstruire et relancer le conteneur.
Autres solutions
modifierOn peut aussi lancer "dos2unix" automatiquement depuis le dockerfile sur une copie de l'exéutable[4].
S'il s'agit d'un dépôt Git, on peut aussi le sauvegarder autrement depuis Linux[5] :
- lancer
git config core.autocrlf false
- créer un fichier .gitattributes[6] contenant
text eol=lf
container_linux.go:349: starting container process caused "exec: \"custom-docker-php-entrypoint\": executable file not found in $PATH": unknown
modifierCela peut se produire quand des conteneurs testés sur Windows sont utilisés sur Linux.
Il faut changer leur donner les droits d'exécution (chmod +x
).
Puis reconstruire et relancer le conteneur.
Pour tout OS
modifier/bin/sh: no such file or directory
modifierForcer la reconstruction :
DOCKER_BUILDKIT=0 docker compose build
Cannot connect to the Docker daemon. Is the docker daemon running on this host?
modifiersudo usermod -aG docker $USER
Si ça ne marche pas, relancer docker en administrateur.
Cannot start service xxx: Address already in use
modifierDeux processus utilisent le même port.
- Si c'est deux conteneurs, dans Docker Compose, si l'un des deux avait été retiré, il était peut-être configuré en
restart: always
et il faut le remettre dans docker-compose.yml pour le stopper. - Si l'un vient de la machine hôte, l'identifier avec
sudo netstat -tulpn | grep ':80 '
puis le stopper.
Cannot start service xxx :driver failed programming external connectivity on endpoint
modifierImpossible de lancer un conteneur sur Windows :
- Soit Docker n'a pas accès au volume, et il faut cocher la case "Shared drives" dans Docker Desktop, ou lancer la commande suivante en acceptant le partage :
docker run --rm -v c:/Users:/data alpine ls /data
- Soit Docker n'a pas accès aux ports de ses conteneurs, et il faut fermer les processus qui les utilisent. Il peut même s'agir d'une deuxième instance de Docker.
Couldn't connect to Docker daemon at http+docker://localhost - is it running?
modifier/etc/init.d/docker start
Si le démon ne se lance pas, upgrader l'OS et redémarrer. Sinon, réinstaller Docker.
Could not resolve host: xxx (pas de DNS)
modifierRevoir la plage d'IP définie dans le paragraphe "networks" de docker-compose.yml.
Device or resource busy, Cette action ne peut pas être réalisée car le fichier est ouvert dans com.docker.backend.exe
modifierC'est un bug connu (sur Linux et Windows) quand composer installe certains paquets[7]. On ne peut supprimer le fichier qu'en fermant tout Docker (sous Windows en tout cas, il ne suffit pas de le redémarrer).
Cela se produit (en cas de réécriture d'historique ?), repartir d'une branche propre avant de relancer "composer install". Sinon, le lancer dans une VM et récupérer le dossier vendor.
Error response from daemon: Get https://xxx: no basic auth credentials
modifierSur certains dépôts privés, pour faire un docker pull
il faut préalablement se loguer. Ex :
docker login -u mon_utilisateur -p mon_mdp mon_url
Invalid interpolation format for "environment" option in service "documents": "^https?://.*?$"
modifierÉchapper le $ interprété dans docker-compose.yml. Par exemple, remplacer :
CORS_ALLOW_ORIGIN: "^https?://.*?$"
par :
CORS_ALLOW_ORIGIN: "^https?://.*?$$"
"encore dev-server --host my_url" ne marche pas
modifierMapper l'URL définie dans cette commande de package.json, avec 0.0.0.0 dans docker-compose.yml :
extra_hosts: - "my_url:0.0.0.0"
Références
modifier- ↑ https://www.thetopsites.net/article/50789087.shtml
- ↑ https://github.com/docker/for-win/issues/6822
- ↑ https://stackoverflow.com/questions/50608301/docker-mounted-volume-adds-c-to-end-of-windows-path-when-translating-from-linux
- ↑ https://willi.am/blog/2016/08/11/docker-for-windows-dealing-with-windows-line-endings/
- ↑ https://stackoverflow.com/questions/53165471/building-docker-images-on-windows-entrypoint-script-no-such-file-or-directory
- ↑ https://git-scm.com/docs/gitattributes
- ↑ https://github.com/moby/moby/issues/22260
GFDL | Vous avez la permission de copier, distribuer et/ou modifier ce document selon les termes de la licence de documentation libre GNU, version 1.2 ou plus récente publiée par la Free Software Foundation ; sans sections inaltérables, sans texte de première page de couverture et sans texte de dernière page de couverture. |