Skip to content

feat: wcow: add support for bind and cache mounts #5708

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

Merged
merged 1 commit into from
Feb 20, 2025

Conversation

profnandaa
Copy link
Collaborator

@profnandaa profnandaa commented Feb 6, 2025

Currently, mounts are not supported for WCOW builds, see #5678. This commit introduces support for bind and cache mounts (through the dockerfile frontend). The remaining two require a little more work and consultation with the platform teams for enlightment.

WIP Checklist:

  • Support for bind mounts
  • Support for cache mounts
  • add frontend/dockerfile integration tests
  • add client integration tests (not all, others waiting complete llb.AddMount support)
  • add documentation

Addresses part of #5678
Fixes #5603


Demo

Prep the context directory:

mkdir mounts-demo
cd mounts-demo
mkdir temp
echo "hello: root" > root.txt
echo "hello: inner" > .\temp\inner.txt

Dockerfile:

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022 AS base
# this is needed for the access of the mounts
USER ContainerAdministrator

# cache mount example
RUN --mount=type=cache,target=/mycache echo "hello" > \mycache\foo
RUN --mount=type=cache,target=/mycache dir \mycache\foo

# bind mount examples
FROM base
# bind root of the context dir
RUN --mount=type=bind,target=/out type out\root.txt
# bind an inner directory (/temp) in the context
RUN --mount=type=bind,src=/temp,dst=/out type out\inner.txt

FROM wintools/nanoserver AS tools
RUN mkdir \bin
RUN copy \Windows\System32\whoami.exe \bin\whoami.exe


FROM base
# bind mount from another stage
RUN --mount=type=bind,from=tools,src=/bin,dst=/bin \bin\whoami.exe

Build command:

buildctl build --frontend dockerfile.v0 `
--local context=. --local dockerfile=. `
--output type=image,name=docker.io/profnandaa/mount-test,push=false `
--progress plain --no-cache

Build log:

#8 [base 2/3] RUN --mount=type=cache,target=/mycache echo "hello" > mycachefoo
#8 ...

#9 [tools 2/3] RUN mkdir bin
#9 DONE 2.8s

#8 [base 2/3] RUN --mount=type=cache,target=/mycache echo "hello" > mycachefoo
#8 DONE 2.8s

#10 [base 3/3] RUN --mount=type=cache,target=/mycache dir mycachefoo
#10 ...

#11 [tools 3/3] RUN copy WindowsSystem32whoami.exe binwhoami.exe
#11 8.133         1 file(s) copied.
#11 ...

#10 [base 3/3] RUN --mount=type=cache,target=/mycache dir mycachefoo
#10 8.217  Volume in drive C has no label.
#10 8.218  Volume Serial Number is 1E6D-2BB8
#10 8.218
#10 8.218  Directory of C:\mycache
#10 8.218
#10 8.222 02/06/2025  02:52 PM                10 foo
#10 8.222                1 File(s)             10 bytes
#10 8.222                0 Dir(s)  389,156,036,608 bytes free
#10 ...

#11 [tools 3/3] RUN copy WindowsSystem32whoami.exe binwhoami.exe
#11 DONE 8.6s

#10 [base 3/3] RUN --mount=type=cache,target=/mycache dir mycachefoo
#10 DONE 8.6s

#12 [stage-3 1/1] RUN --mount=type=bind,from=tools,src=/bin,dst=/bin binwhoami.exe
#12 4.449 user manager\containeradministrator
#12 DONE 4.9s

#13 exporting to image
#13 exporting layers

Copy link
Contributor

@billywr billywr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the fix LGTM

@profnandaa profnandaa changed the title wip: wcow: hack complete for bind and cache mounts support feat: wcow: add support for bind and cache mounts Feb 7, 2025
@danielnilsson9
Copy link

danielnilsson9 commented Feb 7, 2025

I have done some testing on this with cache mounts and it works! But I'm a bit confused by the mount target path.
I'm running the binaries from this build: https://github.com/moby/buildkit/actions/runs/13193504481

It doesn't seem to be possible to specify an absolute path, specifying a full windows path "C:/Users/ContainerAdministrator/.conan2/p" does not work:

RUN --mount=type=cache,id=conan-cache-v1,sharing=locked,target=C:/Users/ContainerAdministrator/.conan2/p `
failed to create shim task: hcs::CreateComputeSystem si4wd93a8a3gf69wkaqhu86uz: The parameter is incorrect.: unknown

