diff --git a/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx b/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx index fa8deeb99..950050ef3 100644 --- a/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx +++ b/src/frontend/src/content/docs/deployment/kubernetes/clusters.mdx @@ -325,11 +325,25 @@ Use [external parameters](/fundamentals/external-parameters/) to configure value ### Parameters inside environment expressions -Parameters embedded inside environment expressions are emitted as their own Helm values. For example, when a URL contains a host parameter, you can override that parameter at deployment time without reconstructing the entire URL. The publisher declares both the composed environment value and the nested parameter in `values.yaml`; deployment resolves the expression using the parameter's effective value. +When a parameter is embedded inside a larger environment variable expression — for example, a URL that contains a host parameter — the publisher declares the parameter as its own entry in `values.yaml`. The embedded parameter doesn't become an extra environment variable; instead, the generated ConfigMap or Secret references it directly, so you can override just that value at deployment time without reconstructing the entire URL. Use an Aspire reference expression for composition, not a TypeScript string interpolation of a resource handle: + + +```csharp title="AppHost.cs" +var builder = DistributedApplication.CreateBuilder(args); +builder.AddKubernetesEnvironment("k8s"); +var host = builder.AddParameter("host", "localhost"); + +builder.AddContainer("myapp", "nginx") + .WithEnvironment("SOME_URL", $"http://{host}/test"); + +builder.Build().Run(); +``` + + ```typescript title="apphost.mts" twoslash @@ -338,28 +352,30 @@ import { createBuilder, refExpr } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); await builder.addKubernetesEnvironment('k8s'); const host = await builder.addParameter('host', { value: 'localhost' }); -const app = await builder.addContainer('app', 'nginx'); -await app.withEnvironment('SOME_URL', refExpr`http://${host}/test`); +const myapp = await builder.addContainer('myapp', 'nginx'); +await myapp.withEnvironment('SOME_URL', refExpr`http://${host}/test`); await builder.build().run(); ``` - + -```csharp title="AppHost.cs" -var builder = DistributedApplication.CreateBuilder(args); -builder.AddKubernetesEnvironment("k8s"); -var host = builder.AddParameter("host", "localhost"); +The generated `values.yaml` declares both the composed environment value and the nested `host` parameter under the resource's `config` section, and the ConfigMap template references the nested value: -builder.AddContainer("app", "nginx") - .WithEnvironment("SOME_URL", $"http://{host}/test"); +```yaml title="values.yaml" +config: + myapp: + SOME_URL: "" + host: "" +``` -builder.Build().Run(); +```yaml title="templates/myapp/config.yaml" +data: + SOME_URL: "http://{{ .Values.config.myapp.host }}/test" ``` - - +When you deploy with `aspire deploy`, Aspire resolves each nested parameter and the composed expression using the parameter's effective value — for example, `SOME_URL` becomes `http://localhost/test`. If you install the chart yourself, override the nested entry, such as `--set config.myapp.host=example.com`. Secret parameters are declared under `secrets.` instead, and any environment variable that embeds a secret parameter is emitted in the resource's Secret rather than its ConfigMap. Conflicting Helm value paths, including names that collide after normalization, fail publishing rather than overwriting another entry.