Skip to content

Commit 1439c66

Browse files
authored
Merge pull request #89 from electric-al/main
feat: adds the ability to pass options to the docker build command
2 parents 0ca7af7 + 1119177 commit 1439c66

File tree

4 files changed

+111
-1
lines changed

4 files changed

+111
-1
lines changed

docs/guides/functions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,11 +298,12 @@ In service configuration, images can be configured via `provider.ecr.images`. To
298298
Additionally, you can define arguments that will be passed to the `docker build` command via the following properties:
299299

300300
- `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))
301+
- `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))
301302
- `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))
302303
- `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))
303304
- `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.
304305

305-
When `uri` is defined for an image, `buildArgs`, `cacheFrom`, and `platform` cannot be defined.
306+
When `uri` is defined for an image, `buildArgs`, `buildOptions`, `cacheFrom`, and `platform` cannot be defined.
306307

307308
Example configuration
308309

docs/guides/serverless.yml.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,15 @@ provider:
390390
file: Dockerfile.dev
391391
buildArgs:
392392
STAGE: ${sls:stage}
393+
buildOptions:
394+
[
395+
'--tag',
396+
'v1.0.0',
397+
'--add-host',
398+
'example.com:0.0.0.0',
399+
'--ssh',
400+
'default=/path/to/private/key/id_rsa',
401+
]
393402
cacheFrom:
394403
- my-image:latest
395404
```

