Skip to content

Commit

Permalink
feat(lambda): expose all docker run options to container bundling of …
Browse files Browse the repository at this point in the history
…all lambda variants (#23318)

This continues the work started in #22829 by exposing the underlying docker run options of the container bundling.
With that the bundling feature can be used in a wider range of setups that the current defaults can not support out of the box.

The removed properties are covered in the same way by the one the interface extends from.

----

### All Submissions:

* [X] Have you followed the guidelines in our [Contributing guide?](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md)

### Adding new Construct Runtime Dependencies:

* [ ] This PR adds new construct runtime dependencies following the process described [here](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md/#adding-construct-runtime-dependencies)

### New Features

* [ ] Have you added the new feature to an [integration test](https://github.com/aws/aws-cdk/blob/main/INTEGRATION_TESTS.md)?
	* [ ] Did you use `yarn integ` to deploy the infrastructure and generate the snapshot (i.e. `yarn integ` without `--dry-run`)?

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
webratz committed Dec 15, 2022
1 parent 4490bea commit 02d0876
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 32 deletions.
15 changes: 15 additions & 0 deletions packages/@aws-cdk/aws-lambda-go/README.md
Expand Up @@ -183,6 +183,21 @@ new go.GoFunction(this, 'GoFunction', {
});
```

You can set additional Docker options to configure the build environment:

```ts
new go.GoFunction(this, 'GoFunction', {
entry: 'app/cmd/api',
bundling: {
network: 'host',
securityOpt: 'no-new-privileges',
user: 'user:group',
volumesFrom: ['777f7dc92da7'],
volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }],
},
});
```

## Command hooks

It is possible to run additional commands by specifying the `commandHooks` prop:
Expand Down
23 changes: 22 additions & 1 deletion packages/@aws-cdk/aws-lambda-go/lib/bundling.ts
Expand Up @@ -78,6 +78,13 @@ export class Bundling implements cdk.BundlingOptions {
command: bundling.command,
environment: bundling.environment,
local: bundling.local,
entrypoint: bundling.entrypoint,
volumes: bundling.volumes,
volumesFrom: bundling.volumesFrom,
workingDirectory: bundling.workingDirectory,
user: bundling.user,
securityOpt: bundling.securityOpt,
network: bundling.network,
},
});
}
Expand All @@ -93,6 +100,13 @@ export class Bundling implements cdk.BundlingOptions {
public readonly command: string[];
public readonly environment?: { [key: string]: string };
public readonly local?: cdk.ILocalBundling;
public readonly entrypoint?: string[]
public readonly volumes?: cdk.DockerVolume[];
public readonly volumesFrom?: string[];
public readonly workingDirectory?: string;
public readonly user?: string;
public readonly securityOpt?: string;
public readonly network?: string;

private readonly relativeEntryPath: string;

Expand Down Expand Up @@ -131,8 +145,15 @@ export class Bundling implements cdk.BundlingOptions {
: cdk.DockerImage.fromRegistry('dummy'); // Do not build if we don't need to

const bundlingCommand = this.createBundlingCommand(cdk.AssetStaging.BUNDLING_INPUT_DIR, cdk.AssetStaging.BUNDLING_OUTPUT_DIR);
this.command = ['bash', '-c', bundlingCommand];
this.command = props.command ?? ['bash', '-c', bundlingCommand];
this.environment = environment;
this.entrypoint = props.entrypoint;
this.volumes = props.volumes;
this.volumesFrom = props.volumesFrom;
this.workingDirectory = props.workingDirectory;
this.user = props.user;
this.securityOpt = props.securityOpt;
this.network = props.network;

// Local bundling
if (!props.forcedDockerBundling) { // only if Docker is not forced
Expand Down
11 changes: 2 additions & 9 deletions packages/@aws-cdk/aws-lambda-go/lib/types.ts
@@ -1,16 +1,9 @@
import { AssetHashType, DockerImage } from '@aws-cdk/core';
import { AssetHashType, DockerImage, DockerRunOptions } from '@aws-cdk/core';

/**
* Bundling options
*/
export interface BundlingOptions {
/**
* Environment variables defined when go runs.
*
* @default - no environment variables are defined.
*/
readonly environment?: { [key: string]: string; };

export interface BundlingOptions extends DockerRunOptions {
/**
* Force bundling in a Docker container even if local bundling is
* possible.
Expand Down
126 changes: 126 additions & 0 deletions packages/@aws-cdk/aws-lambda-go/test/bundling.test.ts
Expand Up @@ -335,3 +335,129 @@ test('with command hooks', () => {
}),
});
});

test('Custom bundling entrypoint', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
entrypoint: ['/cool/entrypoint', '--cool-entrypoint-arg'],
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
entrypoint: ['/cool/entrypoint', '--cool-entrypoint-arg'],
}),
});
});

test('Custom bundling volumes', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }],
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }],
}),
});
});

test('Custom bundling volumesFrom', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
volumesFrom: ['777f7dc92da7'],
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
volumesFrom: ['777f7dc92da7'],
}),
});
});

test('Custom bundling workingDirectory', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
workingDirectory: '/working-directory',
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
workingDirectory: '/working-directory',
}),
});
});

test('Custom bundling user', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
user: 'user:group',
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
user: 'user:group',
}),
});
});

test('Custom bundling securityOpt', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
securityOpt: 'no-new-privileges',
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
securityOpt: 'no-new-privileges',
}),
});
});

test('Custom bundling network', () => {
Bundling.bundle({
entry,
moduleDir,
runtime: Runtime.GO_1_X,
architecture: Architecture.X86_64,
forcedDockerBundling: true,
network: 'host',
});

expect(Code.fromAsset).toHaveBeenCalledWith('/project', {
assetHashType: AssetHashType.OUTPUT,
bundling: expect.objectContaining({
network: 'host',
}),
});
});
14 changes: 14 additions & 0 deletions packages/@aws-cdk/aws-lambda-nodejs/README.md
Expand Up @@ -307,6 +307,20 @@ should also have `npm`, `yarn` or `pnpm` depending on the lock file you're using
Use the [default image provided by `@aws-cdk/aws-lambda-nodejs`](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/aws-lambda-nodejs/lib/Dockerfile)
as a source of inspiration.

You can set additional Docker options to configure the build environment:

```ts
new nodejs.NodejsFunction(this, 'my-handler', {
bundling: {
network: 'host',
securityOpt: 'no-new-privileges',
user: 'user:group',
volumesFrom: ['777f7dc92da7'],
volumes: [{ hostPath: '/host-path', containerPath: '/container-path' }],
},
});
```

## Asset hash

By default the asset hash will be calculated based on the bundled output (`AssetHashType.OUTPUT`).
Expand Down
16 changes: 14 additions & 2 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/bundling.ts
Expand Up @@ -73,9 +73,15 @@ export class Bundling implements cdk.BundlingOptions {

// Core bundling options
public readonly image: cdk.DockerImage;
public readonly entrypoint?: string[]
public readonly command: string[];
public readonly volumes?: cdk.DockerVolume[];
public readonly volumesFrom?: string[];
public readonly environment?: { [key: string]: string };
public readonly workingDirectory: string;
public readonly user?: string;
public readonly securityOpt?: string;
public readonly network?: string;
public readonly local?: cdk.ILocalBundling;

private readonly projectRoot: string;
Expand Down Expand Up @@ -137,11 +143,17 @@ export class Bundling implements cdk.BundlingOptions {
tscRunner: 'tsc', // tsc is installed globally in the docker image
osPlatform: 'linux', // linux docker image
});
this.command = ['bash', '-c', bundlingCommand];
this.command = props.command ?? ['bash', '-c', bundlingCommand];
this.environment = props.environment;
// Bundling sets the working directory to cdk.AssetStaging.BUNDLING_INPUT_DIR
// and we want to force npx to use the globally installed esbuild.
this.workingDirectory = '/';
this.workingDirectory = props.workingDirectory ?? '/';
this.entrypoint = props.entrypoint;
this.volumes = props.volumes;
this.volumesFrom = props.volumesFrom;
this.user = props.user;
this.securityOpt = props.securityOpt;
this.network = props.network;

// Local bundling
if (!props.forceDockerBundling) { // only if Docker is not forced
Expand Down
11 changes: 2 additions & 9 deletions packages/@aws-cdk/aws-lambda-nodejs/lib/types.ts
@@ -1,9 +1,9 @@
import { DockerImage } from '@aws-cdk/core';
import { DockerImage, DockerRunOptions } from '@aws-cdk/core';

/**
* Bundling options
*/
export interface BundlingOptions {
export interface BundlingOptions extends DockerRunOptions {
/**
* Whether to minify files when bundling.
*
Expand Down Expand Up @@ -161,13 +161,6 @@ export interface BundlingOptions {
*/
readonly charset?: Charset;

/**
* Environment variables defined when bundling runs.
*
* @default - no environment variables are defined.
*/
readonly environment?: { [key: string]: string; };

/**
* Replace global identifiers with constant expressions.
*
Expand Down

0 comments on commit 02d0876

Please sign in to comment.