mirror of
https://github.com/kuhyx/testsAndMisc.git
synced 2026-11-15 09:30:48 +01:00
Force-recreate the website container so config and dist changes apply
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Some checks are pending
dependency freshness / dependencies on newest stable (push) Waiting to run
md-naming / markdown naming convention (push) Waiting to run
Pre-commit checks / pre-commit (push) Waiting to run
Shell tests / shell-tests (push) Waiting to run
Shell tests / arch-tests (push) Waiting to run
Two failure modes compose cannot see, both of which report a healthy
container while it serves 404s:
1. The Caddyfile is a bind mount, so its contents are not in the config
hash compose compares. Editing it changes nothing observable, compose
says Running, and the new directives never load.
2. A bind mount resolves once, at start. Replacing dist/ rather than
emptying it leaves the container on the old unlinked inode: /srv reads
empty and every request 404s.
Hit both at once on a real deploy today -- the container was Up 6 hours,
Caddy logs clean, /srv empty, curl 404. Reproduced by rm -rf dist (inode
84695030 -> 84695031) and fixed by the patched function in one run.
wait_for_website also stops using curl -sf, which collapses every non-2xx
into the same "did not become reachable". It now reports the status it saw,
because unreachable and answering-404 are different bugs and the message
named only the first.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A7BaCSV8FEtcNgVDVsRAJj
This commit is contained in:
parent
899b00ae75
commit
61abbf8cf9
@ -0,0 +1,42 @@
|
||||
{
|
||||
"intent": "Make the website deploy apply Caddyfile changes and survive a replaced dist/ directory, instead of reporting a healthy container that serves 404s.",
|
||||
"scope": [
|
||||
"linux_configuration/features/lib/website_build.sh (start_website and wait_for_website only)",
|
||||
"Non-goal: no change to the Gitea stack, the firewall step, the build, or the edge reload"
|
||||
],
|
||||
"changes": [
|
||||
"start_website now runs docker compose up -d --force-recreate; compose cannot detect a bind-mounted Caddyfile's contents changing, nor a bind mount left on an unlinked inode, so it reported 'Running' and applied neither",
|
||||
"wait_for_website records the actual HTTP status instead of using curl -sf, so a failure distinguishes 'no response' from 'answered 404' -- different bugs that had one message",
|
||||
"The 404 message names the two real causes: a stale /srv bind mount, or an empty dist/"
|
||||
],
|
||||
"verification": [
|
||||
{
|
||||
"command": "observed live after setup_personal_website.sh",
|
||||
"result": "fail",
|
||||
"evidence": "Container 'Up 6 hours', Caddy logs healthy, but docker exec ls /srv returned empty and curl 127.0.0.1:8088/ returned 404; dist/ had been replaced with a new inode (84695030) after container start"
|
||||
},
|
||||
{
|
||||
"command": "rm -rf dist && pnpm build, then curl",
|
||||
"result": "fail",
|
||||
"evidence": "Reproduced deterministically: inode 84695030 -> 84695031, container /srv empty, curl -> 404"
|
||||
},
|
||||
{
|
||||
"command": "source website_build.sh && start_website (patched), against that broken state",
|
||||
"result": "pass",
|
||||
"evidence": "Container Recreated; /srv lists assets blog cv.pdf index.html; / -> 200, /blog/hello-world -> 200 with title 'Hello, world — Krzysztof Rudnicki'"
|
||||
},
|
||||
{
|
||||
"command": "shellcheck + bash -n linux_configuration/features/lib/website_build.sh",
|
||||
"result": "pass",
|
||||
"evidence": "no findings"
|
||||
}
|
||||
],
|
||||
"risks": [
|
||||
"Every deploy now restarts the static container, so there is a sub-second window where the loopback port refuses connections; the edge Caddy retries and the wait loop tolerates it",
|
||||
"--force-recreate discards any state inside the container; this service is a read-only static file server and holds none"
|
||||
],
|
||||
"rollback": [
|
||||
"Drop --force-recreate and restore the curl -sf wait loop",
|
||||
"After rollback, verify a Caddyfile edit actually takes effect by curling a prerendered blog post and checking its <title>, since that is what silently regresses"
|
||||
]
|
||||
}
|
||||
@ -76,10 +76,17 @@ EOF
|
||||
}
|
||||
|
||||
# --- Phase 8: start the website container -----------------------------------
|
||||
# Last HTTP status seen by wait_for_website, so a failure can say whether the
|
||||
# server was unreachable or merely answering wrongly. Those are different bugs
|
||||
# and the old message named only the first one.
|
||||
WEBSITE_LAST_CODE=""
|
||||
|
||||
wait_for_website() {
|
||||
local _
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -sf -o /dev/null "http://127.0.0.1:${WEBSITE_PORT}/"; then
|
||||
WEBSITE_LAST_CODE="$(curl -s -o /dev/null -w '%{http_code}' \
|
||||
--max-time 5 "http://127.0.0.1:${WEBSITE_PORT}/" || echo "000")"
|
||||
if [[ "$WEBSITE_LAST_CODE" == "200" ]]; then
|
||||
return 0
|
||||
fi
|
||||
sleep 1
|
||||
@ -89,11 +96,30 @@ wait_for_website() {
|
||||
|
||||
start_website() {
|
||||
log_info "Starting the personal-website container…"
|
||||
docker compose -f "$WEBSITE_COMPOSE" up -d
|
||||
# --force-recreate is required, not tidiness. Two failure modes need it,
|
||||
# and compose cannot see either one:
|
||||
#
|
||||
# 1. The Caddyfile is a BIND MOUNT, so its contents are not part of the
|
||||
# container's config hash. Editing it changes nothing compose compares,
|
||||
# it reports "Running", and the new directives never load. A blog post
|
||||
# served as the landing page is exactly this bug.
|
||||
# 2. A bind mount is resolved once, at container start. Anything that
|
||||
# replaces dist/ rather than emptying it (rm -rf, a git clean, moving
|
||||
# the checkout) leaves the container mounted on the old, unlinked
|
||||
# inode -- /srv reads as empty and every request 404s while the
|
||||
# container still looks healthy.
|
||||
#
|
||||
# Recreating is under a second for a static file server, so it is cheaper
|
||||
# than either failure being diagnosed by hand.
|
||||
docker compose -f "$WEBSITE_COMPOSE" up -d --force-recreate
|
||||
if wait_for_website; then
|
||||
log_ok "Website answering on http://127.0.0.1:${WEBSITE_PORT}/."
|
||||
else
|
||||
die "Website did not become reachable on 127.0.0.1:${WEBSITE_PORT}."
|
||||
if [[ "$WEBSITE_LAST_CODE" == "000" ]]; then
|
||||
die "Website unreachable on 127.0.0.1:${WEBSITE_PORT} (no response)."
|
||||
fi
|
||||
die "Website on 127.0.0.1:${WEBSITE_PORT} answered HTTP ${WEBSITE_LAST_CODE}, not 200. \
|
||||
A 404 here usually means the container's /srv bind mount is stale or ${WEBSITE_SRC}/dist is empty."
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user