lib/plugins/aws/provider.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ class AwsProvider {
11441144
path: { type: 'string' },
11451145
file: { type: 'string' },
11461146
buildArgs: { type: 'object', additionalProperties: { type: 'string' } },
1147+
buildOptions: { type: 'array', items: { type: 'string' } },
11471148
cacheFrom: { type: 'array', items: { type: 'string' } },
11481149
platform: { type: 'string' },
11491150
provenance: { type: 'string' },
@@ -2331,6 +2332,7 @@ Object.defineProperties(
23312332
imagePath,
23322333
imageFilename,
23332334
buildArgs,
2335+
buildOptions,
23342336
cacheFrom,
23352337
platform,
23362338
provenance,
@@ -2377,6 +2379,7 @@ Object.defineProperties(
23772379
pathToDockerfile,
23782380
...buildArgsArr,
23792381
...cacheFromArr,
2382+
...buildOptions,
23802383
imagePath,
23812384
];
23822385

@@ -2515,6 +2518,7 @@ Object.defineProperties(
25152518
const { imageUri, imageName } = resolveImageUriOrName();
25162519
const defaultDockerfile = 'Dockerfile';
25172520
const defaultBuildArgs = {};
2521+
const defaultBuildOptions = [];
25182522
const defaultCacheFrom = [];
25192523
const defaultScanOnPush = false;
25202524
const defaultPlatform = '';
@@ -2561,6 +2565,12 @@ Object.defineProperties(
25612565
'ECR_IMAGE_BOTH_URI_AND_BUILDARGS_DEFINED_ERROR'
25622566
);
25632567
}
2568+
if (imageDefinedInProvider.uri && imageDefinedInProvider.buildOptions) {
2569+
throw new ServerlessError(
2570+
`You can't use the "buildOptions" and the "uri" properties at the same time "${imageName}"`,
2571+
'ECR_IMAGE_URI_AND_BUILDOPTIONS_DEFINED_ERROR'
2572+
);
2573+
}
25642574
if (imageDefinedInProvider.uri && imageDefinedInProvider.cacheFrom) {
25652575
throw new ServerlessError(
25662576
`The "cacheFrom" property cannot be used with "uri" property "${imageName}"`,
@@ -2585,6 +2595,7 @@ Object.defineProperties(
25852595
imagePath: imageDefinedInProvider.path,
25862596
imageFilename: imageDefinedInProvider.file || defaultDockerfile,
25872597
buildArgs: imageDefinedInProvider.buildArgs || defaultBuildArgs,
2598+
buildOptions: imageDefinedInProvider.buildOptions || defaultBuildOptions,
25882599
cacheFrom: imageDefinedInProvider.cacheFrom || defaultCacheFrom,
25892600
platform: imageDefinedInProvider.platform || defaultPlatform,
25902601
provenance: imageDefinedInProvider.provenance || defaultProvenance,
@@ -2601,6 +2612,7 @@ Object.defineProperties(
26012612
imagePath: imageDefinedInProvider,
26022613
imageFilename: defaultDockerfile,
26032614
buildArgs: imageDefinedInProvider.buildArgs || defaultBuildArgs,
2615+
buildOptions: imageDefinedInProvider.buildOptions || defaultBuildOptions,
26042616
cacheFrom: imageDefinedInProvider.cacheFrom || defaultCacheFrom,
26052617
platform: imageDefinedInProvider.platform || defaultPlatform,
26062618
provenance: imageDefinedInProvider.provenance || defaultProvenance,

test/unit/lib/plugins/aws/provider.test.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,35 @@ aws_secret_access_key = CUSTOMSECRET
795795
});
796796

797797
describe('when resolving images', () => {
798+
it('should fail if `functions[].image` references image with both buildOptions and uri', async () => {
799+
await expect(
800+
runServerless({
801+
fixture: 'function',
802+
command: 'package',
803+
configExt: {
804+
provider: {
805+
ecr: {
806+
images: {
807+
invalidimage: {
808+
buildOptions: ['--no-cache'],
809+
uri: '000000000000.dkr.ecr.sa-east-1.amazonaws.com/test-lambda-docker@sha256:6bb600b4d6e1d7cf521097177dd0c4e9ea373edb91984a505333be8ac9455d38',
810+
},
811+
},
812+
},
813+
},
814+
functions: {
815+
fnProviderInvalidImage: {
816+
image: 'invalidimage',
817+
},
818+
},
819+
},
820+
})
821+
).to.be.eventually.rejected.and.have.property(
822+
'code',
823+
'ECR_IMAGE_URI_AND_BUILDOPTIONS_DEFINED_ERROR'
824+
);
825+
});
826+
798827
it('should fail if `functions[].image` references image with both path and uri', async () => {
799828
await expect(
800829
runServerless({
@@ -1659,6 +1688,65 @@ aws_secret_access_key = CUSTOMSECRET
16591688
]);
16601689
});
16611690

1691+
it('should work correctly when image is defined with `buildOptions` set', async () => {
1692+
const awsRequestStubMap = {
1693+
...baseAwsRequestStubMap,
1694+
ECR: {
1695+
...baseAwsRequestStubMap.ECR,
1696+
describeRepositories: describeRepositoriesStub.resolves({
1697+
repositories: [{ repositoryUri }],
1698+
}),
1699+
createRepository: createRepositoryStub,
1700+
},
1701+
};
1702+
const {
1703+
awsNaming,
1704+
cfTemplate,
1705+
fixtureData: { servicePath: serviceDir },
1706+
} = await runServerless({
1707+
fixture: 'ecr',
1708+
command: 'package',
1709+
awsRequestStubMap,
1710+
modulesCacheStub,
1711+
configExt: {
1712+
provider: {
1713+
ecr: {
1714+
images: {
1715+
baseimage: {
1716+
path: './',
1717+
file: 'Dockerfile.dev',
1718+
buildOptions: ['--ssh', 'default=/path/to/file'],
1719+
},
1720+
},
1721+
},
1722+
},
1723+
},
1724+
});
1725+
1726+
const functionCfLogicalId = awsNaming.getLambdaLogicalId('foo');
1727+
const functionCfConfig = cfTemplate.Resources[functionCfLogicalId].Properties;
1728+
const versionCfConfig = Object.values(cfTemplate.Resources).find(
1729+
(resource) =>
1730+
resource.Type === 'AWS::Lambda::Version' &&
1731+
resource.Properties.FunctionName.Ref === functionCfLogicalId
1732+
).Properties;
1733+
1734+
expect(functionCfConfig.Code.ImageUri).to.deep.equal(`${repositoryUri}@sha256:${imageSha}`);
1735+
expect(versionCfConfig.CodeSha256).to.equal(imageSha);
1736+
expect(describeRepositoriesStub).to.be.calledOnce;
1737+
expect(createRepositoryStub.notCalled).to.be.true;
1738+
expect(spawnExtStub).to.be.calledWith('docker', [
1739+
'build',
1740+
'-t',
1741+
`${awsNaming.getEcrRepositoryName()}:baseimage`,
1742+
'-f',
1743+
path.join(serviceDir, 'Dockerfile.dev'),
1744+
'--ssh',
1745+
'default=/path/to/file',
1746+
'./',
1747+
]);
1748+
});
1749+
16621750
it('should work correctly when image is defined with `buildArgs` set', async () => {
16631751
const awsRequestStubMap = {
16641752
...baseAwsRequestStubMap,

0 commit comments

Comments
 (0)