Skip to content

Enable container tunnel by default#14557

Merged
karolz-ms merged 10 commits intomainfrom
dev/karolz/faster-tunnel
Feb 25, 2026
Merged

Enable container tunnel by default#14557
karolz-ms merged 10 commits intomainfrom
dev/karolz/faster-tunnel

Conversation

@karolz-ms
Copy link
Member

This PR enables Aspire container tunnel feature by default. This allows containers to consume resources on the host network. Without the tunnel (current default) it only works with Docker Desktop, because other container orchestrators lack the necessary bridging functionality.

To make it happen I made several changes and bug fixes to app model APIs,DcpExecutor, and tests. Most importantly:

  1. There is a new API for efficiently computing dependencies of a set of resources.
  2. If dashboard resource is present in the workload, dashboard endpoints become part of the model. This allows them to be tunneled into container network space.
  3. DCP model creation is now done as a "set of interdependent Tasks", with finer granularity and greater parallelism. This allows us to treat tunnel-dependent vs tunnel-independent containers differently and shorten overall application startup time (with a caveat--see below).
  4. Fixed the case where the tunnel could not be used for proxy-less services and added a test for it.
  5. Fixed Dashboard doesn't load if Docker not running and ASPIRE_ENABLE_CONTAINER_TUNNEL #12998
  6. Added a test utitlity for finding an un-occupied IP port for testing and modified some DistributedApplicationTests to use it--it should help us get those out of quarantined status.

CAVEAT: with this change, containers that use host resources will commence their startup after a delay (measured on my devbox VM as roughly 3-4 seconds in "warm" case). An example of such container is our Yarp integration, which pushes OTEL telemetry to the dashboard. This is because some of the endpoints they use are now provided by the tunnel, specifically the tunnel proxy container, that needs to start up and allocate these endpoints. Previously these contaienrs were leveraging Docker Desktop host connectivity, which required only textual replacement of the endpoint address localhost --> host.docker.internal. This drawback has to be weighted against the fact that the tunnel provides uniform behavior regardless of the container orchestrator and that we need to get more feedback about it from the users, which we won't get if the tunnel remains off by default.
Making the tunnel as fast as Docker Desktop-based solution is possible, but the plan for that requires making the tunnel itself persistent, which in turn requires persistent Executables, which is tracked here: microsoft/dcp#13

Copilot AI review requested due to automatic review settings February 18, 2026 23:20
@github-actions
Copy link
Contributor

github-actions bot commented Feb 18, 2026

🚀 Dogfood this PR with:

⚠️ WARNING: Do not do this without first carefully reviewing the code of this PR to satisfy yourself it is safe.

curl -fsSL https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 14557

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/dotnet/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 14557"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables Aspire’s container tunnel by default to provide consistent container-to-host connectivity across orchestrators, while updating OTLP/dashboard endpoint modeling and refactoring DCP startup work for better parallelism and correctness.

Changes:

  • Default-enable the container tunnel and refactor DCP object creation into finer-grained parallel tasks.
  • Add a multi-resource dependency computation API and use it to determine tunnel-dependent resources.
  • Update OTLP/dashboard endpoint naming and add/adjust tests (including a helper to reduce port-collision flakiness).

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tools/perf/Measure-StartupPerformance.ps1 Updates perf script launch profile handling and output behavior.
tests/Aspire.Hosting.Tests/ResourceDependencyTests.cs Adds coverage for new multi-resource dependency resolution behavior.
tests/Aspire.Hosting.Tests/Helpers/Network.cs Adds helper for selecting an available TCP port to reduce test flakiness.
tests/Aspire.Hosting.Tests/DistributedApplicationTests.cs Uses dynamic ports in proxyless endpoint/container tests.
tests/Aspire.Hosting.Tests/Dashboard/DashboardResourceTests.cs Switches OTLP endpoint name usage to centralized constants.
tests/Aspire.Hosting.Tests/Dashboard/DashboardLifecycleHookTests.cs Switches OTLP endpoint name usage to centralized constants.
tests/Aspire.Hosting.Tests/ContainerTunnelTests.cs Adds tunnel coverage for proxyless endpoints and adjusts YARP test behavior/timeouts.
tests/Aspire.Hosting.Tests/Aspire.Hosting.Tests.csproj Adds Polly.Core dependency for new test helper.
src/Shared/OtlpEndpointResolver.cs Extends OTLP resolution logic and adds helper to resolve scheme/port.
src/Shared/KnownEndpointNames.cs Introduces shared OTLP endpoint-name constants.
src/Aspire.Hosting/OtlpConfigurationExtensions.cs Centralizes OTLP env var key and uses resolver directly for endpoint/protocol.
src/Aspire.Hosting/Dcp/OtlpEndpointReferenceGatherer.cs Adds DCP gatherer to replace OTLP endpoint env var with dashboard endpoint reference for containers.
src/Aspire.Hosting/Dcp/DcpOptions.cs Enables container tunnel by default.
src/Aspire.Hosting/Dcp/DcpExecutor.cs Refactors startup into interdependent tasks; adds tunnel-dependent container classification and OTLP gatherer hookup.
src/Aspire.Hosting/Dashboard/DashboardEventHandlers.cs Uses shared OTLP endpoint-name constants and ensures endpoints are annotated.
src/Aspire.Hosting/AspireEventSource.cs Adds events for service-object preparation timing.
src/Aspire.Hosting/Aspire.Hosting.csproj Links new shared KnownEndpointNames into hosting assembly.
src/Aspire.Hosting/ApplicationModel/ResourceExtensions.cs Adds efficient multi-resource dependency computation API and exposes direct-dependency gatherer internally.
src/Aspire.Hosting.Maui/Aspire.Hosting.Maui.csproj Links shared KnownResourceNames/KnownEndpointNames into MAUI package.
playground/yarp/Yarp.AppHost/Properties/launchSettings.json Removes explicit tunnel enablement since it’s now default.
Comments suppressed due to low confidence (3)

