wake-up-neo.net

So verwenden Sie mehrere Image-Tags mit Docker-Compose

Gemäß this und this GitHub-Problemen gibt es derzeit keine systemeigene Methode, um mehrere Tags für das Image eines Dienstes bereitzustellen, wenn Sie mit docker-compose ein oder mehrere Images erstellen.

Mein Anwendungsfall wäre, Bilder zu erstellen, die in einer docker-compose.yml-Datei definiert sind, und sie einmal mit einem benutzerdefinierten Tag (z. B. einer Build-Nr. Oder einem Datum oder ähnlichem) und einmal als latest zu kennzeichnen.

Während dies mit plain docker mit docker Tag leicht erreicht werden kann, kann mit docker-compose nur ein einziges Tag in der image key gesetzt werden. Die Verwendung von docker tag zusammen mit docker-compose ist für mich keine Option, da ich alle meine Docker-bezogenen Definitionen in der docker-compose.yml-Datei behalten und nicht in mein Build-Skript kopieren möchte.

Was wäre eine anständige Umgehung, um das Setzen mehrerer Tags mit docker-compose zu erreichen, ohne die Bildnamen zuerst hartcodieren/kopieren zu müssen?

6
Dirk

Sie können auch den folgenden Ansatz wählen:

# 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}

Sie können dann einfach docker-compose build und docker-compose Push ausführen, und Sie werden den richtigen Satz von getaggten Bildern erstellen und pushen

7
mixja

Ich habe ein paar Problemumgehungen verschiedener Komplexität gefunden. Sie alle setzen auf die Annahme, dass ${IMAGE_TAG} das angepasste Tag speichert, das z. ein Build-Nr. und wir möchten die Bilder aller Dienste mit diesem Tag sowie mit latest kennzeichnen.

grep die Bildnamen aus der docker-compose.yml-Datei

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

Dies ist jedoch fehleranfällig, wenn jemand einen Kommentar in docker-compose.yml hinzufügt, der z. aussehen wie # Purpose of this image: do something useful....

Baue zweimal

Verwenden Sie ${IMAGE_TAG} als Umgebungsvariable in Ihrer docker-compose.yml-Datei wie beschrieben hier im ersten Beispiel .

Dann führen Sie einfach den Erstellungsprozess zweimal aus, wobei Sie ${IMAGE_TAG} durch einen anderen Wert ersetzen:

IMAGE_TAG="${IMAGE_TAG}" docker-compose build
IMAGE_TAG=latest docker-compose build

Der zweite Erstellungsprozess sollte viel schneller als der erste sein, da alle Bildebenen beim ersten Durchlauf noch zwischengespeichert werden sollten.

Der Nachteil dieses Ansatzes besteht darin, dass Ihre Protokollausgabe mit zwei aufeinanderfolgenden Erstellungsprozessen für jeden einzelnen Dienst überschwemmt wird, was die Suche nach etwas Nützlichem erschweren könnte. 

Wenn Sie außerdem einen Befehl in Ihrer Dockerfile haben, der den Build-Cache immer leert (z. B. ein ADD-Befehl, der von einem entfernten Ort mit automatisch aktualisierenden last-modified-Headern abruft, Dateien hinzufügt, die ständig von einem externen Prozess aktualisiert werden usw.), dann ist der zusätzliche Build erforderlich könnte die Dinge erheblich verlangsamen.

Analysieren Sie die Bildnamen aus der docker-compose.yml-Datei mit Inline-Python-Code

Die Verwendung eines echten yaml-Parsers in Python (oder einer anderen Sprache wie Ruby oder Perl oder was auch immer auf Ihrem System installiert ist) ist robuster als der zuerst erwähnte grep-Ansatz, da er nicht durch Kommentare oder eigenartige, aber gültige Schreibweisen verwirrt wird yml Datei.

In Python könnte dies so aussehen:

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

Der Nachteil dieses Ansatzes besteht darin, dass auf dem Computer, der den Build ausführt, Python3 zusammen mit der Bibliothek PyYAML installiert sein muss. Wie bereits erwähnt, kann dieses Muster auf ähnliche Weise mit Python2 oder einer anderen installierten Programmiersprache verwendet werden.

Bildnamen durch Kombination einiger docker-Befehle abrufen

Der folgende Ansatz, der einige native docker- und docker-compose-Befehle verwendet (mit go-templates), ist etwas komplexer zu schreiben, funktioniert aber auch gut.

# 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

Dieser Ansatz hat zwar keine externen Abhängigkeiten und ist sicherer als die grep-Methode. Es kann jedoch einige Sekunden dauern, bis er in großen Setups ausgeführt wird, um die Container zu erstellen und zu entfernen (normalerweise jedoch keine Probleme).

6
Dirk

Ich habe eine nette und saubere Lösung, die Umgebungsvariablen verwendet (bash-Syntax für Standardvariablenwert, in meinem Fall ist es latest, aber Sie können alles verwenden), dies ist meine Zusammenstellung:

version: '3'
services:
  app:
    build: .
    image: myapp-name:${version:-latest}

build and push (wenn Sie Push in die Registrierung aufnehmen müssen) mit dem Standard-Tag, ändern Sie die Version mit Umgebungsvariable und build und push erneut:

docker-compose build
docker-compose Push
export version=0.0.1
docker-compose build
docker-compose Push
0
Maoz Zadok