build+deploy: reproducible pipeline via Gitea Actions + gw-04 image-watcher #1
@@ -92,3 +92,48 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: playwright-traces
|
name: playwright-traces
|
||||||
path: frontend/test-results/
|
path: frontend/test-results/
|
||||||
|
|
||||||
|
# Rolling deploy: on green main only, build the three prod images, tag with
|
||||||
|
# :main-<sha> + :latest, push to the fleet registry (redclaw-web-01:5000 via
|
||||||
|
# its Tailscale IP — the fleet's daemons trust it in insecure-registries by
|
||||||
|
# IP, not by hostname). GW-04's clawmates-deploy.timer rolls forward within
|
||||||
|
# ~1 minute of the push. Skipped on PRs.
|
||||||
|
publish:
|
||||||
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [gates, rust, frontend, e2e]
|
||||||
|
env:
|
||||||
|
REGISTRY: 100.94.185.103:5000
|
||||||
|
NAMESPACE: clawmates
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Resolve short SHA
|
||||||
|
run: echo "SHA=${GITHUB_SHA::7}" >> "$GITHUB_ENV"
|
||||||
|
- name: Build images
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for svc in broker server frontend; do
|
||||||
|
docker build \
|
||||||
|
-t "${REGISTRY}/${NAMESPACE}/${svc}:main-${SHA}" \
|
||||||
|
-t "${REGISTRY}/${NAMESPACE}/${svc}:latest" \
|
||||||
|
-f "images/${svc}.Dockerfile" .
|
||||||
|
done
|
||||||
|
- name: Push images
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
for svc in broker server frontend; do
|
||||||
|
docker push "${REGISTRY}/${NAMESPACE}/${svc}:main-${SHA}"
|
||||||
|
docker push "${REGISTRY}/${NAMESPACE}/${svc}:latest"
|
||||||
|
done
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
{
|
||||||
|
echo "## Published images"
|
||||||
|
echo ""
|
||||||
|
for svc in broker server frontend; do
|
||||||
|
echo "- \`${REGISTRY}/${NAMESPACE}/${svc}:main-${SHA}\`"
|
||||||
|
echo "- \`${REGISTRY}/${NAMESPACE}/${svc}:latest\`"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
echo "GW-04 timer picks these up within ~1 minute."
|
||||||
|
} >> "$GITHUB_STEP_SUMMARY"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Clawmates rolling deploy (pull :latest, roll on drift)
|
||||||
|
Wants=docker.service
|
||||||
|
After=docker.service network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/bin/clawmates-deploy.sh
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
Nice=10
|
||||||
Executable
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# clawmates rolling deploy — polls the fleet registry for :latest of the three
|
||||||
|
# prod images (broker, server, frontend). On drift, pulls the new image, retags
|
||||||
|
# it under the un-prefixed name the running compose file uses, and rolls the
|
||||||
|
# affected services with `docker compose up -d`.
|
||||||
|
#
|
||||||
|
# Install:
|
||||||
|
# sudo install -m 0755 clawmates-deploy.sh /usr/local/bin/clawmates-deploy.sh
|
||||||
|
# sudo install -m 0644 clawmates-deploy.service /etc/systemd/system/
|
||||||
|
# sudo install -m 0644 clawmates-deploy.timer /etc/systemd/system/
|
||||||
|
# sudo systemctl daemon-reload
|
||||||
|
# sudo systemctl enable --now clawmates-deploy.timer
|
||||||
|
#
|
||||||
|
# Verify:
|
||||||
|
# systemctl list-timers clawmates-deploy.timer
|
||||||
|
# tail -f /var/log/clawmates-deploy.log
|
||||||
|
#
|
||||||
|
# The retag step (registry/clawmates/<svc>:latest → clawmates/<svc>:latest)
|
||||||
|
# keeps the current /root/clawmates/docker-compose.yml working unchanged until
|
||||||
|
# we're ready to migrate the compose file to registry-prefixed image names.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REGISTRY="${REGISTRY:-100.94.185.103:5000}"
|
||||||
|
NAMESPACE="${NAMESPACE:-clawmates}"
|
||||||
|
COMPOSE_DIR="${COMPOSE_DIR:-/root/clawmates}"
|
||||||
|
LOG="${LOG:-/var/log/clawmates-deploy.log}"
|
||||||
|
SERVICES=(broker server frontend)
|
||||||
|
|
||||||
|
log() { printf '%s %s\n' "$(date -Iseconds)" "$*" | tee -a "$LOG" >/dev/null; }
|
||||||
|
|
||||||
|
changed=()
|
||||||
|
for svc in "${SERVICES[@]}"; do
|
||||||
|
ref="${REGISTRY}/${NAMESPACE}/${svc}:latest"
|
||||||
|
local_ref="${NAMESPACE}/${svc}:latest"
|
||||||
|
|
||||||
|
before=$(docker inspect --format '{{.Id}}' "$ref" 2>/dev/null || echo "")
|
||||||
|
if ! docker pull -q "$ref" >/dev/null 2>&1; then
|
||||||
|
log "pull failed: $ref"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
after=$(docker inspect --format '{{.Id}}' "$ref")
|
||||||
|
|
||||||
|
if [[ "$before" != "$after" ]]; then
|
||||||
|
log "new image for $svc: ${before:-<none>} -> $after"
|
||||||
|
changed+=("$svc")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Always keep the un-prefixed tag pointing at the fresh image, so a stale
|
||||||
|
# local retag can't wedge us.
|
||||||
|
docker tag "$ref" "$local_ref"
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#changed[@]} -eq 0 ]]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "rolling: ${changed[*]}"
|
||||||
|
cd "$COMPOSE_DIR"
|
||||||
|
docker compose up -d "${changed[@]}"
|
||||||
|
log "roll complete: ${changed[*]}"
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Clawmates rolling deploy — every minute
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnBootSec=2min
|
||||||
|
OnUnitActiveSec=1min
|
||||||
|
AccuracySec=15s
|
||||||
|
Unit=clawmates-deploy.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
Reference in New Issue
Block a user