@@ -4,88 +4,104 @@ import {
44 type WorkloadManagerCreateOptions ,
55 type WorkloadManagerOptions ,
66} from "./types.js" ;
7- import { x } from "tinyexec" ;
87import { env } from "../env.js" ;
98import { getDockerHostDomain , getRunnerId } from "../util.js" ;
9+ import Docker from "dockerode" ;
1010
1111export class DockerWorkloadManager implements WorkloadManager {
12- private readonly logger = new SimpleStructuredLogger ( "docker-workload-provider" ) ;
12+ private readonly logger = new SimpleStructuredLogger ( "docker-workload-manager" ) ;
13+ private readonly docker : Docker ;
1314
1415 constructor ( private opts : WorkloadManagerOptions ) {
16+ this . docker = new Docker ( {
17+ socketPath : env . DOCKER_SOCKET_PATH ,
18+ } ) ;
19+
1520 if ( opts . workloadApiDomain ) {
16- this . logger . warn ( "[DockerWorkloadProvider] ⚠️ Custom workload API domain" , {
21+ this . logger . warn ( "⚠️ Custom workload API domain" , {
1722 domain : opts . workloadApiDomain ,
1823 } ) ;
1924 }
2025 }
2126
2227 async create ( opts : WorkloadManagerCreateOptions ) {
23- this . logger . log ( "[DockerWorkloadProvider] Creating container " , { opts } ) ;
28+ this . logger . log ( "create() " , { opts } ) ;
2429
2530 const runnerId = getRunnerId ( opts . runFriendlyId , opts . nextAttemptNumber ) ;
2631
27- const runArgs = [
28- "run" ,
29- "--detach" ,
30- `--network=${ env . DOCKER_NETWORK } ` ,
31- `--env=TRIGGER_DEQUEUED_AT_MS=${ opts . dequeuedAt . getTime ( ) } ` ,
32- `--env=TRIGGER_POD_SCHEDULED_AT_MS=${ Date . now ( ) } ` ,
33- `--env=TRIGGER_ENV_ID=${ opts . envId } ` ,
34- `--env=TRIGGER_RUN_ID=${ opts . runFriendlyId } ` ,
35- `--env=TRIGGER_SNAPSHOT_ID=${ opts . snapshotFriendlyId } ` ,
36- `--env=TRIGGER_SUPERVISOR_API_PROTOCOL=${ this . opts . workloadApiProtocol } ` ,
37- `--env=TRIGGER_SUPERVISOR_API_PORT=${ this . opts . workloadApiPort } ` ,
38- `--env=TRIGGER_SUPERVISOR_API_DOMAIN=${ this . opts . workloadApiDomain ?? getDockerHostDomain ( ) } ` ,
39- `--env=TRIGGER_WORKER_INSTANCE_NAME=${ env . TRIGGER_WORKER_INSTANCE_NAME } ` ,
40- `--env=OTEL_EXPORTER_OTLP_ENDPOINT=${ env . OTEL_EXPORTER_OTLP_ENDPOINT } ` ,
41- `--env=TRIGGER_RUNNER_ID=${ runnerId } ` ,
42- `--hostname=${ runnerId } ` ,
43- `--name=${ runnerId } ` ,
32+ // Build environment variables
33+ const envVars : string [ ] = [
34+ `TRIGGER_DEQUEUED_AT_MS=${ opts . dequeuedAt . getTime ( ) } ` ,
35+ `TRIGGER_POD_SCHEDULED_AT_MS=${ Date . now ( ) } ` ,
36+ `TRIGGER_ENV_ID=${ opts . envId } ` ,
37+ `TRIGGER_RUN_ID=${ opts . runFriendlyId } ` ,
38+ `TRIGGER_SNAPSHOT_ID=${ opts . snapshotFriendlyId } ` ,
39+ `TRIGGER_SUPERVISOR_API_PROTOCOL=${ this . opts . workloadApiProtocol } ` ,
40+ `TRIGGER_SUPERVISOR_API_PORT=${ this . opts . workloadApiPort } ` ,
41+ `TRIGGER_SUPERVISOR_API_DOMAIN=${ this . opts . workloadApiDomain ?? getDockerHostDomain ( ) } ` ,
42+ `TRIGGER_WORKER_INSTANCE_NAME=${ env . TRIGGER_WORKER_INSTANCE_NAME } ` ,
43+ `OTEL_EXPORTER_OTLP_ENDPOINT=${ env . OTEL_EXPORTER_OTLP_ENDPOINT } ` ,
44+ `TRIGGER_RUNNER_ID=${ runnerId } ` ,
4445 ] ;
4546
46- if ( this . opts . dockerAutoremove ) {
47- runArgs . push ( "--rm" ) ;
48- }
49-
5047 if ( this . opts . warmStartUrl ) {
51- runArgs . push ( `--env= TRIGGER_WARM_START_URL=${ this . opts . warmStartUrl } ` ) ;
48+ envVars . push ( `TRIGGER_WARM_START_URL=${ this . opts . warmStartUrl } ` ) ;
5249 }
5350
5451 if ( this . opts . metadataUrl ) {
55- runArgs . push ( `--env= TRIGGER_METADATA_URL=${ this . opts . metadataUrl } ` ) ;
52+ envVars . push ( `TRIGGER_METADATA_URL=${ this . opts . metadataUrl } ` ) ;
5653 }
5754
5855 if ( this . opts . heartbeatIntervalSeconds ) {
59- runArgs . push (
60- `--env=TRIGGER_HEARTBEAT_INTERVAL_SECONDS=${ this . opts . heartbeatIntervalSeconds } `
61- ) ;
56+ envVars . push ( `TRIGGER_HEARTBEAT_INTERVAL_SECONDS=${ this . opts . heartbeatIntervalSeconds } ` ) ;
6257 }
6358
6459 if ( this . opts . snapshotPollIntervalSeconds ) {
65- runArgs . push (
66- `--env= TRIGGER_SNAPSHOT_POLL_INTERVAL_SECONDS=${ this . opts . snapshotPollIntervalSeconds } `
60+ envVars . push (
61+ `TRIGGER_SNAPSHOT_POLL_INTERVAL_SECONDS=${ this . opts . snapshotPollIntervalSeconds } `
6762 ) ;
6863 }
6964
7065 if ( this . opts . additionalEnvVars ) {
7166 Object . entries ( this . opts . additionalEnvVars ) . forEach ( ( [ key , value ] ) => {
72- runArgs . push ( `--env= ${ key } =${ value } ` ) ;
67+ envVars . push ( `${ key } =${ value } ` ) ;
7368 } ) ;
7469 }
7570
71+ const hostConfig : Docker . HostConfig = {
72+ NetworkMode : env . DOCKER_NETWORK ,
73+ AutoRemove : ! ! this . opts . dockerAutoremove ,
74+ } ;
75+
7676 if ( env . ENFORCE_MACHINE_PRESETS ) {
77- runArgs . push ( `--cpus=${ opts . machine . cpu } ` , `--memory=${ opts . machine . memory } G` ) ;
78- runArgs . push ( `--env=TRIGGER_MACHINE_CPU=${ opts . machine . cpu } ` ) ;
79- runArgs . push ( `--env=TRIGGER_MACHINE_MEMORY=${ opts . machine . memory } ` ) ;
77+ envVars . push ( `TRIGGER_MACHINE_CPU=${ opts . machine . cpu } ` ) ;
78+ envVars . push ( `TRIGGER_MACHINE_MEMORY=${ opts . machine . memory } ` ) ;
79+
80+ hostConfig . NanoCpus = opts . machine . cpu * 1e9 ;
81+ hostConfig . Memory = opts . machine . memory * 1024 * 1024 * 1024 ;
8082 }
8183
82- runArgs . push ( `${ opts . image } ` ) ;
84+ const containerCreateOpts : Docker . ContainerCreateOptions = {
85+ Env : envVars ,
86+ name : runnerId ,
87+ Hostname : runnerId ,
88+ HostConfig : hostConfig ,
89+ Image : opts . image ,
90+ AttachStdout : false ,
91+ AttachStderr : false ,
92+ AttachStdin : false ,
93+ } ;
8394
8495 try {
85- const { stdout, stderr } = await x ( "docker" , runArgs ) ;
86- this . logger . debug ( "[DockerWorkloadProvider] Create succeeded" , { stdout, stderr } ) ;
96+ // Create container
97+ const container = await this . docker . createContainer ( containerCreateOpts ) ;
98+
99+ // Start container
100+ const startResult = await container . start ( ) ;
101+
102+ this . logger . debug ( "create succeeded" , { opts, startResult, container, containerCreateOpts } ) ;
87103 } catch ( error ) {
88- this . logger . error ( "[DockerWorkloadProvider] Create failed:" , { opts, error } ) ;
104+ this . logger . error ( "create failed:" , { opts, error, containerCreateOpts } ) ;
89105 }
90106 }
91107}
0 commit comments