#!/usr/bin/env bash # deploy-container.sh — swap or rollback the flights-web container on the host. # # Usage: deploy-container.sh [--dry-run] # # `swap` — assumes the new image is tagged flights-web:${GITHUB_SHA}. # Tags :current → :previous, :sha → :current, restarts container. # `rollback` — runs flights-web:previous in place of :current, repoints :current. # # Env: # GITHUB_SHA (required for swap) # FLIGHTS_WEB_PORT (default 3002 — host port that nginx proxies to) # IMAGE_NAME (default flights-web — set this to point at a registry later) set -euo pipefail DRY_RUN=0 if [ "${1:-}" = "--dry-run" ]; then DRY_RUN=1 shift fi CMD="${1:-}" PORT="${FLIGHTS_WEB_PORT:-3002}" IMAGE="${IMAGE_NAME:-flights-web}" run() { if [ "$DRY_RUN" -eq 1 ]; then printf 'docker %s\n' "$*" else docker "$@" fi } run_or_skip() { # Same as run, but doesn't fail in real mode if the docker call fails. if [ "$DRY_RUN" -eq 1 ]; then printf 'docker %s\n' "$*" else docker "$@" || true fi } case "$CMD" in swap) : "${GITHUB_SHA:?GITHUB_SHA required for swap}" SHORT_SHA="${GITHUB_SHA:0:7}" # 1. Tag the currently-live image as :previous (skip if first deploy). if [ "$DRY_RUN" -eq 1 ] || docker image inspect "${IMAGE}:current" >/dev/null 2>&1; then run tag "${IMAGE}:current" "${IMAGE}:previous" fi # 2. Tag the new SHA as :current. run tag "${IMAGE}:${SHORT_SHA}" "${IMAGE}:current" # 3. Stop + remove existing container if present. run_or_skip stop flights-web run_or_skip rm flights-web # 4. Run new container. run run -d --name flights-web --restart unless-stopped \ -p "127.0.0.1:${PORT}:8080" \ "${IMAGE}:current" # 5. Wait for the SSR inside the container to start listening before # returning. Without this, the next nginx-side probe gets a few # 502s while Node.js is still booting — works (wait-for-url.sh # retries) but adds noise to the deploy log. if [ "$DRY_RUN" -eq 0 ]; then attempt=1 while [ "$attempt" -le 30 ]; do if curl -fsS -o /dev/null "http://127.0.0.1:${PORT}/"; then echo "swap: SSR ready on :${PORT} after $attempt attempt(s)" break fi if [ "$attempt" -eq 30 ]; then echo "swap: SSR did not respond on :${PORT} after 30 attempts" >&2 exit 1 fi sleep 1 attempt=$((attempt + 1)) done fi ;; rollback) if [ "$DRY_RUN" -eq 0 ] && ! docker image inspect "${IMAGE}:previous" >/dev/null 2>&1; then echo "fatal: ${IMAGE}:previous not found — cannot rollback" >&2 exit 1 fi run_or_skip stop flights-web run_or_skip rm flights-web run run -d --name flights-web --restart unless-stopped \ -p "127.0.0.1:${PORT}:8080" \ "${IMAGE}:previous" # Repoint :current to :previous so subsequent swaps have a sane baseline. run tag "${IMAGE}:previous" "${IMAGE}:current" ;; *) echo "usage: $0 [--dry-run] " >&2 exit 2 ;; esac