Repository navigation
Sidecar container support for apply and export.
A multi-container task definition — an init container that prepares a shared volume, a network sidecar, and a hardened application container that waits for the init container to finish — is now expressible as a spec instead of hand-assembled aws ecs register-task-definition JSON.
New spec fields
Per container, inside spec.containers[]:
| Field | Purpose |
|---|---|
user |
Run as a specific uid. ECS has no task-level user, so a root init container beside a non-root app container needs this per container. |
readonlyRootFilesystem |
|
entryPoint |
Override the image's ENTRYPOINT, not just command. |
dependsOn |
Startup ordering — START, SUCCESS or COMPLETE — against another container in the same task. |
linuxParameters.capabilitiesDrop |
Validated against the capability names ECS accepts. |
mountPoints |
containerPath → volume name, or {sourceVolume, readOnly}. |
At task level:
| Field | Purpose |
|---|---|
volumes |
Ephemeral ECS-managed scratch, or an efs block for a persistent file system. |
Example
apiVersion: ecsctl/v1
kind: Service
metadata:
name: my-app
cluster: prod
spec:
cpu: "1024"
memory: "2048"
volumes:
- name: workspace
containers:
- name: init-perms
image: my-app:latest
essential: false # required: AWS refuses a SUCCESS dependency
user: "0" # on an essential container
entryPoint: ["/bin/sh", "-c"]
command: ["chown 1000:1000 /workspace"]
mountPoints:
/workspace: workspace
- name: app
image: my-app:latest
essential: true
user: "1000"
readonlyRootFilesystem: true
linuxParameters:
capabilitiesDrop: ["ALL"]
dependsOn:
- containerName: init-perms
condition: SUCCESS
mountPoints:
/workspace: workspace
/config:
sourceVolume: workspace
readOnly: trueValidation moved earlier
Combinations AWS rejects are now refused locally, with the offending value named, before any API call: unknown or duplicate container and volume names, self-dependencies, dependency cycles (the error prints the actual cycle path), SUCCESS/COMPLETE against an essential: true target, a task with no essential container, unrecognised capability names, EFS iam without transit encryption, an accessPointId conflicting with rootDirectory, and spec-level container fields left alongside containers[] where they would previously have been silently dropped.
export round-trips the new fields
ecsctl export reads all of the above back, and its output is a spec apply accepts. Where a task definition cannot be represented losslessly, export refuses rather than degrading silently — Docker volumes, FSx for Windows, host bind mounts with a source path, EBS volumes configured at launch, and capabilities this spec cannot validate. A dependsOn: HEALTHY condition is dropped with a warning, because healthCheck is not yet configurable here.
Fixes
ecsctl execandecsctl logresolved to a network sidecar rather than the application in a multi-container task, silently running commands in the wrong container. They now prefer the essential container that declaresdependsOn, which in the init-container pattern is the application.ecsctl updatestill refuses multi-container services — it rebuilds the task definition from the flat single-container fields and would drop the rest — but its error now spells out theexport→ edit →applyworkflow instead of refusing without a path forward.- The JSON schema required
spec.image, which every multi-container spec legitimately omits.schemas/service.schema.jsonnow requires eitherimageorcontainers, and CI validates representative specs against it so the schema and the parser cannot drift apart again.
Compatibility
Every new field is optional with a serde default. Existing single-container specs parse, validate and export exactly as before, asserted by test. ecsctl update behaviour for single-container services is unchanged.
Full detail: #55