Selon ceci et this GitHub problèmes, il n'existe actuellement aucun moyen natif de fournir plusieurs balises pour l'image d'un service lorsque vous utilisez docker-compose
pour créer une ou plusieurs images.
Mon cas d'utilisation serait de créer des images définies dans un fichier docker-compose.yml
et de les marquer une fois avec une balise personnalisée (par exemple, un numéro de build ou une date ou similaire) et une fois comme latest
.
Bien que cela puisse être facilement réalisé avec docker
simple en utilisant balise docker, docker-compose
ne permet de définir qu'une seule balise dans la clé d'image . Utiliser docker tag
avec docker-compose
n'est pas une option pour moi car je souhaite conserver toutes mes définitions liées au docker dans le fichier docker-compose.yml
et ne pas les copier dans mon script de construction.
Quelle serait une solution décente pour obtenir la configuration de plusieurs balises avec docker-compose
et sans avoir à coder / copier d'abord les noms d'images?
4 réponses
Vous pouvez également adopter l'approche suivante:
# build is your actual build spec
build:
image: myrepo/myimage
build:
...
...
# these extend from build and just add new tags statically or from environment variables or
version_tag:
extends: build
image: myrepo/myimage:v1.0
some_other_tag:
extends: build
image: myrepo/myimage:${SOME_OTHER_TAG}
Vous pouvez ensuite simplement exécuter docker-compose build
et docker-compose push
et vous allez créer et pousser le bon ensemble d'images taguées
Comme suggéré par @JordanDeyton extends
ne peut plus être utilisé dans le format de fichier Compose > 3
et le Champs d'extension ajoutée dans la version 3.4
peut la remplacer pour atteindre le même objectif. Voici un exemple.
version: "3.4"
# Define common behavior
x-ubi-httpd:
&default-ubi-httpd
build: ubi-httpd
# Other settings can also be shared
image: ubi-httpd:latest
# Define one service by wanted tag
services:
# Use the extension as is
ubi-httpd_latest:
*default-ubi-httpd
# Override the image tag
ubi-httpd_major:
<< : *default-ubi-httpd
image: ubi-httpd:1
ubi-httpd_minor:
<< : *default-ubi-httpd
image: ubi-httpd:1.0
# Using an environment variable defined in a .env file for e.g.
ubi-httpd_patch:
<< : *default-ubi-httpd
image: "ubi-httpd:${UBI_HTTPD_PATCH}"
Les images peuvent être construites maintenant avec toutes les balises définies
$ docker-compose build
# ...
$ docker images | grep ubi-httpd
# ubi-httpd 1 8cc412411805 3 minutes ago 268MB
# ubi-httpd 1.0 8cc412411805 3 minutes ago 268MB
# ubi-httpd 1.0.1 8cc412411805 3 minutes ago 268MB
# ubi-httpd latest 8cc412411805 3 minutes ago 268MB
J'ai une solution agréable et propre utilisant des variables d'environnement (syntaxe bash pour la valeur de la variable par défaut, dans mon cas, c'est latest
mais vous pouvez utiliser n'importe quoi), voici ma composition:
version: '3'
services:
app:
build: .
image: myapp-name:${version:-latest}
Build et push (si vous devez pousser vers le registre) avec la balise par défaut, changez la version à l'aide de la variable d'environnement et compilez et poussez à nouveau:
docker-compose build
docker-compose push
export version=0.0.1
docker-compose build
docker-compose push
J'ai trouvé quelques solutions de contournement de complexité différente. Ils reposent tous sur l'hypothèse que ${IMAGE_TAG}
stocke la balise personnalisée qui représente par exemple un build no. et nous souhaitons marquer les images de tous les services avec cette balise ainsi qu'avec latest
.
grep
les noms d'images du fichier docker-compose.yml
images=$(cat docker-compose.yml | grep 'image: ' | cut -d':' -f 2 | tr -d '"')
for image in $images
do
docker tag "${image}":"${IMAGE_TAG}" "${image}":latest
done
Cependant, ceci est sujet aux erreurs si quelqu'un ajoute un commentaire dans docker-compose.yml
qui par exemple ressemble à # Purpose of this image: do something useful...
.
Construire deux fois
Utilisez ${IMAGE_TAG}
comme variable d'environnement dans votre fichier docker-compose.yml
comme décrit ici dans le premier exemple.
Ensuite, exécutez simplement le processus de construction deux fois, en remplaçant à chaque fois ${IMAGE_TAG}
par une valeur différente:
IMAGE_TAG="${IMAGE_TAG}" docker-compose build
IMAGE_TAG=latest docker-compose build
Le deuxième processus de construction devrait être beaucoup plus rapide que le premier car toutes les couches d'image doivent toujours être mises en cache à partir de la première exécution.
L'inconvénient de cette approche est qu'elle inondera votre sortie de journal de deux processus de construction ultérieurs pour chaque service, ce qui pourrait rendre plus difficile la recherche de quelque chose d'utile.
De plus, si vous avez une commande dans votre Dockerfile
qui vide toujours le cache de construction (par exemple, une commande ADD
récupérant depuis un emplacement distant avec des en-têtes last-modified
à mise à jour automatique, ajoutant des fichiers qui sont constamment mis à jour par un processus externe, etc.), alors la construction supplémentaire pourrait ralentir considérablement les choses.
Analyser les noms d'images du fichier docker-compose.yml
avec du code Python en ligne
L'utilisation d'un véritable analyseur yaml
en Python (ou tout autre langage tel que Ruby
ou perl
ou tout ce qui est installé sur votre système) est plus robuste que la première approche grep
mentionnée car il ne sera pas dérouté par des commentaires ou des manières étranges mais valides d'écrire le fichier yml
.
En Python, cela pourrait ressembler à ceci:
images=$(python3 <<-EOF # make sure below to indent with tabs, not spaces; or omit the "-" before "EOF" and use no indention at all
import yaml
content = yaml.load(open("docker-compose.build.yml"))
services = content["services"].values()
image_names = (service["image"].split(":")[0] for service in services)
print("\n".join(image_names))
EOF
)
for image in ${images}
do
docker tag ${image}:${IMAGE_TAG} ${image}:latest
done
L'inconvénient de cette approche est que la machine exécutant la compilation doit avoir Python3 installé, ainsi que le Bibliothèque PyYAML. Comme déjà mentionné, ce modèle pourrait être utilisé de la même manière avec Python2 ou tout autre langage de programmation installé.
Obtenir les noms d'images avec une combinaison de certaines commandes docker
L'approche suivante utilisant des commandes natives docker
et docker-compose
(utilisant go-templates) est un peu plus complexe à écrire mais fonctionne également très bien.
# this should be set to something unique in order to avoid conflicts with other running docker-compose projects
compose_project_name=myproject.tagging
# create containers for all services without starting them
docker-compose --project-name "${compose_project_name}" up --no-start
# get image names without tags for all started containers
images=$(docker-compose --project-name "${compose_project_name}" images -q | xargs docker inspect --format='{{ index .RepoTags 0}}' | cut -d':' -f1)
# iterate over images and re-tag
for image in ${images}
do
docker tag "${image}":"${IMAGE_TAG}" "${image}":latest
done
# clean-up created containers again
docker-compose --project-name "${compose_project_name}" down
Bien que cette approche n'ait pas de dépendances externes et soit plus sûre que la méthode grep
, elle peut prendre quelques secondes de plus pour s'exécuter sur des configurations volumineuses pour créer et supprimer les conteneurs (ce n'est généralement pas un problème).
Questions liées
De nouvelles questions
docker
Docker est un outil pour construire et exécuter des conteneurs. Les questions concernant les Dockerfiles, les opérations et l'architecture sont acceptées. Les questions sur l'exécution de docker en production peuvent trouver de meilleures réponses sur ServerFault (https://serverfault.com/). La balise docker est rarement utilisée seule et est souvent associée à d'autres balises telles que docker-compose et kubernetes.