Skip to content

Commit

Permalink
feat(core): configure bundling docker entrypoint (#12660)
Browse files Browse the repository at this point in the history
Allow customizing the docker entrypoint for the bundling image.

Note that the option `entrypoint` is a `string[]` which match up with nearly every container runtime. The problem is that `docker run` 's `--entrypoint` only accepts a string. If the entrypoint we specify is `["/bin/sh", "-c"]`, the final command should be like: `docker run --entrypoint /bin/sh some-img -c some commands`.

I have do some experiments to prove this:
```sh
$ docker run -it --rm --name test --entrypoint /bin/sh -c alpine ls
invalid argument "alpine" for "-c, --cpu-shares" flag: strconv.ParseInt: parsing "alpine": invalid syntax
See 'docker run --help'.

$docker run -it --rm --name test --entrypoint "/bin/sh -c" alpine ls
docker: Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "exec: \"/bin/sh -c\": stat /bin/sh -c: no such file or directory": unknown.

$docker run -it --rm --name test --entrypoint /bin/sh alpine -c ls
bin    etc    lib    mnt    proc   run    srv    tmp    var
dev    home   media  opt    root   sbin   sys    usr
```

One more thing: if one specify custom entrypoint but no custom commands, the default cmd for the image will not be presented.
I do think it's a expected behavior for container runtime through.

References:
*  [kubernetes - Define a Command and Arguments for a Container](https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#notes) 


close #11984


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
kirintw authored Feb 9, 2021
1 parent 2b917ec commit 6597a09
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-s3-assets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ new assets.Asset(this, 'BundledAsset', {
},
// Docker bundling fallback
image: BundlingDockerImage.fromRegistry('alpine'),
entrypoint: ['/bin/sh', '-c'],
command: ['bundle'],
},
});
Expand Down
31 changes: 30 additions & 1 deletion packages/@aws-cdk/core/lib/bundling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,17 @@ export interface BundlingOptions {
*/
readonly image: BundlingDockerImage;

/**
* The entrypoint to run in the Docker container.
*
* @example ['/bin/sh', '-c']
*
* @see https://docs.docker.com/engine/reference/builder/#entrypoint
*
* @default - run the entrypoint defined in the image
*/
readonly entrypoint?: string[];

/**
* The command to run in the Docker container.
*
Expand Down Expand Up @@ -152,7 +163,15 @@ export class BundlingDockerImage {
public run(options: DockerRunOptions = {}) {
const volumes = options.volumes || [];
const environment = options.environment || {};
const command = options.command || [];
const entrypoint = options.entrypoint?.[0] || null;
const command = [
...options.entrypoint?.[1]
? [...options.entrypoint.slice(1)]
: [],
...options.command
? [...options.command]
: [],
];

const dockerArgs: string[] = [
'run', '--rm',
Expand All @@ -164,6 +183,9 @@ export class BundlingDockerImage {
...options.workingDirectory
? ['-w', options.workingDirectory]
: [],
...entrypoint
? ['--entrypoint', entrypoint]
: [],
this.image,
...command,
];
Expand Down Expand Up @@ -238,6 +260,13 @@ export enum DockerVolumeConsistency {
* Docker run options
*/
export interface DockerRunOptions {
/**
* The entrypoint to run in the container.
*
* @default - run the entrypoint defined in the image
*/
readonly entrypoint?: string[];

/**
* The command to run in the container.
*
Expand Down
38 changes: 38 additions & 0 deletions packages/@aws-cdk/core/test/bundling.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,44 @@ nodeunitShim({
test.done();
},

'custom entrypoint is passed through to docker exec'(test: Test) {
const spawnSyncStub = sinon.stub(child_process, 'spawnSync').returns({
status: 0,
stderr: Buffer.from('stderr'),
stdout: Buffer.from('stdout'),
pid: 123,
output: ['stdout', 'stderr'],
signal: null,
});

const image = BundlingDockerImage.fromRegistry('alpine');
image.run({
entrypoint: ['/cool/entrypoint', '--cool-entrypoint-arg'],
command: ['cool', 'command'],
environment: {
VAR1: 'value1',
VAR2: 'value2',
},
volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }],
workingDirectory: '/working-directory',
user: 'user:group',
});

test.ok(spawnSyncStub.calledWith('docker', [
'run', '--rm',
'-u', 'user:group',
'-v', '/host-path:/container-path:delegated',
'--env', 'VAR1=value1',
'--env', 'VAR2=value2',
'-w', '/working-directory',
'--entrypoint', '/cool/entrypoint',
'alpine',
'--cool-entrypoint-arg',
'cool', 'command',
], { stdio: ['ignore', process.stderr, 'inherit'] }));
test.done();
},

'cp utility copies from an image'(test: Test) {
// GIVEN
const containerId = '1234567890abcdef1234567890abcdef';
Expand Down

0 comments on commit 6597a09

Please sign in to comment.