Google Cloud
Run the render worker on Cloud Run or a Compute Engine VM.
Both options run the render worker image.
| Option | Pick it for |
|---|---|
| Cloud Run | The default. One job per instance, scales to zero, no servers to manage |
| Compute Engine | One machine with a fixed cost, jobs longer than 60 minutes, or GPUs |
The commands below use the gcloud CLI. Set your project and region once:
export PROJECT_ID=$(gcloud config get-value project)
export REGION=us-central1
export IMAGE=$REGION-docker.pkg.dev/$PROJECT_ID/miraiclip/render-worker:latest
gcloud services enable run.googleapis.com artifactregistry.googleapis.com secretmanager.googleapis.comPush the image to Artifact Registry
gcloud artifacts repositories create miraiclip --repository-format=docker --location=$REGION
gcloud auth configure-docker $REGION-docker.pkg.dev
docker build --platform linux/amd64 -t $IMAGE .
docker push $IMAGEThe image is x86-64 only (Google Chrome has no Linux Arm build), so pick x86-64 machine types for VMs, not Arm (Axion, Tau T2A).
Store the worker's token in Secret Manager, and let the runtime service account read it (Cloud Run and Compute Engine use the Compute Engine default service account unless you choose another):
openssl rand -hex 32 | gcloud secrets create render-token --data-file=-
export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
gcloud secrets add-iam-policy-binding render-token \
--member=serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
--role=roles/secretmanager.secretAccessorCloud Run
gcloud run deploy miraiclip-render-worker \
--image $IMAGE \
--region $REGION \
--cpu 2 \
--memory 4Gi \
--concurrency 1 \
--timeout 3600 \
--max-instances 20 \
--execution-environment gen2 \
--cpu-boost \
--set-secrets RENDER_TOKEN=render-token:latest \
--allow-unauthenticated| Flag | Why |
|---|---|
--concurrency 1 | A worker renders one job at a time. Cloud Run sends each job to a free instance and starts new ones as jobs arrive |
--timeout 3600 | Jobs can run up to 60 minutes, the Cloud Run maximum. Split longer exports with renderDistributed |
--cpu 2 --memory 4Gi | Enough for 1080p. For 4K, use --cpu 4 --memory 8Gi |
--max-instances | A ceiling on cost: at most this many jobs render at once |
--execution-environment gen2 | Full Linux compatibility for Chrome |
--cpu-boost | More CPU while an instance starts, so cold starts are shorter |
--allow-unauthenticated | Cloud Run lets requests through; the worker checks RENDER_TOKEN itself |
Cloud Run's file system lives in memory: the output a job writes to /tmp counts against --memory. Leave room for your largest output on top of Chrome.
Instead of building locally, gcloud run deploy miraiclip-render-worker --source . builds the Dockerfile with Cloud Build and deploys it in one step.
Check it:
URL=$(gcloud run services describe miraiclip-render-worker --region $REGION --format='value(status.url)')
curl $URL/healthz
# okRender
import { httpRunner, renderDistributed } from "@miraiclip/server-export";
const runner = httpRunner({
endpoints: "https://miraiclip-render-worker-<hash>.<region>.run.app",
headers: { authorization: `Bearer ${process.env.RENDER_TOKEN}` },
concurrency: 16, // jobs in flight; Cloud Run starts an instance for each, up to --max-instances
});
await renderDistributed(doc, { format: "mp4", out: "final.mp4", runner });Or send single jobs with fetch, as in Send a render job.
Private services
To keep the service off the public internet, deploy with --no-allow-unauthenticated and call it with a Google identity token. Cloud Run reads the token from X-Serverless-Authorization, which leaves Authorization for the worker's own RENDER_TOKEN:
curl -X POST $URL \
-H "X-Serverless-Authorization: Bearer $(gcloud auth print-identity-token --audiences=$URL)" \
-H "Authorization: Bearer $RENDER_TOKEN" \
-H "content-type: application/json" \
--data @job.json -o final.mp4The caller's service account needs roles/run.invoker on the service. Identity tokens expire after an hour, so refresh them for long batches.
Compute Engine
One VM running the container. Use a compute-optimized x86-64 type, such as c3-standard-4 (4 vCPU, 16 GB):
gcloud compute instances create miraiclip-render-worker \
--zone ${REGION}-a \
--machine-type c3-standard-4 \
--image-family debian-12 --image-project debian-cloud \
--boot-disk-size 50GB \
--scopes cloud-platform
gcloud compute ssh miraiclip-render-worker --zone ${REGION}-aOn the VM, set REGION and IMAGE as above, then:
sudo apt-get update && sudo apt-get install -y docker.io
sudo gcloud auth configure-docker $REGION-docker.pkg.dev
sudo docker run -d --name render-worker --restart unless-stopped \
-p 8080:8080 \
-e RENDER_TOKEN="$(gcloud secrets versions access latest --secret=render-token)" \
$IMAGEPut the VM behind a load balancer or a reverse proxy for HTTPS rather than opening port 8080 to the internet. To use more cores on one machine, run several containers on different ports, one per 2 vCPUs, and list them all in httpRunner's endpoints.