dotnet-buildtools-prereqs-docker icon indicating copy to clipboard operation
dotnet-buildtools-prereqs-docker copied to clipboard

Consider utilizing parameterized Dockerfiles as a means to reduce duplication

Open MichaelSimons opened this issue 6 years ago • 3 comments

Investigate whether or not utilizing parameterized Dockerfiles would reduce the amount of duplication and ease the maintenance cost of the Dockerfiles. It may help increase the developer productivity.

An example of this would be to parameterize the Alpine base image tag within the Alpine Helix Dockerfiles. The base image tag appears to be the only thing different between the various versions

alpine 3.11 amd64 vs alpine 3.10 amd64

The FROM image argument value can be specified within the manifest.

MichaelSimons avatar Jan 16 '20 19:01 MichaelSimons

First of all, my +1 for proposing to DRY stuff in this repo, it is getting baggy by day, and I think it is possible to accomplish true DRY'ness while maintaining the tidiness/readability.

After experimented a few approaches in CI runs of recent PRs and seeing what is and isn't possible/supported, I have a few ideas that I'd like to share, which I believe would scale with a few moving parts.

Here are my 2 cents...

There are two kinds of duplicates which I think worth pursuing:

  1. docker commands; which we solve with WithNode and helix relying on (otherwise useless) amd64 base image.
  • Solution: for this, we can (and in this day and age, should) use one physical Dockerfile with multi-stages, without needing to publish an intermediate/base container to the registry.
  1. dependency list per OS (across versions x architectures with minor exceptions here and there).
  • Background: Dockerfile grammar does not provide INCLUDE or more accurately PASTE idioms for templating OOTB. Their official guidance for syntax extensibility is that we can create our own custom ones in frontend, use # syntax directive in Dockerfile and define some custom semantics on top, which sounds too much (maintenance) work for (relatively) a little gain.
  • Solution: given the above situation, the most natural thing to use is preprocessor, which any C compiler on any platform can expand (think e.g. an #include "../helix_common_dependencies" line in a Dockerfile.in). The semantics of preprocessor are well-established, well-documented and well-understood including its limitations, but it quite adequately fulfills what we need here. Using this we can describe the whole platform matrix as chain of logical partial files and calling clang -E Dockerfile.in -D SomeThingReadFrom_manifest_json... to expand/emit the real Dockerfiles on-the-fly (which will be .gitignore'd) before invoking buildx etc. This likely has zero negative effects on caching. This will deduplicate it all and only requires a good, understandable logical structuring of (partial) files; which we anyway have to do with other options.
    • inspired by https://github.com/moby/moby/issues/735#issuecomment-508028941.

am11 avatar Sep 03 '21 14:09 am11

Note that our infrastructure does now have support for Dockerfile templates and are being used by the dotnet/dotnet-docker and microsoft/dotnet-framework-docker repos. See documentation and example template.

mthalman avatar Sep 03 '21 15:09 mthalman

Great! I can attempt to convert Alpine 3.13 and 3.14 to use the templates and DRY out the repetitions. Most like would need your help, @mthalman on passing build-time vars correctly. :)

I presume Alpine 3.12 and below can probably be deleted, based on https://github.com/dotnet/core/blob/main/release-notes/6.0/supported-os.md#linux; that .NET 6 only supports Alpine 3.13+?

am11 avatar Sep 10 '21 17:09 am11