Skip Docker Lambda image builds when ImageUri is a valid ECR location
- Dominant language
- Python
- Stars
- 6.7k
- Forks
- 1.2k
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 52
Description
### Describe your idea/feature/enhancement
When configuring a lambda / serverless function of which the `PackageType` is `Zip`, SAM preemptively checks whether the resource `CodeUri` is a S3 location or not.
```
# This function is already packaged and will to be ignored by SAM
Function:
Type: AWS::Serverless::Function
Properties:
PackageType: Zip
CodeUri: s3://bucket/function.zip
...
```
If so, SAM will not attempt to build said lambda, and will show a warning to the user:
```
% sam build
The resource AWS::Serverless::Function 'Function' has specified S3 location for CodeUri. It will not be built and SAM CLI does not support invoking it locally.
```
I would expect SAM to do the same when attempting to build a `PackageType: Image` lambda function; checking whether or not the resource property `ImageUri` is a valid ECR URL before attempting to build said images locally, yet this feature is not supported by SAM today:
```
# SAM should not attempt to build this Lambda
Function:
Type: AWS::Serverless::Function
Properties:
PackageType: Image
ImageUri: 123456789012.dkr.ecr.eu-west-1.amazonaws.com/function:latest
```
Instead, attempting to do so will most likely output the following exception (as the `DockerContext` resource metadata, required for building Docker Images using SAM, will most likely be unset, [error traced here](https://github.com/aws/aws-sam-cli/blob/54644dd72c7b227683566ef1d07def5ad343fbf3/samcli/lib/build/app_builder.py#L322)):
```
% sam build
Building image for Function function
Traceback (most recent call last):
File "/usr/local/bin/sam", line 8, in
sys.exit(cli())
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 829, in __call__
return self.main(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 782, in main
rv = self.invoke(ctx)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1259, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 1066, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/click/decorators.py", line 73, in new_func
return ctx.invoke(f, obj, *args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/click/core.py", line 610, in invoke
return callback(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/samcli/lib/telemetry/metric.py", line 153, in wrapped
raise exception # pylint: disable=raising-bad-type
File "/usr/local/lib/python3.8/site-packages/samcli/lib/telemetry/metric.py", line 122, in wrapped
return_value = func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/samcli/lib/utils/version_checker.py", line 42, in wrapped
actual_result = func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/samcli/cli/main.py", line 90, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.8/site-packages/samcli/commands/build/command.py", line 210, in cli
do_cli(
File "/usr/local/lib/python3.8/site-packages/samcli/commands/build/command.py", line 315, in do_cli
artifacts = builder.build()
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/app_builder.py", line 169, in build
return build_strategy.build()
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/build_strategy.py", line 41, in build
result.update(self._build_functions(self._build_graph))
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/build_strategy.py", line 52, in _build_functions
function_build_results.update(self.build_single_function_definition(build_definition))
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/build_strategy.py", line 118, in build_single_function_definition
result = self._build_function(
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/app_builder.py", line 500, in _build_function
return self._build_lambda_image(function_name=function_name, metadata=metadata) # type: ignore
File "/usr/local/lib/python3.8/site-packages/samcli/lib/build/app_builder.py", line 322, in _build_lambda_image
docker_context_dir = pathlib.Path(self._base_dir, docker_context).resolve()
File "/usr/local/Cellar/python@3.8/3.8.10/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pathlib.py", line 1042, in __new__
self = cls._from_parts(args, init=False)
File "/usr/local/Cellar/python@3.8/3.8.10/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pathlib.py", line 683, in _from_parts
drv, root, parts = self._parse_args(args)
File "/usr/local/Cellar/python@3.8/3.8.10/Frameworks/Python.framework/Versions/3.8/lib/python3.8/pathlib.py", line 667, in _parse_args
a = os.fspath(a)
```
As a result, it is currently not possible to deploy Docker-packed Lambda functions, without building the underlying image using SAM, which is, in my opinion, very limiting (e.g., inability to share ECR registries & images among an Organization, inability to use Docker images that require a specific build workflow -passing secrets using buildkit, environment specific args-...)
I did find a workaround, tricking SAM into skipping the build of a `PackageType: Image` Lambda, by setting the `Code.S3Bucket` property to an empty value, but I believe this to be very hack-y:
```
# A working hack to skip the build of a Image Lambda function
Function:
Type: AWS::Lambda::Function
Properties:
PackageType: Image
Code:
S3Bucket: !Ref AWS::NoValue
ImageUri: 123456789012.dkr.ecr.eu-west-1.amazonaws.com/function:latest
```
### Proposal
- Similarly to `Zip` packaged lambdas, check whether or not the `ImageUri` property of a `AWS::Serverless::Function`, or `Code.ImageUri` property of a `AWS::Lambda::Function` is a valid ECR URL before attempting to locally build said function. This could be done by reusing a function in the `package.ecr_utils` module [here](https://github.com/aws/aws-sam-cli/blob/54644dd72c7b227683566ef1d07def5ad343fbf3/samcli/lib/package/ecr_utils.py#L9).
- Show the user a proper warning when skipping the build of Docker lambda images.
Things to consider:
1. Will this require any updates to the [SAM Spec](https://github.com/awslabs/serverless-application-model)
### Additional Details
A PR should follow soon with a workaround proposal.
Contributor guide
Assessment
This issue has not been assessed yet.