-
Notifications
You must be signed in to change notification settings - Fork 4.2k
feat(core): allow mounting existing or volume copy volumes #32832
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
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The pull request linter fails with the following errors:
❌ Features must contain a change to a README file.
❌ Features must contain a change to an integration test file and the resulting snapshot.
If you believe this pull request should receive an exemption, please comment and provide a justification. A comment requesting an exemption should contain the text Exemption Request
. Additionally, if clarification is needed, add Clarification Request
to a comment.
✅ A exemption request has been requested. Please wait for a maintainer's review.
Exemption Request (Integration Test): Unsure what sort of integration test would be beneficial here, as it's a synth time change. Clarification Request (Readme): Happy to add a writeup, but the current |
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
Hi Please also add a README. Let me know if any questions. The descriptions in this issue are a good explanation. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a readme. Please help ans the questions posed above.
Thanks for having a look. I'm happy to add docs and tests, just let me know where is appropriate as there are currently no docs around these features for me to modify. If making a new readme is appropriate, I'll do that. Regarding breaking changes, the I would also appreciate feedback or comments on the typing. I've used Typescript union types as they passed linting and build checks, and give the best developer experience in Typescript, but can also rewrite this a number of other ways (a single large interface with validation checks to ensure the required sets of properties are passed, or separate arrays for volume copy and existing volume mounts, completely separate from the current "volumes" array. both of these are a worse dev experience, but will work if there are restrictions on union types. Cheers, |
Apologies for the delay in response. I suspect that heterogenous typing will cause issues in languages like Java wrt backward compatibility but havent been able to confirm it. Please expect a response by EOW. |
Any update on this? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cgatt apologies for the delayed response. Please see my comments.
Also - I think we need an integration test for this. Granted, a lot of the bundling code can be covered by unit tests, but I still think we have a integ test gap that I would like us to not exacerbate.
It should be pretty straight forward to add a few more tests similar to:
Thanks for all the work you're putting into this!
@@ -61,7 +60,7 @@ export interface BundlingOptions { | |||
* | |||
* @default - no additional volumes are mounted | |||
*/ | |||
readonly volumes?: DockerVolume[]; | |||
readonly volumes?: (DockerVolume | VolumeCopyDockerVolume | ExistingDockerVolume)[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you already surmised, this is a problem because it provides a poor user experience for static languages, where this translates into an generic Object
type.
Before we consider alternatives, I have some questions.
VolumeCopyDockerVolume
Why do we need this new type? Both DockerVolume
and VolumeCopyDockerVolume
offer the same functionality: expose path X on the host machine as path Y inside the container.
So from a properties standpoint, they both should have the same properties. Looking at the code you described in the linked issue:
const codeAsset = new AssetStaging(this, 'CodeAsset', {
sourcePath: path.resolve('mule'),
exclude: ['target/*', 'bin/*', '*.class', '*.jar'],
bundling: {
image: DockerImage.fromRegistry('public.ecr.aws/docker/library/alpine'),
bundlingFileAccess: BundlingFileAccess.VOLUME_COPY,
volumes: [{
hostPath: '~/.m2',
containerPath: '/root/.m2',
}],
},
});
It seems like we can just apply the bundlingFileAccess
for the additional volume configuration as well. I'm not sure I see a use-case for having each individual volume define its own "exposure" mechanism.
ExistingDockerVolume
This one seems to be addressing a different issue/use-case - i'm not opposed to it, but I would prefer for it to be a separate PR.
As for the implementation, lets drop the union type and instead change DockerVolume
to support existing volumes, as proposed by @SamStephens in the issue:
- Change
hostPath
to be optional. - Add a
volumeName
optional property to indicate we want an existing volume. - Validate mutual exclusivity of
hostPath
andvolumeName
.
Its not the best experience because it creates a runtime validation instead of compile time, but is still preferable over union types.
switch (options.bundlingFileAccess) { | ||
case BundlingFileAccess.VOLUME_COPY: | ||
new AssetBundlingVolumeCopy(assetStagingOptions).run(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I prefer these individual helper classes over the proposed DockerVolumeHelper
- even at the expense of some duplication. Since volume commands differ so much between the two options, a common helper class makes it harder to reason through.
|
||
/** | ||
* The path on the host machine to be used as the input for the volume. | ||
* @default - Does not copy from the host machine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then why would we define a VolumeCopy volume if we aren't copying anything?
* The path on the host machine where the output from the volume will be written. | ||
* @default - Does not copy to the host machine | ||
*/ | ||
readonly hostOutputPath?: string; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this capability is really related to what this PR is trying to address. There is also no test for it.
In general I don't think we need this, it poses a slight shift in how we think about bundling. Currently, the bundling mechanism takes N inputs and produces 1 output - thats clear and easy to reason about. Allowing for M outputs makes it more complex and I don't see a reason for it.
If you have a clear use case in mind - please elaborate on it, preferably in a different issue/PR.
@@ -1569,15 +1569,11 @@ describe('staging with docker cp', () => { | |||
expect(staging.isArchive).toEqual(true); | |||
const dockerCalls: string[] = readDockerStubInputConcat(STUB_INPUT_CP_CONCAT_FILE).split(/\r?\n/); | |||
expect(dockerCalls).toEqual(expect.arrayContaining([ | |||
expect.stringContaining('volume create assetInput'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happened to this command? How come we don't need docker volume create
anymore?
Yeah there's no good place for it right now...Lets see how this PR ends up and then decide whether to add a blurb somewhere or exempt it. |
This PR has not received a response in a while. If you want to keep this issue open, please leave a comment below and auto-close will be canceled. |
Issue # (if applicable)
Closes #32805
Closes #20601
Reason for this change
This change is to better support image bundling in atypical (e.g. CI, DinD) environments by allowing volumes to be mounted using the more portable "Volume Copy" method, or to mount an existing volume. This supports use cases such as caching dependencies in CI environments to reduce asset bundling times.
Description of changes
The primary change made was the addition of two new
DockerVolume
varients (VolumeCopyDockerVolume
andExistingDockerVolume
), facilitated by the newDockerVolumeHelper
private class. This replaces the old asset-staging private classesAssetBundlingBindMount
andAssetBundlingVolumeCopy
, reproducing all the behaviours in a more flexible manner.The decision to move these utility functions to
private/bundling.ts
was to better encapsulate the docker related behaviours and abstract them away from the asset management.This currently uses a discriminated union type to clearly show which properties are required for each volume type. This passes linting, but if it's an issue it can be implemented just as an extension to the DockerVolume interface. However, I'm unsure how to best provide a clear developer experience with this approach.
How It Works
The interfaces for
DockerRunOptions.volumes
and the relatedBundlingOptions.volumes
have been changed to acceptVolumeCopyDockerVolume
andExistingDockerVolume
as well as the existingDockerVolume
type. TheBundlingDockerImage.run()
function has been modified slightly to instantiate aDockerVolumeHelper
, which accepts the docker run options and uses them to prepare the volumes passed in, creating the volume command strings thatrun
then uses.If any if the passed volumes are VOLUME_COPY volumes, a copyContainer is spun up with each VOLUME_COPY volume atttached anonymously. The input copy is then performed using the same approach from
AssetBundlingVolumeCopy
. As these volumes are mounted to the primary container via--volumes-from
, them being anonymous doesnt matter and makes creation and deletion of the helper more atomic, reducing the possibility of orphaned volumes or containers. Error handling has been added in multiple places to further prevent this happening in the case of a build failure.BundlingDockerImage.run()
makes use of the volume commands fromDockerVolumeHelper
to complete its image run, then runsDockerVolumeHelper.cleanup()
to copy any outputs from the volume copy volumes, and delete the container (using the-v
option to remove attach anonymous volumes).Describe any new or updated permissions being added
N/A - All changes are at bundling time only
Description of how you validated changes
Unit tests were added to cover the new expected volume behaviours, and existing tests updated to match any changes to argument order. Tests were made to cover the new helper class and new error handling cleanup behaviour. No integration tests were made or modified as this is a local/bundling change,
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license