### Install Airflow Helm Chart Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/guides/quickstart.md Installs the Airflow Helm chart with custom values and specifies the release name and namespace. Ensure you have a custom-values.yaml file prepared. ```shell ## set the release-name & namespace export AIRFLOW_NAME="airflow-cluster" export AIRFLOW_NAMESPACE="airflow-cluster" ## create the namespace kubectl create ns "$AIRFLOW_NAMESPACE" ## install using helm 3 helm install \ "$AIRFLOW_NAME" \ airflow-stable/airflow \ --namespace "$AIRFLOW_NAMESPACE" \ --version "8.X.X" \ --values ./custom-values.yaml ## wait until the above command returns and resources become ready ## (may take a while) ``` -------------------------------- ### Create Redshift Credentials Secret Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/mount-files.md Example command to create a Kubernetes Secret named 'redshift-creds' with user and password literals. ```shell kubectl create secret generic \ redshift-creds \ --from-literal=user=MY_REDSHIFT_USERNAME \ --from-literal=password=MY_REDSHIFT_PASSWORD \ --namespace my-airflow-namespace ``` -------------------------------- ### Example Canary DAG for Task Creation Check Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/monitoring/scheduler-liveness-probe.md A sample DAG definition to run a small task periodically, useful for testing the scheduler's task creation capabilities. Ensure the schedule interval matches or is shorter than `thresholdSeconds` in the liveness probe configuration. ```python from datetime import datetime, timedelta from airflow import DAG # import using try/except to support both airflow 1 and 2 try: from airflow.operators.bash import BashOperator except ModuleNotFoundError: from airflow.operators.bash_operator import BashOperator dag = DAG( dag_id="canary_dag", default_args={ "owner": "airflow", }, schedule_interval="*/5 * * * *", start_date=datetime(2022, 1, 1), dagrun_timeout=timedelta(minutes=5), is_paused_upon_creation=False, catchup=False, ) # WARNING: while `DummyOperator` would use less resources, the check can't see those tasks # as they don't create LocalTaskJob instances task = BashOperator( task_id="canary_task", bash_command="echo 'Hello World!'", dag=dag, ) ``` -------------------------------- ### Define Airflow Plugins ConfigMap Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-plugins.md Example of an `airflow-plugins` ConfigMap containing a Python file for an Airflow plugin. This ConfigMap can be directly applied to your Kubernetes cluster. ```yaml apiVersion: v1 kind: ConfigMap metadata: name: airflow-plugins data: my_airflow_plugin.py: | from airflow.plugins_manager import AirflowPlugin class MyAirflowPlugin(AirflowPlugin): name = "my_airflow_plugin" ... ``` -------------------------------- ### Set Webserver Secret Key using _CMD Config Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/security/set-webserver-secret-key.md Configure Airflow to read the secret key from a file using `AIRFLOW__WEBSERVER__SECRET_KEY_CMD`. Ensure `webserverSecretKey` is set to an empty string to avoid precedence issues. This example also shows mounting a secret as a volume. ```yaml airflow: ## WARNING: you must set `webserverSecretKey` to "", otherwise it will take precedence webserverSecretKey: "" ## NOTE: this is only an example, if your value lives in a Secret, you probably want to use "Option 2" above config: AIRFLOW__WEBSERVER__SECRET_KEY_CMD: "cat /opt/airflow/webserver-secret-key/value" extraVolumeMounts: - name: webserver-secret-key mountPath: /opt/airflow/webserver-secret-key readOnly: true extraVolumes: - name: webserver-secret-key secret: secretName: airflow-webserver-secret-key ``` -------------------------------- ### Install Pip Packages in KubernetesExecutor Pod Template Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Use `airflow.kubernetesPodTemplate.extraPipPackages` to install pip packages within the KubernetesExecutor Pod Template. Global packages defined in `airflow.extraPipPackages` are not installed here. ```yaml airflow: kubernetesPodTemplate: extraPipPackages: - "torch==1.8.0" ``` -------------------------------- ### Dockerfile to Embed Extra Python Packages Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md This Dockerfile extends an official Airflow image to include additional pip packages. It uses `pip install --no-cache-dir` for efficient installation. Use this to build a custom Airflow image with your required dependencies. ```dockerfile FROM apache/airflow:2.8.4-python3.9 # install your pip packages RUN pip install --no-cache-dir \ torch~=1.8.0 ``` -------------------------------- ### Include ConfigMap using extraManifests Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-plugins.md This example demonstrates how to include the `airflow-plugins` ConfigMap definition directly within your Helm chart's `values.yaml` using the `extraManifests` value. This approach embeds the ConfigMap creation into the Helm deployment. ```yaml extraManifests: - | apiVersion: v1 kind: ConfigMap metadata: name: airflow-plugins labels: app: {{ include "airflow.labels.app" . }} chart: {{ include "airflow.labels.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} data: my_airflow_plugin.py: | from airflow.plugins_manager import AirflowPlugin class MyAirflowPlugin(AirflowPlugin): name = "my_airflow_plugin" ... ``` -------------------------------- ### Example Semantic Commit Messages Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/CONTRIBUTING.md Commit messages and PR names must follow semantic conventions to pass automated checks. Examples include 'feat' for new features, 'fix' for bug fixes, and 'docs' for documentation changes. ```text feat: a new feature ``` ```text fix: a bug fix ``` ```text docs: documentation only change ``` ```text style: fix formatting/white-space/etc ``` ```text refactor: code change that neither fixes a bug nor adds a feature ``` ```text test: add or update tests ``` ```text ci: changes to CI configs ``` ```text chore: other changes that dont modify code ``` ```text revert: revert a commit ``` -------------------------------- ### Set Airflow Cluster Policy with airflow_local_settings.py Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-configs.md Implement custom cluster policies by providing the content of `airflow_local_settings.py` via `airflow.localSettings.stringOverride`. This example enforces that DAGs must have at least one tag. ```yaml airflow: localSettings: ## the full content of the `airflow_local_settings.py` file, as a string stringOverride: | from airflow.models import DAG from airflow.exceptions import AirflowClusterPolicyViolation def dag_policy(dag: DAG): """Ensure that DAG has at least one tag""" if not dag.tags: raise AirflowClusterPolicyViolation( f"DAG {dag.dag_id} has no tags. At least one tag required. File path: {dag.fileloc}" ) ``` -------------------------------- ### Add and Update Airflow Helm Repository Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/guides/quickstart.md Adds the Airflow Helm chart repository and updates the local repository cache. This is a prerequisite for installing the chart. ```shell ## add this helm repository helm repo add airflow-stable https://airflow-helm.github.io/charts ## update your helm repo cache helm repo update ``` -------------------------------- ### Uninstall Airflow Helm Chart Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/guides/uninstall.md Use these commands to set the release name and namespace, then uninstall the Airflow chart. Ensure the release name and namespace match your installation. ```shell ## set the release-name & namespace (must be same as previously installed) export AIRFLOW_NAME="airflow-cluster" export AIRFLOW_NAMESPACE="airflow-cluster" ## uninstall the chart helm uninstall \ "$AIRFLOW_NAME" \ --namespace "$AIRFLOW_NAMESPACE" ``` -------------------------------- ### AWS Connection - Plain Text Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Defines an AWS connection using plain-text credentials. Use this for simple setups, but consider more secure options for production. ```yaml airflow: connections: - id: my_aws type: aws description: my AWS connection ## your `AWS_ACCESS_KEY_ID` login: XXXXXXXX ## your `AWS_SECRET_ACCESS_KEY` password: XXXXXXXX ## see the official "aws" connection docs for valid extra configs extra: | { "region_name": "eu-central-1" } ``` -------------------------------- ### Update Helm Repository and Upgrade Airflow Chart Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/guides/upgrade.md This snippet demonstrates how to update your local Helm repository and then upgrade an existing Airflow chart installation. It includes setting environment variables for the release name and namespace, and applying custom values from a file. ```shell ## pull updates from the helm repository helm repo update ## set the release-name & namespace (must be same as previously installed) export AIRFLOW_NAME="airflow-cluster" export AIRFLOW_NAMESPACE="airflow-cluster" ## apply any changed `custom-values.yaml` AND upgrade the chart to version `8.X.X` helm upgrade \ "$AIRFLOW_NAME" \ airflow-stable/airflow \ --namespace "$AIRFLOW_NAMESPACE" \ --version "8.X.X" \ --values ./custom-values.yaml ``` -------------------------------- ### Dockerfile to Embed Airflow Plugins Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-plugins.md This Dockerfile extends an official Airflow image and copies custom plugin files into the container. It also demonstrates installing plugins packaged as Python packages using pip. Use this to build a custom Airflow image with your plugins. ```dockerfile FROM apache/airflow:2.8.4-python3.9 # plugin files can be copied under `/home/airflow/plugins` # (where `./plugins` is relative to the docker build context) COPY plugins/* /home/airflow/plugins/ # plugins exposed as python packages can be installed with pip RUN pip install --no-cache-dir \ example==1.0.0 ``` -------------------------------- ### Create Kubernetes Secret for Airflow Azure Credentials Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Example command to create a Kubernetes secret named 'my-wasb-token' containing Azure credentials. Ensure you replace 'xxxxxxxxxxxxxxxxxxxx' with your actual credentials. ```shell kubectl create secret generic \ my-wasb-token \ --from-literal=AZURE_CLIENT_ID='xxxxxxxxxxxxxxxxxxxx' \ --from-literal=AZURE_CLIENT_SECRET='xxxxxxxxxxxxxxxxxxxx' \ --from-literal=AZURE_TENANT_ID='xxxxxxxxxxxxxxxxxxxx' \ --namespace my-airflow-namespace ``` -------------------------------- ### Configure Airflow for Microsoft Active Directory LDAP Integration Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/security/ldap-oauth.md Use these webserverConfig values to integrate with a typical Microsoft Active Directory server. This example assumes all users can perform an LDAP search. ```yaml web: webserverConfig: ## this is the full text of your `webserver_config.py` stringOverride: | from flask_appbuilder.security.manager import AUTH_LDAP # only needed for airflow 1.10 #from airflow import configuration as conf #SQLALCHEMY_DATABASE_URI = conf.get("core", "SQL_ALCHEMY_CONN") AUTH_TYPE = AUTH_LDAP AUTH_LDAP_SERVER = "ldap://ldap.example.com" AUTH_LDAP_USE_TLS = False # registration configs AUTH_USER_REGISTRATION = True # allow users who are not already in the FAB DB AUTH_USER_REGISTRATION_ROLE = "Public" # this role will be given in addition to any AUTH_ROLES_MAPPING AUTH_LDAP_FIRSTNAME_FIELD = "givenName" AUTH_LDAP_LASTNAME_FIELD = "sn" AUTH_LDAP_EMAIL_FIELD = "mail" # if null in LDAP, email is set to: "{username}@email.notfound" # bind username (for password validation) AUTH_LDAP_USERNAME_FORMAT = "uid=%s,ou=users,dc=example,dc=com" # %s is replaced with the provided username # AUTH_LDAP_APPEND_DOMAIN = "example.com" # bind usernames will look like: {USERNAME}@example.com # search configs AUTH_LDAP_SEARCH = "ou=users,dc=example,dc=com" # the LDAP search base (if non-empty, a search will ALWAYS happen) AUTH_LDAP_UID_FIELD = "uid" # the username field # a mapping from LDAP DN to a list of FAB roles AUTH_ROLES_MAPPING = { "cn=airflow_users,ou=groups,dc=example,dc=com": ["User"], "cn=airflow_admins,ou=groups,dc=example,dc=com": ["Admin"], } # the LDAP user attribute which has their role DNs AUTH_LDAP_GROUP_FIELD = "memberOf" # if we should replace ALL the user's roles each login, or only on registration AUTH_ROLES_SYNC_AT_LOGIN = True # force users to re-auth after 30min of inactivity (to keep roles in sync) PERMANENT_SESSION_LIFETIME = 1800 ``` -------------------------------- ### Install Pip Packages on All Airflow Pods Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Use `airflow.extraPipPackages` to install pip packages on all Airflow Pods. Note that these packages will not be installed in the KubernetesExecutor pod template. ```yaml airflow: extraPipPackages: - "torch==1.8.0" ``` -------------------------------- ### Build PostgreSQL Image for ARM64 Source: https://github.com/airflow-helm/charts/blob/main/images/postgresql-bitnami/11/alpine/README.md These commands are used to build the Docker image for ARM64 architecture, including setting up buildx and caching layers to the GitHub Container Registry. ```bash cd images/postgresql-bitnami/11/alpine docker buildx create --name multiarch --driver docker-container --use || docker buildx use multiarch docker buildx build --cache-to=type=registry,ref=ghcr.io/airflow-helm/ci/images/postgresql-bitnami/11/alpine,mode=max . docker buildx stop multiarch ``` -------------------------------- ### Configure Airflow and Flower Ingress with URL Prefixes Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/ingress.md Set `AIRFLOW__WEBSERVER__BASE_URL` and `AIRFLOW__CELERY__FLOWER_URL_PREFIX` to enable Airflow and Flower under URL prefixes. Configure `ingress.enabled`, `ingress.web.path`, and `ingress.flower.path` to match these prefixes. ```yaml airflow: config: AIRFLOW__WEBSERVER__BASE_URL: "http://example.com/airflow/" AIRFLOW__CELERY__FLOWER_URL_PREFIX: "/airflow/flower" ingress: enabled: true ## WARNING: set as "networking.k8s.io/v1beta1" for Kubernetes 1.18 and earlier apiVersion: networking.k8s.io/v1 ## airflow webserver ingress configs web: annotations: {} host: "example.com" path: "/airflow" ## WARNING: requires Kubernetes 1.18 or later, use "kubernetes.io/ingress.class" annotation for older versions ingressClassName: "nginx" ## flower ingress configs flower: annotations: {} host: "example.com" path: "/airflow/flower" ## WARNING: requires Kubernetes 1.18 or later, use "kubernetes.io/ingress.class" annotation for older versions ingressClassName: "nginx" ``` -------------------------------- ### Install Packages from a Private Pip Index Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Configure pip to use a private Python Package Index by setting `PIP_INDEX_URL` and `PIP_TRUSTED_HOST` in `airflow.config`. This allows installation of internal packages like `my-internal-package`. ```yaml airflow: config: ## pip configs can be set with environment variables PIP_TIMEOUT: 60 PIP_INDEX_URL: https://:@example.com/packages/simple/ PIP_TRUSTED_HOST: example.com extraPipPackages: - "my-internal-package==1.0.0" ``` -------------------------------- ### Enable and Configure PgBouncer Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/database/pgbouncer.md This snippet shows how to enable the PgBouncer deployment and configure various settings including connection limits, pool size, logging, and SSL modes for both client and server connections. ```yaml pgbouncer: ## if the pgbouncer Deployment is created enabled: true ## sets pgbouncer config: `auth_type` authType: md5 ## sets pgbouncer config: `max_client_conn` maxClientConnections: 1000 ## sets pgbouncer config: `default_pool_size` poolSize: 20 ## sets pgbouncer config: `log_disconnections` logDisconnections: 0 ## sets pgbouncer config: `log_connections` logConnections: 0 ## ssl configs for: clients -> pgbouncer ## clientSSL: ## sets pgbouncer config: `client_tls_sslmode` mode: prefer ## sets pgbouncer config: `client_tls_ciphers` ciphers: normal ## sets pgbouncer config: `client_tls_ca_file` caFile: existingSecret: "" existingSecretKey: root.crt ## sets pgbouncer config: `client_tls_key_file` ## WARNING: a self-signed cert & key are generated if left empty keyFile: existingSecret: "" existingSecretKey: client.key ## sets pgbouncer config: `client_tls_cert_file` ## WARNING: a self-signed cert & key are generated if left empty certFile: existingSecret: "" existingSecretKey: client.crt ## ssl configs for: pgbouncer -> postgres ## serverSSL: ## sets pgbouncer config: `server_tls_sslmode` mode: prefer ## sets pgbouncer config: `server_tls_ciphers` ciphers: normal ## sets pgbouncer config: `server_tls_ca_file` caFile: existingSecret: "" existingSecretKey: root.crt ## sets pgbouncer config: `server_tls_key_file` keyFile: existingSecret: "" existingSecretKey: server.key ## sets pgbouncer config: `server_tls_cert_file` certFile: existingSecret: "" existingSecretKey: server.crt ``` -------------------------------- ### Install Pip Packages on Flower Pods Only Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Use `flower.extraPipPackages` to install pip packages exclusively on Airflow Flower Pods. If a package is defined globally and here, the Flower's version takes precedence. ```yaml flower: extraPipPackages: - "torch==1.8.0" ``` -------------------------------- ### Create a Deployment for a Busybox Container Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/extra-manifests.md This snippet demonstrates how to create a Kubernetes Deployment for a busybox container. It includes a command to keep the container running and responsive to SIGTERM signals. ```yaml extraManifests: - | apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "airflow.fullname" . }}-busybox labels: app: {{ include "airflow.labels.app" . }} component: busybox chart: {{ include "airflow.labels.chart" . }} release: {{ .Release.Name }} heritage: {{ .Release.Service }} spec: replicas: 1 selector: matchLabels: app: {{ include "airflow.labels.app" . }} component: busybox release: {{ .Release.Name }} template: metadata: labels: app: {{ include "airflow.labels.app" . }} component: busybox release: {{ .Release.Name }} spec: containers: - name: busybox image: busybox:1.35 command: - "/bin/sh" - "-c" args: - | ## to break the infinite loop when we receive SIGTERM trap "exit 0" SIGTERM; ## keep the container running (so people can `kubectl exec -it` into it) while true; do echo "I am alive..."; sleep 30; done ``` -------------------------------- ### Install Pip Packages on Scheduler Pods Only Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Use `scheduler.extraPipPackages` to install pip packages exclusively on Airflow Scheduler Pods. If a package is defined globally and here, the scheduler's version takes precedence. ```yaml scheduler: extraPipPackages: - "torch==1.8.0" ``` -------------------------------- ### Install Pip Packages on Worker Pods Only (CeleryExecutor) Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/extra-python-packages.md Use `worker.extraPipPackages` to install pip packages exclusively on Airflow Worker Pods when using the CeleryExecutor. If a package is defined globally and here, the worker's version takes precedence. ```yaml worker: extraPipPackages: - "torch==1.8.0" ``` -------------------------------- ### Set Fernet Key using AIRFLOW__CORE__FERNET_KEY_CMD Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/security/set-fernet-key.md Configure the Fernet key using a command that retrieves the key, typically from a mounted secret file. Ensure `airflow.fernetKey` is set to an empty string to avoid precedence issues. This method involves setting `AIRFLOW__CORE__FERNET_KEY_CMD`, `airflow.extraVolumeMounts`, and `airflow.extraVolumes`. ```yaml airflow: ## WARNING: you must set `fernetKey` to "", otherwise it will take precedence fernetKey: "" ## NOTE: this is only an example, if your value lives in a Secret, you probably want to use "Option 2" above config: AIRFLOW__CORE__FERNET_KEY_CMD: "cat /opt/airflow/fernet-key/value" extraVolumeMounts: - name: fernet-key mountPath: /opt/airflow/fernet-key readOnly: true extraVolumes: - name: fernet-key secret: secretName: airflow-fernet-key ``` -------------------------------- ### Linting Command with Chart-Testing Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/CONTRIBUTING.md Run the chart-testing tool to ensure linting succeeds. This command checks the chart configuration and adherence to best practices. ```bash ct lint --config ct-config.yaml --check-version-increment=false ``` -------------------------------- ### Configure SSH Connection using Secret Keyfile Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md This configuration sets up an SSH connection using a private key file stored in a Kubernetes Secret. It mounts the secret as a volume and specifies the key file path in the connection's extra configuration. ```yaml airflow: connections: - id: my_ssh type: ssh description: my SSH connection host: ssh.example.com port: 22 ## see the official "ssh" connection docs for valid extra configs extra: | { "key_file": "/opt/airflow/secrets/ssh-keyfile/id_rsa", "conn_timeout": "15" } extraVolumeMounts: - name: ssh-keyfile mountPath: /opt/airflow/secrets/ssh-keyfile readOnly: true extraVolumes: - name: ssh-keyfile secret: ## assumes that `Secret/my-ssh-keyfile` contains a key called `id_rsa` secretName: my-ssh-keyfile ## ssh complains if `id_rsa` has permissions that are too open defaultMode: 0600 ``` ```shell kubectl create secret generic \ my-ssh-keyfile \ --from-file=id_rsa=$HOME/.ssh/id_rsa \ --namespace my-airflow-namespace ``` -------------------------------- ### Configure Azure Blob Storage Connection (Plain Text) Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Use this method to create a 'wasb' type connection by storing Azure credentials directly in plain text. This is not recommended for production environments. ```yaml airflow: connections: - id: my_wasb type: wasb description: my Azure Blob Storage connection ## your `AZURE_CLIENT_ID` login: XXXXXXXX ## your `AZURE_CLIENT_SECRET` password: XXXXXXXX ## your `AZURE_TENANT_ID` extra: | { "extra__wasb__tenant_id": "XXXXXXXX" } ``` -------------------------------- ### Configure Git-Sync with HTTP Authentication Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/load-dag-definitions.md Use this configuration to sync DAGs from a Git repository using HTTP authentication. Ensure the HTTP secret with username and password is properly configured. ```yaml airflow: config: ## NOTE: set by `dags.gitSync.syncWait`, unless you override it #AIRFLOW__SCHEDULER__DAG_DIR_LIST_INTERVAL: 60 dags: ## NOTE: this is the default value path: /opt/airflow/dags gitSync: enabled: true repo: "https://github.com/USERNAME/REPOSITORY.git" branch: "master" revision: "HEAD" ## the sub-path within your repo where dags are located ## NOTE: airflow will only see dags under this path, but the whole repo will still be synced #repoSubPath: "path/to/dags" ## number of seconds to wait between syncs ## NOTE: also sets `AIRFLOW__SCHEDULER__DAG_DIR_LIST_INTERVAL` unless overwritten in `airflow.config` syncWait: 60 ## the max number of seconds allowed for a complete sync ## NOTE: if your repo takes a very long time to sync, you may need to increase this value #syncTimeout: 120 ## the number of consecutive failures allowed before aborting ## NOTE: if your repo regularly has intermittent failures, you may wish to set a non-0 value #maxFailures: 0 httpSecret: "airflow-http-git-secret" httpSecretUsernameKey: username httpSecretPasswordKey: password ``` -------------------------------- ### Scheduler Task Creation Check Configuration Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/monitoring/scheduler-liveness-probe.md Enable and configure the task creation check for the scheduler liveness probe. This ensures the scheduler is actively creating tasks. ```yaml scheduler: livenessProbe: enabled: true taskCreationCheck: ## if the task creation check is enabled enabled: true ## the maximum number of seconds since the start_date of the most recent LocalTaskJob ## WARNING: must be AT LEAST equal to your shortest DAG schedule_interval ## WARNING: DummyOperator tasks will NOT be seen by this probe thresholdSeconds: 300 ## minimum number of seconds the scheduler must have run before the task creation check begins ## WARNING: must be long enough for the scheduler to boot and create a task ## schedulerAgeBeforeCheck: 180 ``` -------------------------------- ### Airflow Connection with Special Characters in Extra Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Example of an Airflow connection configuration where the 'extra' field contains a JSON object with escaped newlines and double quotes. ```yaml airflow: connections: - id: ... type: ... extra: | { "key_1": "line_one\n line_two\n special_\"_chars\n line_four\n" } ``` -------------------------------- ### Configure GCP Connection with Secret Keyfile Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Use this configuration to create a 'google_cloud_platform' connection named 'my_gcp' that references a keyfile stored in a Kubernetes secret. Ensure the secret and its key are correctly named and mounted. ```yaml airflow: connections: - id: my_gcp type: google_cloud_platform description: my GCP connection ## see the official "google_cloud_platform" connection docs for valid extra configs extra: | { "extra__google_cloud_platform__key_path": "/opt/airflow/secrets/gcp-keyfile/keyfile.json", "extra__google_cloud_platform__num_retries": 5 } extraVolumeMounts: - name: gcp-keyfile mountPath: /opt/airflow/secrets/gcp-keyfile readOnly: true extraVolumes: - name: gcp-keyfile secret: ## assumes that `Secret/my-gcp-keyfile` contains a key called `keyfile.json` secretName: my-gcp-keyfile ``` -------------------------------- ### Set Airflow 1.10 Version Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-version.md To use an Airflow 1.10.x version, you must set `airflow.legacyCommands` to `true`. This example shows how to set Airflow 1.10.15 with Python 3.8. ```yaml airflow: # WARNING: this must be "true" for airflow 1.10 legacyCommands: true image: repository: apache/airflow tag: 1.10.15-python3.8 ``` -------------------------------- ### Mount Persistent Volume on CeleryExecutor Workers Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/mount-persistent-volumes.md Use `workers.extraVolumeMounts` and `workers.extraVolumes` to mount a persistent volume on CeleryExecutor worker pods. This example mounts a volume named 'worker-tmp' at '/tmp'. ```yaml workers: extraVolumeMounts: - name: worker-tmp mountPath: /tmp readOnly: false extraVolumes: - name: worker-tmp persistentVolumeClaim: claimName: worker-tmp ``` -------------------------------- ### Configure Flask-AppBuilder webserver_config.py with stringOverride Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-configs.md Define the content of your `webserver_config.py` file directly using the `web.webserverConfig.stringOverride` value. This allows for custom Flask-AppBuilder configurations, such as setting authentication types. ```yaml web: webserverConfig: ## the full content of the `webserver_config.py` file, as a string stringOverride: | from airflow import configuration as conf from flask_appbuilder.security.manager import AUTH_DB # the SQLAlchemy connection string SQLALCHEMY_DATABASE_URI = conf.get('core', 'SQL_ALCHEMY_CONN') # use embedded DB for auth AUTH_TYPE = AUTH_DB ``` -------------------------------- ### Mount Persistent Volume on KubernetesExecutor Pod Template Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/mount-persistent-volumes.md Use `airflow.kubernetesPodTemplate.extraVolumeMounts` and `airflow.kubernetesPodTemplate.extraVolumes` to mount a persistent volume on KubernetesExecutor pod templates. This example mounts a volume named 'worker-tmp' at '/tmp'. ```yaml airflow: kubernetesPodTemplate: extraVolumeMounts: - name: worker-tmp mountPath: /tmp readOnly: false extraVolumes: - name: worker-tmp persistentVolumeClaim: claimName: worker-tmp ``` -------------------------------- ### Use Custom Airflow Image Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-version.md Configure the chart to use a custom-built Airflow Docker image by specifying your repository and tag. The `legacyCommands` setting may be required for Airflow 1.10.x. Image pull policy and secrets can also be configured. ```yaml airflow: # WARNING: this must be "true" for airflow 1.10 #legacyCommands: true image: repository: MY_REPO tag: MY_TAG ## WARNING: even if set to "Always" do not reuse tag names, as containers only pull the latest image when restarting pullPolicy: IfNotPresent ## sets first element of `spec.imagePullSecrets` on Pod templates (for access to private container registry) pullSecret: "" ``` -------------------------------- ### Configure Git-Sync with SSH Authentication Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/load-dag-definitions.md Use this configuration to sync DAGs from a Git repository using SSH authentication. Ensure the SSH secret is properly configured. ```yaml airflow: config: ## NOTE: set by `dags.gitSync.syncWait`, unless you override it #AIRFLOW__SCHEDULER__DAG_DIR_LIST_INTERVAL: 60 dags: ## NOTE: this is the default value path: /opt/airflow/dags gitSync: enabled: true ## NOTE: some git providers will need an `ssh://` prefix repo: "git@github.com:USERNAME/REPOSITORY.git" branch: "master" revision: "HEAD" ## the sub-path within your repo where dags are located ## NOTE: airflow will only see dags under this path, but the whole repo will still be synced #repoSubPath: "path/to/dags" ## number of seconds to wait between syncs ## NOTE: also sets `AIRFLOW__SCHEDULER__DAG_DIR_LIST_INTERVAL` unless overwritten in `airflow.config` syncWait: 60 ## the max number of seconds allowed for a complete sync ## NOTE: if your repo takes a very long time to sync, you may need to increase this value #syncTimeout: 120 ## the number of consecutive failures allowed before aborting ## NOTE: if your repo regularly has intermittent failures, you may wish to set a non-0 value #maxFailures: 0 sshSecret: "airflow-ssh-git-secret" sshSecretKey: "id_rsa" ## NOTE: "known_hosts" verification can be disabled by setting to "" sshKnownHosts: |- github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= ``` -------------------------------- ### Create HTTP Secret for Git-Sync Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/load-dag-definitions.md Command to create a Kubernetes secret for HTTP authentication with git-sync. Replace placeholders with your actual Git username and token. ```shell kubectl create secret generic \ airflow-http-git-secret \ --from-literal=username='MY_GIT_USERNAME' \ --from-literal=password='MY_GIT_TOKEN' \ --namespace my-airflow-namespace ``` -------------------------------- ### Configure Airflow Webserver for Okta OAuth Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/security/ldap-oauth.md This snippet shows the `webserver_config.py` configuration for integrating Airflow with Okta using OAuth. It includes settings for user registration, role mapping, and session lifetime. ```yaml web: webserverConfig: ## this is the full text of your `webserver_config.py` stringOverride: | from flask_appbuilder.security.manager import AUTH_OAUTH # only needed for airflow 1.10 #from airflow import configuration as conf #SQLALCHEMY_DATABASE_URI = conf.get("core", "SQL_ALCHEMY_CONN") AUTH_TYPE = AUTH_OAUTH # registration configs AUTH_USER_REGISTRATION = True # allow users who are not already in the FAB DB AUTH_USER_REGISTRATION_ROLE = "Public" # this role will be given in addition to any AUTH_ROLES_MAPPING # the list of providers which the user can choose from OAUTH_PROVIDERS = [ { "name": "okta", "icon": "fa-circle-o", "token_key": "access_token", "remote_app": { "client_id": "OKTA_CLIENT_ID", "client_secret": "OKTA_CLIENT_SECRET", "api_base_url": "https://OKTA_DOMAIN.okta.com/oauth2/v1/", "client_kwargs": {"scope": "openid profile email groups"}, "server_metadata_url": "https://OKTA_DOMAIN.okta.com/.well-known/openid-configuration", }, }, ] # a mapping from the values of `userinfo["role_keys"]` to a list of FAB roles AUTH_ROLES_MAPPING = { "MyOktaGroup1": ["User"], "MyOktaGroup2": ["Admin"], } # if we should replace ALL the user's roles each login, or only on registration AUTH_ROLES_SYNC_AT_LOGIN = True # force users to re-auth after 30min of inactivity (to keep roles in sync) PERMANENT_SESSION_LIFETIME = 1800 ``` -------------------------------- ### Set Airflow Configurations via Environment Variables Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/configuration/airflow-configs.md Use the `airflow.config` value to set Airflow configurations as environment variables on each Pod. This is useful for common settings like disabling example DAGs or configuring email backends. ```yaml airflow: config: ## security AIRFLOW__WEBSERVER__EXPOSE_CONFIG: "False" ## dags AIRFLOW__CORE__LOAD_EXAMPLES: "False" AIRFLOW__SCHEDULER__DAG_DIR_LIST_INTERVAL: "30" ## email AIRFLOW__EMAIL__EMAIL_BACKEND: "airflow.utils.email.send_email_smtp" AIRFLOW__SMTP__SMTP_HOST: "smtpmail.example.com" AIRFLOW__SMTP__SMTP_MAIL_FROM: "admin@example.com" AIRFLOW__SMTP__SMTP_PORT: "25" AIRFLOW__SMTP__SMTP_SSL: "False" AIRFLOW__SMTP__SMTP_STARTTLS: "False" ## domain used in airflow emails AIRFLOW__WEBSERVER__BASE_URL: "http://airflow.example.com" ## ether environment variables HTTP_PROXY: "http://proxy.example.com:8080" ``` -------------------------------- ### Configure hostPath Volume for Airflow Logs Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/monitoring/log-persistence.md Mount a hostPath volume for Airflow logs. This is strongly discouraged due to security risks. Ensure scheduler and worker log cleanup are disabled if logs.path is under an extraVolumeMounts. ```yaml airflow: extraVolumeMounts: ## spec: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#volumemount-v1-core - name: logs-volume mountPath: /opt/airflow/logs extraVolumes: ## spec: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.29/#volume-v1-core - name: logs-volume hostPath: ## WARNING: this represents a local path on the Kubernetes Node path: /tmp/airflow type: DirectoryOrCreate scheduler: logCleanup: ## WARNING: scheduler log-cleanup must be disabled if `logs.path` is under an `airflow.extraVolumeMounts` enabled: false workers: logCleanup: ## WARNING: workers log-cleanup must be disabled if `logs.path` is under an `airflow.extraVolumeMounts` enabled: false logs: ## NOTE: this is the default value path: /opt/airflow/logs ``` -------------------------------- ### Configure SSH Connection with Plain Text Credentials Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Use this method to define an SSH connection with login and password stored directly in the values. It is recommended to use secret-based methods for better security. ```yaml airflow: connections: - id: my_ssh type: ssh description: my SSH connection host: ssh.example.com port: 22 login: XXXXXXXX password: XXXXXXXX ## see the official "ssh" connection docs for valid extra configs extra: | { "conn_timeout": "15" } ``` -------------------------------- ### Define Airflow Variables with Plain Text Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-variables.md Use the `airflow.variables` value to declaratively create Airflow Variables. Set `variablesUpdate` to `true` to enable perpetual syncing. ```yaml airflow: variables: - key: "var_1" value: "my_value_1" - key: "var_2" value: "my_value_2" ## if we create a Deployment to perpetually sync `airflow.variables` variablesUpdate: true ``` -------------------------------- ### User Managed Persistent Volume Claim for Airflow Logs Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/monitoring/log-persistence.md Configure the Airflow Helm chart to use an existing PersistentVolumeClaim for log storage. Ensure log cleanup is disabled for both scheduler and workers when persistence is enabled. This example specifies the name of the existing PVC. ```yaml scheduler: logCleanup: ## WARNING: scheduler log-cleanup must be disabled if `logs.persistence.enabled` is `true` enabled: false workers: logCleanup: ## WARNING: workers log-cleanup must be disabled if `logs.persistence.enabled` is `true` enabled: false logs: ## NOTE: this is the default value path: /opt/airflow/logs persistence: enabled: true ## the name of your existing PersistentVolumeClaim existingClaim: my-logs-pvc ## WARNING: as multiple pods will write logs, this MUST be ReadWriteMany accessMode: ReadWriteMany ``` -------------------------------- ### Configure Chart Managed PersistentVolumeClaim for DAGs Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/load-dag-definitions.md Enable persistence for DAGs and specify storage class, size, and access mode when the chart manages the PVC creation. ```yaml dags: ## NOTE: this is the default value path: /opt/airflow/dags persistence: enabled: true ## NOTE: set `storageClass` to "" for the cluster-default storageClass: "default" ## NOTE: some types of StorageClass will ignore this request (for example, EFS) size: 1Gi ## NOTE: as multiple Pods read the DAGs concurrently this MUST be ReadOnlyMany or ReadWriteMany accessMode: ReadOnlyMany ``` -------------------------------- ### Set Fernet Key using airflow.fernetKey Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/security/set-fernet-key.md Use this method to directly set the Fernet encryption key via the `airflow.fernetKey` Helm value. This sets the `AIRFLOW__CORE__FERNET_KEY` environment variable. Avoid using the default key in production. ```yaml aiflow: fernetKey: "7T512UXSSmBOkpWimFHIVb8jK6lfmSAvx4mO6Arehnc=" ``` -------------------------------- ### Postgres Connection - Secret Templates (Recommended) Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/dags/airflow-connections.md Configures a PostgreSQL connection by referencing credentials stored in Kubernetes Secrets. This is the recommended approach for securely managing sensitive information. ```yaml airflow: connections: - id: my_postgres type: postgres description: my Postgres connection host: postgres.example.com port: 5432 ## this string template is defined by `airflow.connectionsTemplates.POSTGRES_USERNAME` login: ${POSTGRES_USERNAME} ## this string template is defined by `airflow.connectionsTemplates.POSTGRES_PASSWORD` password: ${POSTGRES_PASSWORD} schema: my_database ## see the official "postgres" connection docs for valid extra configs extra: | { "sslmode": "allow" } connectionsTemplates: ## extracts the value of `username` from `Secret/my-postgres-credentials` POSTGRES_USERNAME: kind: secret name: my-postgres-credentials key: username ## extracts the value of `password` from `Secret/my-postgres-credentials` POSTGRES_PASSWORD: kind: secret name: my-postgres-credentials key: password ``` -------------------------------- ### Chart Managed Persistent Volume Claim for Airflow Logs Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/monitoring/log-persistence.md Configure the Airflow Helm chart to create and manage a PersistentVolumeClaim for log storage. Ensure log cleanup is disabled for both scheduler and workers when persistence is enabled. This example sets a storage class and size for the PVC. ```yaml scheduler: logCleanup: ## WARNING: scheduler log-cleanup must be disabled if `logs.persistence.enabled` is `true` enabled: false workers: logCleanup: ## WARNING: workers log-cleanup must be disabled if `logs.persistence.enabled` is `true` enabled: false logs: ## NOTE: this is the default value path: /opt/airflow/logs persistence: enabled: true ## NOTE: set `storageClass` to "" for the cluster-default storageClass: "default" ## NOTE: some types of StorageClass will ignore this request (for example, EFS) size: 5Gi ## WARNING: as multiple pods will write logs, this MUST be ReadWriteMany accessMode: ReadWriteMany ``` -------------------------------- ### Configure Preceding Paths for SSL Redirect with AWS ALB Source: https://github.com/airflow-helm/charts/blob/main/charts/airflow/docs/faq/kubernetes/ingress.md Use `ingress.web.precedingPaths` to define paths that should be processed before the main Airflow path. This is common for setting up SSL redirects with controllers like the aws-alb-ingress-controller. ```yaml ingress: web: precedingPaths: - path: "/*" serviceName: "ssl-redirect" servicePort: "use-annotation" ```