Zaroz
Deploy from CI/CD

Deploy from GitHub Actions

Prerequisites: a Workload that already runs (created in the console), its service instance id, and the deploy token. Add zaroz-deploy.sh to your repository as deploy/zaroz-deploy.sh.

Secrets and variables

In Settings > Secrets and variables > Actions, create these on the production environment (Settings > Environments):

NameKindValue
ZAROZ_TOKENsecretthe zaroz_... deploy token
ZAROZ_SERVICEvariablethe service instance UUID
GHCR_PULL_TOKENsecretonly for a private package: a classic token with read:packages, not the one that pushes

Environment secrets are only handed to jobs that target that environment, so add required reviewers to production if a human should approve each deploy.

The workflow

YAMLCode
# .github/workflows/deploy.yml name: deploy on: push: branches: [main] # Two pushes in a row must not deploy at the same time: Zaroz refuses the second # with 409 anyway, and this queues it instead of failing it. concurrency: group: deploy-production cancel-in-progress: false permissions: contents: read packages: write jobs: build: runs-on: ubuntu-latest outputs: image: ${{ steps.meta.outputs.image }} steps: - uses: actions/checkout@v4 - uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - id: meta # One immutable tag per commit: Zaroz does not watch a moved tag. run: echo "image=ghcr.io/${GITHUB_REPOSITORY,,}:${GITHUB_SHA::12}" >> "$GITHUB_OUTPUT" - uses: docker/build-push-action@v6 with: context: . push: true tags: ${{ steps.meta.outputs.image }} deploy: needs: build runs-on: ubuntu-latest # Put the approval rule (reviewers) on this environment, not on the token. environment: production steps: - uses: actions/checkout@v4 - name: Deploy to Zaroz run: sh deploy/zaroz-deploy.sh env: IMAGE: ${{ needs.build.outputs.image }} ZAROZ_TOKEN: ${{ secrets.ZAROZ_TOKEN }} ZAROZ_SERVICE: ${{ vars.ZAROZ_SERVICE }} # Only for a private image: a read-only token that can pull the package. REGISTRY_USERNAME: ${{ github.actor }} REGISTRY_PASSWORD: ${{ secrets.GHCR_PULL_TOKEN }}

How it behaves:

  • build pushes ghcr.io/<owner>/<repo>:<first 12 chars of the commit>. Each commit gets its own tag.
  • deploy runs the script, which fails the job when the rollout fails and has already put the previous image back.
  • concurrency queues a second push instead of racing the first. Zaroz would otherwise refuse it with 409 while the first deployment holds the service.
  • The job log prints deployment #N started, then ... is serving or the failure_reason.

Roll back by hand

Re-run the deploy job of an older successful run: it deploys that run's image again. Or from a terminal: IMAGE=ghcr.io/acme/api:<old tag> sh deploy/zaroz-deploy.sh.

Pull requests

Do not give a pull request from a fork access to ZAROZ_TOKEN. The workflow above runs only on pushes to main, where secrets are available. For a preview environment, mint a second token scoped to a separate preview service.

Last modified on