diff --git a/README.md b/README.md index 7a7b656..6000393 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,9 @@ ways, all pointing at the same image: - `:` — the version from `pom.xml` or `--tag` - `:latest` — moved to this push on every successful deploy -- `:sha256-<12 hex chars>` — immutable tag taken from the registry digest +- `:vYYYY.MM.DD-HH.MM` — UTC timestamp of the push (for rollback; list with `docker images`) + +To roll back on the remote, pick an older `v…` tag from `docker images test-quarkus` and run that reference instead of `:latest`. The temporary registry container and SSH tunnel are removed when the script finishes. See `./scripts/build-and-push.sh --help` for all flags. diff --git a/scripts/build-and-push.sh b/scripts/build-and-push.sh index 3f9a626..a0f5c94 100755 --- a/scripts/build-and-push.sh +++ b/scripts/build-and-push.sh @@ -6,7 +6,7 @@ # - Image name/tag default to pom.xml properties (artifactId and version) # - Builds for linux/amd64 by default (cross-compile from arm64 hosts) # - Transfers layers over the tunnel (no external registry required) -# - On the remote, tags the image as , latest, and sha256- +# - On the remote, tags the image as , latest, and vYYYY.MM.DD-HH.MM (UTC) set -euo pipefail IFS=$'\n\t' @@ -66,7 +66,7 @@ Required: Image identity (defaults read from pom.xml): --name NAME Image repository name --tag TAG Version tag. The remote also receives :latest - and a sha256- tag for this push. + and a vYYYY.MM.DD-HH.MM release tag (UTC). Working directory (defaults to the parent of the script's directory): --project-dir PATH Project root containing pom.xml @@ -242,11 +242,9 @@ REG_REMOTE_PORT="" REG_LOCAL_PORT="" TUNNEL_PID="" LOCAL_REGISTRY_REF="" -DIGEST_REF="" -PUSH_LOG="" +RELEASE_REF="" cleanup_push_resources() { - [[ -n "${PUSH_LOG:-}" ]] && rm -f "$PUSH_LOG" [[ -n "${LOCAL_REGISTRY_REF:-}" ]] \ && docker rmi "$LOCAL_REGISTRY_REF" >/dev/null 2>&1 || true if [[ -n "${TUNNEL_PID:-}" ]]; then @@ -303,47 +301,36 @@ start_ssh_tunnel() { die "Failed to establish SSH tunnel to remote registry." } -digest_tag_from_push_log() { - local log_file="$1" - local digest hex - digest=$(sed -n 's/.*digest: \(sha256:[0-9a-f]\{64\}\).*/\1/p' "$log_file" | tail -1) - if [[ -z "$digest" ]]; then - digest=$(docker image inspect --format '{{index .RepoDigests 0}}' "$LOCAL_REGISTRY_REF" 2>/dev/null \ - | sed -n 's/.*@\(sha256:[0-9a-f]\{64\}\)/\1/p') - fi - [[ -n "$digest" ]] || die "Could not read the image digest after push." - hex="${digest#sha256:}" - printf 'sha256-%s' "${hex:0:12}" +build_release_tag() { + printf 'v%s' "$(TZ=UTC date +%Y.%m.%d-%H.%M)" } push_via_registry_tunnel() { LOCAL_REGISTRY_REF="localhost:${REG_LOCAL_PORT}/${IMAGE_NAME}:${IMAGE_TAG}" local remote_registry_ref="localhost:${REG_REMOTE_PORT}/${IMAGE_NAME}:${IMAGE_TAG}" local latest_ref="${IMAGE_NAME}:latest" - local digest_tag + local release_tag + + release_tag=$(build_release_tag) + RELEASE_REF="${IMAGE_NAME}:${release_tag}" log "Tagging ${IMAGE_REF} as ${LOCAL_REGISTRY_REF}…" docker tag "$IMAGE_REF" "$LOCAL_REGISTRY_REF" log "Pushing ${LOCAL_REGISTRY_REF} through SSH tunnel…" - PUSH_LOG=$(mktemp) - docker push "$LOCAL_REGISTRY_REF" | tee "$PUSH_LOG" - digest_tag=$(digest_tag_from_push_log "$PUSH_LOG") - rm -f "$PUSH_LOG" - PUSH_LOG="" - DIGEST_REF="${IMAGE_NAME}:${digest_tag}" + docker push "$LOCAL_REGISTRY_REF" - log "Tagging local image as ${latest_ref} and ${DIGEST_REF}…" + log "Tagging local image as ${latest_ref} and ${RELEASE_REF}…" docker tag "$IMAGE_REF" "$latest_ref" - docker tag "$IMAGE_REF" "$DIGEST_REF" + docker tag "$IMAGE_REF" "$RELEASE_REF" - log "Pulling image on remote and tagging ${IMAGE_REF}, ${latest_ref}, ${DIGEST_REF}…" + log "Pulling image on remote and tagging ${IMAGE_REF}, ${latest_ref}, ${RELEASE_REF}…" run_remote "${REMOTE_DOCKER} pull ${remote_registry_ref}" run_remote "${REMOTE_DOCKER} tag ${remote_registry_ref} ${IMAGE_REF}" run_remote "${REMOTE_DOCKER} tag ${remote_registry_ref} ${latest_ref}" - run_remote "${REMOTE_DOCKER} tag ${remote_registry_ref} ${DIGEST_REF}" + run_remote "${REMOTE_DOCKER} tag ${remote_registry_ref} ${RELEASE_REF}" run_remote "${REMOTE_DOCKER} rmi ${remote_registry_ref}" >/dev/null || true - ok "Remote tags: ${IMAGE_REF}, ${latest_ref}, ${DIGEST_REF}." + ok "Remote tags: ${IMAGE_REF}, ${latest_ref}, ${RELEASE_REF}." } # ---------- arg parsing ---------- @@ -454,17 +441,19 @@ else log "Verifying tags on ${REMOTE_TARGET}…" remote_images=$(run_remote "${REMOTE_DOCKER} images --format '{{.Repository}}:{{.Tag}}'") missing=0 - for ref in "${IMAGE_REF}" "${IMAGE_NAME}:latest" "${DIGEST_REF}"; do + for ref in "${IMAGE_REF}" "${IMAGE_NAME}:latest" "${RELEASE_REF}"; do if ! printf '%s\n' "$remote_images" | grep -Fxq "$ref"; then err "Missing on remote: ${ref}" missing=1 fi done [[ "$missing" -eq 0 ]] || die "Expected tags were not found on ${REMOTE_TARGET} after push." - ok "Remote has ${IMAGE_REF}, ${IMAGE_NAME}:latest and ${DIGEST_REF}." + ok "Remote has ${IMAGE_REF}, ${IMAGE_NAME}:latest and ${RELEASE_REF}." fi # ---------- next step hint ---------- printf '\n%s→ To run the latest image on the remote:%s\n' "$C_OK" "$C_RESET" -printf ' ssh %s "docker run -d --name %s --restart unless-stopped -p 8080:8080 %s:latest"\n\n' \ +printf ' ssh %s "docker run -d --name %s --restart unless-stopped -p 8080:8080 %s:latest"\n' \ "$REMOTE_TARGET" "$IMAGE_NAME" "$IMAGE_NAME" +printf '%s→ Rollback: list tags with docker images %s, then run a previous vYYYY.MM.DD-HH.MM tag.%s\n\n' \ + "$C_OK" "$IMAGE_NAME" "$C_RESET"