Skip to content

Commit eace286

Browse files
cogwirreliankhou
andauthored
feat(cdk-assets-lib): support --build-context flag for docker image builds (#1128)
Add support for `dockerBuildContexts` in the cloud assembly schema and docker build logic. This allows passing additional named build contexts to the `docker build` command via the `--build-context` flag, enabling multi-context Docker builds where files can be sourced from directories, URLs, or other Docker images outside the primary build directory. This PR adds the CLI changes required to address aws/aws-cdk#31598 --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license Co-authored-by: Ian Hou <45278651+iankhou@users.noreply.github.com>
1 parent bc7d70c commit eace286

File tree

10 files changed

+120
-2
lines changed

10 files changed

+120
-2
lines changed

packages/@aws-cdk/cdk-assets-lib/lib/private/docker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface BuildOptions {
2020
readonly target?: string;
2121
readonly file?: string;
2222
readonly buildArgs?: Record<string, string>;
23+
readonly buildContexts?: Record<string, string>;
2324
readonly buildSecrets?: Record<string, string>;
2425
readonly buildSsh?: string;
2526
readonly networkMode?: string;
@@ -107,6 +108,9 @@ export class Docker {
107108
...flatten(
108109
Object.entries(options.buildArgs || {}).map(([k, v]) => ['--build-arg', `${k}=${v}`]),
109110
),
111+
...flatten(
112+
Object.entries(options.buildContexts || {}).map(([k, v]) => ['--build-context', `${k}=${v}`]),
113+
),
110114
...flatten(
111115
Object.entries(options.buildSecrets || {}).map(([k, v]) => ['--secret', `id=${k},${v}`]),
112116
),

packages/@aws-cdk/cdk-assets-lib/lib/private/handlers/container-images.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ class ContainerImageBuilder {
232232
directory: fullPath,
233233
tag: localTagName,
234234
buildArgs: source.dockerBuildArgs,
235+
buildContexts: source.dockerBuildContexts,
235236
buildSecrets: source.dockerBuildSecrets,
236237
buildSsh: source.dockerBuildSsh,
237238
target: source.dockerBuildTarget,

packages/@aws-cdk/cdk-assets-lib/test/docker-images.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,29 @@ beforeEach(() => {
275275
},
276276
}),
277277
'/platform-arm64/cdk.out/dockerdir/Dockerfile': 'FROM scratch',
278+
'/build-contexts/cdk.out/assets.json': JSON.stringify({
279+
version: Manifest.version(),
280+
dockerImages: {
281+
theAsset: {
282+
source: {
283+
directory: 'dockerdir',
284+
dockerBuildContexts: {
285+
mycontext: '../context',
286+
alpine: 'docker-image://alpine:latest',
287+
},
288+
},
289+
destinations: {
290+
theDestination: {
291+
region: 'us-north-50',
292+
assumeRoleArn: 'arn:aws:role',
293+
repositoryName: 'repo',
294+
imageTag: 'nopqr',
295+
},
296+
},
297+
},
298+
},
299+
}),
300+
'/build-contexts/cdk.out/dockerdir/Dockerfile': 'FROM scratch',
278301
});
279302
aws = new MockAws();
280303
mockEcr.on(DescribeImagesCommand).rejects(err);
@@ -610,6 +633,41 @@ describe('with a complete manifest', () => {
610633
expectAllSpawns();
611634
expect(true).toBeTruthy(); // Expect no exception, satisfy linter
612635
});
636+
637+
test('build with buildContexts option', async () => {
638+
pub = new AssetPublishing(AssetManifest.fromPath(mockfs.path('/build-contexts/cdk.out')), {
639+
aws,
640+
});
641+
const buildContextsDockerpath = '/build-contexts/cdk.out/dockerdir';
642+
643+
const expectAllSpawns = mockSpawn(
644+
{
645+
commandLine: ['docker', 'login', '--username', 'user', '--password-stdin', 'proxy.com'],
646+
},
647+
{ commandLine: ['docker', 'inspect', 'cdkasset-theasset'], exitCode: 1 },
648+
{
649+
commandLine: [
650+
'docker',
651+
'build',
652+
'--build-context',
653+
'mycontext=../context',
654+
'--build-context',
655+
'alpine=docker-image://alpine:latest',
656+
'--tag',
657+
'cdkasset-theasset',
658+
'.',
659+
],
660+
cwd: buildContextsDockerpath,
661+
},
662+
{ commandLine: ['docker', 'tag', 'cdkasset-theasset', '12345.amazonaws.com/repo:nopqr'] },
663+
{ commandLine: ['docker', 'push', '12345.amazonaws.com/repo:nopqr'] },
664+
);
665+
666+
await pub.publish();
667+
668+
expectAllSpawns();
669+
expect(true).toBeTruthy(); // Expect no exception, satisfy linter
670+
});
613671
});
614672

