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

ecr-assets: incomplete .dockerignore support #4450

Closed
kolomied opened this issue Oct 10, 2019 · 8 comments · Fixed by #4473
Closed

ecr-assets: incomplete .dockerignore support #4450

kolomied opened this issue Oct 10, 2019 · 8 comments · Fixed by #4473
Assignees
Labels
@aws-cdk/aws-ecr Related to Amazon Elastic Container Registry bug This issue is a bug. in-progress This issue is being actively worked on. management/devenv Related to CDK development/build environment p2

Comments

@kolomied
Copy link
Contributor

Introduced by #4104.

CDK does not handle the common "exclude everything except" pattern for .dockerignore files:

# Ignore everything
*
# Allow files and directories
!/src/**

Quote from Docker docs:

... you may want to specify which files to include in the context, rather than which to exclude. To achieve this, specify * as the first pattern, followed by one or more ! exception patterns.

With the current implementation the first 'star' glob effectively excludes everything from the asset folder dyring synth stage. Consequently, deploy stage fails to build the docker image.

Reproduction Steps

  1. Create a .dockerignore file next to you Dockerfile with * pattern, like this:
    # Ignore everything
    *
    # Allow files and directories
    !/src/**
  2. Run cdk deploy

Error Log

unable to prepare context: unable to evaluate symlinks in Dockerfile path: CreateFile C:\Dev\GitHub\playground\EcsWindowsCluster\src\Deployment\cdk.out\asset.1ebc9d3ac2033816c4abb63e4afd69d350b4aba8704cc9236b82ea520b74f4b0\Dockerfile: The system cannot find the file specified.

 ❌  win failed: Error: docker build --tag 305168429857.dkr.ecr.eu-west-1.amazonaws.com/cdk/win:latest cdk.out\asset.1ebc9d3ac2033816c4abb63e4afd69d350b4aba8704cc9236b82ea520b74f4b0 exited with error code 1
docker build --tag 305168429857.dkr.ecr.eu-west-1.amazonaws.com/cdk/win:latest cdk.out\asset.1ebc9d3ac2033816c4abb63e4afd69d350b4aba8704cc9236b82ea520b74f4b0 exited with error code 1

Environment

  • CLI Version : 1.12.0 (build 923055e)
  • OS : Windows

This is 🐛 Bug Report

@kolomied kolomied added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. labels Oct 10, 2019
@SomayaB SomayaB added the @aws-cdk/aws-ecr Related to Amazon Elastic Container Registry label Oct 10, 2019
@SomayaB SomayaB added management/devenv Related to CDK development/build environment needs-reproduction This issue needs reproduction. and removed needs-triage This issue or PR still needs to be triaged. labels Oct 10, 2019
@nmussy

This comment has been minimized.

@nmussy
Copy link
Contributor

nmussy commented Oct 11, 2019

Sorry about my previous comment, from what I can see it's working completely fine, assets/fs is doing its magic. I've tested the following successfully:

> tree test/dockerignore-image-advanced/

dockerignore-image-advanced/
├── deep
│   ├── dir
│   │   └── struct
│   │       └── qux.txt
│   └── include_me
│       └── sub
│           └── dir
│               └── quuz.txt
├── Dockerfile
├── foobar.txt
├── foo.txt
├── index.py
└── subdirectory
    ├── baz.txt
    └── quux.txt
# The following line should be ignored
#index.py

# This shouldn't ignore foo.txt
foo.?
# This shoul ignore foobar.txt
foobar.???
# This should catch qux.txt
deep/**/*.txt
# but quuz should be added back
!deep/include_me/**

# baz and quux should be ignored
subdirectory/**
# but baz should be added back
!subdirectory/baz*
const expectedFiles = [
  '.dockerignore',
  'Dockerfile',
  'index.py',
  'foo.txt',
  path.join('subdirectory', 'baz.txt'),
  path.join('deep', 'include_me', 'sub', 'dir', 'quuz.txt'),
];
const unexpectedFiles = [
  'foobar.txt',
  path.join('deep', 'dir', 'struct', 'qux.txt'),
  path.join('subdirectory', 'quux.txt'),
];

for (const expectedFile of expectedFiles) {
  test.ok(fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, expectedFile)), expectedFile);
}
for (const unexpectedFile of unexpectedFiles) {
  test.ok(!fs.existsSync(path.join(session.directory, `asset.${image.sourceHash}`, unexpectedFile)), unexpectedFile);
}

I can add this test case to test.image-asset.ts to make it a more comprehensive, but I can't reproduce @kolomied's issue.

@kolomied
Copy link
Contributor Author

@nmussy Please try to add a '*' as your first pattern in .dockerignore. Here is a small example that I use to reproduce the issue:

Test          
├── .dockerignore
├── Dockerfile   
├── bad.txt      
└── publish      
    └── good.txt 

.dockerignore is as follows:

*
!publish\*

After the synth phase I get the following asset:

asset.1ebc9d3ac2033816c4abb63e4afd69d350b4aba8704cc9236b82ea520b74f4b0          
└── .dockerignore

Howerver, I really expect to see this:

asset.1ebc9d3ac2033816c4abb63e4afd69d350b4aba8704cc9236b82ea520b74f4b0   
├── .dockerignore
├── Dockerfile      
└── publish      
    └── good.txt 

@nmussy
Copy link
Contributor

nmussy commented Oct 11, 2019

I see, thanks for clearing it up for me.

But I don't understand why you would expect anything but publish/good.txt to be present with your .dockerignore:

You can even use the .dockerignore file to exclude the Dockerfile and .dockerignore files. These files are still sent to the daemon because it needs them to do its job. But the ADD and COPY instructions do not copy them to the image.

@kolomied
Copy link
Contributor Author

Hm... My assumption is that synth stage has to prepare a self-contained folder that I can archive and use later to actually deploy the application (CI/CD scenario, for example).

Without Dockerfile there is not way to build the container during deploy stage, so it has to be in the asset folder.

Am I missing something here?

@nmussy
Copy link
Contributor

nmussy commented Oct 11, 2019

You're completely right, the Dockerfile would be required to build the image, we should probably always add it even if the user accidentally ignores it.

@nmussy
Copy link
Contributor

nmussy commented Oct 11, 2019

Here's what I've found:

copyDirectory walks through each directory recursively, making sure they're not excluded. If the directory is excluded, its files and sub-directories won't be explored:

if (shouldExclude(exclude, path.relative(rootDir, sourceFilePath))) {
continue;
}

shouldExclude on the other hand matches .dockerignore lines against the path it's being provided:

const match = minimatch(filePath, pattern, { matchBase: true, flipNegate: true });

So in the case of publish/good.txt, publish is evaluated against each .dockerignore line.

  • * matches publish, and excludes the directory
  • !publish\* does not match publish
  • copyDirectory leaves the directory early, without having checked its files

We need to figure out how to affect either shouldExclude or copyDirectory to prevent the recursion from stopping early

@enricopesce
Copy link

enricopesce commented May 14, 2021

I have today the same problem with:

cdk 1.103.0 (build bc13a66)

@aws-cdk/assets 1.103.0

OS: osx 11.3.1

typescript language

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk/aws-ecr Related to Amazon Elastic Container Registry bug This issue is a bug. in-progress This issue is being actively worked on. management/devenv Related to CDK development/build environment p2
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants