diff --git a/.env.example b/.env.example index 7cd7ef0..da40171 100644 --- a/.env.example +++ b/.env.example @@ -47,3 +47,10 @@ GATEWAY_ADMIN_TOKEN= # DNS provider Traefik's DNS-01 challenge should use for the wildcard cert. # See traefik/static/traefik.shared.yml. GATEWAY_BASE_DOMAIN=boxes.example.com + +# Optional: override the control-plane image `docker stack deploy` pulls +# (Swarm ignores docker-compose.yaml's `build:` key — see README's Swarm +# caveats). Defaults to the `latest` tag CI publishes on every push to +# master; pin to a specific commit-sha tag for a reproducible deploy. +# Not read by plain `docker compose up`, which always builds locally. +GATEWAY_CONTROL_PLANE_IMAGE= diff --git a/.forgejo/workflows/build-image.yml b/.forgejo/workflows/build-image.yml new file mode 100644 index 0000000..91ac73b --- /dev/null +++ b/.forgejo/workflows/build-image.yml @@ -0,0 +1,67 @@ +name: Build control-plane image + +# Publishes control_plane as a versioned image to this Forgejo instance's +# own container registry, so `docker stack deploy` (which never reads +# `build:`, see README's Swarm caveats) doesn't need an operator to build +# and tag it by hand first. +# +# Self-hosted runner, plain `docker build`/`docker push` rather than the +# docker/build-push-action marketplace action: unconfirmed whether that +# action is mirrored on this instance's action runner (furtka's own +# ci.yml hit exactly this gap with lycheeverse/lychee-action and had to +# fall back to a fully-qualified github.com URL), and raw docker commands +# sidestep the question entirely — same reasoning as release.yml/ +# build-iso.yml using plain shell for their heavy lifting. +on: + push: + branches: [master] + tags: ['**'] + paths: + - 'control_plane/**' + - '.forgejo/workflows/build-image.yml' + workflow_dispatch: + +concurrency: + group: build-image-${{ github.ref }} + cancel-in-progress: true + +jobs: + build-image: + runs-on: self-hosted + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + + - name: Log in to this instance's container registry + # GITHUB_TOKEN here is Forgejo's own auto-issued Actions token, + # scoped to this repo with package read/write — not a GitHub + # token. Standard Forgejo/Gitea Actions pattern. + run: | + echo "${{ secrets.GITHUB_TOKEN }}" | docker login "${{ vars.FORGEJO_HOST || 'forgejo.sourcegate.online' }}" \ + -u "${{ github.actor }}" --password-stdin + + - name: Build image + run: | + docker build -t control-plane:build ./control_plane + + - name: Tag and push + env: + REGISTRY: ${{ vars.FORGEJO_HOST || 'forgejo.sourcegate.online' }} + IMAGE: furtka-gateway-control-plane + run: | + set -e + sha_tag="${GITHUB_SHA::12}" + docker tag control-plane:build "$REGISTRY/${{ github.repository_owner }}/$IMAGE:$sha_tag" + docker push "$REGISTRY/${{ github.repository_owner }}/$IMAGE:$sha_tag" + + # `latest` tracks master; a version-tag push (e.g. from a future + # CalVer release process, see furtka/RELEASING.md for the + # pattern this would mirror) additionally publishes under that + # tag's own name. + if [ "${{ github.ref_type }}" = "branch" ]; then + docker tag control-plane:build "$REGISTRY/${{ github.repository_owner }}/$IMAGE:latest" + docker push "$REGISTRY/${{ github.repository_owner }}/$IMAGE:latest" + else + docker tag control-plane:build "$REGISTRY/${{ github.repository_owner }}/$IMAGE:${{ github.ref_name }}" + docker push "$REGISTRY/${{ github.repository_owner }}/$IMAGE:${{ github.ref_name }}" + fi diff --git a/README.md b/README.md index 82ee4ab..d850823 100644 --- a/README.md +++ b/README.md @@ -69,11 +69,13 @@ plan, not yet implemented — see the plan doc for the phased delivery. If deploying via `docker stack deploy` instead of `docker compose up`: - `docker-compose.yaml`'s `build: ./control_plane` doesn't work under - Swarm at all — it only ever schedules pre-built, tagged images. Build - and tag the image yourself first (`docker build -t - furtka-gateway-control-plane:local ./control_plane`) and swap `build:` - for `image: furtka-gateway-control-plane:local` until this is packaged - as a versioned image in CI (the planned long-term fix). + Swarm at all — it only ever schedules pre-built, tagged images. Swarm + falls back to the `image:` key on the same service instead, which + `.forgejo/workflows/build-image.yml` keeps published to this instance's + container registry on every push to `master` (tagged `latest` plus the + short commit sha) — no manual build/tag step needed. Set + `GATEWAY_CONTROL_PLANE_IMAGE` in `.env` first if you want a specific + commit-sha tag rather than whatever `latest` currently points to. - `docker stack deploy` does not read a `.env` file next to the compose file the way `docker compose up` does — `set -a; source .env; set +a` first, or the `${VAR}` substitutions come out empty. diff --git a/docker-compose.yaml b/docker-compose.yaml index 729d9c5..151c6ce 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -72,6 +72,14 @@ services: control-plane: build: ./control_plane + # CI (.forgejo/workflows/build-image.yml) publishes this same build to + # the registry on every push to master, tagged `latest` plus the short + # commit sha. `docker compose up` builds fresh from `build:` above and + # tags the result as this name, ignoring this being a registry ref; + # `docker stack deploy` (Swarm ignores `build:` entirely, see the + # Swarm caveats in README.md) pulls it instead — no manual + # `docker build -t ... ./control_plane` step needed there anymore. + image: ${GATEWAY_CONTROL_PLANE_IMAGE:-forgejo.sourcegate.online/robert/furtka-gateway-control-plane:latest} container_name: furtka-gateway-control-plane environment: - GATEWAY_MODE=${GATEWAY_MODE:-single}