Watch Aspire live streamsBelgelerAspire'ı deneyin

Kind hosting integration

Bu içerik henüz dilinizde mevcut değil.

⭐ Community Toolkit

Use the Kind hosting integration from the Aspire Community Toolkit to model a local Kind cluster, deploy charts and manifests to it, and pass its kubeconfig to AppHost resources. For an introduction and prerequisites, see Get started with the Kind integration.

Install the 📦 CommunityToolkit.Aspire.Hosting.Kind package in the AppHost:

Aspire CLI — CommunityToolkit.Aspire.Hosting.Kind paketi ekle
aspire add communitytoolkit-kind

Aspire CLI etkileşimlidir; istendiğinde uygun sonucu seçin:

Aspire CLI — Örnek çıktı
Select an integration to add:
> communitytoolkit-kind (CommunityToolkit.Aspire.Hosting.Kind)
> Other results listed as selectable options...

The local cluster requires a container runtime and the Kind CLI. Install kubectl for manifest and Helm chart resources. Install Helm for chart resources and Kind-backed deployment workflows.

Add a cluster to the AppHost. By default, Kind uses its configured Kubernetes version and creates one control-plane node without worker nodes.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
await builder.build().run();

The cluster is created when the AppHost starts and is represented as an Aspire resource. The integration registers lifecycle cleanup that attempts to delete a session cluster during graceful shutdown or lifecycle-hook disposal.

Pin a Kubernetes version to use the corresponding Kind node image:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder
.addKindCluster('mycluster')
.withKubernetesVersion('v1.32.2');
await builder.build().run();

Use WithNodeImage when you need to specify a complete image name, such as a private registry image. Don’t configure both a Kubernetes version and a node image on the same cluster.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder
.addKindCluster('mycluster')
.withNodeImage('registry.example.com/kindest/node:v1.32.2');
await builder.build().run();

WithWorkerNodes adds the requested number of worker nodes in addition to the control-plane node. The default is zero workers.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster').withWorkerNodes(2);
await builder.build().run();

Use WithNodeMount to make a host path available inside every Kind node. Relative host paths are resolved against the AppHost project directory. This configures a node mount; it does not install a chart or make a workload consume the mounted content.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder
.addKindCluster('mycluster')
.withNodeMount('./charts', '/var/local/charts', true);
await builder.build().run();

By default, the cluster uses ClusterLifetime.Session. The integration attempts to delete it during graceful shutdown or when its lifecycle hook is disposed. Set the lifetime to Persistent to retain the cluster and reuse it on a later AppHost start.

apphost.mts
import { createBuilder, ClusterLifetime } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder
.addKindCluster('mycluster')
.withClusterLifetime(ClusterLifetime.Persistent);
await builder.build().run();
LifetimeBehavior
ClusterLifetime.SessionDefault. Attempts to delete the cluster at shutdown or lifecycle-hook disposal.
ClusterLifetime.PersistentKeeps the cluster across AppHost restarts and reuses it on the next start.

Kind nodes use the container runtime’s kind network. Aspire-managed containers normally use a different network, and workloads running in Kubernetes use the cluster’s pod and service networks. Connecting a container to the Kind network gives it a route to the Kind node containers, but does not expose Kubernetes pod or service networks by itself.

Reference the cluster from a non-container resource to inject the host kubeconfig path and cluster name. Reference it from a container to mount the container-compatible kubeconfig, set environment variables, and connect the container to the Kind network.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const operator = await builder
.addContainer('operator', 'myregistry/my-operator')
.withKindContainerReference(cluster);
await builder.build().run();

The container reference sets KUBECONFIG to /etc/kubeconfig/config, mounts the container-compatible kubeconfig read-only at that path, and sets K8S_CLUSTER_NAME to the cluster resource name. Its kubeconfig uses the Kind control-plane container name instead of 127.0.0.1.

For a project or executable that runs on the host, use the non-container reference overload:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const operator = await builder
.addProject('operator', '../Operator/Operator.csproj')
.withKindClusterReference(cluster);
await builder.build().run();

For non-container resources, KUBECONFIG contains the host kubeconfig path. Both reference overloads set K8S_CLUSTER_NAME to the cluster resource name.

