cambios en script y version
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user