Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/guides/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,11 +298,12 @@ In service configuration, images can be configured via `provider.ecr.images`. To
Additionally, you can define arguments that will be passed to the `docker build` command via the following properties:

- `buildArgs`: With the `buildArgs` property, you can define arguments that will be passed to `docker build` command with `--build-arg` flag. They might be later referenced via `ARG` within your `Dockerfile`. (See [Documentation](https://docs.docker.com/engine/reference/builder/#arg))
- `buildOptions`: With the `buildOptions` property, you can define options that will be passed to the `docker build` command. (See [Documentation](https://docs.docker.com/engine/reference/commandline/image_build/#options))
- `cacheFrom`: The `cacheFrom` property can be used to specify which images to use as a source for layer caching in the `docker build` command with `--cache-from` flag. (See [Documentation](https://docs.docker.com/engine/reference/builder/#usage))
- `platform`: The `platform` property can be used to specify the architecture target in the `docker build` command with the `--platform` flag. If not specified, Docker will build for your computer's architecture by default. AWS Lambda typically uses `x86` architecture unless otherwise specified in the Lambda's runtime settings. In order to avoid runtime errors when building on an ARM-based machine (e.g. Apple M1 Mac), `linux/amd64` must be used here. The options for this flag are `linux/amd64` (`x86`-based Lambdas), `linux/arm64` (`arm`-based Lambdas), or `windows/amd64`. (See [Documentation](https://docs.docker.com/engine/reference/builder/#from))
- `provenance` Use the `provenance` property to disable multi-architecture manifest generated from BuildKit or `docker buildx`, allows the architecture specified in `platform` to be recognized by AWS Lambda during deployment.

When `uri` is defined for an image, `buildArgs`, `cacheFrom`, and `platform` cannot be defined.
When `uri` is defined for an image, `buildArgs`, `buildOptions`, `cacheFrom`, and `platform` cannot be defined.

Example configuration

Expand Down
9 changes: 9 additions & 0 deletions docs/guides/serverless.yml.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,15 @@ provider:
file: Dockerfile.dev
buildArgs:
STAGE: ${sls:stage}
buildOptions:
[
'--tag',
'v1.0.0',
'--add-host',
'example.com:0.0.0.0',
'--ssh',
'default=/path/to/private/key/id_rsa',
]
cacheFrom:
- my-image:latest
```
Expand Down
12 changes: 12 additions & 0 deletions lib/plugins/aws/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,7 @@ class AwsProvider {
path: { type: 'string' },
file: { type: 'string' },
buildArgs: { type: 'object', additionalProperties: { type: 'string' } },
buildOptions: { type: 'array', items: { type: 'string' } },
cacheFrom: { type: 'array', items: { type: 'string' } },
platform: { type: 'string' },
provenance: { type: 'string' },
Expand Down Expand Up @@ -2331,6 +2332,7 @@ Object.defineProperties(
imagePath,
imageFilename,
buildArgs,
buildOptions,
cacheFrom,
platform,
provenance,
Expand Down Expand Up @@ -2377,6 +2379,7 @@ Object.defineProperties(
pathToDockerfile,
...buildArgsArr,
...cacheFromArr,
...buildOptions,
imagePath,
];

Expand Down Expand Up @@ -2515,6 +2518,7 @@ Object.defineProperties(
const { imageUri, imageName } = resolveImageUriOrName();
const defaultDockerfile = 'Dockerfile';
const defaultBuildArgs = {};
const defaultBuildOptions = [];
const defaultCacheFrom = [];
const defaultScanOnPush = false;
const defaultPlatform = '';
Expand Down Expand Up @@ -2561,6 +2565,12 @@ Object.defineProperties(
'ECR_IMAGE_BOTH_URI_AND_BUILDARGS_DEFINED_ERROR'
);
}
if (imageDefinedInProvider.uri && imageDefinedInProvider.buildOptions) {
throw new ServerlessError(
`You can't use the "buildOptions" and the "uri" properties at the same time "${imageName}"`,
'ECR_IMAGE_URI_AND_BUILDOPTIONS_DEFINED_ERROR'
);
}
if (imageDefinedInProvider.uri && imageDefinedInProvider.cacheFrom) {
throw new ServerlessError(
`The "cacheFrom" property cannot be used with "uri" property "${imageName}"`,
Expand All @@ -2585,6 +2595,7 @@ Object.defineProperties(
imagePath: imageDefinedInProvider.path,
imageFilename: imageDefinedInProvider.file || defaultDockerfile,
buildArgs: imageDefinedInProvider.buildArgs || defaultBuildArgs,
buildOptions: imageDefinedInProvider.buildOptions || defaultBuildOptions,
cacheFrom: imageDefinedInProvider.cacheFrom || defaultCacheFrom,
platform: imageDefinedInProvider.platform || defaultPlatform,
provenance: imageDefinedInProvider.provenance || defaultProvenance,
Expand All @@ -2601,6 +2612,7 @@ Object.defineProperties(
imagePath: imageDefinedInProvider,
imageFilename: defaultDockerfile,
buildArgs: imageDefinedInProvider.buildArgs || defaultBuildArgs,
buildOptions: imageDefinedInProvider.buildOptions || defaultBuildOptions,
cacheFrom: imageDefinedInProvider.cacheFrom || defaultCacheFrom,
platform: imageDefinedInProvider.platform || defaultPlatform,
provenance: imageDefinedInProvider.provenance || defaultProvenance,
Expand Down
88 changes: 88 additions & 0 deletions test/unit/lib/plugins/aws/provider.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -795,6 +795,35 @@ aws_secret_access_key = CUSTOMSECRET
});

describe('when resolving images', () => {
it('should fail if `functions[].image` references image with both buildOptions and uri', async () => {
await expect(
runServerless({
fixture: 'function',
command: 'package',
configExt: {
provider: {
ecr: {
images: {
invalidimage: {
buildOptions: ['--no-cache'],
uri: '000000000000.dkr.ecr.sa-east-1.amazonaws.com/test-lambda-docker@sha256:6bb600b4d6e1d7cf521097177dd0c4e9ea373edb91984a505333be8ac9455d38',
},
},
},
},
functions: {
fnProviderInvalidImage: {
image: 'invalidimage',
},
},
},
})
).to.be.eventually.rejected.and.have.property(
'code',
'ECR_IMAGE_URI_AND_BUILDOPTIONS_DEFINED_ERROR'
);
});

it('should fail if `functions[].image` references image with both path and uri', async () => {
await expect(
runServerless({
Expand Down Expand Up @@ -1659,6 +1688,65 @@ aws_secret_access_key = CUSTOMSECRET
]);
});

it('should work correctly when image is defined with `buildOptions` set', async () => {
const awsRequestStubMap = {
...baseAwsRequestStubMap,
ECR: {
...baseAwsRequestStubMap.ECR,
describeRepositories: describeRepositoriesStub.resolves({
repositories: [{ repositoryUri }],
}),
createRepository: createRepositoryStub,
},
};
const {
awsNaming,
cfTemplate,
fixtureData: { servicePath: serviceDir },
} = await runServerless({
fixture: 'ecr',
command: 'package',
awsRequestStubMap,
modulesCacheStub,
configExt: {
provider: {
ecr: {
images: {
baseimage: {
path: './',
file: 'Dockerfile.dev',
buildOptions: ['--ssh', 'default=/path/to/file'],
},
},
},
},
},
});

const functionCfLogicalId = awsNaming.getLambdaLogicalId('foo');
const functionCfConfig = cfTemplate.Resources[functionCfLogicalId].Properties;
const versionCfConfig = Object.values(cfTemplate.Resources).find(
(resource) =>
resource.Type === 'AWS::Lambda::Version' &&
resource.Properties.FunctionName.Ref === functionCfLogicalId
).Properties;

expect(functionCfConfig.Code.ImageUri).to.deep.equal(`${repositoryUri}@sha256:${imageSha}`);
expect(versionCfConfig.CodeSha256).to.equal(imageSha);
expect(describeRepositoriesStub).to.be.calledOnce;
expect(createRepositoryStub.notCalled).to.be.true;
expect(spawnExtStub).to.be.calledWith('docker', [
'build',
'-t',
`${awsNaming.getEcrRepositoryName()}:baseimage`,
'-f',
path.join(serviceDir, 'Dockerfile.dev'),
'--ssh',
'default=/path/to/file',
'./',
]);
});

it('should work correctly when image is defined with `buildArgs` set', async () => {
const awsRequestStubMap = {
...baseAwsRequestStubMap,
Expand Down
Loading