feat(supervisor): optional image registry rewrite for run pods

Adds two optional env vars that rewrite the registry host of run pod images at pod creation, so a supervisor can pull from a registry in its own region. Off by default and inert unless both are set. Exact host-prefix matching, so look-alike hosts pass through untouched.
This commit is contained in:
nicktrn
2026-08-18 15:03:12 +01:00
committed by GitHub
parent b4313c8199
commit 2496a8a863
4 changed files with 65 additions and 1 deletions
+2
View File
@@ -185,6 +185,8 @@ export const Env = z
KUBERNETES_EPHEMERAL_STORAGE_SIZE_LIMIT: z.string().default("10Gi"),
KUBERNETES_EPHEMERAL_STORAGE_SIZE_REQUEST: z.string().default("2Gi"),
KUBERNETES_STRIP_IMAGE_DIGEST: BoolEnv.default(false),
KUBERNETES_IMAGE_REGISTRY_REWRITE_FROM: z.string().optional(),
KUBERNETES_IMAGE_REGISTRY_REWRITE_TO: z.string().optional(),
KUBERNETES_CPU_REQUEST_MIN_CORES: z.coerce.number().min(0).default(0),
KUBERNETES_CPU_REQUEST_RATIO: z.coerce.number().min(0).max(1).default(0.75), // Ratio of CPU limit, so 0.75 = 75% of CPU limit
KUBERNETES_MEMORY_REQUEST_MIN_GB: z.coerce.number().min(0).default(0),
@@ -0,0 +1,42 @@
import { describe, expect, it } from "vitest";
import { rewriteImageRegistry } from "./imageRegistry.js";
const FROM = "123456789012.dkr.ecr.us-east-1.amazonaws.com";
const TO = "123456789012.dkr.ecr.eu-central-1.amazonaws.com";
describe("rewriteImageRegistry", () => {
it("rewrites the registry host and keeps the rest of the reference", () => {
expect(rewriteImageRegistry(`${FROM}/deployments/proj_abc:20260818.1`, FROM, TO)).toBe(
`${TO}/deployments/proj_abc:20260818.1`
);
});
it("preserves a digest", () => {
expect(rewriteImageRegistry(`${FROM}/deployments/proj_abc@sha256:abc123`, FROM, TO)).toBe(
`${TO}/deployments/proj_abc@sha256:abc123`
);
});
it("is a no-op unless both ends are configured", () => {
const ref = `${FROM}/deployments/proj_abc:tag`;
expect(rewriteImageRegistry(ref, undefined, TO)).toBe(ref);
expect(rewriteImageRegistry(ref, FROM, undefined)).toBe(ref);
expect(rewriteImageRegistry(ref, undefined, undefined)).toBe(ref);
});
it("leaves other registries alone", () => {
const ref = "ghcr.io/triggerdotdev/something:tag";
expect(rewriteImageRegistry(ref, FROM, TO)).toBe(ref);
});
it("only matches on a host boundary", () => {
const lookalike = `${FROM}.evil.example.com/deployments/proj_abc:tag`;
expect(rewriteImageRegistry(lookalike, FROM, TO)).toBe(lookalike);
});
it("does not rewrite a host that merely contains the source", () => {
const ref = `registry.example.com/${FROM}/proj_abc:tag`;
expect(rewriteImageRegistry(ref, FROM, TO)).toBe(ref);
});
});
@@ -0,0 +1,15 @@
export function rewriteImageRegistry(
imageRef: string,
from: string | undefined,
to: string | undefined
): string {
if (!from || !to) {
return imageRef;
}
if (!imageRef.startsWith(`${from}/`)) {
return imageRef;
}
return `${to}${imageRef.slice(from.length)}`;
}
@@ -20,6 +20,7 @@ import {
withRunnerSeccompProfile,
withNodeSelector,
} from "./kubernetesPodSpec.js";
import { rewriteImageRegistry } from "./imageRegistry.js";
type ResourceQuantities = {
[K in "cpu" | "memory" | "ephemeral-storage"]?: string;
@@ -163,7 +164,11 @@ export class KubernetesWorkloadManager implements WorkloadManager {
containers: [
{
name: "run-controller",
image: this.stripImageDigest(opts.image),
image: rewriteImageRegistry(
this.stripImageDigest(opts.image),
env.KUBERNETES_IMAGE_REGISTRY_REWRITE_FROM,
env.KUBERNETES_IMAGE_REGISTRY_REWRITE_TO
),
ports: [
{
containerPort: 8000,