Register a Kind cluster to initialize the network services, then use WithKindNetwork to connect a container without configuring a cluster reference on that container:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
await builder.addKindCluster('mycluster');
const toolbox = await builder
.addContainer('toolbox', 'myregistry/kubectl')
.withKindNetwork();
await builder.build().run();

Use AddHelmChart to deploy a chart after the Kind cluster is healthy. The resource uses helm upgrade --install; the release name defaults to the resource name. A configured namespace is created for the release.

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const redis = await cluster
.addHelmChart('redis', 'oci://registry-1.docker.io/bitnamicharts/redis')
.withChartVersion('20.0.0')
.withHelmValue('replica.replicaCount', '0')
.withHelmStringValue('auth.password', '000123')
.withNamespace('cache');
await builder.build().run();

Use WithHelmStringValue for values such as passwords that resemble numbers or booleans but must remain strings. Add values files with WithHelmValuesFile.

Use AddManifest to apply a local manifest file, directory, or Kustomize overlay after the cluster becomes healthy. Manifest paths must be absolute so a published AppHost does not depend on the original project directory. URL fetching is not supported. Download remote manifests in a build step and use the local path instead.

The following example resolves a manifest path from the AppHost directory and uses server-side apply:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
import { fileURLToPath } from 'node:url';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const manifestPath = fileURLToPath(
new URL('./manifests/platform.yaml', import.meta.url)
);
const platform = await cluster
.addManifest('platform', manifestPath)
.withServerSideApply()
.withFieldManager('aspire-apphost');
await builder.build().run();

Use AddManifestFromContent to apply inline manifest text with kubectl apply -f -. For example:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const demoNamespace = await cluster.addManifestFromContent(
'demo-namespace',
`
apiVersion: v1
kind: Namespace
metadata:
name: aspire-demo
`
);
await builder.build().run();

Configure manifest application with WithRecursive, WithNamespace, WithApplyTimeout, and WithClusterReadyTimeout. WithNamespace passes a namespace to kubectl apply but does not create it. WithApplyTimeout sets the maximum duration for kubectl apply; WithClusterReadyTimeout sets how long to wait for the Kubernetes API before applying the manifest. A directory containing a Kustomize marker file is applied with kubectl apply -k; WithRecursive does not apply to Kustomize overlays.

Use Aspire’s WaitFor dependency to keep another resource from starting until a chart or manifest has completed its deployment and passed its applicable health checks:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
import { fileURLToPath } from 'node:url';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const manifestPath = fileURLToPath(
new URL('./manifests/crds.yaml', import.meta.url)
);
const crds = await cluster.addManifest('crds', manifestPath);
const operator = await builder
.addContainer('operator', 'myregistry/my-operator')
.withKindContainerReference(cluster);
await operator.waitFor(crds);
await builder.build().run();

After a manifest successfully applies, the integration checks directly applied CRDs and waits for them to reach the Kubernetes Established condition. This check is a post-apply check, not a recurring health probe. It does not check the readiness of other object kinds or CRDs created later by a controller.

The default CRD wait timeout is five minutes. By default, a failed check prevents the resource from reaching Running, so dependent resources remain blocked. Set FailureBehavior to BestEffort only when it is acceptable to continue without verifying CRD readiness:

apphost.mts
import { createBuilder, CrdWaitBehavior } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const cluster = await builder.addKindCluster('mycluster');
const manifest = await cluster.addManifestFromContent(
'demo-namespace',
`
apiVersion: v1
kind: Namespace
metadata:
name: aspire-demo
`
);
await manifest.withCrdWait(async (options) => {
await options.timeout.set(120_000);
await options.failureBehavior.set(CrdWaitBehavior.BestEffort);
});
await builder.build().run();

The TypeScript callback shape is supported by the generated TypeScript AppHost SDK and is exercised by the integration’s TypeScript AppHost tests.

For Helm charts, the integration compares CRDs before and after a successful install and waits for newly observed CRDs to become established. A separate workload health check continues after installation. A successful install can therefore be Running but Unhealthy if its tracked workload health check fails.

Configure an Aspire Kubernetes environment with .WithKind() to use a local Kind cluster as the target for aspire publish and aspire deploy:

apphost.mts
import { createBuilder } from './.aspire/modules/aspire.mjs';
const builder = await createBuilder();
const k8s = await builder
.addKubernetesEnvironment('k8s')
.withKind()
.withKubernetesVersion('v1.32.2');
await builder.addContainer('redis', 'redis:7');
await builder.addProject('api', '../Api/Api.csproj');
await builder.build().run();

