Skip to content

feat(k3s): DNS, developer certificate and run-time Helm values for local clusters - #2265

Open
edmondshtogu wants to merge 1 commit into
CommunityToolkit:mainfrom
edmondshtogu:main
Open

edmondshtogu wants to merge 1 commit into
CommunityToolkit:mainfrom
edmondshtogu:main

Conversation

@edmondshtogu

@edmondshtogu edmondshtogu commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Makes a k3s cluster usable as a local install target for real charts: workloads can reach the AppHost's
other resources, the ingress serves a trusted certificate, and charts can be installed from a directory with
values resolved at run time.

Pods could not reach Aspire resources

Pods resolve through CoreDNS, which forwards to the node's resolver — Docker's embedded DNS on 127.0.0.11,
unreachable from a pod's network namespace. From a pod, nslookup host.docker.internal and nslookup postgres
both return NXDOMAIN, so the README's "Reaching Aspire services from k3s pods" did not work.

  • WithHostAlias(resource, hostName?) resolves the container on the Aspire network at every start and writes
    a hosts block into the coredns-custom ConfigMap (k3s's documented extension point), then restarts CoreDNS.
  • WithCoreDnsCustomization(fileName, content) adds a .override or .server file to the same ConfigMap.

Components disabled with no way back

--disable=servicelb and --disable=metrics-server were fixed arguments, and K3sClusterOptions is not
consumed by any API. WithEnabledComponent(component) removes a disable; WithDisabledComponent no longer
repeats a flag.

Developer certificate on the ingress

WithIngressDeveloperCertificate() stores the AppHost's developer certificate as the TLS Secret
aspire-developer-certificate in kube-system and in every Helm release's namespace, and makes it the
default of the bundled Traefik (TLSStore default). Hosts under *.dev.localhost then open without a warning,
and charts can name the Secret for their ingress and mount its tls.crt to trust it.

Helm

  • AddHelmRelease accepts a chart directory, mounted read-only and copied inside the container, where every
    HTTP repository in Chart.yaml is added and helm dependency build runs. A version is refused for it.
  • WithHelmValue overloads take a parameter, a ReferenceExpression or an EndpointReference. The value is an
    environment variable escaped for --set inside the container, so secrets stay out of the generated script.
    The polyglot export stays one withHelmValue, with a union-typed value.

Persistent clusters

WithDataVolume also pins --node-name to the resource name and keeps /etc/rancher/node in a second
volume. Before, a recreated container — a k3s upgrade, a changed argument — registered as a new node and
volumes bound to the old one stayed Pending.

Every Helm release and manifest of the cluster waits for the DNS and certificate containers, whatever order
they are declared in.

PR Checklist

  • Created a feature/dev branch in your fork (vs. submitting directly from a commit on main)
  • Based off latest main branch of toolkit
  • PR doesn't include merge commits (always rebase on top of our main, if needed)
  • Tests for the changes have been added (for bug fixes / features) (if applicable)
  • Contains NO breaking changes
  • Every new API (including internal ones) has full XML docs
  • Code follows all style conventions

Other information

  • Behaviour change: with WithDataVolume, the server node is registered under the resource name. An
    existing persistent cluster re-registers once under the new name.
  • CI: restore currently fails on main for every PR (GHSA-qhrr-8q5h-9q3h, MessagePack via Aspire.Hosting);
    fixed separately in fix: suppress GHSA-qhrr-8q5h-9q3h, which every project inherits from … #2266. This PR's checks go green once that merges.
  • Tests: 40 new unit tests; the K3s suite (260 tests, including the TypeScript AppHost) passes. The generated
    TypeScript SDK exposes withEnabledComponent, withHostAlias, withCoreDnsCustomization,
    withIngressDeveloperCertificate and the union-typed withHelmValue.
  • Verified end to end against a Helm chart with external PostgreSQL, Redis and SMTP in Aspire containers,
    served on 443 with the trusted developer certificate.

@github-actions

Copy link
Copy Markdown
Contributor

🚀 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/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.sh | bash -s -- 2265

Or

  • Run remotely in PowerShell:
iex "& { $(irm https://raw.githubusercontent.com/CommunityToolkit/Aspire/main/eng/scripts/dogfood-pr.ps1) } 2265"

…cal clusters

Pods resolve names through CoreDNS, which forwards to the node's resolver —
inside a container, Docker's embedded DNS on a loopback address pods cannot
reach. So a pod could resolve neither another Aspire container nor
host.docker.internal, and the README's advice to use it did not work.
WithHostAlias looks each container up on the Aspire network and writes it into
the coredns-custom ConfigMap; WithCoreDnsCustomization adds files to the same
ConfigMap.

servicelb and metrics-server were disabled with fixed arguments nothing could
undo, and K3sClusterOptions is not consumed by any API. WithEnabledComponent
takes a default back: a LoadBalancer that binds the node's ports, an HPA.

WithIngressDeveloperCertificate makes the AppHost's trusted developer
certificate Traefik's default, and stores it in each Helm release's namespace
so charts can serve and trust it.

AddHelmRelease accepts a chart directory, building its dependencies inside the
Helm container. WithHelmValue accepts a parameter, an expression or an
endpoint, carried as an environment variable so a secret never lands in the
generated script; the polyglot export is one union-typed withHelmValue.

WithDataVolume now keeps the server node's name and password, so a recreated
container rejoins as the same node instead of orphaning its volumes.

Every Helm release and manifest waits for the DNS and certificate steps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant