From 2354f10be5c276773e92de9639dbaeb3cb19bfdb Mon Sep 17 00:00:00 2001 From: Victor Lin <13424970+victorlin@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:35:01 +0000 Subject: [PATCH] localhost-to-dockerhub: Use skopeo to "push" images The old scripts depended on having the built images locally tagged. The new multi-arch images are pushed directly to the local registry. One might think it'd be possible to pull from localhost, tag locally, then push to Docker Hub - but that has problems [1]. The new scripts utilize registry API tooling (skopeo) to interface with the registries directly without unnecessary pull/push. A containerized version is used since the version pre-installed on the GitHub Actions Ubuntu runners does not support --multi-arch [2]. Notably, the tag-latest script is replaced by a conditional block in the new script which copies the tag from localhost to latest on Docker Hub. [1]: https://stackoverflow.com/a/68576882 [2]: https://github.com/containers/skopeo/releases/tag/v1.6.0 --- .github/workflows/ci.yml | 9 +++--- README.md | 7 ++--- devel/localhost-to-dockerhub | 61 ++++++++++++++++++++++++++++++++++++ devel/push | 30 ------------------ devel/tag-latest | 19 ----------- 5 files changed, 67 insertions(+), 59 deletions(-) create mode 100755 devel/localhost-to-dockerhub delete mode 100755 devel/push delete mode 100755 devel/tag-latest diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c41331b..051b9093 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,8 +33,8 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} - if: github.event_name != 'pull_request' && startsWith(env.TAG, 'branch-') - name: Push $TAG (non-default branch) - run: ./devel/push $TAG + name: Copy $TAG images to Docker Hub (non-default branch) + run: ./devel/localhost-to-dockerhub $TAG - uses: actions/setup-python@v4 with: @@ -46,10 +46,9 @@ jobs: nextstrain build --image localhost:5000/nextstrain/base:$TAG zika-tutorial -F - if: startsWith(env.TAG, 'build-') - name: Push $TAG + latest (default branch) + name: Copy $TAG + latest images to Docker Hub (default branch) run: | - ./devel/tag-latest $TAG - ./devel/push latest $TAG + ./devel/localhost-to-dockerhub $TAG latest - if: always() run: ./devel/stop-localhost-registry diff --git a/README.md b/README.md index 949eb701..7bf4fd1a 100644 --- a/README.md +++ b/README.md @@ -74,12 +74,9 @@ during development iterations. To push images you've built locally to Docker Hub, you can run: - ./devel/push latest + ./devel/localhost-to-dockerhub latest -This will publish your local `nextstrain/base:latest` image. This is also what -happens if you run `./devel/push` with no tags specified. If you have images -with other tags, you may provide those tags in addition to or instead of -`latest`. +This will copy the `nextstrain/base:latest` and `nextstrain/base-builder:latest` images from the local Docker registry to Docker Hub. If you have images with another tag, you may provide that tag instead of `latest`. ### Best practices diff --git a/devel/localhost-to-dockerhub b/devel/localhost-to-dockerhub new file mode 100755 index 00000000..870aa148 --- /dev/null +++ b/devel/localhost-to-dockerhub @@ -0,0 +1,61 @@ +#!/bin/bash +# +# Push the nextstrain/base and nextstrain/base-builder images from the local registry to Docker Hub. +# +# This pushes just the provided tag. If "latest" is provided as a second argument, +# the provided tag will also be pushed as "latest" +# +# Errors if any of the tagged images have already been pushed. +# +set -euo pipefail + +if [[ $# -lt 1 ]]; then + echo "Please provide a tag." >&2 + exit 1 +fi + +tag=$1 + +BASE_IMAGE="nextstrain/base" +BASE_BUILDER_IMAGE="nextstrain/base-builder" + +if [[ $(docker image inspect --format "{{.RepoDigests}}" $BASE_IMAGE:$tag) != '[]' || $(docker image inspect --format "{{.RepoDigests}}" $BASE_BUILDER_IMAGE:$tag) != '[]' ]]; then + echo "At least one of $BASE_IMAGE:$tag and $BASE_BUILDER_IMAGE:$tag has already been pushed. This can happen if the newly built image is not available in the local registry." >&2 + exit 1 +fi + + +# Use Skopeo via a Docker container to copy a tagged image. +# https://github.com/containers/skopeo/blob/07da29fd371dd88615a0b86e91c6824237484172/install.md#container-images +copy-image() { + local source="$1" + local dest="$2" + + docker run --rm \ + -v $HOME/.docker/config.json:/docker-auth.json:ro \ + --network="host" \ + quay.io/skopeo/stable \ + copy \ + --multi-arch=all \ + --src-tls-verify=false \ + --dest-authfile /docker-auth.json \ + $source $dest +} + +# copy local $tag to remote $tag +copy-image \ + docker://localhost:5000/$BASE_IMAGE:$tag \ + docker://docker.io/$BASE_IMAGE:$tag +copy-image \ + docker://localhost:5000/$BASE_BUILDER_IMAGE:$tag \ + docker://docker.io/$BASE_BUILDER_IMAGE:$tag + +if [[ "$tag" != latest && "${2:-}" == latest ]]; then + # copy local $tag to remote latest + copy-image \ + docker://localhost:5000/$BASE_IMAGE:$tag \ + docker://docker.io/$BASE_IMAGE:latest + copy-image \ + docker://localhost:5000/$BASE_BUILDER_IMAGE:$tag \ + docker://docker.io/$BASE_BUILDER_IMAGE:latest +fi diff --git a/devel/push b/devel/push deleted file mode 100755 index 9facf42a..00000000 --- a/devel/push +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash -# -# Push the nextstrain/base and nextstrain/base-builder images to Docker Hub. -# -# By default this publishes the "latest" tag, but you can provide other tags in -# addition to or instead of "latest". -# -# Errors if any of the tagged images have already been pushed. -# -set -euo pipefail - -# If no tags are given, default to "latest". -if [[ $# -eq 0 ]]; then - set -- latest -fi - -BASE_IMAGE="nextstrain/base" -BASE_BUILDER_IMAGE="nextstrain/base-builder" - -for tag in "$@"; do - if [[ $(docker image inspect --format "{{.RepoDigests}}" $BASE_IMAGE:$tag) != '[]' || $(docker image inspect --format "{{.RepoDigests}}" $BASE_BUILDER_IMAGE:$tag) != '[]' ]]; then - echo "At least one of $BASE_IMAGE:$tag and $BASE_BUILDER_IMAGE:$tag has already been pushed. This can happen if the newly built image is not available in the local registry." >&2 - exit 1 - fi -done - -for tag in "$@"; do - docker push $BASE_BUILDER_IMAGE:$tag - docker push $BASE_IMAGE:$tag -done diff --git a/devel/tag-latest b/devel/tag-latest deleted file mode 100755 index cf53b1aa..00000000 --- a/devel/tag-latest +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Assign the latest tag to the nextstrain/base:$tag and -# nextstrain/base-builder:$tag images. -# -set -euo pipefail - -if [[ $# -ne 1 ]]; then - echo "Please provide a tag." >&2 - exit 1 -fi - -tag=$1 - -BASE_IMAGE="nextstrain/base" -BASE_BUILDER_IMAGE="nextstrain/base-builder" - -docker tag $BASE_BUILDER_IMAGE:{$tag,latest} -docker tag $BASE_IMAGE:{$tag,latest}