生产指南

以下是在生产环境中使用此 Helm Chart 时需要考虑的事项。

数据库

建议为 Airflow 元数据存储设置外部数据库。默认的 Helm Chart 会部署一个运行在容器中的 Postgres 数据库。对于生产用途,应使用运行在专用机器上或利用云提供商的数据库服务(例如 AWS RDS)的数据库,因为嵌入式 Postgres 缺乏生产数据库所需的稳定性、监控和持久化功能。它仅用于方便在“独立”版本中测试 Helm Chart,但使用它可能会导致数据丢失。支持的数据库和版本可以在此处找到:设置数据库后端

注意

使用 helm chart 时,无需使用 airflow db migrate 初始化数据库,如 设置数据库后端 中所述。

首先禁用 Postgres,这样 chart 就不会部署自己的 Postgres 容器

postgresql:
  enabled: false

要向 Airflow 提供数据库凭据,您有两种选择——在您的 values 文件中或在 Kubernetes Secret 中。

Values 文件

这是更简单的选项,因为 chart 将为您创建一个 Kubernetes Secret。但是,请记住您的凭据将存储在您的 values 文件中。

data:
  metadataConnection:
    user: <username>
    pass: <password>
    protocol: postgresql
    host: <hostname>
    port: 5432
    db: <database name>

Kubernetes Secret

您还可以将凭据存储在您创建的 Kubernetes Secret 中。请注意,用户名/密码中的特殊字符必须进行 URL 编码。

kubectl create secret generic mydatabase --from-literal=connection=postgresql://user:pass@host:5432/db

最后,配置 chart 以使用您创建的 secret

data:
  metadataSecretName: mydatabase

警告

如果您使用 CeleryExecutor 且 Airflow 版本小于 2.4,请记住 resultBackendSecretName 期望以 db+postgresql:// 开头的 URL,而 metadataSecretName 期望使用 postgresql:// 并且不适用于 db+postgresql://。您需要创建使用正确 scheme 的单独 secret。对于 Airflow 版本大于等于 2.4,可以省略 result backend secret,因为 Airflow 默认将使用 sql_alchemy_conn(在 metadataSecret 中指定)并带有 db+ scheme 前缀。

PgBouncer

如果您使用 PostgreSQL 作为数据库,您很可能也想启用 PgBouncer。Airflow 由于其分布式特性可以打开大量数据库连接,而使用连接池可以显著减少数据库上的开放连接数。

数据库凭据存储在 Values 文件中

pgbouncer:
  enabled: true

数据库凭据存储在 Kubernetes Secret 中

在这种情况下,默认连接字符串将不起作用,您需要相应地修改

kubectl create secret generic mydatabase --from-literal=connection=postgresql://user:pass@pgbouncer_svc_name.deployment_namespace:6543/airflow-metadata

在此配置中,PgBouncer 要正常工作还需要两个额外的 Kubernetes Secret

airflow-pgbouncer-stats

kubectl create secret generic airflow-pgbouncer-stats --from-literal=connection=postgresql://user:pass@127.0.0.1:6543/pgbouncer?sslmode=disable

airflow-pgbouncer-config

apiVersion: v1
kind: Secret
metadata:
  name: airflow-pgbouncer-config
data:
  pgbouncer.ini: dmFsdWUtMg0KDQo=
  users.txt: dmFsdWUtMg0KDQo=

pgbouncer.ini 等于此文本的 base64 编码版本

[databases]
airflow-metadata = host={external_database_host} dbname={external_database_dbname} port=5432 pool_size=10

[pgbouncer]
pool_mode = transaction
listen_port = 6543
listen_addr = *
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/users.txt
stats_users = postgres
ignore_startup_parameters = extra_float_digits
max_client_conn = 100
verbose = 0
log_disconnections = 0
log_connections = 0

server_tls_sslmode = prefer
server_tls_ciphers = normal

users.txt 等于此文本的 base64 编码版本

"{ external_database_host }" "{ external_database_pass }"

values.yaml 应如下所示

pgbouncer:
  enabled: true
  configSecretName: airflow-pgbouncer-config
  metricsExporterSidecar:
    statsSecretName: airflow-pgbouncer-stats

根据您的 Airflow 实例的大小,您可能还需要调整以下设置(显示为默认值)

pgbouncer:
  # The maximum number of connections to PgBouncer
  maxClientConn: 100
  # The maximum number of server connections to the metadata database from PgBouncer
  metadataPoolSize: 10
  # The maximum number of server connections to the result backend database from PgBouncer
  resultBackendPoolSize: 5

Webserver Secret Key

使用此 chart 进行部署时,应设置一个静态 webserver secret key,这将有助于确保您的 Airflow 组件仅在必要时重启。

警告

您运行的每个实例都应使用不同的 secret key,因为此 key 用于签署会话 cookie 并执行其他安全相关功能!

首先,生成一个强 secret key

python3 -c 'import secrets; print(secrets.token_hex(16))'

现在将此 secret 添加到您的 values 文件中

webserverSecretKey: <secret_key>

或者,创建一个 Kubernetes Secret 并使用 webserverSecretKeySecretName

webserverSecretKeySecretName: my-webserver-secret
# where the random key is under `webserver-secret-key` in the k8s Secret

kubectl 创建 Kubernetes Secret 的示例

kubectl create secret generic my-webserver-secret --from-literal="webserver-secret-key=$(python3 -c 'import secrets; print(secrets.token_hex(16))')"

Webserver key 还用于在检索日志时授权对 Celery worker 的请求。但是,使用 secret key 生成的 token 有一个较短的过期时间 - 请确保运行 airflow 组件的所有机器上的时间都已同步(例如使用 ntpd),否则在访问日志时可能会出现“forbidden”错误。

驱逐配置

Kubernetes Cluster Autoscaler 一起运行 Airflow 时,配置 pod 是否可以安全驱逐非常重要。此设置可以在 Airflow chart 的不同级别进行配置

workers:
  safeToEvict: true
scheduler:
  safeToEvict: true
webserver:
  safeToEvict: true

workers.safeToEvict 默认为 false,并且在使用 KubernetesExecutor 时,workers.safeToEvict 不应设置为 true,否则 worker 可能会在完成前被移除。

扩展和定制 Airflow 镜像

Apache Airflow 社区发布 Docker 镜像,这些镜像 是 Apache Airflow 的 参考镜像。然而,Airflow 拥有超过 60 个社区管理的 provider(可通过 extra 安装),其中一些默认安装的 extras/providers 并非每个人都使用,有时需要其他 extras/providers,有时(实际上非常频繁)您需要添加自己的自定义依赖、包,甚至自定义 provider,或者添加部署所需的自定义工具和二进制文件。

在 Kubernetes 和 Docker 术语中,这意味着您需要一个包含您特定需求的另一个镜像。这就是为什么您应该学习如何构建自己的 Docker(或更准确地说 容器)镜像。

您可能想要使用自定义镜像的典型场景

  • 添加 apt

  • 添加 PyPI

  • 添加部署所需的二进制资源

  • 添加部署所需的自定义工具

请参阅 构建镜像,了解如何扩展和定制 Airflow 镜像的更多详细信息。

管理 DAG 文件

请参阅 管理 DAG 文件

knownHosts

如果您正在使用 dags.gitSync.sshKeySecret,您还应该设置 dags.gitSync.knownHosts。这里我们将演示 GitHub 的过程,但对于任何 provider 都可以进行相同的操作

获取 GitHub 的公钥

ssh-keyscan -t rsa github.com > github_public_key

接下来,打印公钥的 fingerprint

ssh-keygen -lf github_public_key

将该输出与 GitHub 的 SSH key fingerprint 进行比较。

它们匹配,对吧?好的。现在,将公钥添加到您的 values 文件中。它看起来像这样

dags:
  gitSync:
    knownHosts: |
      github.com ssh-rsa AAAA...1/wsjk=

外部 Scheduler

要使用外部 Scheduler 实例

scheduler:
  enabled: false

确保您的外部 webserver/scheduler 连接到同一个 redis 主机。这将确保 scheduler 知道 helm-chart 中部署的 worker。

访问 Airflow UI

您如何访问 Airflow UI 将取决于您的环境;但是,chart 支持各种选项

外部 Webserver

要使用外部 Webserver

webserver:
  enabled: false

确保您的外部 webserver/scheduler 连接到同一个 redis 主机。这将确保 scheduler 知道 helm-chart 中部署的 worker。

Ingress

您可以创建和配置 Ingress 对象。请参阅 Ingress chart 参数。有关 Ingress 的更多信息,请参阅 Kubernetes Ingress 文档

LoadBalancer Service

您可以将 webserver 的 Service 类型更改为 LoadBalancer,并设置任何必要的 annotation

webserver:
  service:
    type: LoadBalancer

有关 LoadBalancer Service 的更多信息,请参阅 Kubernetes LoadBalancer Service 文档

日志记录

根据您选择的 executor,任务日志可能无法直接工作。所有日志记录选项都可以在此处找到:管理日志

指标

chart 支持将指标发送到现有的 StatsD 实例或提供 Prometheus endpoint。

Prometheus

指标 endpoint 可在此处访问:svc/{{ .Release.Name }}-statsd:9102/metrics

外部 StatsD

要使用外部 StatsD 实例

statsd:
  enabled: false
