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

> ## Agent Instructions
> If you are an AI assistant asked to build, change or ship a Gliss app, read the For AI agents page first (/for-ai-agents.md on this site) and follow its steps.
> Inside an app's folder, the app's own AGENTS.md is the authority; `gliss guide` prints it. Never ask the user for a secret's value.

# Kubernetes manifests

> Deploy your own Kubernetes manifests with Garden's kubernetes Deploy action, at level 2.

> [!WARNING]
>
> **Planned.** This page describes designed behaviour that is not built yet. Details may change before it ships.

> [!NOTE]
>
> Ported from Garden's documentation: [garden-for/kubernetes/deploy-k8s-resource.md](https://docs.garden.io/garden-for/kubernetes/deploy-k8s-resource), gliss-cli at `3bc62a036` (Garden 0.14). Gliss runs Garden under the hood; the notes on this page say where Gliss differs.

> [!NOTE]
>
> **In Gliss,** `kubernetes` Deploy actions are available at [level 2](https://docs.glissando.dev/engineers/levels.md) only. Your IT team enables level 2 per project, and every release is checked against IT's policy instead of the catalog. The project still uses the `gliss` provider: the deploy becomes a signed release request, and the cluster agent applies it. You don't configure Garden's `kubernetes` provider or a kubeconfig.

You deploy your own Kubernetes resources with the `kubernetes` Deploy action. This page shows how to point Garden at your manifests, deploy an image you build, and change values per environment.

The `kubernetes` Deploy action works much like the [`helm`](https://docs.glissando.dev/engineers/helm) Deploy action. The full field list is in Garden's [`kubernetes` Deploy reference](https://docs.garden.io/reference/action-types/Deploy/kubernetes).

## Reference manifests

Point Garden at your manifest files with the `spec.manifestFiles` field. You can also put manifests inline in `spec.manifests`, but files are easier to reuse with other tools.

### Option 1: Manifest files (recommended)

If your project looks like this:

```console theme={null}
.
├── api
│   ├── garden.yml
│   ├── manifests
│   │   ├── Deployment.yaml
│   │   ├── Ingress.yaml
│   │   └── Service.yaml
│   └── src
└── project.garden.yml
```

reference the manifests like this:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
spec:
  manifestFiles:
    - ./manifests/Deployment.yaml
    - ./manifests/Ingress.yaml
    - ./manifests/Service.yaml
```

Glob patterns work too:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
spec:
  manifestFiles:
    - ./manifests/*
```

You can use templating to pick manifests per environment, for example with a `manifests/dev` and a `manifests/prod` directory:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
spec:
  manifestFiles:
    - ./manifests/${environment.name}/Deployment.yaml
    - ./manifests/${environment.name}/Ingress.yaml
    - ./manifests/${environment.name}/Service.yaml
```

Garden can't include files from parent directories. If your manifests are in a parent directory of the action's `garden.yml`, set `source.path`:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
source:
  path: ../ # <--- Garden will now treat the parent directory as the action source path
spec:
  manifestFiles:
    - ./manifests/Deployment.yaml # <--- Reference the manifests relative to the source path
    - ./manifests/Ingress.yaml
    - ./manifests/Service.yaml
```

### Option 2: Inline

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
spec:
  manifests:
    - apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: api
        labels:
          app: api
      spec:
        # ...
    - apiVersion: v1
      kind: Service
      metadata:
        name: api
        labels:
          app: api
      spec:
        # ...
```

## Deploy an image built by Garden

Most commonly you use the `kubernetes` Deploy action with a `container` Build action: one builds your code, the other deploys it. Your manifests will likely contain a hard-coded image, while the image Garden builds has a different version. The recommended way to set the right image is the `patchResources` field.

### Option 1: Patch resources (recommended)

`patchResources` overwrites any field in your manifests with [Kubernetes' built-in patch functionality](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/update-api-object-kubectl-patch/), without changing the manifest files:

```yaml theme={null}
kind: Build
type: container
name: api
---
kind: Deploy
type: kubernetes
name: api
dependencies: [build.api]
spec:
  manifestFiles: [my-manifests.yml]
  patchResources:
    - name: api # <--- The name of the resource to patch, should match the name in the K8s manifest
      kind: Deployment # <--- The kind of the resource to patch
      patch:
        spec:
          template:
            spec:
              containers:
                - name: api # <--- Should match the container name from the K8s manifest
                  image: ${actions.build.api.outputs.deployment-image-id} # <--- The output from the Build action above
```

This way you add the Garden action to your project without changing existing configuration. Garden has a [complete example project](https://github.com/garden-io/garden/tree/0.14.20/examples/k8s-deploy-patch-resources) that uses this approach.

### Option 2: Template strings in inline manifests

If you define the manifests inline, you can use template strings in them directly:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
dependencies: [build.api]
spec:
  manifests:
    - apiVersion: apps/v1
      kind: Deployment
      spec:
        template:
          spec:
            containers:
              - name: api
                image: ${actions.build.api.outputs.deployment-image-id} # <--- The output from the Build action above
```

## Overwrite values

The same `patchResources` pattern overwrites other values. For example, to change the number of replicas and an environment variable per environment:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api
spec:
  manifestFiles: [my-manifests.yml]
  patchResources:
    - name: api # <--- The name of the resource to patch, should match the name in the K8s manifest
      kind: Deployment # <--- The kind of the resource to patch
      patch:
        spec:
          replicas: "${environment.name == 'dev' ? 1 : 3}" # <--- Set replicas depending on environment
          template:
            spec:
              containers:
                - name: api # <--- Should match the container name from the K8s manifest
                  env:
                    - name: LOG_LEVEL
                      value: "${environment.name == 'dev' ? 'verbose' : 'info' }"
```

You can also loop over Garden variables and set each one as a container environment variable:

```yaml theme={null}
kind: Deploy
type: kubernetes
name: api

variables:
  apiEnv: # <--- Garden variables that we'll set as K8s container env vars
    NODE_ENV: development
    PORT: ${var.API_PORT} # <--- A shared variable that's set in the project config that we reference here

spec:
  manifestFiles: [my-manifests.yml]
  patchResources:
    - name: api
      kind: Deployment
      patch:
        spec:
          template:
            spec:
              containers:
                - name: api
                  env:
                    $forEach: ${var.apiEnv} # <--- Iterate over the values of ${var.apiEnv} variable...
                    $filter: "${item.value ? true : false}" # <--- ...optionally filter out empty values since Kubernetes doesn't support it...
                    $return: # <--- ...return them as valid Kubernetes name/value pairs
                      name: ${item.key}
                      value: ${string(item.value)}
```

See [Variables and templating](https://docs.glissando.dev/engineers/variables-and-templating.md) for the template syntax.

> [!NOTE]
>
> **In Gliss,** don't put secret values in Garden variables or manifests, and don't use Garden Cloud secrets. Secret values are set through Gliss secret requests, and your configuration refers to secrets by name only.

> [!NOTE]
>
> **In Gliss,** Garden's sync mode and port forwarding aren't available, so the `spec.sync` field and Garden's guidance on default targets for sync don't apply. Live code changes are Git-backed and work in Preview only, through `gliss dev`.

To add tests, see [Tests and runs](https://docs.glissando.dev/engineers/tests.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.