615673
describe('external assets', () => {

packages/@aws-cdk/cdk-assets-lib/test/private/docker.test.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,29 @@ describe('Docker', () => {
115115
}),
116116
);
117117
});
118+
119+
test('includes --build-context flags when buildContexts are provided', async () => {
120+
const spy = makeShellExecuteMock(() => undefined);
121+
122+
await docker.build({
123+
directory: 'foo',
124+
tag: 'bar',
125+
buildContexts: {
126+
mycontext: '../context',
127+
alpine: 'docker-image://alpine:latest',
128+
},
129+
});
130+
131+
expect(spy.mock.calls[0][0]).toEqual([
132+
'build',
133+
'--build-context',
134+
'mycontext=../context',
135+
'--build-context',
136+
'alpine=docker-image://alpine:latest',
137+
'--tag',
138+
'bar',
139+
'.',
140+
]);
141+
});
118142
});
119143
});

packages/@aws-cdk/cloud-assembly-api/lib/assets.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export const ASSET_RESOURCE_METADATA_ENABLED_CONTEXT = 'aws:cdk:enable-asset-met
1212
export const ASSET_RESOURCE_METADATA_PATH_KEY = 'aws:asset:path';
1313
export const ASSET_RESOURCE_METADATA_DOCKERFILE_PATH_KEY = 'aws:asset:dockerfile-path';
1414
export const ASSET_RESOURCE_METADATA_DOCKER_BUILD_ARGS_KEY = 'aws:asset:docker-build-args';
15+
export const ASSET_RESOURCE_METADATA_DOCKER_BUILD_CONTEXTS_KEY = 'aws:asset:docker-build-contexts';
1516
export const ASSET_RESOURCE_METADATA_DOCKER_BUILD_SECRETS_KEY = 'aws:asset:docker-build-secrets';
1617
export const ASSET_RESOURCE_METADATA_DOCKER_BUILD_SSH_KEY = 'aws:asset:docker-build-ssh';
1718
export const ASSET_RESOURCE_METADATA_DOCKER_BUILD_TARGET_KEY = 'aws:asset:docker-build-target';

packages/@aws-cdk/cloud-assembly-schema/lib/assets/docker-image-asset.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ export interface DockerImageSource {
7070
*/
7171
readonly dockerBuildArgs?: { [name: string]: string };
7272

73+
/**
74+
* Additional build contexts
75+
*
76+
* Only allowed when `directory` is set.
77+
*
78+
* @default - No additional build contexts
79+
*/
80+
readonly dockerBuildContexts?: { [name: string]: string };
81+
7382
/**
7483
* SSH agent socket or keys
7584
*

packages/@aws-cdk/cloud-assembly-schema/lib/cloud-assembly/metadata-schema.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,13 @@ export interface ContainerImageAssetMetadataEntry extends BaseAssetMetadataEntry
161161
*/
162162
readonly buildArgs?: { [key: string]: string };
163163

164+
/**
165+
* Build contexts to pass to the `docker build` command
166+
*
167+
* @default no build contexts are passed
168+
*/
169+
readonly buildContexts?: { [key: string]: string };
170+
164171
/**
165172
* SSH agent socket or keys to pass to the `docker build` command
166173
*

packages/@aws-cdk/cloud-assembly-schema/schema/assets.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@
168168
"type": "string"
169169
}
170170
},
171+
"dockerBuildContexts": {
172+
"description": "Additional build contexts\n\nOnly allowed when `directory` is set. (Default - No additional build contexts)",
173+
"type": "object",
174+
"additionalProperties": {
175+
"type": "string"
176+
}
177+
},
171178
"dockerBuildSsh": {
172179
"description": "SSH agent socket or keys\n\nRequires building with docker buildkit. (Default - No ssh flag is set)",
173180
"type": "string"

packages/@aws-cdk/cloud-assembly-schema/schema/cloud-assembly.schema.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,13 @@
232232
"type": "string"
233233
}
234234
},
235+
"buildContexts": {
236+
"description": "Build contexts to pass to the `docker build` command (Default no build contexts are passed)",
237+
"type": "object",
238+
"additionalProperties": {
239+
"type": "string"
240+
}
241+
},
235242
"buildSsh": {
236243
"description": "SSH agent socket or keys to pass to the `docker build` command (Default no ssh arg is passed)",
237244
"type": "string"
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"schemaHash": "22c511a4ddd185761b8d56ac21d48c8384873ffe4b953b3567654746f8dd26f1",
2+
"schemaHash": "25d8ad154190878ec8a9e970fa21a0e182fa834304913d43be86f9b0613271f5",
33
"$comment": "Do not hold back the version on additions: jsonschema validation of the manifest by the consumer will trigger errors on unexpected fields.",
4-
"revision": 52
4+
"revision": 53
55
}

0 commit comments

Comments
 (0)