如何通过GitLab CI/CD变量参数化Pod模板文件(airflow_template.yaml)并替换指定Airflow环境变量?
嘿,我看你碰到的问题是airflow_template.yaml里的$DEV_AIRFLOW_CONTAINER_REPO和$DEV_AIRFLOW_LOG_FOLDER这两个变量,没法被GitLab CI/CD的环境变量自动替换对吧?其实核心原因很简单:这个yaml文件本身不会被shell或者CI流程自动解析,那些$开头的字符串就是纯文本,得你主动在部署或构建阶段处理模板,把变量换成实际值才行。
下面给你几个适配你项目结构的靠谱方案,从简单到优雅都有:
方案1:用envsubst批量替换模板变量
envsubst是GNU工具集里的小工具,能自动把文件里的环境变量引用替换成实际值,刚好适配这种模板场景。
修改deploy_to_dev阶段的脚本
在部署前先处理模板文件,把变量替换好:
deploy_to_dev: stage: deploy_to_dev image: $CI_REGISTRY_IMAGE:kube-image script: - echo $DEV_CREDENTIALS > service_account.json && cat service_account.json | docker login -u _json_key --password-stdin https://gcr.io - echo "当前日志目录变量值: $DEV_AIRFLOW_LOG_FOLDER" # 把CI变量导出到当前shell环境,让envsubst能读到 - export DEV_AIRFLOW_CONTAINER_REPO="${DEV_AIRFLOW_CONTAINER_REPO}" - export DEV_AIRFLOW_LOG_FOLDER="${DEV_AIRFLOW_LOG_FOLDER}" # 替换模板变量,生成可用的yaml文件 - envsubst < dataops/docker/base/airflow_template.yaml > dataops/docker/base/airflow.yaml # 后续的集群认证和Helm部署命令 - gcloud auth activate-service-account $DEV_SERVICE_ACCOUNT --key-file=./service_account.json --project=$DEV_PROJECT_NAME - gcloud container clusters get-credentials $DEV_GKE_CLUSTER --region $REGION - echo $DEV_DB_CONN > dataops/helm/airflow-loadbalancer/files/secrets/airflow/AIRFLOW__CORE__SQL_ALCHEMY_CONN - cd dataops/helm/ - helm upgrade airflow-dev airflow-loadbalancer/ --install --atomic --set dags_image.tag=$CI_COMMIT_SHORT_SHA only: refs: - develop
注意:如果你的
kube-image镜像里没有envsubst,得先安装它——比如Debian/Ubuntu系镜像可以加一句apt-get update && apt-get install -y gettext-base。
方案2:把Airflow模板集成到Helm(更推荐)
既然你已经在用Helm部署,把airflow_template.yaml的逻辑迁移到Helm的templates目录下,用Helm的变量系统管理会更优雅,还能完美适配多环境。
步骤1:迁移模板到Helm
把dataops/docker/base/airflow_template.yaml的内容复制到dataops/helm/templates/airflow-worker-pod-template.yaml,然后把变量改成Helm模板语法:
apiVersion: v1 kind: Pod metadata: labels: {} spec: containers: - args: [] command: [] env: - name: AIRFLOW__KUBERNETES__WORKER_CONTAINER_REPOSITORY value: {{ .Values.airflow.workerContainerRepo }} - name: AIRFLOW__LOGGING__REMOTE_BASE_LOG_FOLDER value: {{ .Values.airflow.remoteBaseLogFolder }} envFrom: [] imagePullPolicy: Always name: base ports: [] volumeMounts: - mountPath: /usr/local/airflow/logs name: airflow-logs hostNetwork: false imagePullSecrets: [] initContainers: [] nodeSelector: {} restartPolicy: Never securityContext: runAsUser: 1000 serviceAccountName: default volumes: - emptyDir: {} name: airflow-logs
步骤2:在Helm的values.yaml加默认值
打开dataops/helm/values.yaml,添加默认配置:
airflow: workerContainerRepo: "default-repo" remoteBaseLogFolder: "default-log-folder"
步骤3:CI里通过Helm传递变量
修改deploy_to_dev的Helm命令,直接把CI变量传进去:
deploy_to_dev: stage: deploy_to_dev image: $CI_REGISTRY_IMAGE:kube-image script: - echo $DEV_CREDENTIALS > service_account.json && cat service_account.json | docker login -u _json_key --password-stdin https://gcr.io - gcloud auth activate-service-account $DEV_SERVICE_ACCOUNT --key-file=./service_account.json --project=$DEV_PROJECT_NAME - gcloud container clusters get-credentials $DEV_GKE_CLUSTER --region $REGION - echo $DEV_DB_CONN > dataops/helm/airflow-loadbalancer/files/secrets/airflow/AIRFLOW__CORE__SQL_ALCHEMY_CONN - cd dataops/helm/ - helm upgrade airflow-dev airflow-loadbalancer/ --install --atomic \ --set dags_image.tag=$CI_COMMIT_SHORT_SHA \ --set airflow.workerContainerRepo=$DEV_AIRFLOW_CONTAINER_REPO \ --set airflow.remoteBaseLogFolder=$DEV_AIRFLOW_LOG_FOLDER only: refs: - develop
这种方式的好处太多了:
- 天然支持dev/prod多环境变量隔离
- 可以用values文件维护默认值,CI只需要传递差异值
- 不用额外处理模板文件,Helm会自动帮你渲染
方案3:用sed逐个替换变量
如果不想加新工具,用sed直接替换字符串也能搞定,适合变量少、值不复杂的场景:
deploy_to_dev: stage: deploy_to_dev image: $CI_REGISTRY_IMAGE:kube-image script: - echo $DEV_CREDENTIALS > service_account.json && cat service_account.json | docker login -u _json_key --password-stdin https://gcr.io # 逐个替换模板里的变量 - sed -i "s/\$DEV_AIRFLOW_CONTAINER_REPO/$DEV_AIRFLOW_CONTAINER_REPO/g" dataops/docker/base/airflow_template.yaml - sed -i "s/\$DEV_AIRFLOW_LOG_FOLDER/$DEV_AIRFLOW_LOG_FOLDER/g" dataops/docker/base/airflow_template.yaml # 后续的集群认证和部署命令...
注意:如果变量值里有特殊字符(比如
/、&),得先转义,不然sed会报错。
为啥原来的方式没生效?
你之前只是把变量导出到shell环境,但airflow_template.yaml文件根本没被任何工具解析——里面的$DEV_AIRFLOW_*就是普通字符串,不会自动变成环境变量的值。必须主动用工具(envsubst/Helm/sed)来完成替换操作才行。
内容的提问来源于stack exchange,提问作者Sandeep Singh




