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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions