Skip to content

Proposal: Add --platform parameter to support multiple OS platforms for build/run/pull/import #33854

@PatrickLang

Description

@PatrickLang

As mentioned in #33850, we're building support to be able to run images from multiple platforms (Linux & Windows) managed by a single Moby engine. This would need some changes to the CLI & APIs to make sure that the user can choose between platforms on a per-container basis when there is a multiarch image available such as microsoft/dotnet

Running Containers

In this proposal docker run should support running multiple platforms on a single machine.

Both of these would work on a Windows node:

docker run -it alpine /bin/bash
docker run -it microsoft/nanoserver powershell.exe

Neither of these are multi-arch images, so the OS will be determined from the image metadata.

API

The HostConfig definition is used in /containers/create, and already includes the
isolation parameter. The proposal is to add a new property platform.


Building containers

In this proposal, docker build would use the same --platform parameter as docker run to override platform when needed.

API

/containers/build doesn't use HostConfig as /containers/create does, so platform needs to be added to the call.


Choosing the platform & multi-arch images

Multi-arch images bring an extra layer of complexity to the build and run actions. If
the image has a multi-arch manifest, then there's a chance the node could run multiple images.

Here's a decision tree for how the platform is determined for a build or run action:

  1. Runtime parameter - docker build --platform=... or docker run --platform=...
  2. Infer from Dockerfile & image metadata - FROM microsoft/windowsservercore or FROM alpine or other image
  3. If single-arch, use Image.Os from image definition
  • If not in daemon's PlatformCapability list, fail
  • Note: You can also use a specific image:tag to force the platform this way
  1. If multi-arch, then
  • Use default container platform from daemon config DefaultPlatform
  • If not configured, then DefaultPlatform = OSType from daemon

Example - Building a Windows container

In the simple case, the platform will be chosen based on the FROM image.

For this Dockerfile:

FROM microsoft/windowsservercore:10.0.14393.976
...

And this build command:

docker build .
  • On a Windows host, the image runs as normal. Metadata matches host OS
  • On a Linux host, the image platform != host platform. Pull of microsoft/windowsservercore fails

Example - Building a Linux container

FROM alpine:latest
...
docker build .
  • On a Windows host, alpine is pulled and stored to disk
    • As the container is started, Hyper-V isolation uses the default Linux runtime to run the container
  • On a Linux host, the image platform != host platform. Pull of microsoft/windowsservercore fails

Recommendations for build & dev tools

Many tools such as IDEs, CI/CD pipelines, and more need to be able to handle building either
type of container. Here's a few proposed best practices to make automation work well.

Dockerfile

  • If a project will only ever target a single OS, use the most restrictive FROM statement
    • FROM alpine
    • FROM microsoft/dotnet:alpine
    • FROM microsoft/dotnet:nanoserver
  • If it will be multiarch, use FROM a multiarch image

docker build/run

  • Single arch - (optional) specify --platform=...
  • Multi arch - use multiple build/run commands with different --platform=... parameters

Pulling & importing containers

The same api /images/create is used for both operations. The same order of precedence
as build and run should be followed to figure out which specific image to pull.
When pulling an image from a repo, the metadata includes the platform.

However, in the case of docker import this metadata is not known. The default should be
the platform of the host, but can be overridden with --platform.

Note: Windows doesn't support docker import today at all

Examples:

docker pull --platform linux microsoft/dotnet-runtime will force pulling the Linux
version of this multiarch image.

docker import --platform linux dotnet-runtime.tgz would force importing to use the
Linux platform image store.


Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions