cambios en script y version

This commit is contained in:
2026-09-24 16:41:36 -03:00
parent bc5ffaf1d2
commit 5b4bbce5c8
3 changed files with 151 additions and 38 deletions
+144 -34
View File
@@ -1,20 +1,18 @@
#!/usr/bin/env bash
#
# Build the native Quarkus image and push it to a remote Docker host
# via docker-pussh (unregistry): https://github.com/psviderski/unregistry
# via a temporary registry:2 on the remote, reached through an SSH tunnel.
#
# - Image name/tag default to pom.xml properties (quarkus.application.*)
# - Builds for linux/amd64 by default (cross-compile from arm64 hosts)
# - Transfers only missing layers over SSH (no external registry required)
# - Transfers layers over the tunnel (no external registry required)
set -euo pipefail
IFS=$'\n\t'
readonly DOCKERFILE="src/main/docker/Dockerfile"
readonly DEFAULT_PLATFORM="linux/amd64"
readonly UNREGISTRY_PLUGIN="https://raw.githubusercontent.com/psviderski/unregistry/main/docker-pussh"
readonly PLUGIN_DIR="${HOME}/.docker/cli-plugins"
readonly PLUGIN_PATH="${PLUGIN_DIR}/docker-pussh"
readonly TEMP_REGISTRY_IMAGE="registry:2"
readonly SCRIPT_DIR="$(cd "$(dirname "$(readlink -f "$0")")" && pwd)"
REMOTE=""
@@ -56,7 +54,7 @@ usage() {
Usage: $(basename "$0") --remote USER@HOST[:PORT] [options]
Build the native Quarkus image and push it to a remote Docker host using
unregistry (docker-pussh).
a temporary Docker registry on the remote, reached through an SSH tunnel.
Required:
--remote TARGET SSH destination. Either 'user@host[:port]'
@@ -72,10 +70,10 @@ Working directory (defaults to the parent of the script's directory):
(override with env PROJECT_DIR)
Build options:
--skip-build Skip docker build, only pussh an existing image
--skip-build Skip docker build, only push an existing image
(platform is fixed to ${DEFAULT_PLATFORM})
SSH options forwarded to docker pussh:
SSH options:
--ssh-key PATH Private key file (overrides SSH config)
--ssh-config PATH SSH config file (default: ~/.ssh/config)
@@ -178,6 +176,126 @@ resolve_ssh_alias() {
printf '%s@%s:%s|%s\n' "$user" "$hostname" "$port" "$identity"
}
random_port() {
echo $((55000 + RANDOM % 10536))
}
# REMOTE_TARGET is user@host:port; OpenSSH needs -p and user@host separately.
parse_ssh_target() {
if [[ "$REMOTE_TARGET" == *:* ]]; then
SSH_PORT="${REMOTE_TARGET##*:}"
SSH_HOST_USER="${REMOTE_TARGET%:*}"
else
SSH_PORT="22"
SSH_HOST_USER="$REMOTE_TARGET"
fi
}
# Populates global ssh_args for ssh(1).
build_ssh_args() {
ssh_args=()
[[ -n "$SSH_KEY" ]] && ssh_args+=(-i "$SSH_KEY")
[[ -n "$SSH_CONFIG" ]] && ssh_args+=(-F "$SSH_CONFIG")
[[ "$SSH_PORT" != "22" ]] && ssh_args+=(-p "$SSH_PORT")
ssh_args+=("$SSH_HOST_USER")
}
run_remote() {
ssh "${ssh_args[@]}" "$@"
}
# Sets REMOTE_DOCKER to "docker" or "sudo -n docker".
detect_remote_docker() {
if run_remote "docker info" >/dev/null 2>&1; then
REMOTE_DOCKER="docker"
return 0
fi
if run_remote "sudo -n docker info" >/dev/null 2>&1; then
REMOTE_DOCKER="sudo -n docker"
return 0
fi
die "Cannot run docker on ${REMOTE_TARGET}. Ensure Docker is installed and the SSH user may run docker (or passwordless sudo docker)."
}
REG_PUSH_CONTAINER=""
REG_REMOTE_PORT=""
REG_LOCAL_PORT=""
TUNNEL_PID=""
LOCAL_REGISTRY_REF=""
cleanup_push_resources() {
[[ -n "${LOCAL_REGISTRY_REF:-}" ]] \
&& docker rmi "$LOCAL_REGISTRY_REF" >/dev/null 2>&1 || true
if [[ -n "${TUNNEL_PID:-}" ]]; then
kill "$TUNNEL_PID" >/dev/null 2>&1 || true
wait "$TUNNEL_PID" 2>/dev/null || true
fi
if [[ -n "${REG_PUSH_CONTAINER:-}" && -n "${REMOTE_DOCKER:-}" && -n "${REMOTE_TARGET:-}" ]]; then
parse_ssh_target
build_ssh_args
run_remote "${REMOTE_DOCKER} rm -f ${REG_PUSH_CONTAINER}" >/dev/null 2>&1 || true
fi
}
start_remote_registry() {
local attempt output
run_remote "${REMOTE_DOCKER} image inspect ${TEMP_REGISTRY_IMAGE}" >/dev/null 2>&1 \
|| run_remote "${REMOTE_DOCKER} pull ${TEMP_REGISTRY_IMAGE}"
for attempt in $(seq 1 10); do
REG_REMOTE_PORT=$(random_port)
REG_PUSH_CONTAINER="reg-push-$$-${REG_REMOTE_PORT}"
if output=$(run_remote "${REMOTE_DOCKER} run -d \
--name ${REG_PUSH_CONTAINER} \
-p 127.0.0.1:${REG_REMOTE_PORT}:5000 \
${TEMP_REGISTRY_IMAGE}" 2>&1); then
return 0
fi
run_remote "${REMOTE_DOCKER} rm -f ${REG_PUSH_CONTAINER}" >/dev/null 2>&1 || true
if ! echo "$output" | grep -qi bind; then
die "Failed to start temporary registry on remote:\n${output}"
fi
done
die "Failed to start temporary registry on remote (port binding)."
}
start_ssh_tunnel() {
local attempt
for attempt in $(seq 1 10); do
REG_LOCAL_PORT=$(random_port)
if command -v nc >/dev/null 2>&1 && nc -z 127.0.0.1 "$REG_LOCAL_PORT" 2>/dev/null; then
continue
fi
ssh "${ssh_args[@]}" \
-o ExitOnForwardFailure=yes \
-N \
-L "127.0.0.1:${REG_LOCAL_PORT}:127.0.0.1:${REG_REMOTE_PORT}" &
TUNNEL_PID=$!
sleep 1
if kill -0 "$TUNNEL_PID" 2>/dev/null; then
return 0
fi
TUNNEL_PID=""
done
die "Failed to establish SSH tunnel to remote registry."
}
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}"
log "Tagging ${IMAGE_REF} as ${LOCAL_REGISTRY_REF}…"
docker tag "$IMAGE_REF" "$LOCAL_REGISTRY_REF"
log "Pushing ${LOCAL_REGISTRY_REF} through SSH tunnel…"
docker push "$LOCAL_REGISTRY_REF"
log "Pulling image on remote and retagging as ${IMAGE_REF}…"
run_remote "${REMOTE_DOCKER} pull ${remote_registry_ref}"
run_remote "${REMOTE_DOCKER} tag ${remote_registry_ref} ${IMAGE_REF}"
run_remote "${REMOTE_DOCKER} rmi ${remote_registry_ref}" >/dev/null || true
}
# ---------- arg parsing ----------
while [[ $# -gt 0 ]]; do
case "$1" in
@@ -226,26 +344,17 @@ log "Dockerfile: ${DOCKERFILE}"
log "Remote: ${REMOTE_TARGET}"
require docker
require ssh
docker info >/dev/null 2>&1 \
|| die "Docker daemon is not reachable. Start Docker Desktop (or your daemon) and retry."
if ! docker pussh --help >/dev/null 2>&1; then
cat >&2 <<EOF
'docker pussh' plugin not found. Install it with:
mkdir -p ${PLUGIN_DIR}
curl -fsSL ${UNREGISTRY_PLUGIN} -o ${PLUGIN_PATH}
chmod +x ${PLUGIN_PATH}
Then rerun this script.
EOF
exit 1
fi
[[ -f "$DOCKERFILE" ]] || die "Dockerfile not found at ${DOCKERFILE}."
[[ -f pom.xml ]] || die "pom.xml not found in current directory."
parse_ssh_target
build_ssh_args
detect_remote_docker
# ---------- build ----------
if [[ "$SKIP_BUILD" -eq 1 ]]; then
warn "Skipping build (--skip-build). Assuming ${IMAGE_REF} exists locally."
@@ -261,27 +370,28 @@ else
ok "Build finished."
fi
# ---------- pussh ----------
log "Pusshing ${IMAGE_REF} to ${REMOTE_TARGET} via unregistry…"
# ---------- push via temporary registry ----------
trap cleanup_push_resources EXIT
pussh_args=( "$REMOTE_TARGET" )
[[ -n "$SSH_KEY" ]] && pussh_args+=( -i "$SSH_KEY" )
[[ -n "$SSH_CONFIG" ]] && pussh_args+=( -F "$SSH_CONFIG" )
log "Pushing ${IMAGE_REF} to ${REMOTE_TARGET} via temporary registry…"
docker pussh "${IMAGE_REF}" "${pussh_args[@]}"
ok "Pussh complete."
start_remote_registry
ok "Temporary registry listening on remote 127.0.0.1:${REG_REMOTE_PORT}."
start_ssh_tunnel
ok "SSH tunnel localhost:${REG_LOCAL_PORT} → remote:${REG_REMOTE_PORT}."
push_via_registry_tunnel
ok "Push complete."
# ---------- verify ----------
if [[ "$SKIP_VERIFY" -eq 1 ]]; then
warn "Skipping post-push verification (--no-verify)."
else
log "Verifying ${IMAGE_REF} on ${REMOTE_TARGET}…"
ssh_args=( "$REMOTE_TARGET" )
[[ -n "$SSH_KEY" ]] && ssh_args=( -i "$SSH_KEY" "${ssh_args[@]}" )
[[ -n "$SSH_CONFIG" ]] && ssh_args=( -F "$SSH_CONFIG" "${ssh_args[@]}" )
if ! ssh "${ssh_args[@]}" "docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep -E '^${IMAGE_NAME}:${IMAGE_TAG} '"; then
die "Image ${IMAGE_REF} not found on ${REMOTE_TARGET} after pussh."
if ! run_remote "${REMOTE_DOCKER} images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep -E '^${IMAGE_NAME}:${IMAGE_TAG} '"; then
die "Image ${IMAGE_REF} not found on ${REMOTE_TARGET} after push."
fi
ok "Image present on remote."
fi