From dd980efc24bc345132d05a59dc6f66fed8a555c6 Mon Sep 17 00:00:00 2001 From: ianhodge Date: Mon, 1 Jun 2026 17:59:39 +0000 Subject: [PATCH] Publish immutable worker image releases Automatically create timestamped worker releases from main and document image pinning guidance for self-hosted customers. Co-Authored-By: Oz --- .github/workflows/build_release.yml | 43 ++++++++++++++++++++++++++-- .github/workflows/ci.yml | 18 ------------ .github/workflows/create_release.yml | 9 +++++- README.md | 27 ++++++++++++++--- charts/oz-agent-worker/values.yaml | 4 ++- 5 files changed, 75 insertions(+), 26 deletions(-) diff --git a/.github/workflows/build_release.yml b/.github/workflows/build_release.yml index 7a8698b..4f04e54 100644 --- a/.github/workflows/build_release.yml +++ b/.github/workflows/build_release.yml @@ -8,6 +8,11 @@ on: required: false default: '' type: string + publish_latest: + description: 'Also tag the Docker image as latest when docker_tag is provided' + required: false + default: false + type: boolean version: description: 'Build version stamped into the binary via -ldflags="-X main.Version=...". Defaults to docker_tag, then to the commit SHA.' required: false @@ -20,6 +25,11 @@ on: required: false default: '' type: string + publish_latest: + description: 'Also tag the Docker image as latest when docker_tag is provided' + required: false + default: false + type: boolean version: description: 'Build version stamped into the binary via -ldflags="-X main.Version=...". Defaults to docker_tag, then to the commit SHA.' required: false @@ -34,6 +44,9 @@ on: image: description: 'Full Docker image reference' value: ${{ jobs.docker.outputs.image }} + tagged_image: + description: 'Primary tagged Docker image reference' + value: ${{ jobs.docker.outputs.tagged_image }} jobs: build: @@ -109,6 +122,7 @@ jobs: runs-on: namespace-profile-ubuntu-small outputs: image: "warpdotdev/oz-agent-worker@${{ steps.push.outputs.digest }}" + tagged_image: ${{ steps.image-tags.outputs.primary }} steps: - name: Check out repository uses: actions/checkout@v6 @@ -118,6 +132,28 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Resolve Docker image tags + id: image-tags + env: + DOCKER_TAG: ${{ inputs.docker_tag }} + PUBLISH_LATEST: ${{ inputs.publish_latest }} + run: | + if [ -n "$DOCKER_TAG" ]; then + { + echo 'tags<> "$GITHUB_OUTPUT" + else + { + echo "tags=warpdotdev/oz-agent-worker:${GITHUB_SHA}" + echo "primary=warpdotdev/oz-agent-worker:${GITHUB_SHA}" + } >> "$GITHUB_OUTPUT" + fi - name: Build and push image id: push @@ -132,11 +168,14 @@ jobs: # See https://docs.docker.com/reference/cli/docker/buildx/build/#docker outputs: ${{ inputs.docker_tag != '' && 'type=registry' || 'type=local,dest=built-images' }} platforms: linux/amd64,linux/arm64 - tags: warpdotdev/oz-agent-worker:${{ inputs.docker_tag || github.sha }} + tags: ${{ steps.image-tags.outputs.tags }} # Forward the resolved version to the Dockerfile so the binary baked # into the image carries the same main.Version as the standalone # release artifacts. build-args: | VERSION=${{ inputs.version != '' && inputs.version || (inputs.docker_tag != '' && inputs.docker_tag || github.sha) }} - labels: + labels: | dev.warp.worker-commit=${{ github.sha }} + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.version=${{ inputs.version != '' && inputs.version || (inputs.docker_tag != '' && inputs.docker_tag || github.sha) }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3289ecd..ae3875e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,21 +58,3 @@ jobs: run: helm lint ./charts/oz-agent-worker --set worker.workerId=ci-worker --set image.tag=ci - name: Render Helm chart run: helm template oz-agent-worker ./charts/oz-agent-worker --namespace agents --set worker.workerId=ci-worker --set image.tag=ci >/tmp/oz-agent-worker-chart.yaml - - docker: - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - steps: - - uses: actions/checkout@v4 - - uses: docker/setup-buildx-action@v3 - - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - uses: docker/build-push-action@v5 - with: - context: . - file: ./Dockerfile - push: true - platforms: linux/amd64,linux/arm64 - tags: warpdotdev/oz-agent-worker:latest diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml index 62474a9..32b0ba3 100644 --- a/.github/workflows/create_release.yml +++ b/.github/workflows/create_release.yml @@ -2,6 +2,8 @@ name: Create Release on: workflow_dispatch: + push: + branches: [main] jobs: generate-tag: @@ -20,6 +22,7 @@ jobs: secrets: inherit with: docker_tag: ${{ needs.generate-tag.outputs.tag_name }} + publish_latest: true # Stamp the same tag into main.Version so `oz_worker_info{version=...}` # in /metrics matches the published release tag and Docker image tag. version: ${{ needs.generate-tag.outputs.tag_name }} @@ -44,5 +47,9 @@ jobs: target_commitish: ${{ github.sha }} generate_release_notes: true append_body: true - body: "**Docker image:** `${{ needs.build.outputs.image }}`" + body: | + **Docker image tag:** `${{ needs.build.outputs.tagged_image }}` + **Docker image digest:** `${{ needs.build.outputs.image }}` + + `latest` was updated to this same image as part of this release. For production self-hosted workers, pin the immutable release tag or digest instead of `latest`. files: artifacts/**/* diff --git a/README.md b/README.md index 3dd4a62..ab42058 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,30 @@ The worker needs access to the Docker daemon to spawn task containers. Mount the ```bash docker run -v /var/run/docker.sock:/var/run/docker.sock \ -e WARP_API_KEY="wk-abc123" \ - warpdotdev/oz-agent-worker --worker-id "my-worker" + warpdotdev/oz-agent-worker: --worker-id "my-worker" ``` > **Note:** Mounting the Docker socket gives the container access to the host's Docker daemon. This is required for the worker to create and manage task containers. +### Image releases and pinning + +Production self-hosted workers should pin an immutable image version instead of relying on `latest`. + +Each merge to `main` creates a GitHub release and publishes a multi-architecture Docker image with a UTC timestamp tag: + +```text +warpdotdev/oz-agent-worker:vYYYY-MM-DD-HH-MM-SS +``` + +The GitHub release body includes both the Docker tag and digest. Use either the timestamp tag or the digest in production deployments: + +```bash +docker pull warpdotdev/oz-agent-worker:v2026-06-01-10-09-37 +docker pull warpdotdev/oz-agent-worker@sha256: +``` + +`latest` is updated to the same image when a release is published, but it is a moving tag intended for quick testing only. + ### Direct The direct backend executes tasks directly on the host instead of inside Docker or Kubernetes. It requires the `oz` CLI to be available on `PATH` (or configured explicitly with `backend.direct.oz_path`) and stores per-task workspaces under `backend.direct.workspace_root` (default: `/var/lib/oz/workspaces`). @@ -128,7 +147,7 @@ helm install oz-agent-worker ./charts/oz-agent-worker \ --namespace agents \ --create-namespace \ --set worker.workerId=my-worker \ - --set image.tag=v1.2.3 + --set image.tag=v2026-06-01-10-09-37 ``` The chart assumes the worker runs inside the target cluster and uses in-cluster Kubernetes auth by default. It does not create CRDs or cluster-scoped RBAC. Set `image.tag` explicitly for each install so the worker image is pinned instead of defaulting to `latest`. @@ -203,7 +222,7 @@ When using Docker to run the worker, note that `-e` flags for the worker itself ```bash docker run -v /var/run/docker.sock:/var/run/docker.sock \ -e WARP_API_KEY="wk-abc123" \ - warpdotdev/oz-agent-worker --worker-id "my-worker" -e MY_SECRET=hunter2 + warpdotdev/oz-agent-worker: --worker-id "my-worker" -e MY_SECRET=hunter2 ``` When configuring the Kubernetes backend via YAML or Helm, declarative task-container env belongs in `backend.kubernetes.pod_template` / `kubernetesBackend.podTemplate` rather than a separate top-level Kubernetes env list. The `-e` / `--env` flags remain available as backend-agnostic runtime overrides. @@ -275,7 +294,7 @@ metrics only. helm install oz-agent-worker ./charts/oz-agent-worker \ --namespace agents --create-namespace \ --set worker.workerId=my-worker \ - --set image.tag=v1.2.3 \ + --set image.tag=v2026-06-01-10-09-37 \ --set metrics.enabled=true ``` diff --git a/charts/oz-agent-worker/values.yaml b/charts/oz-agent-worker/values.yaml index 654d959..3d036a8 100644 --- a/charts/oz-agent-worker/values.yaml +++ b/charts/oz-agent-worker/values.yaml @@ -3,7 +3,9 @@ fullnameOverride: "" image: repository: warpdotdev/oz-agent-worker - # Set this explicitly to a published worker image tag for each install. + # Set this explicitly to a published immutable worker image tag for each + # install, e.g. v2026-06-01-10-09-37. Avoid using the mutable `latest` tag for + # production self-hosted workers. tag: "" pullPolicy: IfNotPresent pullSecrets: []