Copier une image Docker d'une registry à une autre

J’ai récemment eu le besoin de copier plusieurs images d’une registry Docker à une autre. Bien que cette opération peut sembler simple au premier abord, il y a quelques points auxquels il faut prêter attention.

La première solution à laquelle on pourrait penser serait de récupérer l’image sur sa machine afin de créer un nouveau tag pointant vers la registry de destination. Par exemple, si je souhaite copier l’image MySQL vers une la registry Gitlab, je pourrais m’y prendre comme cela:

docker pull mysql:9.1.0-oracle
docker tag mysql:9.1.0-oracle registry.gitlab.com/jdecool/docker/mysql:9.1.0-oracle
docker push registry.gitlab.com/jdecool/docker/mysql:9.1.0-oracle

Le problème de cette approche est qu’elle va copier uniquement l’image récupérée par la machine qui effectue l’opération et qui est propre à son architecture. Dans le cas de l’image MySQL, si j’effectue l’opération depuis mon Macbook je ne copierai que la version ARM alors que, si je le fais depuis mon PC, je ne copierai que la version amd64.

Or, dans le cadre d’une migration, il est indispensable de prendre en compte les images multiarchitectures. Une solution envisageable serait de construire les images en mode multiarchitecture en se basant sur l’image d’origine. La commande docker buildx build permet par exemple de spécifier dynamiquement le contenu d’un Dockerfile. On peut alors modifier les commandes précédentes de la sorte:

docker buildx build --platform linux/amd64,linux/arm64/v8 \
  --tag registry.gitlab.com/jdecool/docker/mysql:9.1.0-oracle \
  --push \
  --build-context base=docker-image://mysql:9.1.0-oracle \
  - <<EOF
FROM base
EOF

Bien que verbeuse, cette solution est parfaitement fonctionnelle. Mais il est possible de se simplifier un peu la vie. Depuis peu, Docker a introduit une nouvelle fonctionnalité dans buildx permettant de copier directement les images entre Registry. L’opération peut alors être réalisée via une seule ligne de commande:

docker buildx imagetools create \
  --tag "registry.gitlab.com/jdecool/docker/mysql:9.1.0-oracle" "mysql:9.1.0-oracle"

Je n’ai évoqué dans ce billet que les outils officiels proposés par Docker, mais il existe également des outils créés par d’autres éditeurs et qui permettent également d’effectuer cette tâche.