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?

14
Dirk 16 nov. 2017 à 14:02

4 réponses

Meilleure réponse

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

12
mixja 28 févr. 2018 à 19:46

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
6
Romain 25 janv. 2020 à 17:24

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
9
Maoz Zadok 15 janv. 2019 à 11:23

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).

11
Dirk 16 nov. 2017 à 11:02
47327979