src/Shared/KnownEndpointNames.cs:9

  • These endpoint name fields are mutable static strings. They should be const (or at least static readonly) to prevent accidental mutation and to satisfy analyzers that flag non-constant static fields.
internal static class KnownEndpointNames
{
    public static string OtlpGrpcEndpointName = "otlp-grpc";
    public static string OtlpHttpEndpointName = "otlp-http";

src/Aspire.Hosting/Dcp/DcpExecutor.cs:3012

  • Typo in exception message: 'follwing' should be 'following'.
            var containerNames = persistentTunnelDependent.Select(td => td.ModelResource.Name).Aggregate(string.Empty, (acc, next) => acc + " '" + next + "'");
            throw new InvalidOperationException($"The follwing containers are marked as persistent and rely on resources on the host network:{containerNames}. This is not supported.");
        }

tests/Aspire.Hosting.Tests/ResourceDependencyTests.cs:779

  • There is a stray extra semicolon here (...WithHttpEndpoint(...); ;) which results in an empty statement. Please remove it to keep the test code clean.
        // A -> B -> C -> A (circular), plus D as external dependency
        var d = builder.AddContainer("d", "alpine")
            .WithHttpEndpoint(8083, 8083, "http"); ;
        var a = builder.AddContainer("a", "alpine")

@github-actions
Copy link
Contributor

github-actions bot commented Feb 19, 2026

🎬 CLI E2E Test Recordings

The following terminal recordings are available for commit 8b081c0:

Test Recording
AgentCommands_AllHelpOutputs_AreCorrect ▶️ View Recording
AgentInitCommand_MigratesDeprecatedConfig ▶️ View Recording
AspireUpdateRemovesAppHostPackageVersionFromDirectoryPackagesProps ▶️ View Recording
Banner_DisplayedOnFirstRun ▶️ View Recording
Banner_DisplayedWithExplicitFlag ▶️ View Recording
CreateAndDeployToDockerCompose ▶️ View Recording
CreateAndDeployToDockerComposeInteractive ▶️ View Recording
CreateAndPublishToKubernetes ▶️ View Recording
CreateAndRunAspireStarterProject ▶️ View Recording
CreateAndRunAspireStarterProjectWithBundle ▶️ View Recording
CreateAndRunJsReactProject ▶️ View Recording
CreateAndRunPythonReactProject ▶️ View Recording
CreateEmptyAppHostProject ▶️ View Recording
CreateStartAndStopAspireProject ▶️ View Recording
CreateStartWaitAndStopAspireProject ▶️ View Recording
CreateTypeScriptAppHostWithViteApp ▶️ View Recording
DoctorCommand_DetectsDeprecatedAgentConfig ▶️ View Recording
DoctorCommand_WithSslCertDir_ShowsTrusted ▶️ View Recording
DoctorCommand_WithoutSslCertDir_ShowsPartiallyTrusted ▶️ View Recording
LogsCommandShowsResourceLogs ▶️ View Recording
PsCommandListsRunningAppHost ▶️ View Recording
ResourcesCommandShowsRunningResources ▶️ View Recording
StagingChannel_ConfigureAndVerifySettings_ThenSwitchChannels ▶️ View Recording

📹 Recordings uploaded automatically from CI run #22375825749

@karolz-ms karolz-ms self-assigned this Feb 19, 2026
@karolz-ms karolz-ms force-pushed the dev/karolz/faster-tunnel branch from 4cc4a4d to 6c74b5c Compare February 19, 2026 23:46
@karolz-ms karolz-ms requested a review from danegsta February 20, 2026 21:12
@karolz-ms karolz-ms enabled auto-merge (squash) February 24, 2026 23:39
@karolz-ms karolz-ms merged commit 0b5acf0 into main Feb 25, 2026
678 of 681 checks passed
@karolz-ms karolz-ms deleted the dev/karolz/faster-tunnel branch February 25, 2026 01:17
@dotnet-policy-service dotnet-policy-service bot added this to the 13.3 milestone Feb 25, 2026
radical added a commit that referenced this pull request Mar 6, 2026
The merge conflict on DcpExecutor.cs was resolved by taking release/13.2's
version, which discarded PR #14557's parallel, tunnel-aware container creation.
However, DcpOptions.cs had no conflict, so #14557's EnableAspireContainerTunnel
= true default was auto-preserved.

The old DcpExecutor unconditionally blocks ALL container creation behind tunnel
initialization (10-minute timeout), causing polyglot tests to time out waiting
for Redis. The new DcpExecutor from #14557 intelligently parallelizes
tunnel-dependent vs independent containers, but that code was lost in the merge.

Reverting to false makes DcpOptions consistent with the DcpExecutor code taken
from release/13.2. After the backmerge lands, main already has both the correct
= true default AND the matching DcpExecutor from #14557.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard doesn't load if Docker not running and ASPIRE_ENABLE_CONTAINER_TUNNEL

4 participants