Run aspire publish --output-path ./charts to generate the Helm chart. Run aspire deploy to create the Kind cluster, build and load the application images, and install the generated chart. For deployment, have the Kind and Helm CLIs available along with Docker or Podman.

The package’s generated API export includes the following Kind-specific methods. The listed methods are available to TypeScript AppHosts unless marked C# only. TypeScript names use camelCase.

APIPurpose
AddKindCluster(name)Add a managed Kind cluster resource.
WithKubernetesVersion(version)Pin the Kubernetes version used for the cluster nodes.
WithNodeImage(image)Specify the complete node image name instead of a version.
WithWorkerNodes(count)Add worker nodes to the control-plane node.
WithNodeMount(hostPath, containerPath, readOnly)Mount a host path in each node.
WithClusterLifetime(lifetime)Choose Session or Persistent cluster lifetime.
WithReference(kind) for non-container resourcesProvide the host kubeconfig path and cluster name to a project, executable, or other resource with environment support. TypeScript name: withKindClusterReference.
WithReference(kind) for containersMount the container-compatible kubeconfig, set cluster environment variables, and connect to the Kind network. TypeScript name: withKindContainerReference.
WithKindNetwork()Connect a container resource to the Kind container network.
WithKindConfig(configure)Configure the Kind cluster using KindConfigModel. C# only: the action callback is not TypeScript-compatible.
AddHelmChart(name, chartRef)Add a Helm chart resource.
WithChartVersion(version)Pin a chart version.
WithHelmValue(key, value)Set a Helm value.
WithHelmStringValue(key, value)Set a Helm value as a string.
WithHelmValuesFile(path)Add a Helm values file.
WithNamespace(namespace)Set the namespace for a chart or manifest resource.
AddManifest(name, manifestPath)Apply a local manifest file or directory.
AddManifestFromContent(name, content)Apply inline manifest content.
WithRecursive()Apply manifest files recursively in a directory.
WithServerSideApply(forceConflicts)Enable server-side apply, optionally forcing conflicts.
WithFieldManager(fieldManager)Set the kubectl apply field manager name.
WithApplyTimeout(timeout)Set the kubectl apply timeout.
WithClusterReadyTimeout(timeout)Set the time allowed for the Kubernetes API to become reachable before applying a manifest.
WithCrdWait(configure)Configure the CRD Established wait timeout and failure behavior for a chart or manifest.
WithCrdWaitTimeout(timeout) and WithCrdWaitBehavior(behavior)Obsolete manifest-specific compatibility APIs. Prefer WithCrdWait.
AddKubernetesEnvironment(name).WithKind()Configure a Kubernetes environment to use Kind for publish and deploy workflows.

The exported API also includes these public types:

TypeMembers or purpose
ClusterLifetimeSession and Persistent cluster lifetime values.
CrdWaitBehaviorFail and BestEffort policies for failed CRD readiness checks.
CrdWaitOptionsTimeout and FailureBehavior values configured by WithCrdWait.
IKindResourceResource interface exposing KubeconfigPath.
KindConfigModelKind configuration containing ApiVersion, Kind, Nodes, Networking, RuntimeConfig, FeatureGates, ContainerdConfigPatches, and KubeadmConfigPatches. Configured with the C#-only WithKindConfig callback.
KindNetworkingModelKind API server address and port, CNI setting, IP family, kube-proxy mode, and pod and service subnets.
KindNodeModelNode role and image, labels, kubeadm patches, extra mounts, and port mappings.
KindMountModelHost and container paths, read-only mode, propagation, and SELinux relabel options for a node mount.
KindPortMappingModelContainer and host ports, listen address, and protocol for a node port mapping.
KindClusterResource and KindEnvironmentResourceCluster resources exposing their kubeconfig path; the cluster resource also exposes its container-compatible kubeconfig path.
KindHelmChartResourceChart reference, release name, values, string values, values files, version, and namespace.
K8sManifestResourceManifest path or inline content, namespace, apply and cluster-ready timeouts, recursive and server-side apply options, field manager, and Kustomize state.
KindDeployedResourceParent cluster and namespace shared by chart and manifest resources.