Skip to content
This repository was archived by the owner on May 8, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 32 additions & 49 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: Release

on:
push:
branches:
- main
tags:
- "v*.*.*"
workflow_dispatch: {}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[minor] workflow_dispatch: {} is still a trigger, but both jobs now gate on startsWith(github.ref, 'refs/tags/v'). A manual dispatch from a branch silently skips every job with no feedback. Either remove workflow_dispatch entirely (since releases are tag-driven) or add an inputs.tag parameter that the jobs can reference, so manual runs are explicitly scoped to a tag.

Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -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

Expand Down
69 changes: 21 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -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).
1 change: 0 additions & 1 deletion charts/docker-runner/templates/hpa.yaml

This file was deleted.

1 change: 0 additions & 1 deletion charts/docker-runner/templates/pdb.yaml

This file was deleted.

1 change: 0 additions & 1 deletion charts/docker-runner/templates/servicemonitor.yaml

This file was deleted.

47 changes: 42 additions & 5 deletions devspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: |-
Expand All @@ -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" \
Expand Down Expand Up @@ -85,6 +95,20 @@ pipelines:
)"
start_dev --disable-pod-replace docker-runner

test:e2e:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] The test:e2e pipeline uses run: |- while the existing dev pipeline (line 37) uses the shorthand inline string form. Both are valid in DevSpace v2beta1, but the inconsistency is distracting. Consider aligning them — either both use run: |- or both use the shorthand.

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:
Expand Down Expand Up @@ -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/
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
2 changes: 1 addition & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
},
Expand Down
Loading