If I specify "/Users/ContainerAdministrator/.conan2/p" is seems to be relative to the current set WORKDIR and not the root of the C:/ disk which I think is inconsistent with the linux implementation.

@profnandaa
Copy link
Collaborator Author

profnandaa commented Feb 7, 2025 via email

@danielnilsson9
Copy link

Thanks :) Here is a small reproduce:

# escape=`

FROM mcr.microsoft.com/windows/servercore:ltsc2022

SHELL ["C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]

USER ContainerAdministrator

WORKDIR /build

# Does not work, cache directory mounted in C:/build/cache instead of C:/cache
RUN --mount=type=cache,id=cache-mount-v3,target=/cache `
    Get-ChildItem -Path "C:\\" ; `
    Get-ChildItem -Path "C:\\build"

# Does not work, no directory mounted, not in C:/cache and not in C:/build/cache
RUN --mount=type=cache,id=cache-mount-v3,target=C:/cache `
    Get-ChildItem -Path "C:\\" ; `
    Get-ChildItem -Path "C:\\build"

Thanks for testing, let me take a look at this on Monday. --- // sent from a tiny device while on the move. forgive the tie pose.

On Fri, Feb 7, 2025, 15:18 Daniel Nilsson @.> wrote: I have done some testing on this with cache mounts and it works! But I'm a bit confused by the mount target path. I'm running the binaries from this build: https://github.com/moby/buildkit/actions/runs/13193504481 It doesn't seem to be possible to specify an absolute path, specifying a full windows path "C:/mycache" does not work: RUN --mount=type=cache,id=conan-cache-v1,sharing=locked,target=C:/Users/ContainerAdministrator/.conan2/p ` failed to create shim task: hcs::CreateComputeSystem si4wd93a8a3gf69wkaqhu86uz: The parameter is incorrect.: unknown If I specify "/Users/ContainerAdministrator/.conan2/p" is seems to be relative to the current set WORKDIR and not the root of the C:/ disk which I think is inconsistent with the linux implementation. — Reply to this email directly, view it on GitHub <#5708 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAB7ZELBM76SSE6V7EIIZRD2OSQCFAVCNFSM6AAAAABWTGIERSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDMNBSG43DQNBYGM . You are receiving this because you authored the thread.Message ID: @.>

@profnandaa
Copy link
Collaborator Author

@danielnilsson9 -- you are right, this is not as it is on Linux, eg:

FROM alpine
WORKDIR /build
RUN --mount=type=cache,target=/cache ls / && echo -- && ls ./

build log:

#7 [stage-0 3/3] RUN --mount=type=cache,target=/cache ls / && echo -- && ls ./ 
#7 0.216 bin
#7 0.216 build 
#7 0.216 cache <--- 
#7 0.216 dev
#7 0.216 etc
#7 0.216 home   

Ok, will fix that. Thanks for the catch!

@profnandaa
Copy link
Collaborator Author

@danielnilsson9 -- fixed, please take a look.

For a consistent experience, we'll add to the documentation that for mount src and dst options, users supply unix paths instead.

@danielnilsson9
Copy link

@profnandaa Nice! Can confirm it is working as expected now.

@slonopotamus
Copy link
Contributor

slonopotamus commented Feb 11, 2025

users supply unix paths instead.

That's a kinda strange rule. Can't I have multiple drives in Windows container and want to mount cache to other letter than C:\?

@profnandaa
Copy link
Collaborator Author

users supply unix paths instead.

That's a kinda strange rule. Can't I have multiple drives in Windows container and want to mount cache to other letter than C:\?

I see... makes sense. I had noticed for instance when target=C:/something vs target=/something, they are treated differently for the cache coz of:

mount.CacheID = path.Clean(mount.Target)

I didn't know which other more surprises might be there.

However, for other drive locations, that should still work okay. Let me run some tests.

@profnandaa profnandaa force-pushed the wcow_mount_support branch 2 times, most recently from 42f8214 to ba74219 Compare February 12, 2025 07:04
@profnandaa
Copy link
Collaborator Author

profnandaa commented Feb 13, 2025

No issues mounting from a different drive than C:

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
USER ContainerAdministrator

RUN --mount=type=bind,target=/test type \test\example.txt
> ls -Name E:\sample\
example.txt

> buildctl build --frontend dockerfile.v0 --local context=E:\sample --local dockerfile=. `
--output type=image,name=docker.io/profnandaa/mount-test,push=false `
--progress plain --no-cache

...
#6 [stage-0 2/2] RUN --mount=type=bind,target=/test type testexample.txt
#6 1.387 mounted!!! from E:\
#6 DONE 1.7s

@profnandaa profnandaa force-pushed the wcow_mount_support branch 2 times, most recently from 6fef8df to 59b5b09 Compare February 14, 2025 05:37
@profnandaa
Copy link
Collaborator Author

profnandaa commented Feb 14, 2025

NOTE: with this diff, now supports backslashes on windows paths for mount options. However, you have to change the default escape token from \ to `, e.g.

#escape=`

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
USER ContainerAdministrator

RUN --mount=type=cache,target=C:\mycache echo "hello" > \mycache\foo
# then for options on multilines you have to go with ` instead of \
RUN --mount=type=cache,`
target=C:\mycache dir \mycache\foo

@profnandaa
Copy link
Collaborator Author

I'll carry out the rest of the llb.AddMount support as a separate PR. See #5678 (comment)

This should be ready for review. /cc. @tonistiigi @crazy-max

@profnandaa profnandaa marked this pull request as ready for review February 14, 2025 10:59
Copy link
Contributor

@billywr billywr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@profnandaa profnandaa marked this pull request as draft February 19, 2025 08:50
@profnandaa
Copy link
Collaborator Author

NOTE: taken it back to draft to cover some cases in llb.AddMount that are related to this, will update.

@profnandaa
Copy link
Collaborator Author

With the latest update, you can now set / as source from an image. Initially, this would raise some access denied error like:

error: failed to solve: 
failed to compute cache key: failed to calculate checksum of ref p11yciubfsq2s4670o7j7htlv::shece2fgarkdis8ki7jsuzhvd: 
failed to open /WcSandboxState/Hives/DefaultUser_Delta: 
open C:\Users\annandaa\AppData\Local\Temp\buildkit-mount577988685\WcSandboxState\Hives\DefaultUser_Delta: 
Access is denied.

Now, such a dockerfile can build:

# escape=`

FROM mcr.microsoft.com/windows/nanoserver:ltsc2022
USER ContainerAdministrator

RUN --mount=type=bind,from=docker.io/wintools/nanoserver,`
src=/,dst=/bin C:\bin\Windows\System32\whoami.exe

@profnandaa profnandaa marked this pull request as ready for review February 20, 2025 13:12
@profnandaa profnandaa force-pushed the wcow_mount_support branch 3 times, most recently from 26dfae5 to 7ba4fb1 Compare February 20, 2025 13:37
@@ -862,6 +862,10 @@ func (cc *cacheContext) scanChecksum(ctx context.Context, m *mount, p string, fo
}

func (cc *cacheContext) checksum(ctx context.Context, root *iradix.Node[*CacheRecord], txn *iradix.Txn[*CacheRecord], m *mount, k []byte, followTrailing bool) (*CacheRecord, bool, error) {
// only applies for Windows, it's a no-op on non-Windows.
enableProcessPrivileges()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this be in a more top-level function. This one gets called recursively I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me crosscheck.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You right, it's recursive here. I've taken it up to a more top-level function now.

@@ -119,3 +119,9 @@ func generateCDIOpts(_ *cdidevices.Manager, devices []*pb.CDIDevice) ([]oci.Spec
// https://github.com/cncf-tags/container-device-interface/issues/28
return nil, errors.New("no support for CDI on Windows")
}

func getMountType(_ string) string {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this true only for bind? In that case should be normalizeBindType() with an input parameter comparison.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not just for bind, all of them are referred to as windows-layer by this point. They all fail with:

failed to create shim task: invalid OCI spec - Type 'windows-layer' not supported: unknown

However, I think I can rename this to normalizeMountType instead?

@@ -113,12 +114,12 @@ func dispatchRunMounts(d *dispatchState, c *instructions.RunCommand, sources []*
sharing = llb.CacheMountLocked
}
if mount.CacheID == "" {
mount.CacheID = path.Clean(mount.Target)
mount.CacheID = filepath.Clean(mount.Target)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filepath in here doesn't look right as this code can run in a different OS than daemon or the mount.Target

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was my attempt to have the Windows path resolve to the same default cache ID e.g.

C:/temp -> C:\\temp

though this quickly falls apart with cases like /temp -> \\temp.

Best guarantee is just for the user to set their own IDs if they are using different path schemes. Will add that as part of the documentation note.

Let me revert back to path.Clean.

Currently, mounts are not supported for WCOW builds,
see moby#5678. This commit introduces support for
bind and cache mounts. The remaining two require
a little more work and consultation with the platform
teams for enlightment.

WIP Checklist:

- [x] Support for bind mounts
- [x] Support for cache mounts
- [x] add frontend/dockerfile integration tests
- [x] add client integration tests (not all, `llb.AddMount` not
  complete)

Fixes moby#5603

Signed-off-by: Anthony Nandaa <[email protected]>
@tonistiigi tonistiigi merged commit 26b1f2b into moby:master Feb 20, 2025
104 checks passed
@profnandaa profnandaa deleted the wcow_mount_support branch February 24, 2025 17:40
profnandaa added a commit to profnandaa/buildkit that referenced this pull request Apr 4, 2025
After completing support for `llb.AddMount` in moby#5708 --
this made possible to add some more `client` integration tests
that were making `llb.AddMount` calls.

Most of the tests below are related to this:

- [x] testCacheExportCacheKeyLoop
- [x] testOCILayoutSource
- [x] testBuildMultiMount
- [x] testTarExporterSymlink
- [x] testCacheExportIgnoreError
- [x] testBasicCacheImportExport
- [x] testUncompressedLocalCacheImportExport
- [x] testImageManifestRegistryCacheImportExport
- [x] testBasicLocalCacheImportExport
- [x] testBasicInlineCacheImportExport
- [x] testRegistryEmptyCacheExport
- [x] testCachedMounts
- [x] testDuplicateCacheMount
- [x] testRunCacheWithMounts
- [x] testMountWithNoSource
- [x] testProxyEnv
- [x] testRelativeMountpoint
- [x] testValidateDigestOrigin
- [x] testExportAnnotations
- [x] testExportAnnotationsMediaTypes
- [x] testAttestationDefaultSubject
- [x] testAttestationBundle
- [x] testLLBMountPerformance

Skipped tests (due to registry setup issue, to be addressed separately):
- testUncompressedRegistryCacheImportExport
- testBasicRegistryCacheImportExport
- testMultipleRegistryCacheImportExport

Related to moby#5678

Signed-off-by: Anthony Nandaa <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WCOW: RUN with bind/cache mounts
5 participants