Sign inSign up

opergow/runner

By opergow

•Updated 4 days ago

Run Opergow host tasks on your own infrastructure: Docker, Kubernetes or Linux. Scale with one key.

Image
Integration & delivery
Developer tools
0

119

opergow/runner repository overview

⁠Opergow Runner

The Opergow Runner executes the host tasks of your Opergow workflows on your own infrastructure — as a Docker container, in Kubernetes or on a Linux server. It signs in with a runner key of your organisation, picks up the tasks of the key's runner pool, runs them locally and returns the results.

  • Headless: no login, no UI, no state on disk. All settings except the key live in the pool profile in the Opergow web app.
  • Scales out: start more containers with the same key. Every container is one instance of the pool; every task runs exactly once.
  • Starts tasks instantly through a wake-up connection (MQTT over secure WebSockets) and falls back to adaptive polling.
  • Keeps your secrets local: tool credentials stay on your machines and are removed from every result before it leaves.
  • Outbound only: HTTPS and WSS to the platform; no inbound ports except the optional health and metrics port.

⁠Tags

TagBaseContents
1.0.0Debian slim with aptrunner + bash, curl, git, jq, python3
1.0.0-minimaldistroless (static)runner only — built-in actions and API calls

Both tags are available for linux/amd64 and linux/arm64. Pin an exact version; there is no latest tag.

⁠Quick start

  1. In the Opergow web app, open Runner, create a pool and save the key (ork_eu_…, shown only once) to a file named runner_key with mode 0600.

  2. Check the key and the connection:

    docker run --rm --user "$(id -u):$(id -g)" \
      -v "$PWD/runner_key:/run/secrets/opergow/runner_key:ro" \
      docker.io/opergow/runner:1.0.0 check
    
  3. Start the runner:

    docker run -d --name opergow-runner --restart unless-stopped \
      --user "$(id -u):$(id -g)" -e HOME=/tmp \
      --read-only --tmpfs /work:mode=1777 --tmpfs /tmp:mode=1777 \
      --cap-drop ALL --security-opt no-new-privileges --stop-timeout 90 \
      -v "$PWD/runner_key:/run/secrets/opergow/runner_key:ro" \
      -e OPERGOW_RUNNER_LABELS=docker,linux \
      docker.io/opergow/runner:1.0.0
    

    --user runs the container as the owner of runner_key, so the key file can keep mode 0600.

The instance appears under Runner → Instances. In the Studio, select the runner pool as the target of a host task.

⁠Docker Compose

services:
  runner:
    image: docker.io/opergow/runner:1.0.0
    restart: unless-stopped
    user: "${RUNNER_UID:-65532}:${RUNNER_GID:-65532}"
    environment:
      OPERGOW_RUNNER_LABELS: "docker,linux"
      HOME: /tmp
    secrets:
      - source: opergow_runner_key
        target: /run/secrets/opergow/runner_key
    stop_grace_period: 90s
    read_only: true
    tmpfs:
      - /work:mode=1777
      - /tmp:mode=1777
    cap_drop: [ALL]
    security_opt: ["no-new-privileges:true"]

secrets:
  opergow_runner_key:
    file: ./runner_key

Start with RUNNER_UID=$(id -u) RUNNER_GID=$(id -g) docker compose up -d; scale with docker compose up -d --scale runner=3.

⁠Kubernetes

kubectl create secret generic opergow-runner-key --from-file=runner_key=./runner_key
apiVersion: apps/v1
kind: Deployment
metadata:
  name: opergow-runner
spec:
  replicas: 2
  selector:
    matchLabels: { app: opergow-runner }
  template:
    metadata:
      labels: { app: opergow-runner }
    spec:
      automountServiceAccountToken: false
      terminationGracePeriodSeconds: 90
      securityContext:
        runAsNonRoot: true
        runAsUser: 65532
        runAsGroup: 65532
        fsGroup: 65532
        seccompProfile: { type: RuntimeDefault }
      containers:
        - name: runner
          image: docker.io/opergow/runner:1.0.0
          env:
            - name: OPERGOW_RUNNER_INSTANCE
              valueFrom: { fieldRef: { fieldPath: metadata.name } }
            - name: OPERGOW_RUNNER_LABELS
              value: "k8s,linux"
            - name: HOME
              value: /tmp
          securityContext:
            allowPrivilegeEscalation: false
            readOnlyRootFilesystem: true
            capabilities: { drop: ["ALL"] }
          ports:
            - { name: health, containerPort: 8080 }
          livenessProbe: { httpGet: { path: /healthz, port: health }, periodSeconds: 20 }
          readinessProbe: { httpGet: { path: /readyz, port: health }, periodSeconds: 10 }
          volumeMounts:
            - { name: runner-key, mountPath: /run/secrets/opergow/runner_key, subPath: runner_key, readOnly: true }
            - { name: work, mountPath: /work }
            - { name: tmp, mountPath: /tmp }
      volumes:
        - name: runner-key
          secret:
            secretName: opergow-runner-key
            defaultMode: 0440   # octal (288 in JSON): readable for the pod's group 65532
            items: [{ key: runner_key, path: runner_key }]
        - { name: work, emptyDir: {} }
        - { name: tmp, emptyDir: {} }

Every pod is one instance of the pool; scale with kubectl scale deployment opergow-runner --replicas=5.

⁠Configuration

Only a key file and environment variables — everything else comes from the pool profile.

SettingDefaultMeaning
/run/secrets/opergow/runner_key—The runner key (file). Other path: OPERGOW_RUNNER_KEY_FILE.
OPERGOW_RUNNER_INSTANCEhost nameInstance ID, unique per running container.
OPERGOW_RUNNER_LABELS—Comma-separated labels (name or name=value, max. 16). Tasks that require labels run only on instances that carry all of them.
OPERGOW_RUNNER_HEALTH_ADDR:8080Address of /healthz, /readyz and /metrics.
OPERGOW_RUNNER_LOG_LEVELpool profiledebug, info, warn or error.
OPERGOW_RUNNER_WORKDIR/workBase of the per-task work directories (deleted after each task).
OPERGOW_RUNNER_CREDENTIALS_DIR/run/secrets/opergow/credentialsTool credentials, one JSON file or folder per credential; the values never leave your machine.
OPERGOW_RUNNER_WAKEonoff disables the wake-up connection (polling only).

⁠Add your own tools

Build on the standard image:

FROM docker.io/opergow/runner:1.0.0
USER root
RUN apt-get update \
 && apt-get install -y --no-install-recommends ffmpeg \
 && rm -rf /var/lib/apt/lists/*
USER runner

The Opergow web app can also generate this Dockerfile for you (Runner → Images) or, depending on your plan, build the image in the cloud and host it for you.

⁠Health, metrics and logs

/healthz, /readyz and /metrics (Prometheus format) on port 8080. Logs are JSON lines on stdout; they never contain the key, tokens or credential values.

⁠Security

  • The key only opens the token exchange; all other calls use a runner token that expires after 30 minutes. Blocking or rotating the key in the web app takes effect at the next exchange. Keep the key in a secret store — never in an image or a repository.
  • The images run as a non-root user (UID 65532) and work with a read-only root file system.
  • At access level 3 with shell approval, a task can run any command as the runner's user. Grant this only to pools whose task authors you trust, and run such pools on dedicated machines.

⁠License

Apache License 2.0.

Tag summary

Content type

Image

Digest

sha256:558280080…

Size

4.2 MB

Last updated

4 days ago

docker pull opergow/runner:1.0.0-minimal