> ## 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.

# Deploy Airflow with the Airflow Operator

> Manage an Astro Private Cloud Deployment through the Airflow Kubernetes Operator instead of a Helm release.

Astro Private Cloud (APC) manages Airflow Deployments with Helm by default. Operator mode is an alternative that manages a Deployment through the Airflow Kubernetes Operator — a kubebuilder-based controller that reconciles Airflow Deployments from a custom resource definition (CRD) — instead of a Helm release. You choose the mode for each Deployment. Helm remains the default and is fully supported.

<Note>
  **Astro Private Cloud 2.1**

  This feature was introduced in Astro Private Cloud 2.1. To access this feature, upgrade your Astro Private Cloud installation to 2.1 or later.
</Note>

<Warning>
  Airflow operator support is under active development for Astro Private Cloud. Several Helm-mode features aren't available in operator mode yet. See [Feature support](#feature-support).
</Warning>

If your cluster already runs the Astro Runtime Operator, you can bring its existing Airflow Deployments under APC management with [Adopt Astro Runtime Operator managed Deployments](/docs/astro-private-cloud/v-2-x/adopt-operator-deployments), and hand the operator itself over with [Move the operator under APC](/docs/astro-private-cloud/v-2-x/transition-operator-to-apc).

## Concepts

* Deployment mode: each APC Deployment is either Helm (a Helm release, the default) or operator (an Airflow CRD reconciled by the operator).
* Reconciliation: the control plane builds the Airflow custom resource (CR) spec from the Deployment configuration, and the data plane applies the CR and monitors the operator's reconciliation, rather than managing a Helm release.
* Mixed mode: a single APC installation can run Helm and operator Deployments side by side, and you can enable operator support for each data plane.
* Cluster-scoped resources: the operator requires cluster-level CRDs, mutating and validating webhooks, and cert-manager. Review these with your security team before you enable operator support. See [Security and governance](#security-and-governance).

## Prerequisites

* An APC 2.1 or later installation running in [split mode](/docs/astro-private-cloud/v-2-x/data-plane-architecture) or [unified mode](/docs/astro-private-cloud/v-2-x/unified-architecture).
* Permission to update the Helm values for the data plane, or for the unified installation.
* Cluster-level permission to install CRDs and to configure mutating and validating webhooks.
* Either [cert-manager](https://cert-manager.io/) in the cluster, or a serving certificate you generate yourself. See [Provide the webhook TLS certificate](#provide-the-webhook-tls-certificate).

## Enable operator support

Operator support is off by default, and it installs with the data plane, which hosts operator Deployments. In [split mode](/docs/astro-private-cloud/v-2-x/data-plane-architecture), enable it in the Helm configuration for the data plane. In [unified mode](/docs/astro-private-cloud/v-2-x/unified-architecture), where the control plane and data plane run in the same cluster, enable it in that installation's Helm configuration:

```yaml theme={null}
global:
  airflowOperator:
    enabled: true
```

Enabling operator support installs the operator CRDs, configures the mutating and validating webhooks, adds the Prometheus label filters for operator Deployments, and grants the data plane the role-based access control (RBAC) it needs for `airflow.apache.org` CRD resources.

### Enable the operator Deployment mode in the APC API

The APC API accepts an operator Deployment only when the operator Deployment mode is enabled in the effective `deployments.mode` configuration for the target cluster. `global.airflowOperator.enabled: true` sets `deployments.mode.operator.enabled: true` in the platform-level APC API configuration, so you don't need to set `astronomer.houston.config.deployments.mode` in `values.yaml` yourself.

The platform-level value applies only to clusters that you register after you enable operator support. It doesn't change the `deployments` configuration of a cluster that was already registered. Enable operator mode in the cluster configuration for each existing cluster where you want to create operator Deployments. See [Set the mode in a cluster override](#set-the-mode-in-a-cluster-override).

If operator mode isn't enabled for the cluster, creating or updating an operator Deployment fails with the following error:

```text theme={null}
Deployment with mode - operator cannot be created or updated.
Reason: deployments.mode.operator.enabled is false
```

#### Set the mode in a cluster override

For a cluster that you registered before you enabled operator support, set `mode.operator.enabled: true` in the cluster's **Cluster Deployments Configuration** override:

1. In the APC UI, go to **Clusters** and select the cluster.

2. Click **Edit**. In the **Cluster Deployments Configuration** YAML editor, add the following override:

   ```yaml theme={null}
   mode:
     operator:
       enabled: true
   ```

3. Click **Update Cluster**.

You can also set the same key through the APC API `updateCluster` mutation with `deploymentsConfigOverride`. See [Override data plane cluster configurations](/docs/astro-private-cloud/v-2-x/override-data-plane-cluster#override-base-configuration).

The `deployments.mode` keys follow the same [config governance](/docs/astro-private-cloud/v-2-x/config-governance) tiers as other `deployments` settings. A Workspace or Deployment override that sets `mode.operator.enabled: false` also blocks operator Deployments in that scope.

#### Verify the enabled Deployment modes

Run the following query against the [APC API](/docs/astro-private-cloud/v-2-x/houston-api) to confirm which Deployment modes a cluster accepts. Replace `<cluster-id>` with the ID of the cluster:

```graphql theme={null}
query {
  appConfig(clusterId: "<cluster-id>") {
    enabledDeploymentModes
  }
}
```

The expected result is `["helm", "operator"]`. If the result is only `["helm"]`, operator mode isn't enabled for the cluster. Complete [Set the mode in a cluster override](#set-the-mode-in-a-cluster-override).

### Provide the webhook TLS certificate

The Kubernetes API server calls the operator's mutating and validating webhooks over TLS, so the webhooks need a serving certificate and the CA bundle that signed it. Choose one of the following methods based on whether cert-manager is available in your cluster.

<Warning>
  Configure exactly one of these methods. The operator sub-chart uses cert-manager by default; if you disable cert-manager without providing your own certificate, the chart fails to render with an error instead of installing a broken webhook.
</Warning>

#### Use cert-manager

cert-manager is enabled for the operator sub-chart by default. If [cert-manager](https://cert-manager.io/) is available in your cluster, keep it enabled: it generates the serving certificate with the correct DNS names and injects the CA bundle into the webhook configurations automatically:

```yaml theme={null}
airflow-operator:
  certManager:
    enabled: true
```

This is the recommended method. It requires no manual certificate management, and cert-manager renews the certificate before it expires.

#### Provide your own certificate

If cert-manager isn't available, generate a serving certificate yourself and pass it to the operator sub-chart. The webhook Service is named `<release-name>-airflow-operator-webhook-service`.

<Steps>
  <Step title="Set the Service DNS names">
    Set the DNS names as shell variables. The certificate must be valid for both, or the API server rejects the webhook connection:

    ```bash theme={null}
    export NAMESPACE=<apc-namespace>
    export SERVICE=<release-name>-airflow-operator-webhook-service
    export DNS1="${SERVICE}.${NAMESPACE}.svc"
    export DNS2="${SERVICE}.${NAMESPACE}.svc.cluster.local"
    ```
  </Step>

  <Step title="Generate the CA and serving certificate">
    Generate a CA and a serving certificate whose Subject Alternative Names (SANs) cover both DNS names:

    ```bash theme={null}
    # Generate a CA key and self-signed CA certificate. This becomes the caBundle.
    openssl genrsa -out ca.key 2048
    openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
      -subj "/CN=airflow-operator-webhook-ca" -out ca.crt

    # Generate the serving key and certificate signing request.
    openssl genrsa -out tls.key 2048
    openssl req -new -key tls.key -subj "/CN=${DNS1}" -out tls.csr

    # Sign the request with the CA, embedding the required SANs.
    cat > san.ext <<EOF
    subjectAltName = DNS:${DNS1}, DNS:${DNS2}
    extendedKeyUsage = serverAuth
    EOF

    openssl x509 -req -in tls.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
      -out tls.crt -days 3650 -sha256 -extfile san.ext
    ```

    Don't reuse an ingress or general-purpose certificate. A certificate that lacks the `.svc` SANs fails the webhook TLS handshake even when the CA bundle is correct.
  </Step>

  <Step title="Create the TLS secret">
    Create a `kubernetes.io/tls` secret in the release namespace from the serving certificate and key:

    ```bash theme={null}
    kubectl -n "${NAMESPACE}" create secret tls airflow-operator-webhook-tls \
      --cert=tls.crt --key=tls.key
    ```
  </Step>

  <Step title="Configure the operator sub-chart">
    Point the operator sub-chart at the secret and provide the CA bundle. Set `certManager.enabled` to `false`, `webhooks.useCustomTlsCerts` to `true`, `webhooks.customCertsSecretName` to the secret name, and `webhooks.caBundle` to the raw contents of `ca.crt`:

    ```yaml theme={null}
    airflow-operator:
      certManager:
        enabled: false
      webhooks:
        useCustomTlsCerts: true
        customCertsSecretName: airflow-operator-webhook-tls
        caBundle: |
          -----BEGIN CERTIFICATE-----
          ...
          -----END CERTIFICATE-----
    ```

    Provide `caBundle` as raw PEM text, not base64. When `webhooks.useCustomTlsCerts` is `true`, both `webhooks.customCertsSecretName` and `webhooks.caBundle` are required — the chart fails to render if either is missing.
  </Step>
</Steps>

<Note>
  Certificates you provide yourself don't renew automatically. Before `tls.crt` expires, regenerate it, update the secret, and redeploy. If the CA changes, update `caBundle` as well.
</Note>

## Create an operator Deployment

After you enable operator support, a **Deployment Mode** selector appears when you create a Deployment. To create an operator-managed Deployment, set **Deployment Mode** to **Operator**, then complete the rest of the Deployment configuration as usual.

**Helm** is the default, and the selector doesn't appear when operator support is off.

<Frame>
  <img src="https://mintcdn.com/astronomer/V_9YWWO4aJDSUYR5/images/astro-private-cloud/deployment-mode-selector.png?fit=max&auto=format&n=V_9YWWO4aJDSUYR5&q=85&s=b6a84e788d5c36fca27525c967eead31" alt="The New Deployment page with the Deployment Mode selector showing Helm and Operator options, with Operator selected." width="2894" height="1914" data-path="images/astro-private-cloud/deployment-mode-selector.png" />
</Frame>

### Operator mode preconditions

The APC API validates the configuration of an operator Deployment when you create or update it. It rejects the Deployment with an `InvalidConfigForOperatorMode` error when any of the following conditions apply:

* The executor is `LocalExecutor`. Use the Celery executor or the Kubernetes executor.
* The Dag deployment type is `github`, `volume`, or `dag_only`. Operator mode supports image-based Dag deploys only.
* Free-form namespace entry is enabled in the cluster configuration (`namespaceManagement.namespaceFreeFormEntry.enabled: true`).
* Manual namespace names are enabled in the cluster configuration (`namespaceManagement.manualNamespaceNames.enabled: true`). APC enables this setting when you configure namespace pools.

Each condition fails with its own reason in the error message. Fix the configuration that the message names, then create the Deployment again.

## Feature support

Operator mode reaches most Helm capabilities, but not all. Use Helm mode for a Deployment that needs a feature in the second of the following lists.

Available in operator mode in APC 2.1:

* Celery executor and Kubernetes executor
* Airflow 2 and Airflow 3
* PostgreSQL-backed Deployments
* Private registry
* Auth sidecar and bring-your-own ingress
* Network policies for Airflow components and platform-level network policy
* Custom resource configuration (CPU and memory)
* Manual release name
* DaemonSet logging
* In-cluster and external Elasticsearch logging
* Airflow rollback
* OpenShift support

Not yet available in operator mode — use Helm mode:

* Dag-only deploy, Network File System (NFS) volume and git-sync Dag Deployment
* Namespace pools
* Sidecar logging
* MySQL-backed Deployments
* Resource-quota enforcement
* Enabling or disabling the triggerer independently
* Celery Flower UI
* Disaster-recovery (DR) failover and control-plane high availability (HA)

## Security and governance

Operator mode installs cluster-scoped resources:

* The Airflow CRDs
* A mutating and validating webhook
* cert-manager integration, when you use cert-manager to issue the webhook certificate

Because these are cluster-level, review them with your security team before you enable operator support.

If your change-control process requires it, you can manage the CRDs out-of-band — for example, install them separately as a cluster admin or through GitOps — so the platform chart doesn't create them. Set `crd.create` to `false` on the operator sub-chart:

```yaml theme={null}
airflow-operator:
  crd:
    create: false
```

The default is `true`, which lets the chart create the CRDs. When you set it to `false`, install the operator CRDs yourself before you create any operator Deployment.

<Note>
  The operator CRDs carry a `helm.sh/resource-policy: keep` annotation, so Helm never deletes them, even when you set `crd.create` to `false` on an existing installation. This prevents an upgrade from removing the CRDs, which would delete every operator Deployment. Remove the CRDs manually only after you delete all operator Deployments.
</Note>

## Known limitations

* Several Helm-mode features aren't available in operator mode. See [Feature support](#feature-support). Helm remains the default and the fuller-featured mode.
* Operator mode isn't a migration path between modes. You set the mode when you create a Deployment, and you can't convert an existing Deployment from Helm to operator or from operator to Helm. To change modes, create a new Deployment in the target mode.
