Skip to content

feat(deploy): release-driven deploy via GH release tarball + polling deployer service #1107

@aaylward

Description

@aaylward

Goal

Replace the manual deploy/consolidated/deploy.sh scp/ssh workflow with a GitHub-release-triggered deploy pipeline:

  1. CI bundles deploy assets into a versioned tarball and publishes a GH release tagged release-deploy-assets/<sha>
  2. A small deployer service running on the consolidated host polls for new releases, downloads the tarball, and applies the deploy — replacing what deploy.sh does today

Part 1: CI — release-deploy-assets step in publish.yml

Add a final step to the test-and-publish job (after images are pushed and SHA-tagged) that:

  1. Collects the following files into a staging directory:
  2. Creates a tarball: deploy-assets-<sha>.tar.gz
  3. Publishes a GH release tagged release-deploy-assets/<sha> (pre-release, auto-generated notes) with the tarball as an asset

The release tag scheme release-deploy-assets/<sha> lets the deployer service unambiguously identify new deploy-asset releases vs. other release types (microgpt, wordchains, etc.).

Note: use POSIX-compatible shell in run: steps — the CI container default shell is sh, not bash.


Part 2: Deployer service (deploy/consolidated/deployer/)

A small long-running service (suggest: Go or shell + systemd, or a minimal Docker container already in compose.yaml) that:

  • Polls the GH Releases API for new release-deploy-assets/* releases (e.g. every 60s)
  • Persists the last-applied release tag to a state file (e.g. ~/.deployer-state) to avoid re-applying on restart
  • On new release detected:
    1. Downloads the tarball asset via the GH API
    2. Extracts to a working directory
    3. Copies config files into place (mirrors current deploy.sh logic):
    4. Runs docker compose -f compose.yaml -f docker-compose.observability.yml pull
    5. Runs docker compose -f compose.yaml -f docker-compose.observability.yml up -d --remove-orphans
    6. Runs docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
    7. Writes the new release tag to the state file
  • Logs each deploy attempt with timestamp and outcome
  • Needs a GH token (read:packages + contents) in the environment — sourced from .env or a secrets file on the host

The deployer should be added to compose.yaml so it is itself managed by Docker Compose. On first boot / initialize_host.sh, it gets started with the rest of the stack.


Out of scope (v2)

  • Per-service granular deploys (only restart the service whose image changed)
  • Rollback automation
  • Slack/webhook deploy notifications

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions