From 35f53a0b4524953d5cc75dfc8f37f0c8ce6ec4d3 Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Tue, 17 Mar 2026 02:35:52 +0000 Subject: [PATCH] chore: align docker-runner architecture --- .github/workflows/release.yml | 81 ++++++++----------- Dockerfile | 2 +- README.md | 69 +++++----------- charts/docker-runner/templates/hpa.yaml | 1 - charts/docker-runner/templates/pdb.yaml | 1 - .../templates/servicemonitor.yaml | 1 - devspace.yaml | 47 +++++++++-- .../e2e/docker-runner.e2e.test.ts | 2 +- vitest.config.e2e.ts | 2 +- vitest.config.ts | 2 +- 10 files changed, 99 insertions(+), 109 deletions(-) delete mode 100644 charts/docker-runner/templates/hpa.yaml delete mode 100644 charts/docker-runner/templates/pdb.yaml delete mode 100644 charts/docker-runner/templates/servicemonitor.yaml rename {__tests__ => test}/e2e/docker-runner.e2e.test.ts (97%) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b00cc44..7bf5cfc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,8 +2,6 @@ name: Release on: push: - branches: - - main tags: - "v*.*.*" workflow_dispatch: {} @@ -14,13 +12,14 @@ permissions: env: REGISTRY: ghcr.io + IMAGE_NAME: ghcr.io/agynio/docker-runner DOCKER_PLATFORMS: linux/amd64,linux/arm64 CHART_REGISTRY: oci://ghcr.io/agynio/charts jobs: - image-main: - name: Build and publish docker image (main) - if: github.ref == 'refs/heads/main' + image-release: + name: Build and publish docker image (release) + if: startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest steps: - name: Checkout @@ -41,8 +40,17 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract short SHA - run: echo "SHORT_SHA=${GITHUB_SHA::7}" >> "$GITHUB_ENV" + - name: Extract Docker metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE_NAME }} + tags: | + type=sha,format=short,prefix=sha- + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }} - name: Build and push docker-runner image uses: docker/build-push-action@v6 @@ -51,52 +59,27 @@ jobs: file: Dockerfile platforms: ${{ env.DOCKER_PLATFORMS }} push: true - tags: | - ghcr.io/agynio/docker-runner:main - ghcr.io/agynio/docker-runner:sha-${{ env.SHORT_SHA }} - - image-release: - name: Build and publish docker image (release) - if: startsWith(github.ref, 'refs/tags/v') - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha,scope=docker-runner + cache-to: type=gha,scope=docker-runner,mode=max - - name: Extract release version + - name: Verify multi-arch manifest run: | - if [[ "${GITHUB_REF_NAME}" != v*.*.* ]]; then - echo "Tag must follow v*.*.*" >&2 + TAG="${GITHUB_REF_NAME#v}" + INSPECT="$(docker buildx imagetools inspect "$IMAGE_NAME:$TAG" --raw)" + FOUND="$(echo "$INSPECT" | jq -r '[.manifests[].platform.architecture] | sort | join(",")')" + MISSING=() + for ARCH in amd64 arm64; do + if ! echo "$FOUND" | grep -q "$ARCH"; then + MISSING+=("linux/$ARCH") + fi + done + if [ ${#MISSING[@]} -gt 0 ]; then + echo "::error::Missing architectures in $IMAGE_NAME:$TAG: ${MISSING[*]}" exit 1 fi - VERSION="${GITHUB_REF_NAME#v}" - echo "RELEASE_VERSION=${VERSION}" >> "$GITHUB_ENV" - - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - with: - platforms: linux/arm64 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to GHCR - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Build and push docker-runner image - uses: docker/build-push-action@v6 - with: - context: . - file: Dockerfile - platforms: ${{ env.DOCKER_PLATFORMS }} - push: true - tags: | - ghcr.io/agynio/docker-runner:${{ env.RELEASE_VERSION }} - ghcr.io/agynio/docker-runner:latest + echo "Manifest $IMAGE_NAME:$TAG includes linux/amd64 and linux/arm64" chart: name: Package and publish Helm chart diff --git a/Dockerfile b/Dockerfile index d1f24e7..65b2567 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # syntax=docker/dockerfile:1.7 -FROM node:20-slim AS base +FROM --platform=$BUILDPLATFORM node:20-slim AS base ARG TARGETARCH diff --git a/README.md b/README.md index 59cfd04..fc3ddf2 100644 --- a/README.md +++ b/README.md @@ -1,65 +1,38 @@ -# docker-runner +# Docker Runner -Standalone Docker runner service extracted from the agynio/platform monorepo. +Docker Engine-backed runner service that executes workloads over gRPC. -## Prerequisites +Architecture: [Runner](https://github.com/agynio/architecture/blob/main/architecture/runner.md) -Access to an agynio Kubernetes cluster (kubeconfig configured) and: +## Local Development -| Tool | Version | Purpose | -| --- | --- | --- | -| kubectl | Compatible with cluster | Manage Kubernetes resources. | -| devspace | Latest | Run the in-cluster DevSpace workflow. | -| Docker Engine | Latest | Runs the k3d cluster used by bootstrap. | -| k3d | v5.x | Local Kubernetes cluster for bootstrap. | -| Terraform | >= 1.5.0 | Provision the bootstrap infrastructure. | +Full setup: [Local Development](https://github.com/agynio/architecture/blob/main/architecture/operations/local-development.md) -No local Node.js or pnpm required; the dev container in the cluster runs the toolchain. +### Prepare environment -## Cluster Setup - -```sh -gh repo clone agynio/bootstrap_v2 -cd bootstrap_v2 +```bash +git clone https://github.com/agynio/bootstrap.git +cd bootstrap +chmod +x apply.sh ./apply.sh -y -kubectl get deployment docker-runner -n platform ``` -## Development (DevSpace) +See [bootstrap](https://github.com/agynio/bootstrap) for details. -```sh -cd /path/to/docker-runner -devspace dev -``` +### Run from sources -DevSpace syncs the repo into the cluster dev container, runs `pnpm install` and -`pnpm proto:generate`, then starts `tsx watch src/service/main.ts` for hot reload. -It also forwards gRPC on port `50051` to your local machine. +```bash +# Deploy once (exit when healthy) +devspace dev -## Running Tests +# Watch mode (streams logs, re-syncs on changes) +devspace dev -w +``` -Keep `devspace dev` running in another terminal, then use: +### Run tests -```sh -devspace run test +```bash devspace run test:e2e -devspace run enter ``` -`devspace run test` runs unit + integration tests; the integration suite -requires Docker, provided by the DinD sidecar in the dev pod. `devspace run -test:e2e` runs the e2e suite, with `DOCKER_RUNNER_SHARED_SECRET` already -provided by the Helm deployment. `devspace run enter` opens an interactive shell -in the dev container. - -## Troubleshooting - -- **Sync timeout**: if the dev container logs `ERROR: sync timeout`, restart - `devspace dev` and confirm the repo sync completed before the process starts. -- **ArgoCD reverting changes**: DevSpace disables auto-sync for the - `docker-runner` ArgoCD app. If it keeps reverting, manually disable - auto-sync or re-run `devspace dev` to apply the patch again. -- **Docker socket missing**: if `/var/run/docker.sock` is missing in the pod, - ensure the cluster nodes expose the Docker socket and the deployment mounts it. -- **Port forwarding**: if `50051` is unavailable, confirm `devspace dev` is - still running and restart it to re-establish the port forward. +See [E2E Testing](https://github.com/agynio/architecture/blob/main/architecture/operations/e2e-testing.md). diff --git a/charts/docker-runner/templates/hpa.yaml b/charts/docker-runner/templates/hpa.yaml deleted file mode 100644 index 2006e67..0000000 --- a/charts/docker-runner/templates/hpa.yaml +++ /dev/null @@ -1 +0,0 @@ -{{- include "service-base.hpa" . -}} diff --git a/charts/docker-runner/templates/pdb.yaml b/charts/docker-runner/templates/pdb.yaml deleted file mode 100644 index 80686e0..0000000 --- a/charts/docker-runner/templates/pdb.yaml +++ /dev/null @@ -1 +0,0 @@ -{{- include "service-base.pdb" . -}} diff --git a/charts/docker-runner/templates/servicemonitor.yaml b/charts/docker-runner/templates/servicemonitor.yaml deleted file mode 100644 index c7242a4..0000000 --- a/charts/docker-runner/templates/servicemonitor.yaml +++ /dev/null @@ -1 +0,0 @@ -{{- include "service-base.metrics" . -}} diff --git a/devspace.yaml b/devspace.yaml index e2e1dc0..65f550a 100644 --- a/devspace.yaml +++ b/devspace.yaml @@ -2,6 +2,20 @@ version: v2beta1 vars: DOCKER_RUNNER_NAMESPACE: platform + E2E_IMAGE: ghcr.io/agynio/devcontainer-node:1 + +deployments: + e2e-runner: + namespace: ${DOCKER_RUNNER_NAMESPACE} + helm: + chart: + name: component-chart + repo: https://charts.devspace.sh + values: + containers: + - image: ${E2E_IMAGE} + labels: + app.kubernetes.io/name: docker-runner-e2e commands: test: |- @@ -11,11 +25,7 @@ commands: -n ${DOCKER_RUNNER_NAMESPACE} \ -- pnpm test test:e2e: |- - exec_container \ - --label-selector "app.kubernetes.io/name=docker-runner,app.kubernetes.io/instance=docker-runner" \ - --container docker-runner \ - -n ${DOCKER_RUNNER_NAMESPACE} \ - -- pnpm test:e2e + devspace run-pipeline test:e2e $@ enter: |- exec_container \ --label-selector "app.kubernetes.io/name=docker-runner,app.kubernetes.io/instance=docker-runner" \ @@ -85,6 +95,20 @@ pipelines: )" start_dev --disable-pod-replace docker-runner + test:e2e: + run: |- + create_deployments e2e-runner + start_dev e2e-runner & + sleep 5 + exec_container \ + --label-selector "app.kubernetes.io/name=docker-runner-e2e" \ + -n ${DOCKER_RUNNER_NAMESPACE} \ + -- bash -c 'cd /opt/app/data && pnpm install --frozen-lockfile && pnpm proto:generate && pnpm test:e2e' + EXIT_CODE=$? + stop_dev e2e-runner + purge_deployments e2e-runner + exit $EXIT_CODE + hooks: - name: restore-argocd-auto-sync events: @@ -119,3 +143,16 @@ dev: - .devspace/ ports: - port: "50051" + + e2e-runner: + namespace: ${DOCKER_RUNNER_NAMESPACE} + labelSelector: + app.kubernetes.io/name: docker-runner-e2e + command: ["sleep", "infinity"] + workingDir: /opt/app/data + sync: + - path: ./:/opt/app/data + excludePaths: + - .git/ + - .devspace/ + - node_modules/ diff --git a/__tests__/e2e/docker-runner.e2e.test.ts b/test/e2e/docker-runner.e2e.test.ts similarity index 97% rename from __tests__/e2e/docker-runner.e2e.test.ts rename to test/e2e/docker-runner.e2e.test.ts index cccdd62..54de644 100644 --- a/__tests__/e2e/docker-runner.e2e.test.ts +++ b/test/e2e/docker-runner.e2e.test.ts @@ -4,7 +4,7 @@ import { afterAll, afterEach, beforeAll, describe, expect, it } from 'vitest'; import { credentials, status } from '@grpc/grpc-js'; import { RunnerServiceGrpcClient, type RunnerServiceGrpcClientInstance } from '../../src/proto/grpc.js'; -import { createGrpcTestClient, type GrpcTestClient } from '../helpers/grpc-test-client'; +import { createGrpcTestClient, type GrpcTestClient } from '../../__tests__/helpers/grpc-test-client'; const grpcAddress = process.env.DOCKER_RUNNER_GRPC_URL ?? 'localhost:50051'; const sharedSecret = process.env.DOCKER_RUNNER_SHARED_SECRET; diff --git a/vitest.config.e2e.ts b/vitest.config.e2e.ts index ec02a6d..7a83674 100644 --- a/vitest.config.e2e.ts +++ b/vitest.config.e2e.ts @@ -4,7 +4,7 @@ export default defineConfig({ test: { environment: 'node', globals: true, - include: ['__tests__/e2e/**/*.e2e.test.ts'], + include: ['test/e2e/**/*.e2e.test.ts'], testTimeout: 120_000, hookTimeout: 30_000, coverage: { enabled: false }, diff --git a/vitest.config.ts b/vitest.config.ts index 0ffad7c..7c53010 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -5,7 +5,7 @@ export default defineConfig({ environment: 'node', globals: true, include: ['__tests__/**/*.test.ts'], - exclude: ['__tests__/e2e/**'], + exclude: ['test/e2e/**'], hookTimeout: 60_000, coverage: { enabled: false }, },