Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SAM CDK -> sam build -> DockerImageCode.from_image_asset: Unable to set parent folder as the DockerContext #4059

Closed
dunika opened this issue Jul 15, 2022 · 9 comments

Comments

@dunika
Copy link

dunika commented Jul 15, 2022

Description:

I am having trouble with the following setup.

I have the following folder structure:

/root
  .Pipfile
  /shared_dependencies
  /project
    /runtime
      DockerFile

I need to set /root as the DockerContext and /root/project/runtime/DockerFile as the path to the Dockerfile

If I create a DockerImageCode instance and use it to create a DockerImageFunction like so:

code = DockerImageCode.from_image_asset(
  directory="/filesystem_path/root",
  file="/project/runtime/DockerFile",
)

DockerImageFunction(
  code=code,
)

cdk synth >| template.yaml will output a template and an AWS:Serverless:Function resource with the following metadata:

Metadata:
  aws:asset:path: /filesystem_path/root
  aws:asset:dockerfile-path: /project/runtime/DockerFile

My DockerFile contains the following:

COPY Pipfile .

To facilitate local development, I need to run sam build. When I do so, I get the following error:

COPY failed: file not found in build context or excluded by .dockerignore:
 stat Pipfile: file does not exist

Upon inspecting .aws-sam/build.toml, it would seem that the DockerContext is being set to /filesystem_path/root/project/runtime, the folder in which the DockerFile resides.

I would have assumed that the DockerContext would correspond to the directory parameter that gets passed into DockerImageCode.from_image_asset? (Which corresponds to aws:asset:path in the template)

As far as I can tell, there is no way of setting the DockerContext to any folder that is not the folder in which the DockerFile resides.

This pull request added the mapping logic for cdk image asset metadata -> sam build params.

Looking at the changes in this file, it would seem that the DockerContext will always be equal to the folder in which the DockerFile resides.

Is there a way of setting the DockerContext that I am not aware of? Or is it currently impossible?

I came across this issue which is now closed but does not offer a satisfactory resolution to this problem.

Additional environment details:

OS: Mac

sam --version -> SAM CLI, version 1.53.0

@dunika dunika added stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. type/bug labels Jul 15, 2022
@jfuss
Copy link
Contributor

jfuss commented Jul 15, 2022

@dunika Please see our docs: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-using-build.html#build-container-image

You can do this by providing additional Metadata on the resources.

@jfuss jfuss added type/question area/cdk blocked/close-if-inactive Blocked for >14 days with no response, will be closed if still inactive after 7 days and removed type/bug stage/needs-triage Automatically applied to new issues and PRs, indicating they haven't been looked at. labels Jul 15, 2022
@dunika
Copy link
Author

dunika commented Jul 15, 2022

@jfuss thanks for your reply

I am aware of the DockerFile and DockerContext Metadata properties.

As far as I can tell, I am unable to add these properties to the DockerImageFunction construct using the CDK.

I have tried to do so using some of the methods outlined here, but they don't seem to work with DockerImageFunction (perhaps they only work with constructs that are prefixed with Cfn?)

If I manually add the Metadata properties to my template like so:

Metadata:
  aws:asset:path: /filesystem_path/root
  aws:asset:dockerfile-path: /project/runtime/DockerFile
  DockerContext: /filesystem_path/root
  Dockerfile: /project/runtime/DockerFile

It still does not work, although it will if I remove the aws:asset properties.

Manually editing the template file that is generated from cdk synth is not a maintainable solution to the problem.

As mentioned above, running sam build translates the aws:asset properties into build parameters that get written to .aws-sam/build.toml

This is what my build.toml looks like after running sam build:

[function_build_definitions.1234.metadata]
"aws:asset:path" = "/filesystem_path/root"
"aws:asset:dockerfile-path" = " /project/runtime/DockerFile"
DockerContext = "/filesystem_path/root/project/runtime"
Dockerfile = "Dockerfile"

I've also mentioned above where that translation takes place.

So in summary; when using the CDK with sam build, I am unable to set the DockerContext to any folder that is not the folder in which the DockerFile resides in when using DockerImageFunction construct without having to manually edit the template that gets generated from cdk synth