config:
  metrics:  # or 'scheduler' for Airflow 1
    statsd_on: true
    statsd_host: ...
    statsd_port: ...

IPv6 StatsD

要使用带有 IPv6 地址的 StatsD 实例。示例:在启用 IPv6 的 Kubernetes 中使用

statsd:
  enabled: true
config:
  metrics:  # or 'scheduler' for Airflow 1
    statsd_on: 'True'
    statsd_host: ...
    statsd_ipv6: 'True'
    statsd_port: ...
    statsd_prefix: airflow

Datadog

如果您在环境中使用 Datadog agent,这将使 Airflow 能够将指标导出到 Datadog agent。

statsd:
  enabled: false
config:
  metrics: # or 'scheduler' for Airflow 1
    statsd_on: true
    statsd_port: 8125
extraEnv: |-
  - name: AIRFLOW__METRICS__STATSD_HOST
    valueFrom:
      fieldRef:
        fieldPath: status.hostIP

Celery 后端

如果您使用 CeleryExecutorCeleryKubernetesExecutor,您可以使用自己的 Celery 后端。

默认情况下,chart 将部署 Redis。但是,您可以使用任何支持的 Celery 后端代替

redis:
  enabled: false
data:
  brokerUrl: redis://redis-user:password@redis-host:6379/0

有关设置 Celery broker 的更多信息,请参阅详细的 Celery 相关主题文档

Security Context Constraints

Security Context Constraint (SCC) 是 OpenShift 的一个构造,作用类似于 RBAC 规则;但是,它针对的是 Pod 而不是用户。定义 SCC 时,可以控制 POD 在启动和运行时可以执行或访问的操作和资源。

SCC 被划分为不同的级别或类别,其中 restricted SCC 是分配给 Pod 的默认 SCC。将 Airflow 部署到 OpenShift 时,可以利用 SCC 并允许 Pod 启动使用 anyuid SCC 的容器。

为了启用 SCC 的使用,必须将参数 rbac.createSCCRoleBinding 设置为 true,如下所示

rbac:
  create: true
  createSCCRoleBinding: true

在此 chart 中,SCC 通过 RoleBindings 绑定到 Pod,这意味着选项 rbac.create 也必须设置为 true,以完全启用 SCC 的使用。

有关 SCC 以及通过此构造可以实现的功能的更多信息,请参阅 管理 security context constraints

Security Context

在 Kubernetes 中,securityContext 可用于定义用户 ID、组 ID 和能力,例如以特权模式运行容器。

将应用程序部署到 Kubernetes 时,建议赋予容器最小权限,以减少访问并保护容器运行的主机。

在 Airflow Helm chart 中,securityContext 可以通过多种方式进行配置

与配置全局 securityContexts 的方式相同,也可以通过设置特定工作负载的本地 securityContexts 如下所示配置不同的值

workers:
  securityContexts:
    pod:
      runAsUser: 5000
      fsGroup: 0
    containers:
      allowPrivilegeEscalation: false

在上面的示例中,worker Pod 的 securityContexts 将设置为 runAsUser: 5000fsGroup: 0。容器 Pod 将设置为 allowPrivilegeEscalation: false

可以看到,本地设置优先于全局设置(如果已定义)。下面解释了此 chart 中 securityContexts 选项的优先级规则

uid: 40000
gid: 0

securityContexts:
  pod:
    runAsUser: 50000
    fsGroup: 0

workers:
  securityContexts:
    pod:
      runAsUser: 1001
      fsGroup: 0

这将生成以下 worker 部署

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: airflow-worker
spec:
  serviceName: airflow-worker
  template:
    spec:
      securityContext:    # As the securityContexts was defined in ``workers``, its value will take priority
        runAsUser: 1001
        fsGroup: 0

如果我们从上面的示例中同时删除 securityContextsworkers.securityContexts,输出将如下所示

uid: 40000
gid: 0

securityContexts: {}

workers:
  securityContexts: {}

这将生成以下 worker 部署

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: airflow-worker
spec:
  serviceName: airflow-worker
  template:
    spec:
      securityContext:
        runAsUser: 40000   # As the securityContext was not defined in ``workers`` or ``podSecurity``, the value from uid will be used
        fsGroup: 0         # As the securityContext was not defined in ``workers`` or ``podSecurity``, the value from gid will be used
      initContainers:
        - name: wait-for-airflow-migrations
      ...
      containers:
        - name: worker
      ...

最后,如果我们设置了 securityContexts 但没有设置 workers.securityContexts

uid: 40000
gid: 0

securityContexts:
  pod:
    runAsUser: 50000
    fsGroup: 0

workers:
  securityContexts: {}

这将生成以下 worker 部署

kind: StatefulSet
apiVersion: apps/v1
metadata:
  name: airflow-worker
spec:
  serviceName: airflow-worker
  template:
    spec:
      securityContext:     # As the securityContexts was not defined in ``workers``, the values from securityContexts will take priority
        runAsUser: 50000
        fsGroup: 0
      initContainers:
        - name: wait-for-airflow-migrations
      ...
      containers:
        - name: worker
      ...

内置 Secret 和环境变量

默认情况下,Helm Chart 使用 Kubernetes Secret 来存储 Airflow 所需的 secret。这些 secret 的内容默认会转换为 Airflow 读取的环境变量(一些环境变量有多种变体以支持旧版本的 Airflow)。

默认情况下,secret 名称是根据部署 Helm Chart 时使用的 Release Name 确定的,但您也可以使用不同的 secret 来设置变量,或者完全禁用使用 secret,转而依赖环境变量(特别是如果您想使用环境变量的 _CMD__SECRET 变体)。

然而,Airflow 支持其他设置 secret 配置的变体——您可以指定一个系统命令来检索并自动轮换 secret(通过定义带有 _CMD 后缀的变量),或者从 secret 后端检索变量(通过定义带有 _SECRET 后缀的变量)。

如果设置了 <VARIABLE_NAME>>,它将优先于 _CMD_SECRET 变体,因此如果您想设置 _CMD_SECRET 变体之一,则必须通过将 .Values.enableBuiltInSecretEnvVars.<VARIABLE_NAME> 设置为 false 来禁用从 Kubernetes secret 中检索的内置变量。

例如,为了使用命令检索数据库连接,您应该(在您的 values.yaml 文件中)指定

extraEnv:
  AIRFLOW_CONN_AIRFLOW_DB_CMD: "/usr/local/bin/retrieve_connection_url"
enableBuiltInSecretEnvVars:
  AIRFLOW_CONN_AIRFLOW_DB: false

以下是可以禁用并由 _CMD_SECRET 变体替换的全部 secret 列表

未指定 secret 名称时的默认 secret 名称

使用不同的 Kubernetes Secret

Airflow 环境变量

<RELEASE_NAME>-airflow-metadata

.Values.data.metadataSecretName

AIRFLOW_CONN_AIRFLOW_DB
AIRFLOW__DATABASE__SQL_ALCHEMY_CONN

<RELEASE_NAME>-fernet-key

.Values.fernetKeySecretName

AIRFLOW__CORE__FERNET_KEY

<RELEASE_NAME>-webserver-secret-key

.Values.webserverSecretKeySecretName

AIRFLOW__WEBSERVER__SECRET_KEY

<RELEASE_NAME>-airflow-result-backend

.Values.data.resultBackendSecretName

AIRFLOW__CELERY__CELERY_RESULT_BACKEND
AIRFLOW__CELERY__RESULT_BACKEND

<RELEASE_NAME>-airflow-broker-url

.Values.data.brokerUrlSecretName

AIRFLOW__CELERY__BROKER_URL

<RELEASE_NAME>-elasticsearch

.Values.elasticsearch.secretName

AIRFLOW__ELASTICSEARCH__HOST
AIRFLOW__ELASTICSEARCH__ELASTICSEARCH_HOST

还有一些 secret,它们的名称也是根据 release name 确定的,但不需要禁用。这是因为它们要么不遵循 _CMD_SECRET 模式,要么是以非 AIRFLOW__ 开头的变量,或者它们没有对应的变量。

还有一个 _AIRFLOW__* 变量 AIRFLOW__CELERY__FLOWER_BASIC_AUTH,即使您想设置 _CMD_SECRET 变体,也不需要禁用它。默认情况下不设置此变量。仅当设置了 .Values.flower.secretName 或设置了 .Values.flower.user.Values.flower.password 时,才会设置此变量。因此,如果您未设置任何 .Values.flower.* 变量,则可以自由地使用 _CMD_SECRET 变体配置 flower Basic Auth,而无需禁用基本变体。

未指定 secret 名称时的默认 secret 名称

使用不同的 Kubernetes Secret

Airflow 环境变量

<RELEASE_NAME>-redis-password

.Values.redis.passwordSecretName

REDIS_PASSWORD

<RELEASE_NAME>-pgbouncer-config

.Values.pgbouncer.configSecretName

<RELEASE_NAME>-pgbouncer-certificates

<RELEASE_NAME>-registry

.Values.registry.secretName

<RELEASE_NAME>-kerberos-keytab

<RELEASE_NAME>-flower

.Values.flower.secretName

AIRFLOW__CELERY__FLOWER_BASIC_AUTH

您可以在 设置配置选项 中阅读有关设置配置变量的高级方法的更多信息。

此条目有帮助吗?