> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nuon.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Kubernetes Manifest Components

> Kubernetes manifest components allow you to deploy raw Kubernetes resources directly into your customer's cloud account.

Kubernetes manifest components allow you to deploy raw Kubernetes resources using YAML manifests.

## Configuring a Kubernetes Manifest component

To configure a Kubernetes manifest component, specify a namespace and the manifest files to deploy.

```toml components/kubernetes_manifest.toml theme={null}
# kubernetes-manifest
name = "kubernetes_manifest"
type = "kubernetes_manifest"

namespace = "nuon-sample"
manifest = """
apiVersion: v1
kind: ConfigMap
metadata:
  name: demo
data:
  sample_data: "3"
"""
```

## Multiple Resources in a Single Manifest

Kubernetes manifest components support multiple resources separated by the standard YAML document separator `---`:

```yaml components/deployment.yaml theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  namespace: default
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app
        image: "alpine:latest"
        ports:
        - containerPort: 8080

---
apiVersion: v1
kind: Service
metadata:
  name: my-app-service
  namespace: default
spec:
  selector:
    app: my-app
  ports:
  - port: 80
    targetPort: 8080
  type: ClusterIP
```

## Using Nuon Context Variables

Kubernetes manifest components support Nuon's templating system, allowing you to access variables and outputs from other components:

```yaml components/configmap.yaml theme={null}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  # access a synced image
  image_repository: "{{.nuon.components.image.image.repository.uri}}"
  image_tag: "{{.nuon.components.image.image.tag}}"
  
  # access outputs from a terraform component
  database_url: "{{.nuon.components.terraform.outputs.database_url}}"
  
  # access outputs from the sandbox
  aws_region: "{{.nuon.install.sandbox.outputs.account.aws_region}}"
  vpc_id: "{{.nuon.install.sandbox.outputs.vpc.id}}"
  
  # access information about the install domain
  public_domain: "{{.nuon.sandbox.outputs.nuon_dns.public_domain.name}}"
  internal_domain: "{{.nuon.sandbox.outputs.nuon_dns.internal_domain.name}}"
```

## Common Use Cases

### Deploying with Custom Images

```yaml components/app-deployment.yaml theme={null}
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: "{{.nuon.app.name}}"
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: "{{.nuon.app.name}}"
  template:
    metadata:
      labels:
        app: "{{.nuon.app.name}}"
    spec:
      containers:
      - name: app
        image: "{{.nuon.components.app_image.image.repository.uri}}:{{.nuon.components.app_image.image.tag}}"
        env:
        - name: DATABASE_URL
          value: "{{.nuon.components.infra.outputs.database_url}}"
        - name: AWS_REGION
          value: "{{.nuon.install.sandbox.outputs.account.aws_region}}"
        ports:
        - containerPort: 8080
```

### Creating Ingress Resources

```yaml components/ingress.yaml theme={null}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  namespace: default
  annotations:
    external-dns.alpha.kubernetes.io/hostname: "app.{{.nuon.sandbox.outputs.nuon_dns.public_domain.name}}"
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: "public-issuer"
spec:
  tls:
  - hosts:
    - "app.{{.nuon.sandbox.outputs.nuon_dns.public_domain.name}}"
    secretName: app-tls
  rules:
  - host: "app.{{.nuon.sandbox.outputs.nuon_dns.public_domain.name}}"
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
```

### Using AWS Load Balancer Controller

```yaml components/nlb-service.yaml theme={null}
---
apiVersion: v1
kind: Service
metadata:
  name: app-nlb
  namespace: default
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
    service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
    service.beta.kubernetes.io/aws-load-balancer-ssl-cert: "{{.nuon.components.infra.outputs.public_domain_certificate_arn}}"
    service.beta.kubernetes.io/aws-load-balancer-ssl-ports: https
    external-dns.alpha.kubernetes.io/hostname: "app.{{.nuon.sandbox.outputs.nuon_dns.public_domain.name}}"
spec:
  type: LoadBalancer
  loadBalancerClass: service.k8s.aws/nlb
  selector:
    app: my-app
  ports:
  - name: https
    port: 443
    targetPort: 8080
```

