Astuces Docker
Ajouters des fichiers facultatifs dans une image
Cas concret : ajout facultatif de fichiers depuis un dossier de l'hôte dans un dossier existant de l'image
Exemple :
- une image de base dispose de cette arborescence :
app
└── config
└── application.properties
- on veut ajouter des fichiers de configuration locaux :
config
├── application-h2.properties
└── application-local.properties
Dans mon projet, je repars de l'image de base et j'ajoute les configurations locales :
COPY configs/* /app/configs/
Si le dossier est vide, dans la pipeline de CI/CD par exemple,
j'aurai une erreur no source files were specified
Créer un fichier caché
En ajoutant un fichier caché, l'instruction trouve toujours un fichier, mais celui-ci sera ignoré par l'application.
configs/
└── .keep
Avantages :
- Simple et efficace
- Ce fichier coïncide bien avec Git et permet au dossier d'être versionné
Inconvénients :
- Il s'agit d'un contournement plus que d'une solution à long terme
- Peut poser problème dans d'autres cas d'usage, notamment si l'application cherche à lister tous les fichiers du dossier
Ne pas utiliser d'astérisques
Il semblerait que ce soit la solution la plus robuste :
COPY configs/ /app/configs/
Avec cette instruction :
- si le dossier est vide, rien ne se passe
- si un ou plusieurs fichiers sont présents dans le dossier hôte, ils sont copiés dans l'image
- si des fichiers sont présents dans l'image, il y a fusion
- les fichiers du dossier hôtes sont copiés, écrasant potentiellement ceux de l'image
- les fichiers de l'image non ecrasés sont conservés
Exemple
Déplier
Création des fichiers à copier dans l'image :
mkdir -p /tmp/docker-tips/copy
cd /tmp/docker-tips/copy
mkdir -p resources/test_empty
mkdir -p resources/test_merge
mkdir -p resources/test_overwrite
mkdir -p resources/test_both
echo "two" > resources/test_empty/number.txt
echo "two" > resources/test_merge/other_number.txt
echo "two" > resources/test_overwrite/number.txt
echo "two" > resources/test_both/number.txt
echo "two" > resources/test_both/other_number.txt
Dockerfile :
# Base image
FROM alpine:latest AS base_image
RUN mkdir -p /opt/test
WORKDIR /opt/test
CMD ["ls"]
RUN mkdir -p /opt/test/dir_empty \
&& mkdir -p /opt/test/dir_merge \
&& mkdir -p /opt/test/dir_overwrite \
&& mkdir -p /opt/test/dir_both \
&& echo "one" > /opt/test/dir_merge/number.txt \
&& echo "one" > /opt/test/dir_overwrite/number.txt \
&& echo "one" > /opt/test/dir_both/number.txt \
&& echo "a" > /opt/test/dir_both/letter.txt
FROM base_image AS test_empty
COPY resources/test_empty/ /opt/test/dir_empty/
FROM base_image AS test_merge
COPY resources/test_merge/ /opt/test/dir_merge/
FROM base_image AS test_overwrite
COPY resources/test_overwrite/ /opt/test/dir_overwrite/
FROM base_image AS test_both
COPY resources/test_both/ /opt/test/dir_both/
Test 1 : Le dossier est vide dans l'image.
Résultat : on retrouve le fichier copié dans l'image.
docker build --target test_empty -t test-empty .
docker run --rm -it test-empty ls dir_empty
# number.txt
docker run --rm -it test-empty cat dir_empty/number.txt
# two
Test 2 : Le dossier contient un fichier dans l'image.
On ajoute un nouveau fichier (nom différent) depuis l'hôte.
Résultat : les deux fichiers sont présents
docker build --target test_merge -t test-merge .
docker run --rm -it test-merge ls dir_merge
# number.txt
# other_number.txt
docker run --rm -it test-merge cat dir_merge/number.txt
# one
docker run --rm -it test-merge cat dir_merge/other_number.txt
# two
Test 3 : Le dossier contient un fichier dans l'image.
On ajoute un fichier avec le même nom depuis l'hôte.
Résultat : le fichier d'origin a été ecrasé par celui de l'hôte
docker build --target test_overwrite -t test-overwrite .
docker run --rm -it test-overwrite ls dir_overwrite
# number.txt
docker run --rm -it test-overwrite cat dir_overwrite/number.txt
# two
Test 4 : Le dossier contient plusieurs fichiers dans l'image.
On ajoute un nouveau fichier (nom différent) et un fichier avec le
même nom depuis l'hôte.
Résultat : on a bien les trois fichiers dans l'iamge, l'un a été écrasé, l'autre a été ajouté et le dernier est resté intact.
docker build --target test_both -t test-both .
docker run --rm -it test-both ls dir_both
# number.txt
# other_number.txt
# letter.txt
docker run --rm -it test-both cat dir_both/number.txt
# two
docker run --rm -it test-both cat dir_both/other_number.txt
# two
docker run --rm -it test-both cat dir_both/letter.txt
# a