From 75bc305f541f9f2fc382040635f8e29d05320900 Mon Sep 17 00:00:00 2001 From: sebasnallar Date: Wed, 19 Aug 2026 10:44:22 -0300 Subject: [PATCH] ci: publish containers/scheduled-task/datadog scope images + register artifacts Manually-verified publish-images workflow (v* tag trigger) that builds each scope worker image via the org reusable ECR workflow and registers it as an oci_image platform artifact (visible-to organization=*), fanned out over the 3 images: containers (k8s base), scheduled-task, containers-datadog (metric overlay). Uses the existing NP_API_KEY secret. Rebased onto beta so the PR carries only the feature (no main-only drift such as the cloudwatch deployment annotations). CHANGELOG: Publish containers and scheduled task scopes as docker images. --- .github/workflows/publish-images.yml | 123 +++++++++++++++++++++++++++ CHANGELOG.md | 1 + docker/containers-datadog.Dockerfile | 11 +++ docker/containers.Dockerfile | 37 ++++++++ docker/scheduled-task.Dockerfile | 18 ++++ 5 files changed, 190 insertions(+) create mode 100644 .github/workflows/publish-images.yml create mode 100644 docker/containers-datadog.Dockerfile create mode 100644 docker/containers.Dockerfile create mode 100644 docker/scheduled-task.Dockerfile diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml new file mode 100644 index 00000000..1e0d12f7 --- /dev/null +++ b/.github/workflows/publish-images.yml @@ -0,0 +1,123 @@ +name: publish-images + +# Publishes every scope's worker image to ECR Public on each semver tag, then +# registers each as an oci_image platform artifact (visible-to organization=*). +# Same mold as scopes-lambda (publish-image.yml), fanned out to the 3 images: +# +# scopes/containers <- k8s/ (base; FROM worker-bridge + tooling) +# scopes/scheduled-task <- scheduled_task/ (leaner) +# scopes/containers-datadog <- containers + datadog/ overlay (metric) +# +# The datadog overlay is FROM the containers base (which bakes the whole repo +# into /app/pkg), so it must be pushed first — its build `needs: containers` and +# passes BASE_VERSION so its Dockerfile can FROM containers:. +# (azure / azure-aro are pure config overlays the tofu modules configure at +# install time via NP_OVERRIDES_PATH, so they need no image of their own.) +# +# Explicit job per image on purpose: a matrixed job that calls the reusable +# workflow collapses `image_digest` to a single value (matrix outputs overwrite +# each other), which would register every artifact against the same image. +on: + push: + tags: + - 'v*' + +permissions: + id-token: write # OIDC against AWS + contents: read + +jobs: + # ── containers (base) ────────────────────────────────────────────────────── + containers: + uses: nullplatform/actions-nullplatform/.github/workflows/docker-build-push-ecr.yml@main + with: + image_name: scopes/containers + context: . + dockerfile: docker/containers.Dockerfile + tag: ${{ github.ref_name }} + secrets: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN_ECR_PUSH }} + + register-containers: + name: Register containers artifact + needs: containers + runs-on: ubuntu-24.04 + env: + NULLPLATFORM_API_KEY: ${{ secrets.NP_API_KEY }} + NP_ARTIFACT_NRN: ${{ vars.NP_ARTIFACT_NRN }} + steps: + - name: Install np CLI (alpha-packages build) + run: curl -s https://cli.nullplatform.com/install.sh | VERSION=alpha-packages sh + - name: Register scopes/containers image artifact (visible to everyone) + run: | + np artifact create \ + --nrn "$NP_ARTIFACT_NRN" \ + --type oci_image \ + --registry public.ecr.aws \ + --repository nullplatform/scopes/containers \ + --digest "${{ needs.containers.outputs.image_digest }}" \ + --visible-to "organization=*" + + # ── scheduled-task (standalone) ──────────────────────────────────────────── + scheduled-task: + uses: nullplatform/actions-nullplatform/.github/workflows/docker-build-push-ecr.yml@main + with: + image_name: scopes/scheduled-task + context: . + dockerfile: docker/scheduled-task.Dockerfile + tag: ${{ github.ref_name }} + secrets: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN_ECR_PUSH }} + + register-scheduled-task: + name: Register scheduled-task artifact + needs: scheduled-task + runs-on: ubuntu-24.04 + env: + NULLPLATFORM_API_KEY: ${{ secrets.NP_API_KEY }} + NP_ARTIFACT_NRN: ${{ vars.NP_ARTIFACT_NRN }} + steps: + - name: Install np CLI (alpha-packages build) + run: curl -s https://cli.nullplatform.com/install.sh | VERSION=alpha-packages sh + - name: Register scopes/scheduled-task image artifact (visible to everyone) + run: | + np artifact create \ + --nrn "$NP_ARTIFACT_NRN" \ + --type oci_image \ + --registry public.ecr.aws \ + --repository nullplatform/scopes/scheduled-task \ + --digest "${{ needs.scheduled-task.outputs.image_digest }}" \ + --visible-to "organization=*" + + # ── containers-datadog (overlay) ─────────────────────────────────────────── + containers-datadog: + needs: containers + uses: nullplatform/actions-nullplatform/.github/workflows/docker-build-push-ecr.yml@main + with: + image_name: scopes/containers-datadog + context: . + dockerfile: docker/containers-datadog.Dockerfile + tag: ${{ github.ref_name }} + build_args: BASE_VERSION=${{ github.ref_name }} + secrets: + aws_role_arn: ${{ secrets.AWS_ROLE_ARN_ECR_PUSH }} + + register-containers-datadog: + name: Register containers-datadog artifact + needs: containers-datadog + runs-on: ubuntu-24.04 + env: + NULLPLATFORM_API_KEY: ${{ secrets.NP_API_KEY }} + NP_ARTIFACT_NRN: ${{ vars.NP_ARTIFACT_NRN }} + steps: + - name: Install np CLI (alpha-packages build) + run: curl -s https://cli.nullplatform.com/install.sh | VERSION=alpha-packages sh + - name: Register scopes/containers-datadog image artifact (visible to everyone) + run: | + np artifact create \ + --nrn "$NP_ARTIFACT_NRN" \ + --type oci_image \ + --registry public.ecr.aws \ + --repository nullplatform/scopes/containers-datadog \ + --digest "${{ needs.containers-datadog.outputs.image_digest }}" \ + --visible-to "organization=*" diff --git a/CHANGELOG.md b/CHANGELOG.md index c93e4766..6f826434 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +- Publish containers and scheduled task scopes as docker images - Remove unused cloudwatch annotations from deployment objects - Fix: log queries on k8s scopes now return the time range that was selected, instead of the most recent lines whatever range was chosen - Fix: paging through logs on k8s scopes no longer repeats lines already shown, and now reaches the end of the selected range diff --git a/docker/containers-datadog.Dockerfile b/docker/containers-datadog.Dockerfile new file mode 100644 index 00000000..bd157826 --- /dev/null +++ b/docker/containers-datadog.Dockerfile @@ -0,0 +1,11 @@ +# syntax=docker/dockerfile:1 +# +# containers-datadog — the containers scope with the datadog overlay baked in +# (the datadog/ folder overrides the metric step). The containers base already +# COPYied the whole repo into /app/pkg (incl. datadog/), so this only layers the +# overlay onto the service-path. datadog uses jq + curl, already in the base. +ARG BASE_VERSION +FROM public.ecr.aws/nullplatform/scopes/containers:${BASE_VERSION} + +ENV NP_PACKAGE_NAME=containers-datadog \ + NP_OVERRIDES_PATH=/app/pkg/datadog diff --git a/docker/containers.Dockerfile b/docker/containers.Dockerfile new file mode 100644 index 00000000..19d1d553 --- /dev/null +++ b/docker/containers.Dockerfile @@ -0,0 +1,37 @@ +# syntax=docker/dockerfile:1 +# +# containers (k8s) scope image — the full Kubernetes scope on the lean gRPC +# worker bridge. The bridge dials over gRPC and runs the repo's bash entrypoint +# on each action; this image adds the cloud tooling the k8s steps call and bakes +# the whole repo in, so the package-exec channel needs no cmdline. +# +# NP_SERVICE_PATH=k8s + NP_SCOPE_ENTRYPOINT=/entrypoint mirrors the classic +# `.../scopes/entrypoint --service-path=k8s` the git-clone model used. +FROM public.ecr.aws/nullplatform/scopes/worker-bridge:1.0.0 + +# apk tooling the k8s steps call. bash, jq, np, base64, curl, ca-certs ship in +# the base. aws-cli 2.x, gomplate and yq are packaged on alpine. +RUN apk add --no-cache aws-cli gomplate yq + +# Pinned binaries not reliably packaged on alpine: OpenTofu, kubectl, helm. +# NOTE: review/pin these versions to what the scopes actually target. +ARG TARGETARCH +ARG TOFU_VERSION=1.10.6 +ARG KUBECTL_VERSION=1.30.4 +ARG HELM_VERSION=3.15.4 +RUN set -eux; \ + curl -fsSL "https://github.com/opentofu/opentofu/releases/download/v${TOFU_VERSION}/tofu_${TOFU_VERSION}_linux_${TARGETARCH}.tar.gz" \ + | tar -xz -C /usr/local/bin tofu; \ + curl -fsSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl"; \ + chmod +x /usr/local/bin/kubectl; \ + curl -fsSL "https://get.helm.sh/helm-v${HELM_VERSION}-linux-${TARGETARCH}.tar.gz" | tar -xz -C /tmp; \ + mv "/tmp/linux-${TARGETARCH}/helm" /usr/local/bin/helm; \ + rm -rf "/tmp/linux-${TARGETARCH}"; \ + tofu version && kubectl version --client && helm version --short + +# Bake the whole repo in; the overlays (containers-azure, -datadog, -aro) are +# FROM this image and only flip NP_OVERRIDES_PATH — no re-copy needed. +COPY . /app/pkg +ENV NP_PACKAGE_NAME=containers \ + NP_SERVICE_PATH=/app/pkg/k8s \ + NP_SCOPE_ENTRYPOINT=/app/pkg/entrypoint diff --git a/docker/scheduled-task.Dockerfile b/docker/scheduled-task.Dockerfile new file mode 100644 index 00000000..1ece0e96 --- /dev/null +++ b/docker/scheduled-task.Dockerfile @@ -0,0 +1,18 @@ +# syntax=docker/dockerfile:1 +# +# scheduled-task scope image — the scheduled_task scope. Leaner than containers: +# its steps only reach for kubectl + gomplate (bash/jq/np ship in the base). +FROM public.ecr.aws/nullplatform/scopes/worker-bridge:1.0.0 + +RUN apk add --no-cache gomplate + +ARG TARGETARCH +ARG KUBECTL_VERSION=1.30.4 +RUN curl -fsSL -o /usr/local/bin/kubectl "https://dl.k8s.io/release/v${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl" \ + && chmod +x /usr/local/bin/kubectl \ + && kubectl version --client + +COPY . /app/pkg +ENV NP_PACKAGE_NAME=scheduled-task \ + NP_SERVICE_PATH=/app/pkg/scheduled_task \ + NP_SCOPE_ENTRYPOINT=/app/pkg/entrypoint