-
Notifications
You must be signed in to change notification settings - Fork 41
Description
It's possible for containers to be specified in a 'manifest list' - a set of container image manifests that represent the same application on different underlying OS/hardware configurations.
Fundamentally this would be something like a multitargeted build. For some selection of OS/OSVersions and Architectures we'd need to orchestrate
- building the app for that os/version/architecture
- publishing a container image for that os/version/architecture
then, once all of those were done, we'd need to
- create a new 'manifest list',
- add each of the created images to the list,
- ensure each one was 'annotated' with the correct os/platform/etc annotations, and
- push the manifest list to the registry
There are a couple hurdles we'd need to cover:
- if we would like to perform this by default for projects that specify multiple RIDs, then we may need a concept of a cross-RID/cross-TFM publish. This doesn't exist right now, and in fact is explicitly stopped by the cross-targeting targets in the .NET SDK.
- if we modeled this as a different, standlone target, then we wouldn't need to tie it to 'publish' necessarily, but we might lose the benefit of associating with 'publish' as a concept
- I'm unsure how much users would use this - is it worth pioneering a potentially-new publishing concept?
- This would bring us parity with Jib and Ko - maybe parity is enough of a motivator
Other requirements:
- Need to ensure that tarball export works for multi-arch images as well.
- This work might also be useful/necessary for users on the 8 LTS, so we should strongly consider keeping the NuGet package and making that package work seamlessly with 8 and 9 SDKs. We should do this work off of the .NET SDK 8.0.4xx branch and merge forward to 9.0 as a result.
Proposal
The gesture we want users to perform for multi-arch manifest publishing is
dotnet publish -t:PublishContainer
i.e. the same gesture they use today. To do this, we should change the implementation of the current PublishContainer
Target from its current behavior of 'publish a single image for a single RID' to more of a decision-making target.
PublishContainer
should
- check if the project is currently in multi-TFM state. if so, error out. we require specifying a single specific TFM for now.
- check if the project is in a 'multi RID' state - meaning the project does not have a
RuntimeIdentifier
specified and does have eitherContainerRuntimeIdentifiers
orRuntimeIdentifiers
specified. If so, invoke a new"_BuildMultiImageManifest"
target - otherwise, the project is in a single-RID, single-TFM state. In this state, invoke a new
"_BuildSingleContainer"
Target whose behavior is exactly the same as the single-image version ofPublishContainer
today.
An example of this per-scenario break-out is here.
Anticipated hurdles
Defaulted RIDs
The SDK does not have a concept of 'multi-RID' publish, and so today there are several places where it has assumed that the publish
gesture implicates the desire for a single RID. The main way this negatively impacts us is the UseCurrentRuntimeIdentifier
property, which is inferred as true
here and ends up erroneously pinning us to a single RID. Setting it explicitly to false in the project files works around this.
PublishSingleFile
If PublishSingleFile is set and UseCurrentRuntimeIdentifier
is not (as mentioned above), there is a mismatch in expectations. For now, for scenarios like our initial set, users may have to condition properties to only light up when the RID-specific build(s) are being done (for example, adding a Condition="'$(RuntimeIdentifier)' != ''"
to several properties.
This is a symptom of the overall Publishing mechanisms of the .NET SDK not being designed for multi-RID publish today. In general, I think many SDK checks could be deferred to the 'inner RID' builds with no loss of intent, but we may have to push for this functionality in phases.
BuildMultiImageManifest
This target broadly should do two things
- orchestrate the building of N RID-specific images, collecting output information about them
- N in this case is either the ContainerRuntimeIdentfiers Property (invented for this feature), or the RuntimeIdentifiers property (existing)
- combine those outputs into a single Manifest List structure
- orchestrate the export of the RID-specific images and the Manifest List to a registry, local daemon, or tarball in the correct order
Ideally, it would also unify any shared work that may happen during the multiple single-RID publishes into one unit of work that is shared. A specific example of this is
- determination of Base Image to and fetching of the various manifests for that Base Image
- tracking and parallelization of image layers that for the base Image(s)
Characteristics of the Manifest List
- It should use the OCI Image Index schema, not the Docker Manifest List structure, if at all possible
- It should contain N manifests, one for each RID created. These should map to the existing 'PlatformSpecificManifest` structure we know today
- It should contain annotations matching all of the conventionally-applied labels that we support for individual images
Visual Aids
flowchart TD
A[Start Build] --> B[dotnet publish -t:PublishContainer]
B --> D[Publish for linux-x64]
D --> E[Package a linux-x64 container]
B --> F[Publish for linux-arm64]
F --> G[Package a linux-arm64 container]
G --> I[Package both containers into an image index]
E --> I
I --> H[Push containers and image index to registry]
Work Stages/Milestones
We should have two phases of the work - initial MVP and then productizing.
Initial MVP
In this stage we implement the multi-RID aware publishing feature with external registries as the primary destination - so no pushing to local daemons or exporting to tarballs. This is the most well-known area of development. Once this is implemented, we can hand a preview nupkg over to the internal partner teams that want to test the feature so they can begin validation.
Productizing
In this stage we would implement tarball export and local-Daemon export of manifest lists, as well as full testing and error handling scenarios.