February 7, 2018·5 min read·engineeringdockermanifestsmultiarch

Docker adds a CLI for publishing multi-platform manifest lists

Docker 18.02 introduces experimental commands for creating, inspecting and publishing manifest lists. Platform selection becomes part of image publication without requiring a new combined filesystem image.

Publishing the same application for different processor architectures creates a naming problem as well as a build problem. Each resulting image has its own contents and platform requirements, but users benefit from a common application reference. Docker 18.02 adds an experimental docker manifest command that lets publishers assemble that reference. The February 7 release notes identify the command alongside a new Compose file version, but the manifest work changes a particularly useful part of the publication workflow.

A manifest list records references to individual image manifests with information about their target platforms. It does not combine their files into a larger filesystem. That distinction preserves the separate image artifacts while giving a registry a common object that clients can use through an image name. The original implementation and command documentation describe the operations that Docker now exposes directly.

I regard Docker's image format as one of its most useful contributions. Packaging an environment is more useful when the reference to that environment also expresses the available platforms. A publisher should be able to document one application release without forcing every consumer to learn a separate architecture-specific naming convention.

Publication follows the individual builds

The command documentation divides the work into creating a local manifest list, optionally annotating its entries, and pushing it to a registry. The constituent images already exist as image references. create establishes a local list from those references. annotate supplies or overrides platform information, and push publishes the list.

For a publisher who has already pushed two equivalent application images, the basic sequence can look like this. The repository names are illustrative, and the images must exist before assembling the list.

docker manifest create registry.example.com/service:release \
  registry.example.com/service:amd64 \
  registry.example.com/service:arm
docker manifest annotate registry.example.com/service:release \
  registry.example.com/service:arm --os linux --arch arm
docker manifest push registry.example.com/service:release

This sequence uses the commands described in the original patch. It assumes that the experimental CLI commands are available. No step builds an executable or translates an existing binary to another architecture. The publisher remains responsible for producing each constituent image with the behavior promised by the common release name.

That responsibility follows from what a manifest list contains. A valid collection of references does not establish that the referenced programs are equivalent. The CLI can package the selection metadata, but application compatibility still belongs to the build and release process. If one image has a different configuration or application version, grouping it under the same release reference does not remove that difference.

The distinction also helps explain why annotations deserve attention. The documented options include operating system, architecture and architecture variant, with operating system feature information available as well. These values describe where an entry belongs. Editing an annotation changes the description used to identify the image, without changing the executable inside it.

Inspection exposes the selection metadata

docker manifest inspect can inspect an individual manifest or a manifest list. The original documentation shows a single image manifest containing its configuration reference and layer descriptors. Its verbose example also includes the image reference, digest and platform. A list contains descriptors for its constituent manifests, including their platform information.

This provides a useful distinction during release investigation. Inspecting the list answers which platform entries the publisher included. Inspecting one constituent image answers questions about that image's manifest. A common tag alone cannot show that all intended platforms have entries, so the structured list is a more direct account of what was published.

The command accepts image names and references by digest, according to its initial documentation. That gives publication tooling a way to identify a particular manifest separately from the human-readable release tag. A list assembled from precise references can express the intended collection without relying solely on the names used for intermediate platform builds. The documented push --purge option removes the local list after publication. This makes the lifetime of the local assembly explicit, while the published list remains a separate registry object that can be inspected through its registry reference.

I prefer this separation because it keeps the published object understandable. The filesystem layers remain associated with their individual images. The manifest list records the choice among those images, and its own inspection output makes that choice visible to someone investigating a release.

Registry access happens in the CLI

The manifest commands communicate directly with a registry. Their documentation explicitly says they cannot ask the engine for its list of allowed insecure registries. As a result, registry access policy for these commands cannot be inferred from the daemon configuration that an operator might already have set for other image operations.

The initial command implementation provides an --insecure option on the operations that contact a registry. Its documentation requires that option separately for each applicable transaction. Annotating a local list does not require it, because annotation changes local data. A registry query during creation and the later push are separate interactions.

This is a practical consequence of the command's architecture. A manifest operation can fail against a private registry even when a different engine-mediated operation works against that registry. The appropriate explanation is the different connection path and configuration, rather than a problem with the application layers. The published documentation also states that the engine does not use the locally stored manifest list for docker pull, so creating a local list does not itself change registry-visible image selection.

Compose gains a separately versioned capability

The same Docker release adds Compose file format 3.6 and support for a tmpfs mode in Compose configuration. Ethan Haynes's CLI patch for the schema and conversion work includes the new schema. This is a separate configuration change, with a different purpose from assembling image manifests.

Keeping those concerns distinct makes the release easier to interpret. Compose describes application deployment configuration, while the manifest command describes the platform alternatives available under an image reference. A service definition can name the common published image without containing the construction of its manifest list. The publisher handles that construction after the platform-specific images are available, and registry inspection can then show the entries consumers will encounter.