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

Add support for platform (os and architecture) on image import #43103

Merged
merged 4 commits into from
Jan 24, 2022

Conversation

thaJeztah
Copy link
Member

@thaJeztah thaJeztah commented Dec 23, 2021

fixes #42813
fixes docker/cli#3408

Commit 0380fbf (part of #34642) added the ability to pass a --platform flag on docker import when importing an archive. The intent of that commit was to allow importing a Linux rootfs on a Windows daemon (as part of the experimental LCOW feature).

A later commit (337ba71, part of #37350) changed some of this code to take both OS and Architecture into account (for docker build and docker pull), but did not yet update the docker image import.

This patch updates the import endpoitn to allow passing both OS and Architecture. Note that currently only matching OSes are accepted, and an error will be produced when (e.g.) specifying linux on Windows and vice-versa.

- How to verify it

A test has been added, which can be run with:

make DOCKER_GRAPHDRIVER=vfs TEST_SKIP_INTEGRATION_CLI=1 TESTFLAGS='-test.run TestImportWithCustomPlatform' test-integration

...

INFO: Testing against a local daemon
=== RUN   TestImportWithCustomPlatform
=== PAUSE TestImportWithCustomPlatform
=== CONT  TestImportWithCustomPlatform
=== RUN   TestImportWithCustomPlatform/#00
=== RUN   TestImportWithCustomPlatform/_______
=== RUN   TestImportWithCustomPlatform//
=== RUN   TestImportWithCustomPlatform/linux
=== RUN   TestImportWithCustomPlatform/LINUX
=== RUN   TestImportWithCustomPlatform/linux/sparc64
=== RUN   TestImportWithCustomPlatform/macos
=== RUN   TestImportWithCustomPlatform/macos/arm64
=== RUN   TestImportWithCustomPlatform/nintendo64
--- PASS: TestImportWithCustomPlatform (1.44s)
    --- PASS: TestImportWithCustomPlatform/#00 (0.14s)
    --- PASS: TestImportWithCustomPlatform/_______ (0.00s)
    --- PASS: TestImportWithCustomPlatform// (0.00s)
    --- PASS: TestImportWithCustomPlatform/linux (0.13s)
    --- PASS: TestImportWithCustomPlatform/LINUX (0.13s)
    --- PASS: TestImportWithCustomPlatform/linux/sparc64 (0.13s)
    --- PASS: TestImportWithCustomPlatform/macos (0.03s)
    --- PASS: TestImportWithCustomPlatform/macos/arm64 (0.00s)
    --- PASS: TestImportWithCustomPlatform/nintendo64 (0.00s)
PASS

- Description for the changelog

- A picture of a cute animal (not mandatory but encouraged)

@thaJeztah thaJeztah added status/2-code-review kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. impact/changelog area/images impact/documentation labels Dec 23, 2021
@thaJeztah thaJeztah added this to the 21.xx milestone Dec 23, 2021
Copy link
Member

@samuelkarp samuelkarp left a comment

Choose a reason for hiding this comment

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

Typo in commit message ("endpoitn") but otherwise LGTM.

@thaJeztah
Copy link
Member Author

Typo in commit message ("endpoitn")

Ah! 🤦. I think I'll leave that one be 😅

@thaJeztah
Copy link
Member Author

@tonistiigi ptal

platform = &specs.Platform{}
}
if platform.Architecture == "" {
// TODO platforms.Normalize() is inconsistent: it sets default OS, but does not set default Architecture.
Copy link
Member

Choose a reason for hiding this comment

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

what case is this?

Copy link
Member Author

Choose a reason for hiding this comment

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

This was mostly an observation; the Normalize() code is here;

func Normalize(platform specs.Platform) specs.Platform {
platform.OS = normalizeOS(platform.OS)
platform.Architecture, platform.Variant = normalizeArch(platform.Architecture, platform.Variant)

That code calls both normalizeOS() and normalizeArch(); I would expect those to act the same, but where normalizeOS() both normalizes the OS, and sets a default;

func normalizeOS(os string) string {
if os == "" {
return runtime.GOOS
}

But normalizeArch() only "normalizes" (but does not set defaults);

func normalizeArch(arch, variant string) (string, string) {

I would've expected them both to do the same (fill in missing fields if not set, and normalize the fields where needed), so if no architecture is set, it would set the local architecture as default.

Copy link
Member

Choose a reason for hiding this comment

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

Parse() adds the same runtime.GOARCH if one is not set in the string so this should not be needed.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, but that's assuming it always originates from a string that's parsed using that function 🤔, so it's either string -> parse (which also normalises), or Normalize() which normalises, but slightly different.

config, err := dockerfile.BuildFromConfig(&container.Config{}, changes, os)
// Normalize platform - default to the operating system and architecture if not supplied.
if platform == nil {
platform = &specs.Platform{}
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 platforms.DefaultSpec()?

Copy link
Member Author

Choose a reason for hiding this comment

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

Ah, hm.. yes, perhaps I could've gone for DefaultSpec(). My train of thought was to have the platforms.Normalize() take care of filling in the missing bits, but I guess if we have no platform at all, we could as well use DefaultSpec(). Let me have a look at that

@thaJeztah
Copy link
Member Author

@tonistiigi updated; PTAL

Comment on lines +7683 to +7696
Platform in the format os[/arch[/variant]].

When used in combination with the `fromImage` option, the daemon checks
if the given image is present in the local image cache with the given
OS and Architecture, and otherwise attempts to pull the image. If the
option is not set, the host's native OS and Architecture are used.
If the given image does not exist in the local image cache, the daemon
attempts to pull the image with the host's native OS and Architecture.
If the given image does exists in the local image cache, but its OS or
architecture does not match, a warning is produced.

When used with the `fromSrc` option to import an image from an archive,
this option sets the platform information for the imported image. If
the option is not set, the host's native OS and Architecture are used
for the imported image.
Copy link
Member Author

Choose a reason for hiding this comment

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

Also tried to improve the description here (but it's complicated to describe the full behaviour as there's many variations possible due to the same endpoint being used both for import and pull 😞)

@thaJeztah
Copy link
Member Author

Seeing more failures like this on Windows (not sure what changed; we updated the docker version on the Windows machines, but no other changes afaik);

=== RUN   TestDockerSuite/TestCpRelativePath
    check_test.go:170: assertion failed: error is not nil: Error response from daemon: container d14484dbcaa7e7d302c1182e17b30e1a87d283475f356db80b903602d1976871: driver "windowsfilter" failed to remove root filesystem: failed to detach VHD: failed to detach virtual disk: The device is not ready.: rename D:\CI\PR-43103\3\daemon\windowsfilter\d14484dbcaa7e7d302c1182e17b30e1a87d283475f356db80b903602d1976871 D:\CI\PR-43103\3\daemon\windowsfilter\d14484dbcaa7e7d302c1182e17b30e1a87d283475f356db80b903602d1976871-removing: Access is denied.: failed to remove d14484dbcaa7e7d302c1182e17b30e1a87d283475f356db80b903602d1976871
    --- FAIL: TestDockerSuite/TestCpRelativePath (3.01s)

@thaJeztah
Copy link
Member Author

win-2022/c8d failed to build the Dockerfile (again, similar failiures as I've seen elsewhere with permission denied on renaming files);

INFO: Downloading git...
INFO: Downloading go...
INFO: Downloading compiler 1 of 3...
INFO: Downloading compiler 2 of 3...
INFO: Downloading compiler 3 of 3...
INFO: Extracting git...
Move-Item : Access to the path 'C:\git-tmp\tools\usr' is denied.
At line:1 char:2427
+ ... tory C:\git | Out-Null; Move-Item C:\git-tmp\tools\* C:\git\.; Remove ...
+                             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (C:\git-tmp\tools\usr:DirectoryInfo) 
    [Move-Item], IOException
    + FullyQualifiedErrorId : MoveDirectoryItemIOError,Microsoft.PowerShell.Commands.MoveItemCommand

win-2022; similar failure, but during a test:

=== FAIL: github.com/docker/docker/integration-cli TestDockerSuite/TestCreateArgs (0.24s)
    check_test.go:170: assertion failed: error is not nil: Error response from daemon: container 246731ba67ccd21726ce31502329ce11628a20b35dc7fe2f8a42084e39882154: driver "windowsfilter" failed to remove root filesystem: failed to detach VHD: failed to detach virtual disk: The device is not ready.: rename D:\CI\PR-43103\5\daemon\windowsfilter\246731ba67ccd21726ce31502329ce11628a20b35dc7fe2f8a42084e39882154 D:\CI\PR-43103\5\daemon\windowsfilter\246731ba67ccd21726ce31502329ce11628a20b35dc7fe2f8a42084e39882154-removing: Access is denied.: failed to remove 246731ba67ccd21726ce31502329ce11628a20b35dc7fe2f8a42084e39882154
    --- FAIL: TestDockerSuite/TestCreateArgs (0.24s)

win-2022: known flaky test:

=== FAIL: github.com/docker/docker/integration-cli TestDockerSuite/TestSlowStdinClosing (0.91s)
    docker_cli_run_test.go:4177: assertion failed: error is not nil: exit status 127
    --- FAIL: TestDockerSuite/TestSlowStdinClosing (0.91s)

windows rs5 timed out after 2 hours

@thaJeztah
Copy link
Member Author

@tonistiigi @tianon PTAL

Comment on lines 62 to 65
if platform.Architecture == "" {
// TODO platforms.Normalize() only sets default OS, but does not set default Architecture if missing.
platform.Architecture = runtime.GOARCH
}
Copy link
Member Author

Choose a reason for hiding this comment

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

Discussing with @tonistiigi to remove this part, and make it the caller's responsibility to fill in the fields

// TODO platforms.Normalize() only sets default OS, but does not set default Architecture if missing.
platform.Architecture = runtime.GOARCH
}
p = platforms.Normalize(*platform)
Copy link
Member Author

Choose a reason for hiding this comment

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

This can also be removed (assuming that the caller has called Parse()

@thaJeztah
Copy link
Member Author

@tonistiigi updated as discussed

// Normalize platform - default to the operating system and architecture if not supplied.
var p specs.Platform
if platform == nil {
p = platforms.DefaultSpec()
Copy link
Member

Choose a reason for hiding this comment

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

you need to set platform

This error is meant to be used in the output stream, and some comments
were added to prevent accidentally using local variables.

Renaming the variable instead to make it less ambiguous.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
Commit 0380fbf added the ability to pass a
--platform flag on `docker import` when importing an archive. The intent
of that commit was to allow importing a Linux rootfs on a Windows daemon
(as part of the experimental LCOW feature).

A later commit (337ba71) changed some
of this code to take both OS and Architecture into account (for `docker build`
and `docker pull`), but did not yet update the `docker image import`.

This patch updates the import endpoitn to allow passing both OS and
Architecture. Note that currently only matching OSes are accepted,
and an error will be produced when (e.g.) specifying `linux` on Windows
and vice-versa.

Signed-off-by: Sebastiaan van Stijn <[email protected]>
Copy link
Member

@tianon tianon left a comment

Choose a reason for hiding this comment

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

👍

@thaJeztah
Copy link
Member Author

Windows failure is unrelated (known flaky test)

=== RUN   TestDockerSuite/TestSlowStdinClosing
    docker_cli_run_test.go:4177: assertion failed: error is not nil: exit status 127
    --- FAIL: TestDockerSuite/TestSlowStdinClosing (4.54s)

@thaJeztah
Copy link
Member Author

@tonistiigi PTAL

@paralin
Copy link

paralin commented Aug 4, 2022

This seems to still ignore the --platform in docker import with linux/386 as the platform... it shows up as amd64.

@pfuntner
Copy link

pfuntner commented Aug 4, 2022

I also still see the problem with Docker version 20.10.14, build a224086 on Ubuntu 20

@thaJeztah
Copy link
Member Author

This change is only in master, and not the 20.10 releases, so that's expected.

gitlab-runner-bot pushed a commit to gitlabhq/gitlab-runner that referenced this pull request May 8, 2023
According to moby/moby#43103, when --platform
was initially added to docker import, it only honored the OS portion
of the argument, and Architecture was silently ignored. That PR, which
resolved the issue and made import honor the architecture segment, was
merged for 23.0.0. Therefore, in order for docker import --platform to
resolve https://gitlab.com/gitlab-org/gitlab-runner/-/issues/30869, we
must use at least Docker 23.0.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/images impact/changelog impact/documentation kind/enhancement Enhancements are not bugs or new features but can improve usability or performance. status/2-code-review
Projects
None yet
6 participants