microsoft / microsoft/aspire

Expose IHelmRunner (or allow helm-install pipeline steps to run in run mode) for community Kubernetes integrations

Open
#17,425 1 comment 0 reactions 0 assignees View on GitHub
needs-area-label triage:bot-seen
Dominant language
C#
Stars
6.3k
Forks
991
Avg merge
2d 15h
Merged PRs (30d)
196

Description

## Context

The Aspire Community Toolkit is adding a `CommunityToolkit.Aspire.Hosting.Kind` integration ([CommunityToolkit/Aspire#1270](https://github.com/CommunityToolkit/Aspire/pull/1270)) that targets two scenarios:

1. **Managed dependency (run / F5):** `AddKindCluster("dev")` provisions a local Kind cluster as an Aspire resource, with `AddHelmChart(...)` to install supporting charts (operators, dependencies) while the AppHost is running.
2. **Compute environment (publish / deploy):** `AddKubernetesEnvironment("k8s").WithKind()` so `aspire deploy` provisions Kind, loads images, and installs the generated chart locally.

Scenario 2 lines up with `Aspire.Hosting.Kubernetes` cleanly — the integration just contributes pipeline steps that depend on `WellKnownPipelineSteps.Publish`/`Build`/`Deploy`. Scenario 1 is where things diverge: there is no first-class way to install a Helm chart from inside `aspire run`, so the PR ships its own `IProcessRunner` + `HelmManager` that re-implements what `Aspire.Hosting.Kubernetes` already does internally with `IHelmRunner` / `DefaultHelmRunner`.

Having two parallel Helm CLI orchestrators in the .NET ecosystem (one inside Aspire, one inside the toolkit) is going to drift — different argument handling, different validation, different telemetry, different error messages. It would be much better if community integrations could ride on the same primitive.

## Proposal

There are two ways to solve this; we'd like guidance on which one the team would accept (or a third option I haven't considered).

### Option A — Expose `IHelmRunner` (and its argument-building helpers) as public, evaluation-only API

Promote `Aspire.Hosting.Kubernetes.IHelmRunner` and `DefaultHelmRunner` (or a thin wrapper) to public surface gated by an existing experimental diagnostic (e.g. `ASPIREPIPELINES001` or a new `ASPIREKUBERNETES001`). Concretely:

```csharp
namespace Aspire.Hosting.Kubernetes;

[Experimental("ASPIREKUBERNETES001")]
public interface IHelmRunner
{
Task RunAsync(
string arguments,
string? workingDirectory = null,
Action? onOutputData = null,
Action? onErrorData = null,
CancellationToken cancellationToken = default);
}
```

Pairs nicely with #16101 — the typed methods proposed there (`DeployAsync`, `UninstallAsync`, `VerifyAsync`) become the public contract; the string-arguments overload can stay internal.

Pros: minimal change, ships today, unblocks the toolkit.
Cons: another piece of experimental surface to maintain; doesn't address the broader "run-mode helm install" gap that other integrations (e.g. a future `microk8s`, `k3d`, or `minikube` toolkit integration) will hit.

### Option B — Make the existing helm-install pipeline reusable from run mode

Today `KubernetesEnvironmentResource` and `KubernetesHelmChartResource` only enter the model in publish mode (see `AddKubernetesEnvironment` and `AddHelmChart` — both return a non-added builder when `ExecutionContext.IsRunMode`). The `helm-install-{name}` pipeline step is also implicitly publish-only.

If pipelines can be executed in run mode for a specific subset of steps (or if there's a `WellKnownPipelineSteps.RunDeploy`-style hook), the Kind integration's `WithKind()` could simply:

1. Keep `KubernetesEnvironmentResource` and `KubernetesHelmChartResource` in the model in run mode when a local provider is attached.
2. Trigger the same `helm-install-*` steps after the local cluster is ready, instead of re-implementing them.

This benefits every future local-Kubernetes integration in the same way and means Helm orchestration only lives in one place. The downside is it requires plumbing in Aspire itself (pipeline-in-run-mode is not a documented pattern today) and the user is effectively running deploy steps during F5, which may surprise people.

## Why this matters

Without one of these, every CTK Kubernetes provider (Kind today; k3d, minikube, microk8s tomorrow) will ship its own copy of "shell out to helm." That's bad for users (inconsistent behaviour, inconsistent diagnostics) and bad for Aspire (community implementations will diverge from upstream's HelmDeploymentEngine conventions around release-name resolution, namespace validation, values-file handling, etc.).

I'd lean toward Option A as the short-term unblocker and Option B as the longer-term direction, but would appreciate the team's view.

## Related

- #16101 — typed methods for `IHelmRunner` (internal). The public API proposed here would build on whatever shape that issue lands.
- #16977 — Helm version validation. Once `IHelmRunner` is shared, this validation benefits the toolkit's Kind integration for free.
- CommunityToolkit/Aspire#1270 — the PR that motivated this issue.

cc @davidfowl @mitchdenny

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.