#!/usr/bin/env bash # Local build -> ship over ssh -> swap on host. No container registry (see docs/DECISIONS.md D8). # # Run this from a real terminal on your workstation (NOT inside a sandboxed # coding-agent shell) with the `gcp-lab` podman connection already configured: # # podman system connection add gcp-lab \ # --identity ~/.ssh/google_compute_engine \ # ssh://matt@35.203.147.44:22/run/user/1001/podman/podman.sock # # Usage: # ./deploy.sh # build both, ship both, swap both containers # VERSION=v2 ./deploy.sh # tag images v2 instead of a timestamp # ./deploy.sh --build --ship --swap # explicit equivalent of the default # ./deploy.sh --restart-caddy # after editing imperva-proxy/Caddyfile set -euo pipefail # --- config ------------------------------------------------------------- HOST="35.203.147.44" HOST_USER="matt" SSH_KEY="$HOME/.ssh/google_compute_engine" CONNECTION="gcp-lab" VERSION="${VERSION:-$(date +%Y%m%d%H%M%S)}" REMOTE_PROXY_DIR="/home/matt/imperva-proxy" BACKEND_IMAGE="backend-api" FRONTEND_IMAGE="frontend-vue" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" # --- steps ---------------------------------------------------------------- do_build() { echo "==> Building ${BACKEND_IMAGE}:${VERSION}" podman build -t "${BACKEND_IMAGE}:${VERSION}" -t "${BACKEND_IMAGE}:latest" ./backend echo "==> Building ${FRONTEND_IMAGE}:${VERSION}" podman build -t "${FRONTEND_IMAGE}:${VERSION}" -t "${FRONTEND_IMAGE}:latest" ./frontend } do_ship() { echo "==> Shipping ${BACKEND_IMAGE}:${VERSION} over ssh" podman save "${BACKEND_IMAGE}:${VERSION}" | ssh -i "$SSH_KEY" "${HOST_USER}@${HOST}" podman load echo "==> Shipping ${FRONTEND_IMAGE}:${VERSION} over ssh" podman save "${FRONTEND_IMAGE}:${VERSION}" | ssh -i "$SSH_KEY" "${HOST_USER}@${HOST}" podman load } do_swap() { echo "==> Swapping backend-api container" podman --connection "$CONNECTION" rm -f backend-api >/dev/null 2>&1 || true podman --connection "$CONNECTION" run -d \ --name backend-api \ --restart always \ -p 8000:8000 \ "${BACKEND_IMAGE}:${VERSION}" echo "==> Swapping frontend-vue container" podman --connection "$CONNECTION" rm -f frontend-vue >/dev/null 2>&1 || true podman --connection "$CONNECTION" run -d \ --name frontend-vue \ --restart always \ -p 8080:8080 \ "${FRONTEND_IMAGE}:${VERSION}" } do_restart_caddy() { echo "==> Copying Caddyfile to host" scp -i "$SSH_KEY" ./imperva-proxy/Caddyfile "${HOST_USER}@${HOST}:${REMOTE_PROXY_DIR}/Caddyfile" echo "==> Validating Caddyfile on host" podman --connection "$CONNECTION" exec caddy-proxy caddy validate --config /etc/caddy/Caddyfile echo "==> Restarting caddy-proxy" podman --connection "$CONNECTION" restart caddy-proxy } check_connection() { if ! podman system connection list --format '{{.Name}}' 2>/dev/null | grep -qx "$CONNECTION"; then echo "error: podman connection '${CONNECTION}' is not configured." >&2 echo " podman system connection add ${CONNECTION} --identity ${SSH_KEY} ssh://${HOST_USER}@${HOST}:22/run/user/1001/podman/podman.sock" >&2 exit 1 fi } # --- arg parsing ------------------------------------------------------ RUN_BUILD=false RUN_SHIP=false RUN_SWAP=false RUN_RESTART_CADDY=false if [ "$#" -eq 0 ]; then RUN_BUILD=true RUN_SHIP=true RUN_SWAP=true else for arg in "$@"; do case "$arg" in --build) RUN_BUILD=true ;; --ship) RUN_SHIP=true ;; --swap) RUN_SWAP=true ;; --restart-caddy) RUN_RESTART_CADDY=true ;; *) echo "unknown flag: $arg" >&2 exit 1 ;; esac done fi if [ "$RUN_SHIP" = true ] || [ "$RUN_SWAP" = true ] || [ "$RUN_RESTART_CADDY" = true ]; then check_connection fi [ "$RUN_BUILD" = true ] && do_build [ "$RUN_SHIP" = true ] && do_ship [ "$RUN_SWAP" = true ] && do_swap [ "$RUN_RESTART_CADDY" = true ] && do_restart_caddy echo "==> Done (version: ${VERSION})"