The image moves off registry.netork.io. That registry is plain registry:2 with htpasswd auth, which knows nothing about repositories: every account that can log in reads and writes everything on it, including the accounts issued to customer instances. Verified -- a customer server's credentials list the whole catalogue. It keeps the images those instances are meant to pull; the marketing site is not one of them. Gitea scopes packages to their owning account, and no customer has one. netOrk #172. Login uses a REGISTRY_TOKEN secret (a Gitea token with write:package). The token Actions injects per run does not work here -- the package registry rejects it with a bare "unauthorized", which is a confusing way to spend an afternoon. The deploy job is removed rather than migrated, because it had quietly stopped being correct. It ran `docker run` against whatever runner picked the job up, which worked while exactly one runner existed. There are now several -- netork-runner-12 on .12, netork-runner-13 on .13, plus the original netork-runner -- and none of them is on 10.7.224.11, where this site runs and where the proxy-net it attaches to lives. The next push would have started a second website container on the wrong host and reported success while netork.io went on serving the old one. Nothing had failed yet; the last deploy was 2026-07-17, back when the pool was one runner. scripts/deploy.sh replaces it: it names the target, pulls before it removes anything, compares the running container's image id against what was pulled, and finishes by checking that netork.io actually answers 200. Push-to-deploy can come back by registering a runner on .11 with a label of its own and pinning `runs-on:` to it, or by giving CI an ssh key. Both decide where a credential lives, so neither was decided here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
63 lines
2.5 KiB
Bash
Executable File
63 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Deploy the marketing site to the host that actually serves it.
|
|
#
|
|
# ./scripts/deploy.sh [--version=<tag>] [server]
|
|
#
|
|
# This used to be a CI job. It ran `docker run` on whichever runner picked the
|
|
# job up, which was correct while exactly one runner existed — there are now
|
|
# several, none of them on the host this site runs on, so the job would have
|
|
# started a second container in the wrong place and reported success. Naming the
|
|
# target is the whole point of this script.
|
|
set -euo pipefail
|
|
|
|
SERVER="${DEPLOY_SERVER:-10.7.224.11}"
|
|
REGISTRY="${REGISTRY:-git.netork.io/netork}"
|
|
VERSION="${VERSION:-latest}"
|
|
NAME="${CONTAINER_NAME:-netork-website}"
|
|
|
|
ENV_FILE="$(cd "$(dirname "$0")/.." && pwd)/deploy.env"
|
|
# shellcheck source=/dev/null
|
|
[[ -f "$ENV_FILE" ]] && source "$ENV_FILE"
|
|
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
--version=*) VERSION="${arg#--version=}" ;;
|
|
*) SERVER="$arg" ;;
|
|
esac
|
|
done
|
|
|
|
IMAGE="${REGISTRY}/website:${VERSION}"
|
|
echo "[${SERVER}] Deploying ${IMAGE}"
|
|
|
|
if [[ -n "${REGISTRY_TOKEN:-}" ]]; then
|
|
ssh -n "$SERVER" "echo '${REGISTRY_TOKEN}' | docker login git.netork.io -u '${REGISTRY_USER:-christianmanivong}' --password-stdin" \
|
|
| sed "s/^/[${SERVER}] /"
|
|
fi
|
|
|
|
# Pull first, and let a failure stop the script here: the container is only
|
|
# removed once there is something to replace it with.
|
|
echo "[${SERVER}] Pulling..."
|
|
ssh -n "$SERVER" "docker pull '${IMAGE}'" | tail -2 | sed "s/^/[${SERVER}] /"
|
|
|
|
echo "[${SERVER}] Recreating..."
|
|
ssh -n "$SERVER" "docker rm -f '${NAME}' >/dev/null 2>&1 || true; \
|
|
docker run -d --name '${NAME}' --restart unless-stopped --network proxy-net '${IMAGE}' >/dev/null && echo started" \
|
|
| sed "s/^/[${SERVER}] /"
|
|
|
|
# `docker run` cannot silently reuse an old container the way `compose up -d`
|
|
# can, but the tag it resolved might still not be the one that was just pulled.
|
|
# Compare, rather than trust.
|
|
echo "[${SERVER}] Verifying..."
|
|
WANT=$(ssh -n "$SERVER" "docker image inspect --format '{{.Id}}' '${IMAGE}'")
|
|
GOT=$(ssh -n "$SERVER" "docker inspect --format '{{.Image}}' '${NAME}'")
|
|
if [[ "$WANT" != "$GOT" ]]; then
|
|
echo "[${SERVER}] ERROR: container runs ${GOT}, expected ${WANT}" >&2
|
|
exit 1
|
|
fi
|
|
echo "[${SERVER}] Verified: ${NAME} runs ${IMAGE}."
|
|
|
|
echo "[${SERVER}] Checking the site answers..."
|
|
CODE=$(curl -s -o /dev/null -w '%{http_code}' --max-time 20 https://netork.io/ || echo 000)
|
|
echo "[${SERVER}] https://netork.io -> ${CODE}"
|
|
[[ "$CODE" == "200" ]] || { echo "[${SERVER}] ERROR: site is not answering 200" >&2; exit 1; }
|