## Kustomize

In addition to inline manifests, Kubernetes manifest components can be sourced from a [Kustomize](https://kustomize.io) overlay in a Git repo. Use this when you want to assemble your manifests from a base + overlays, layer in patches, or share manifests across multiple components.

### Pointing a component at a Kustomize overlay

A Kustomize-backed component references the repo holding the overlay (either `public_repo` for a public GitHub repo, or `connected_repo` for a Nuon-connected private repo) and a `kustomize.path` relative to the source root.

```toml components/kustomize-demo.toml theme={null}
name = "kustomize-demo"
type = "kubernetes_manifest"

namespace = "kustomize-demo"

[public_repo]
repo = "nuonco/example-app-configs"
directory = "gke-simple/src/components/kustomize-demo"
branch = "main"

[kustomize]
path = "."
```

The directory at `directory` must contain a standard `kustomization.yaml`. Nuon runs `kustomize build` on it during deploy.

```yaml gke-simple/src/components/kustomize-demo/kustomization.yaml theme={null}
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - namespace.yaml
  - configmap.yaml
  - deployment.yaml
```

### State interpolation in Kustomize trees

Kustomize-backed components support the same `{{.nuon.*}}` template variables as inline manifests. Placeholders are rendered on the runner, against the live install state, **after** `kustomize build` produces the final manifest. This means you can reference install IDs, app metadata, install stack outputs, and other component outputs directly from any YAML file inside your Kustomize overlay.

```yaml gke-simple/src/components/kustomize-demo/configmap.yaml theme={null}
apiVersion: v1
kind: ConfigMap
metadata:
  name: install-info
  namespace: kustomize-demo
  annotations:
    nuon.co/rendered-install-id: "{{.nuon.install.id}}"
data:
  install_id: "{{.nuon.install.id}}"
  install_name: "{{.nuon.install.name}}"
  app_id: "{{.nuon.app.id}}"
  project_id: "{{.nuon.install_stack.outputs.project_id}}"
```

After a deploy, the rendered ConfigMap on the cluster will have the placeholders replaced with the install's actual values — for example, `install_id: inl...`, `project_id: nuon-gcp-support`.

<Note>
  Kustomize-backed manifests are interpolated on the runner, not in the planner. This keeps the Temporal workflow payload small even for large Kustomize trees. Inline manifests, by contrast, are still rendered in the planner.
</Note>

## Nuon Managed Sandbox Components

The `aws-eks-sandbox` [managed Sandbox](/concepts/sandboxes#nuon-managed-sandboxes) ships with standard components that your Kubernetes manifests can leverage:

* [AWS ALB Ingress Controller](https://kubernetes-sigs.github.io/aws-load-balancer-controller)
* [External DNS](https://github.com/kubernetes-sigs/external-dns)
* [Cert Manager](https://cert-manager.io/)
* [Nginx Ingress](https://docs.nginx.com/nginx-ingress-controller/)
* [EBS CSI](https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html)

The Sandboxes are [open source](/concepts/sandboxes#nuon-managed-sandboxes) and can be [customized](/concepts/sandboxes#create-a-custom-sandbox), if these components do not work for your application.

## Best Practices

### Namespace Management

Always specify namespaces explicitly in your manifests. If not provided, it defaults to the namespace specified in the config. If both the component configuration and manifest are missing namespace specifications, the component deployment will fail:

```yaml components/namespace.yaml theme={null}
---
apiVersion: v1
kind: Namespace
metadata:
  name: "{{.nuon.app.name}}"
  labels:
    app: "{{.nuon.app.name}}"

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
  namespace: "{{.nuon.app.name}}"
spec:
  # deployment spec...
```

<br />

<Note>
  Kubernetes manifest components are processed in the order they appear in your repository. If you have dependencies between resources, ensure they are ordered appropriately or use proper Kubernetes resource dependencies.
</Note>
