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

# Laminar on Astro Private Cloud

> Turn on Laminar in an Astro Private Cloud data plane, so the Deployments running there can hibernate when they're idle and autoscale their workers.

*Laminar* is a reliability service that runs in the Astro Private Cloud (APC) data plane. It ships as a sub-chart of the APC Helm chart and is off by default. It has two components: the Hypervisor, which scales and monitors Deployment resources, and the API Server, which proxies between operator-based Airflow Deployments and the KEDA scaling endpoints.

Enable Laminar on a data plane to make [Deployment hibernation](https://astronomer.io/docs/astro-private-cloud/v-2-x/hibernate-deployments.md) and [worker autoscaling](https://astronomer.io/docs/astro-private-cloud/v-2-x/configure-worker-autoscaling.md) available there; neither works without it. Laminar manages only Deployments that run in [Airflow operator mode](https://astronomer.io/docs/astro-private-cloud/v-2-x/airflow-operator-mode.md).

> [!NOTE]
>
> **Astro Private Cloud 2.2**
>
> This feature was introduced in Astro Private Cloud 2.2. To access this feature, upgrade your Astro Private Cloud installation to 2.2 or later.

> [!NOTE]
>
> Laminar is an enterprise feature. To enable it, contact [Astronomer support](https://support.astronomer.io) to request image pull credentials.

Set `global.laminar.enabled` to enable both components:

| Component | Deployment name | What it does |
| - | - | - |
| Hypervisor | `<release>-laminar-hypervisor` | Scales and monitors Deployment resources. It evaluates hibernation schedules and overrides, then writes the resulting intent onto each Deployment's Airflow custom resource. |
| API Server | `<release>-laminar-api-server` | Proxies between operator-based Airflow Deployments and the KEDA scaling endpoints, serving the per-queue worker count that KEDA scales on. It also backs Otto investigation and the MCP tooling for the Airflow operator. |

For the full platform install procedure, see [Install the data plane](https://astronomer.io/docs/astro-private-cloud/v-2-x/install-data-plane.md). To install KEDA, which worker autoscaling requires, see [Configure worker autoscaling](https://astronomer.io/docs/astro-private-cloud/v-2-x/configure-worker-autoscaling.md#step-1-install-keda). To run without the platform creating RBAC resources, see [Bring your own Kubernetes service accounts](https://astronomer.io/docs/astro-private-cloud/v-2-x/byo-service-accounts.md).

## Prerequisites

* APC 2.2 or later on both the control plane and the data plane.
* Deployments in [Airflow operator mode](https://astronomer.io/docs/astro-private-cloud/v-2-x/airflow-operator-mode.md).
* Permission to change the data plane's `values.yaml` and upgrade the platform release. See [Apply a config change](https://astronomer.io/docs/astro-private-cloud/v-2-x/apply-platform-config.md).

## Enable Laminar

Set `global.laminar.enabled` in the data plane's `values.yaml`, then upgrade the release:

```yaml wrap theme={null}
global:
  laminar:
    enabled: true
```

| Value | Default | Description |
| - | - | - |
| `global.laminar.enabled` | `false` | Installs both the Hypervisor and the API Server on the data plane. Required for hibernation and worker autoscaling. |

Laminar components render only on a data plane or in a unified installation. Setting this value on a split control plane creates nothing.

In a unified installation, set the value in the single `values.yaml`. On a split installation, set it in each data plane that runs Deployments you want to hibernate or autoscale.

## Configure image pull credentials

Standard APC installation credentials don't cover the Laminar images, so apply the credentials you requested from Astronomer support in the platform namespace, using the method that matches how your installation pulls platform images.

> [tab] Private registry
>
> If you mirror platform images into your own registry, mirror `ap-laminar` alongside them and pull it the same way as every other platform component:
>
> ```yaml wrap theme={null}
> global:
>   privateRegistry:
>     enabled: true
>     repository: registry.example.com/astronomer
>     secretName: registry-credentials
> ```
>
> Laminar then uses `global.privateRegistry.secretName`, and you don't set `laminar.imagePullSecrets`. The chart ignores that value whenever `global.privateRegistry.enabled` is `true`. For the full procedure, including how to create the registry secret, see [Install the control plane](https://astronomer.io/docs/astro-private-cloud/v-2-x/install-control-plane.md).

> [tab] Laminar image pull secret
>
> If you pull platform images directly from `quay.io/astronomer`, create a secret in the platform namespace from the credentials Astronomer support issued:
>
> ```bash wrap theme={null}
> kubectl create secret docker-registry laminar-registry \
>   --namespace <platform-namespace> \
>   --docker-server=quay.io \
>   --docker-username=<username> \
>   --docker-password=<password>
> ```
>
> Then name that secret in `laminar.imagePullSecrets`, which takes a list:
>
> ```yaml wrap theme={null}
> laminar:
>   imagePullSecrets:
>     - name: laminar-registry
> ```

If the secret is missing or holds the wrong credentials, the Laminar Pods stay in `ImagePullBackOff` and never become ready, leaving hibernation and worker autoscaling unavailable. Check the Pod events:

```bash wrap theme={null}
kubectl describe pod -n <platform-namespace> -l tier=laminar
```

## Configure the database secret

Laminar stores its state in its own database and reads the connection string from a Kubernetes secret with a `connection` key.

> [tab] Auto-managed
>
> This is the default. Each time a Laminar Pod starts, the bootstrapper init container checks for the `<release>-laminar` database, creates it if it doesn't exist, and creates or updates the connection string in a secret named `<release>-laminar-backend` in the platform namespace.
>
> To use your own database name, set `laminar.databaseBootstrapper.dbName`:
>
> ```yaml wrap theme={null}
> laminar:
>   databaseBootstrapper:
>     dbName: laminar_prod
> ```
>
> The bootstrapper then creates and connects to that database rather than one named after the Helm release. Use this when the database name has to outlive the release name, because reinstalling under a different release name otherwise points Laminar at a new, empty database.
>
> > [!NOTE]
> >
> > Set `dbName` when you enable Laminar. Changing it on a running installation switches Laminar to a different database, which the bootstrapper creates empty. The previous database isn't migrated or deleted.

> [tab] Customer-managed
>
> Set `laminar.databaseBootstrapper.backendSecretName` to the name of a secret you create and maintain:
>
> ```yaml wrap theme={null}
> laminar:
>   databaseBootstrapper:
>     backendSecretName: laminar-database
> ```
>
> Create the secret in the platform namespace with a single `connection` key holding the full connection string:
>
> ```bash wrap theme={null}
> kubectl create secret generic laminar-database \
>   --namespace <platform-namespace> \
>   --from-literal=connection='postgresql://<user>:<password>@<host>:5432/<database>'
> ```
>
> Laminar reads only the `connection` key, by name.

Once you set `backendSecretName`, the bootstrapper init container no longer runs, and Laminar reads only your secret. A name that points at a secret you haven't created leaves Laminar waiting for a secret nothing creates.

To switch from auto-managed to customer-managed, create your secret first, then set `backendSecretName` and upgrade. To switch back, remove `backendSecretName` and upgrade. The bootstrapper runs again and recreates `<release>-laminar-backend`.

> [!WARNING]
>
> A customer-managed secret must point at a database Laminar can reach from the platform namespace, and you own its lifecycle. Rotating the credential means updating the secret and restarting both Laminar Deployments, because Pods read the connection string at start.

## Set resources and replicas

Override the default requests and limits with `laminar.apiServer.resources` and `laminar.hypervisor.resources`.

| Component | CPU request | Memory request | CPU limit | Memory limit |
| - | - | - | - | - |
| API Server | `400m` | `256Mi` | `1` | `1Gi` |
| Hypervisor | `200m` | `256Mi` | `1` | `1Gi` |

Edit the data plane's `values.yaml`:

```yaml wrap theme={null}
laminar:
  apiServer:
    resources:
      requests:
        cpu: "800m"
        memory: "512Mi"
      limits:
        cpu: "2"
        memory: "2Gi"
  hypervisor:
    resources:
      requests:
        cpu: "400m"
        memory: "512Mi"
      limits:
        cpu: "2"
        memory: "2Gi"
```

Replica counts differ by component:

* The Hypervisor always runs with one replica, with no user overrides. High availability for the Hypervisor isn't supported.
* `laminar.apiServer.replicas` defaults to `2` and takes any number. The API Server is stateless, so add replicas when the request volume from KEDA and the operator grows.

### Sizing

Astronomer hasn't published sizing guidance for larger Deployment counts. Until the benchmarks are complete, start from the chart defaults, watch CPU and memory use against the limits, and raise the limits for any component that approaches them. The API Server scales with the number of Deployments and worker queues.

## Compatibility and limits

Laminar in APC 2.2 supports the following:

* Deployments in Airflow operator mode. Laminar doesn't manage Helm-mode Deployments.
* Both the Celery executor and the Kubernetes executor. Laminar doesn't change which executor a Deployment runs.
* Mixed data planes. Deployments that Laminar manages and Deployments it doesn't can run side by side on the same data plane.
* Deployments in Airflow operator mode that run Astro Runtime 3.3.x or earlier.

The following limits apply in APC 2.2:

* [Namespace pools](https://astronomer.io/docs/astro-private-cloud/v-2-x/namespace-pools.md) are unsupported.
* Installations that run without cluster roles, where `global.clusterRoles` is `false`, are unsupported. Both Laminar components need cluster-scoped read and scale access to Airflow custom resources.
* Existing Deployments aren't brought under Laminar's management until the next time each one is updated.
* Incident detection and automatic healing aren't available.

## Security

Laminar runs entirely in the data plane. Its components communicate only with in-cluster platform components and the Kubernetes API, so Laminar adds no outbound connection to an Astronomer-hosted service and works in an air-gapped installation.

When Laminar is enabled, the metadata database secret for every operator-based Airflow Deployment on the data plane is synced into the platform namespace, so Laminar can read it and manage those Deployments. The originals also stay in their Deployment namespaces, so count both copies when you audit where Deployment database credentials exist.

When `global.rbac.enabled` is `true`, the chart creates the following for each component:

* A namespaced `Role` and `RoleBinding` in the platform namespace, granting `get`, `list`, and `watch` on secrets.
* A `ClusterRole` and `ClusterRoleBinding` for the `airflow.apache.org` API group. The Hypervisor reads Airflow resources and patches their scale subresources, along with Kubernetes Deployments, Pods, and KEDA scaled objects. The API Server reads and patches Airflow resources and reads the scheduler scale subresource.

When `global.networkPolicy.enabled` is `true`, the sub-chart ships an ingress `NetworkPolicy` for each component. Both accept traffic on port 8000 from Prometheus, Houston, and the data plane internal API only. The API Server additionally accepts traffic from the ingress controller, and, when worker autoscaling is on, from the namespace named in `global.keda.namespace`.

## Monitor Laminar

Both components serve Prometheus metrics at `/laminar/metrics` on port 8000. When `global.laminar.enabled` is `true`, the platform's Prometheus scrapes them as the `laminar-hypervisor` and `laminar-api-server` jobs, and prefixes the Hypervisor's metrics with `hypervisor_`. On a split installation, the control plane federates both jobs from each data plane.

Two platform alerts cover Laminar:

| Alert | Fires when |
| - | - |
| `LaminarComponentUnhealthy` | A Hypervisor or API Server container has been not-ready for more than five minutes. |
| `LaminarDeploymentDown` | Either component has had zero available replicas for more than 10 minutes. |

Both are critical. To route them, see [Platform alerts](https://astronomer.io/docs/astro-private-cloud/v-2-x/platform-alerts.md).

## Turn Laminar off

Set `global.laminar.enabled` back to `false` and upgrade the release. Helm removes both components and everything the sub-chart created for them.

> [!NOTE]
>
> Turning Laminar off doesn't delete its database. The `<release>-laminar` database and the secret holding its connection string stay in place, and Laminar reuses them if you turn it back on. Drop the database yourself after disabling this feature.

Before you turn it off:

1. Wake any hibernated Deployment. With the Hypervisor gone, nothing evaluates hibernation schedules or overrides, and a Deployment that is scaled to zero stays there.
2. Confirm that no Deployment relies on worker autoscaling. Without the API Server, KEDA gets no worker count, and every autoscaling queue drops to its minimum worker count.

Running Deployments that use neither feature are unaffected. Their Airflow components keep running at the replica counts they were last set to.

> [!WARNING]
>
> Laminar runs in the platform release namespace, alongside the rest of the platform components. Don't delete the namespace to turn Laminar off.

## Related documentation

* [Hibernate Deployments](https://astronomer.io/docs/astro-private-cloud/v-2-x/hibernate-deployments.md)
* [Configure worker autoscaling](https://astronomer.io/docs/astro-private-cloud/v-2-x/configure-worker-autoscaling.md)
* [Deploy Airflow with the Airflow Operator](https://astronomer.io/docs/astro-private-cloud/v-2-x/airflow-operator-mode.md)
* [Apply a config change](https://astronomer.io/docs/astro-private-cloud/v-2-x/apply-platform-config.md)
* [Platform alerts](https://astronomer.io/docs/astro-private-cloud/v-2-x/platform-alerts.md)