@jfuss
Copy link
Contributor

jfuss commented Jul 15, 2022

This is the logic we do to convert what CDK provides: https://github.com/aws/aws-sam-cli/blob/develop/samcli/lib/samlib/resource_metadata_normalizer.py#L187

Looking at the built template could give a hint here too. It will at least (should) show the paths we resolved too.

The issue here is probably related to how the paths are defined in you CDK app.

@dunika
Copy link
Author

dunika commented Jul 15, 2022

@jfuss so looking at the code responsible for the conversion:

asset_path = Path(metadata.get(ASSET_PATH_METADATA_KEY, ""))
dockerfile_path = Path(metadata.get(ASSET_DOCKERFILE_PATH_KEY), "")
dockerfile, path_from_asset = dockerfile_path.stem, dockerfile_path.parent
dockerfile_context = str(Path(asset_path.joinpath(path_from_asset)))
return {
    SAM_METADATA_DOCKERFILE_KEY: dockerfile,
    SAM_METADATA_DOCKER_CONTEXT_KEY: dockerfile_context,
}

From what I can see, dockerfile_context will always be the folder that the DockerFile resides in and there doesn't seem to be a way around it?

EDIT: As mentioned above, my built template looks something similar to the following:

Metadata:
  aws:asset:path: /filesystem_path/root
  aws:asset:dockerfile-path: /project/runtime/DockerFile

@jfuss
Copy link
Contributor

jfuss commented Jul 15, 2022

EDIT: As mentioned above, my built template looks something similar to the following:

I thought we wrote out the Metadata too, which would have helped here.

From what I can see, dockerfile_context will always be the folder that the DockerFile resides in and there doesn't seem to be a way around it?

So I thought this was supported. Re-looking at the docs and code, you are correct that the Dockerfile needs to be in the CodeUri directory. This is a restriction within all builders and not specific to Docker building. So the solution here is to place the Dockerfile inside the CodeUri directory.

@dunika
Copy link
Author

dunika commented Jul 21, 2022

@jfuss thanks for looking into this.

I thought we wrote out the Metadata too, which would have helped here.

Sorry, I did leave some stuff out that I didn't think was relevant.

In case it helps, the full Metadata for the lambda resource looks like this:

    Metadata:
      aws:cdk:path: StackName/ResourceId/Resource
      aws:asset:path: /filesystem_path/root
      aws:asset:dockerfile-path: ./project/runtime/DockerFile
      aws:asset:property: Code.ImageUri
    CDKMetadata:
        Type: AWS::CDK::Metadata
        Properties:
          Analytics: hash
        Metadata:
           aws:cdk:path: FetchBBDemoSAMAppStageStack/CDKMetadata/Default
           Condition: CDKMetadataAvailable

So I thought this was supported. Re-looking at the docs and code, you are correct that the Dockerfile needs to be in the CodeUri directory. This is a restriction within all builders and not specific to Docker building. So the solution here is to place the Dockerfile inside the CodeUri directory.

So it does work if I remove the CDK metadata and simply make it look like this:

Metadata:
  DockerContext = "/filesystem_path/root"
  Dockerfile = "/project/runtime/Dockerfile"

So it is actually possible to manually set the DockerContext.

I think the main problem is that the current CDK implementation is a bit misleading.

I would have assumed that the directory parameter that is passed to DockerImageCode.from_image_asset would map to the DockerContext.

It seems like being able to set the DockerContext would be a useful feature to have for this construct.

What do you think?

@i18n-tribe
Copy link
Contributor

@jfuss I've submitted a PR to address this issue.

The code in the PR makes sam-cli behaviour consistent with how the cdk is working.

@qingchm
Copy link
Contributor

qingchm commented Jul 25, 2022

@i18n-tribe Thanks for your contribution! As this change will likely change the existing behaviour, we will need some deeper discussion before we can approve the contribution!

@moelasmar moelasmar removed the blocked/close-if-inactive Blocked for >14 days with no response, will be closed if still inactive after 7 days label Jul 27, 2022
@mndeveci
Copy link
Contributor

Changes have been released with SAM CLI v1.62.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants