Deploy from GitHub with a systemd timer instead of Gitea Actions

Cosmos keeps a deploy-only clone of the GitHub repo. gk-deploy.timer runs
pull-and-deploy.sh every 5 minutes: it fetches master and, when it has
moved, runs deploy.sh (build, check, restart, roll back if unhealthy). A
commit that failed is not retried until master moves (FORCE=1 retries), and
DEPLOY_HEALTHCHECK_URL turns red on a failed fetch or deploy. Removes the
Gitea workflow and updates the runbook, README and inventory note.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
Claude
2026-10-12 00:56:28 +00:00
parent 79f1c26426
commit dcfd97e823
11 changed files with 119 additions and 49 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
# The GregKilmer.com stack on Cosmos: content service, admin page and public site.
#
# Lives at /home/greg/homelab/gregkilmer/compose.yaml (the Gitea Actions deploy
# Lives at /home/greg/homelab/gregkilmer/compose.yaml (deploy/deploy.sh
# copies it there from deploy/compose.yaml on every build). Settings:
# .env stack settings: GK_TAG, VAULT_SITE, PUID, PGID (deploy/stack.env.example)
# content.env content service secrets (services/content/.env.example)
+1 -1
View File
@@ -2,7 +2,7 @@
# Builds the three images for the checked-out commit, runs the checks, and
# restarts the stack on it. If the new containers don't come up healthy, the
# stack goes back to the last good tag. Run from the repo root on Cosmos, by the
# Gitea Actions workflow or by hand. See docs/deploy.md.
# deploy timer (pull-and-deploy.sh) or by hand. See docs/deploy.md.
set -euo pipefail
STACK="${GK_STACK_DIR:-/home/greg/homelab/gregkilmer}"
+15
View File
@@ -0,0 +1,15 @@
# Deploys GregKilmer.com from the GitHub clone when master moves.
# Install: sudo cp deploy/gk-deploy.{service,timer} /etc/systemd/system/
# sudo systemctl daemon-reload && sudo systemctl enable --now gk-deploy.timer
# Logs: journalctl -u gk-deploy. See docs/deploy.md.
[Unit]
Description=Deploy GregKilmer.com from GitHub
Wants=network-online.target
After=network-online.target docker.service
[Service]
Type=oneshot
User=greg
Environment=GK_STACK_DIR=/home/greg/homelab/gregkilmer
ExecStart=/home/greg/homelab/gregkilmer/repo/deploy/pull-and-deploy.sh
TimeoutStartSec=30min
+9
View File
@@ -0,0 +1,9 @@
[Unit]
Description=Check GitHub for a new GregKilmer.com commit every 5 minutes
[Timer]
OnBootSec=2min
OnUnitInactiveSec=5min
[Install]
WantedBy=timers.target
+46
View File
@@ -0,0 +1,46 @@
#!/usr/bin/env bash
# Run by gk-deploy.timer on Cosmos: fetches master from GitHub into the
# deploy-only clone and, when it has moved, runs deploy.sh on it. A commit that
# failed to deploy is not retried until master moves again (or FORCE=1).
# Pings DEPLOY_HEALTHCHECK_URL from the stack's .env when set. See docs/deploy.md.
set -uo pipefail
STACK="${GK_STACK_DIR:-/home/greg/homelab/gregkilmer}"
export GK_STACK_DIR="$STACK"
cd "$(dirname "$0")/.."
hc="$(grep -E '^DEPLOY_HEALTHCHECK_URL=' "$STACK/.env" 2>/dev/null | cut -d= -f2- || true)"
ping() { [ -n "$hc" ] && curl -fsS -m 10 --retry 3 "$hc$1" >/dev/null 2>&1 || true; }
if ! git fetch --quiet origin master; then
echo "Could not fetch from GitHub"
ping /fail
exit 1
fi
target="$(git rev-parse --short=12 origin/master)"
running="$(grep -E '^GK_TAG=' "$STACK/.env" 2>/dev/null | cut -d= -f2- || true)"
failed="$(cat "$STACK/.failed-tag" 2>/dev/null || true)"
if [ "$target" = "$running" ] && [ "${FORCE:-}" != "1" ]; then
ping ""
exit 0
fi
if [ "$target" = "$failed" ] && [ "${FORCE:-}" != "1" ]; then
echo "$target failed to deploy before; waiting for a new commit (FORCE=1 to retry)"
ping /fail
exit 0
fi
# The clone is for deploys only, so it always matches master exactly.
git reset --quiet --hard origin/master
git clean -fdq
ping /start
if ./deploy/deploy.sh; then
rm -f "$STACK/.failed-tag"
ping ""
else
echo "$target" > "$STACK/.failed-tag"
ping /fail
exit 1
fi
+4 -1
View File
@@ -1,5 +1,5 @@
# Stack settings for compose.yaml. On Cosmos: /home/greg/homelab/gregkilmer/.env
# The Gitea Actions deploy rewrites GK_TAG on every build; GK_PREVIOUS_TAG is the rollback.
# deploy.sh rewrites GK_TAG on every deploy; GK_PREVIOUS_TAG is the rollback.
GK_TAG=
GK_PREVIOUS_TAG=
# The vault's Site folder on the host.
@@ -7,3 +7,6 @@ VAULT_SITE=/home/greg/homelab/obsidian-vault/20-29_Makerspace/24_Homelab_Infrast
# The user the containers run as: the owner of the vault files (id -u greg, id -g greg).
PUID=1000
PGID=1000
# Healthchecks ping for the deploy timer (5-minute period): red when GitHub
# can't be reached or a commit fails to deploy.
DEPLOY_HEALTHCHECK_URL=