-
Notifications
You must be signed in to change notification settings - Fork 1.1k
.NET 8: MSBuild improvements for containers #26249
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
Comments
It could be useful to do perf tests for this with big and small projects. I assume More exotically, we'd want to test with Looks related: #4140 |
@DamianEdwards was telling me that this "container experience" exactly maps to "CI experience". The patterns and needs are identical. I can see that. |
It seems there are certainly similarities. Our .NET default yaml files for GitHub Actions and AzDO Pipelines break out into separate steps for restore, build, test, publish, etc. along with opted out of the implied dependent stages for the later steps (e.g. |
Yes. That scenario exactly matches what I'm hoping to improve. |
This has confused me since the beginning. Whenever I stand up a new repo I always delete like three redundant things. Do we have background on why this was thought to be a good idea? Is it more than "in the ancient days you had to run For containers with layer caching I think it makes some sense, though for any nontrivial repo I'd bet the caching is causing incorrect builds (because the default prior step @richlander didn't show above is |
This is an interesting idea. How could it work? What consistency guarantees would be provided? What constraints on user operations between operations would be imposed? |
@rainersigwald the thinking behind it is that it makes it much clearer when a failure occurs where it happened, as the failed stage will be immediately apparent, rather than a single stage doing |
That doesn't seem worth the cost of increasing the likelihood of an inconsistency failure in a later step, to me. |
This is true but also the state of the art, to some degree. With
These all have side-effects that need to be considered.
User cannot change any files. With a This much like an official build where you use sourcelink where the strong intent/implication is that the resultant binary is a faithful reproduction of a given commit. |
Avoiding a failure due to inconsistency is a motivator of this proposal. |
Sure, so I'd like to ensure "merge steps so you don't have inconsistencies" is on the table as an option. |
I want to be super clear that you don't need parent directories here. If you use Central Package Version Management, for instance, copying |
All true. Perhaps we need to find some better samples to point to that add additional MSBuild assets. @glennc and I have been talking about this exact issue for 5+ years. It's challenging. Also, the additional |
Indeed. And I'd like to ensure that the trade-offs associated with any option are explored and acknowledged. Adding @timheuer as he's involved in the these defaults for Actions/Pipelines today too. |
With |
Some of these concerns might be mitigated by the SDK container work that we're targeting for 7. Part of the motivation here is to get the right build assets at the end of the build into the correct places in the container, and that's the scenario we're optimizing for in this effort. We've talked a bit about what an 'eject button' for the SDK containerization might look like, and that often looks like generated Dockerfile that is 100% correct for your particular project. It might be generated for the user via something like |
That seems complementary. Even if we generate a Dockerfile, we want it to be pretty, understandable and easily editable. I'm proposing making the SDK work well for immutable environments. That seems like its still a good direction. As others stated, there are other common environments where that is valuable. |
We mostly cache the restore into a separate layer and sometimes, very rarely the artefacts too when we want so many test suites to run on top of a finished build. The problems I found when doing the above is that I had to separate NuGet or paket restores out from I also foresaw that separate directories are needed for isolating things that are used in a build but doesn't need several entries in various ignore files or overriding them anywhere else. We should only have 2 top most folders holding the Yes, it's a breaking change but it's possible to do it in a non-breaking way that does not break existing builds through opt-in mechanism. The first step is to remove the dependency of The 10-foot ViewI already had a prototype under MSBuild repo but it needed separate props/targets for easy maintainance. I could've put all logic in existing props/targets files but that meant heavy maintainance cost. I also didn't want to introduce new props/targets in the root when we already have a proposal to pack the common props and targets into an SDK. I tried packing them into an SDK but since I don't know much about MSBuild's build infra, I gave up half way. Tasks needed to be refactored to work as an SDK package. I'm also aware that MSBuild is being deployed in more than one way. I'm interested in doing both but need some pointers from the person who knows the build infra best. Finally, the end goal, atleast I envision, is to have MSBuild |
You could use |
I thought about this more. I no longer really like the idea I proposed. The This is the key idea ... specifying characteristics for my build once and then not needing to do so again: dotnet restore -c Release -r linux-x64 --self-contained false
dotnet publish However, tying that to export DOTNET_CLI_ARGS="-c Release -r linux-x64 --self-contained false"
dotnet restore
dotnet publish |
Uh oh!
There was an error while loading. Please reload this page.
.NET 8: MSBuild improvements for containers
I get a lot of my inspiration for SDK improvements from container workflows. Containers constrain the MSBuild environment considerably, mostly due to the
docker build
context. That makes idiomatic experiences like global config at root less than convenient or performant. Separately, MSBuild is not optimized for an immutable by default build environment, which docker offers as a strength.Samples
Let's take a look at one our Docker samples:
Here's another one:
There are two important aspects at play:
no-blah
commands to ensure no repeated work or bookkeeping in an immutable environment.Ideally, would be a way to lock a configuration and to tell MSBuild that that we're in an immutable environment.
Locking in a configuraton
Directory.Build.props
enables locking in a configuration. It's not always convenient to create a file for that purpose. However, that's the effect that I'm after.Instead, something like the following would be awesome:
That's an improvement since the configuration is just specified once. However, it doesn't feel right. I don't want a new command. I just want to be able to lock-in my configuration with an existing command.
Like:
Immutable mode
MSBuild (and possibly NuGet) does significant work to check if the environment has changed since the last run of the command. The time since the last command was run could have been as short as <1s ago! There are reasons why that behavior is a good one, but it's also very conservative.
Today, we have
--no-restore
and--no-build
commands. That's a lot of extra ceremony.Here's a naive option:
That's not much of an improvement on
--no-restore
andno-build
.How about:
That's looking much better. MSBuild can manage states for me. In this mode, I would expect that only the first
dotnet build
would run and the second two would just early-exit. Same with the implicitbuild
withinrestore
. Actually, same with the implicitrestore
withinbuild
andpublish
.Pulling it all together
The initial idea with locking in a configuration with
restore
is likely a breaking change. Let's avoid that.We could introduce a new
--lock
argument onrestore
. It locks in a configuration untilrestore
is run again. That overloadsrestore
a bit, but its also the most basic command. I think it works.Our experience now looks like the following
It's reasonable for
--immutable
to also force--lock
. That enables the following experience.build
is only run once, which includesbuild
withinpublish
.Clearly, I don't want to run
dotnet build
multiple times. That's not the point I'm trying to make.Really, I want just the following:
I want to ensure that three things:
Closing thoughts
These changes have the potential to make it so much easier to make a high-performance docker build (with MSBuild). I'm certain we can make improvements here.
The examples are centered exclusively on locking with
restore
. That's likely not a good idea. We'd want to rationalize that.These types of experiences always break with
dotnet test
and (to a lesser degree)dotnet run
. We'd need to validate that. Both are reasonable to run within containers (particularlydotnet test
.The text was updated successfully, but these errors were encountered: