Skip to content

About

deploy controller for ramitos-web

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

ramitos-web-controller

This service deploys cadcc/ramitos-web releases into a web root. When it gets a GitHub release webhook, it:

  1. Downloads the release's dist.zip and checks it against the SHA-256 digest GitHub publishes for the asset. If the checksum doesn't match, nothing in the web root changes.
  2. Installs the files in this order: everything under assets/, then index.html, then the rest. Each file is written beside its destination and renamed into place, so the web server never serves a partially written file.
  3. Deletes every file in the web root that belongs to neither this deploy nor the previous one, then removes directories left empty. The previous deploy's files stay so that browsers still running the old index.html can load its chunks. The first deploy skips this step.

Tags are treated as opaque strings and can be in any format. The service doesn't use GitHub's "latest" flag. It deploys the release that triggered the webhook, or the tag you name on the command line.

Commands

controller serve                      # receive webhooks (the container's default)
controller deploy [--force] [--allow-prerelease] [--wait 5m] <tag>
controller healthcheck [--url URL]    # exit 0 if /healthz answers 200

deploy installs a specific release. Use it for the first deploy, or to roll back to an older tag. It skips a release whose digest is already the current deploy, unless you pass --force. It refuses pre-releases unless you pass --allow-prerelease, which is useful for pushing a release candidate to a QA environment. Deploys take a lock on STATE_DIR/deploy.lock, so a deploy started with docker exec and a webhook deploy never overlap. --wait sets how long the command waits for a deploy that is already running.

docker compose exec controller /controller deploy <tag>

healthcheck is the image's HEALTHCHECK, because the distroless image has no curl. GET /healthz returns {"status":"ok","current_tag":…,"deployed_at":…}.

Configuration

Variable Default Purpose
WEBHOOK_SECRET / WEBHOOK_SECRET_FILE required for serve GitHub webhook secret
GITHUB_REPO cadcc/ramitos-web the only repository accepted
GITHUB_TOKEN empty needed for a private repository; also raises the API rate limit
GITHUB_API_URL https://api.github.com API base URL
ASSET_NAME dist.zip release asset to deploy
TARGET_DIR /srv/www web root; it must already exist
STATE_DIR /var/lib/controller deploy history (deploys.json), lock file, staging area
LISTEN_ADDR :8080 HTTP listen address
ALLOW_PRERELEASE false also deploy pre-releases, for a QA environment (see below)
MAX_ZIP_BYTES 209715200 (200 MiB) maximum size of the download, and of its extracted contents

Running

  1. Create the web root and the state directory on the host. Both must be owned by the UID/GID the container runs as. The reverse proxy serves the web root. It shouldn't serve the state directory.

  2. Copy .env.example to .env and set WEBHOOK_SECRET. You can generate one with openssl rand -hex 32.

  3. Run DEPLOY_UID=$(id -u www) DEPLOY_GID=$(id -g www) WEB_ROOT=/srv/ramitos-web docker compose up -d --build.

  4. Point a route on the reverse proxy at the controller. For example, with nginx:

    location = /_deploy/webhook {
        proxy_pass http://127.0.0.1:8080/webhook;
    }
  5. In cadcc/ramitos-web, go to Settings → Webhooks → Add webhook:

    • Payload URL: https://<host>/_deploy/webhook
    • Content type: application/json
    • Secret: the value of WEBHOOK_SECRET
    • Events: choose Let me select individual events and select Releases only.
  6. Deploy the current release once by hand with docker compose exec controller /controller deploy <tag>. After that, every release deploys automatically when it's published, or when a pre-release is promoted to a release. Pre-releases are not deployed by the webhook unless ALLOW_PRERELEASE=true.

QA environments: set ALLOW_PRERELEASE=true to deploy every release and pre-release as soon as it's published. In this mode the webhook triggers on published instead of released, and deploy accepts pre-releases without --allow-prerelease. Promoting a pre-release doesn't trigger a deploy, because its contents were already deployed when it was published.

The webhook answers with 202 as soon as a release is queued, and the deploy runs in the background. Watch progress with docker compose logs -f controller. Deliveries that aren't relevant get a 200 with ignored: <reason>; these include other events, actions other than released (published also fires for pre-releases), drafts, pre-releases, other repositories, and releases without ASSET_NAME. If a release arrives while a deploy is running, it waits. A newer release replaces one that is still waiting.

The controller takes only the release ID from a webhook. It fetches the asset URL and digest from the GitHub API, and it only downloads from GITHUB_API_URL/repos/GITHUB_REPO/releases/assets/…. So someone who has the webhook secret can trigger a deploy of an existing release, but can't choose what gets downloaded or where GITHUB_TOKEN is sent.

With Podman, build with podman build --format docker so the HEALTHCHECK is kept.

Layout

  • cmd/controller/: the binary. It holds the CLI (main.go), the environment configuration (config.go), and the webhook handler with its deploy worker (server.go).
  • internal/deploy/: the deploy pipeline. It covers the GitHub release client, the download and digest check, zip validation, the ordered install, cleanup, the deploy history and the lock.

Development

go vet ./... && go test -race ./...

About

deploy controller for ramitos-web

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages