Skip to content

Commit

Permalink
copy-images: Use skopeo to "push" images
Browse files Browse the repository at this point in the history
Instead of pushing images that are available locally (different from a
local registry) to Docker Hub, the proper way to make them available in
the destination is to copy from the source registry directly without
unnecessary pull/push. This is what skopeo can do.

A containerized version of skopeo is used since the version
pre-installed on the GitHub Actions Ubuntu runners is stuck in the past¹
and does not support --multi-arch², which may be used in the future.

Also note that the tag-latest script is replaced by a conditional block
in the new script which copies the tag from one registry to `latest` on
another another.

¹ actions/runner-images#6180 (comment)
² https://github.com/containers/skopeo/releases/tag/v1.6.0
  • Loading branch information
victorlin committed Dec 15, 2022
1 parent a09605f commit 5b1272c
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 59 deletions.
9 changes: 4 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/copy-images -i localhost:$REGISTRY_PORT -o docker.io -t $TAG

- uses: actions/setup-python@v4
with:
Expand All @@ -46,10 +46,9 @@ jobs:
nextstrain build --image localhost:$REGISTRY_PORT/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/copy-images -i localhost:$REGISTRY_PORT -o docker.io -t $TAG -l
- if: always()
run: ./devel/stop-localhost-registry
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,11 @@ during development iterations.

To push images you've built locally to Docker Hub, you can run:

./devel/push latest
./devel/copy-images -t <tag>

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:<tag>` and `nextstrain/base-builder:<tag>`
images from the local Docker registry to Docker Hub. See instructions at the top
of the script for more options.

### Best practices

Expand Down
109 changes: 109 additions & 0 deletions devel/copy-images
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#!/bin/bash
#
# Copy the Nextstrain images from one Docker registry (-i <registry>) to
# another (-o <registry>).
#
# If authentication is required for a registry, ensure the credentials are
# available in ~/.docker/config.json.
#
# This copies just the tag specified by -t <tag>. If the boolean -l flag is
# specified, the tag will also be copied to "latest" on the destnation.
#
# Errors if any of the tagged images have already been pushed.
#
set -euo pipefail

# Set default values.
registry_in=localhost:5000
registry_out=docker.io
tag=""
push_latest=false

# Read command-line arguments.
while getopts "i:o:t:l" opt; do
case "$opt" in
i) registry_in="$OPTARG";;
o) registry_out="$OPTARG";;
t) tag="$OPTARG";;
l) push_latest=true;;
*) echo "Usage: $0 [-i <registry>] [-o <registry>] [-t <tag>] [-l]" 1>&2; exit 1;;
esac
done

if [[ "$tag" = "" ]]; then
echo "Please provide a tag." >&2
exit 1
fi

BUILDER_IMAGE=nextstrain/base-builder
FINAL_IMAGE=nextstrain/base

if [[ $(docker image inspect --format "{{.RepoDigests}}" $FINAL_IMAGE:$tag) != '[]' || $(docker image inspect --format "{{.RepoDigests}}" $BUILDER_IMAGE:$tag) != '[]' ]]; then
echo "At least one of $BUILDER_IMAGE:$tag and $FINAL_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 between registries.
#
# Two positional parameters are required, representing the source and
# destination images each qualified with a Docker registry.
# Format should be <registry>/image:tag, e.g. docker.io/nextstrain/base:latest.
#
# If a registry starts with localhost, do not require HTTPS or verify
# certificates, and access the registry without authentication.
#
# ¹ https://github.com/containers/skopeo/blob/07da29fd371dd88615a0b86e91c6824237484172/install.md#container-images
copy-image() {
local src="$1"
local dest="$2"

docker_run_params=(--rm --network=host)
skopeo_copy_params=(--multi-arch=all)

if [[ "$src" == localhost* ]]; then
skopeo_copy_params+=(--src-tls-verify=false)
else
docker_run_params+=(-v "$HOME"/.docker/config.json:/config.json:ro)
skopeo_copy_params+=(--src-authfile config.json)
fi

if [[ "$dest" == localhost* ]]; then
skopeo_copy_params+=(--dest-tls-verify=false)
else
docker_run_params+=(-v "$HOME"/.docker/config.json:/config.json:ro)
skopeo_copy_params+=(--dest-authfile config.json)
fi

docker run "${docker_run_params[@]}" \
quay.io/skopeo/stable \
copy "${skopeo_copy_params[@]}" \
"docker://$src" \
"docker://$dest"
}

# Copy $tag between registries.

echo "Copying $registry_in/$FINAL_IMAGE:$tag to $registry_out/$FINAL_IMAGE:$tag."
copy-image \
"$registry_in/$FINAL_IMAGE:$tag" \
"$registry_out/$FINAL_IMAGE:$tag"

echo "Copying $registry_in/$BUILDER_IMAGE:$tag to $registry_out/$BUILDER_IMAGE:$tag."
copy-image \
"$registry_in/$BUILDER_IMAGE:$tag" \
"$registry_out/$BUILDER_IMAGE:$tag"

if [[ "$push_latest" = true ]]; then
# Copy $tag to latest.

echo "Copying $registry_in/$FINAL_IMAGE:$tag to $registry_out/$FINAL_IMAGE:latest."
copy-image \
"$registry_in/$FINAL_IMAGE:$tag" \
"$registry_out/$FINAL_IMAGE:latest"

echo "Copying $registry_in/$BUILDER_IMAGE:$tag to $registry_out/$BUILDER_IMAGE:latest."
copy-image \
"$registry_in/$BUILDER_IMAGE:$tag" \
"$registry_out/$BUILDER_IMAGE:latest"
fi
30 changes: 0 additions & 30 deletions devel/push

This file was deleted.

19 changes: 0 additions & 19 deletions devel/tag-latest

This file was deleted.

0 comments on commit 5b1272c

Please sign in to comment.