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
+6 -3
View File
@@ -7,8 +7,10 @@ If you want to learn more about Quarkus, please visit its website: https://quark
## Building and deploying natively
Build the native image with the Mandrel-based multi-stage Dockerfile and push it
directly to a remote Docker host via [unregistry](https://github.com/psviderski/unregistry)
(no external registry required; only missing layers are transferred over SSH):
to a remote Docker host over an SSH tunnel. The script starts a temporary
`registry:2` container on the remote (localhost only), forwards it to the build
machine, pushes the image through that tunnel, then pulls and retags it on the
remote Docker daemon. No external registry is required.
```shell script
./scripts/build-and-push.sh --remote deploy@prod.example.com
@@ -16,7 +18,8 @@ directly to a remote Docker host via [unregistry](https://github.com/psviderski/
The script reads `artifactId` and `version` from `pom.xml` for the image name
and tag, builds for `linux/amd64`, and verifies the image is present on the
remote after pushing. See `./scripts/build-and-push.sh --help` for all flags.
remote after pushing. The temporary registry container and SSH tunnel are removed
when the script finishes. See `./scripts/build-and-push.sh --help` for all flags.
It can be invoked from any directory: by default it resolves the project root
from the script's own location. Override with `--project-dir PATH` or the
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>test-quarkus</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>1.0.1</version>
<packaging>jar</packaging>
<name>Test Quarkus</name>
+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