GitLab CI:如何根据流水线启动时的变量为其他变量赋值?
问题解决:GitLab CI 根据参数动态赋值变量失败
问题背景
需要在GitLab CI流水线启动时,根据选择的OS_VERSION和COMPONENT_TYPE参数,给DOCKERFILE、IMAGE_NAME、IMAGE_VERSION等变量赋值。当前在gitlab-ci.yml的before_script中用Shell条件语句实现时,出现variables:: not found错误,后续lint步骤提示$DOCKERFILE未找到,调整多行字符格式(>改|)也无法解决。
原配置代码
variables: DOCKER_DRIVER: overlay REGISTRY: registry.restream.ru:5000 CENTOS_TESTS_VERSION: 1.1.3 CENTOS_PYTHON_VERSION: 1.0.5 CENTOS_CPP_VERSION: 1.0.4 REDOS7_CPP_VERSION: 1.0.0 REDOS8_TESTS_VERSION: 1.0.0 REDOS8_CPP_VERSION: 1.0.0 REDOS8_PYTHON_VERSION: 1.0.0 OS_VERSION: value: "RedOS-8" options: - "RedOS-8" - "CentOS-7" - "RedOS-7" description: "The deployment target. Set to 'RedOS-8' by default." COMPONENT_TYPE: value: "Python" options: - "Python" - "C++" - "Tests" description: "The deployment component type. Set to 'Python' by default." default: before_script: - > if [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "C++" ]]; then variables: DOCKERFILE = ./redos8/cpp.Dockerfile IMAGE_NAME = redos8-cpp IMAGE_VERSION = $REDOS8_CPP_VERSION elif [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "Python" ]]; then variables: DOCKERFILE = ./redos8/python.Dockerfile IMAGE_NAME: redos8-python IMAGE_VERSION = REDOS8_PYTHON_VERSION elif [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "Tests" ]]; then variables: DOCKERFILE: ./redos8/tests.Dockerfile IMAGE_NAME: redos8-tests IMAGE_VERSION = $REDOS8_TESTS_VERSION elif [[ $OS_VERSION = "RedOS-7" ]]; then variables: DOCKERFILE = ./redos7/cpp.Dockerfile IMAGE_NAME = redos7-cpp IMAGE_VERSION = $REDOS7_CPP_VERSION elif [[ $OS_VERSION = "CentOS-7" ]] && [[ $COMPONENT_TYPE = "Python" ]]; then variables: DOCKERFILE = ./redos7/python.Dockerfile IMAGE_NAME = centos7-python IMAGE_VERSION = $CENTOS_PYTHON_VERSION else variables: DOCKERFILE = ./centos7/cpp.Dockerfile fi stages: - lint - build .lint: stage: lint image: $REGISTRY/hadolint/hadolint:v2.12.0-alpine rules: - changes: - $DOCKERFILE - repo/* - scripts/* tags: - dind script: - hadolint $DOCKERFILE .build: image: $REGISTRY/docker:latest services: - $REGISTRY/docker:dind stage: build variables: FULL_IMAGE_NAME: $REGISTRY/rtpp-team/ci-cd/$IMAGE_NAME:$IMAGE_VERSION rules: - changes: - $DOCKERFILE - repo/* - scripts/* tags: - dind script: - docker build --pull --tag $FULL_IMAGE_NAME --file $DOCKERFILE . - docker push $FULL_IMAGE_NAME lint_dockerfile:tests: extends: .lint variables: DOCKERFILE: $DOCKERFILE build_image:tests: extends: .build variables: DOCKERFILE: $DOCKERFILE IMAGE_NAME: $IMAGE_NAME IMAGE_VERSION: $CENTOS_TESTS_VERSION needs: - job: lint_dockerfile:tests lint_dockerfile:python: extends: .lint variables: DOCKERFILE: $DOCKERFILE build_image:python: extends: .build variables: DOCKERFILE: $DOCKERFILE IMAGE_NAME: $IMAGE_NAME IMAGE_VERSION: $CENTOS_PYTHON_VERSION needs: - job: lint_dockerfile:python lint_dockerfile:cpp: extends: .lint variables: DOCKERFILE: $DOCKERFILE build_image:cpp: extends: .build variables: DOCKERFILE: $DOCKERFILE IMAGE_NAME: $IMAGE_VERSION IMAGE_VERSION: $CENTOS_CPP_VERSION needs: - job: lint_dockerfile:cpp
错误日志(RedOS-8 + C++组合时)
Getting source from Git repository 00:01 Fetching changes with git depth set to 20... Reinitialized existing Git repository in /builds/dev_team/devops/ci-cd-docker-images/.git/ Checking out 61cad3e4 as detached HEAD (ref is devops/WINK-5057) Skipping Git submodules setup Executing "step_script" stage of the job script 00:01 Using docker image sha256:19b38dcec411d7f333601a68f55cb3e710fca099615a7eee0fa2e020adfc7292 for registry.team.ru:5000/hadolint/hadolint:v2.12.0-alpine with digest hadolint/hadolint@sha256:3c206a451cec6d486367e758645269fd7d696c5ccb6ff59d8b03b0e45268a199 $ if [[ $OS_VERSION = "RedOS-8" ]] && [[ $COMPONENT_TYPE = "C++" ]]; then # collapsed multi-line command /bin/sh: eval: line 179: variables:: not found
错误原因
- 混淆YAML与Shell语法:在Shell脚本里写了YAML格式的
variables:块,Shell根本不认识这个语法,直接抛出variables:: not found错误。 - 变量传递问题:即使Shell赋值正确,默认情况下before_script里的变量只在当前Shell进程有效,不会自动传递到后续job步骤;子job里重复定义
DOCKERFILE: $DOCKERFILE属于无效操作,还可能覆盖变量。 - 笔误问题:
build_image:cpp里的IMAGE_NAME: $IMAGE_VERSION是明显笔误,把IMAGE_NAME写成了IMAGE_VERSION的引用。
解决方案
1. 修正before_script的Shell赋值逻辑
用标准Shell语法赋值,通过export导出变量到环境,同时写入dotenv文件让GitLab CI识别并传递给后续步骤:
default: before_script: - | # 初始化变量默认值 DOCKERFILE="./centos7/cpp.Dockerfile" IMAGE_NAME="centos7-cpp" IMAGE_VERSION="$CENTOS_CPP_VERSION" # 根据参数赋值 if [[ "$OS_VERSION" = "RedOS-8" ]]; then case "$COMPONENT_TYPE" in "C++") DOCKERFILE="./redos8/cpp.Dockerfile" IMAGE_NAME="redos8-cpp" IMAGE_VERSION="$REDOS8_CPP_VERSION" ;; "Python") DOCKERFILE="./redos8/python.Dockerfile" IMAGE_NAME="redos8-python" IMAGE_VERSION="$REDOS8_PYTHON_VERSION" ;; "Tests") DOCKERFILE="./redos8/tests.Dockerfile" IMAGE_NAME="redos8-tests" IMAGE_VERSION="$REDOS8_TESTS_VERSION" ;; esac elif [[ "$OS_VERSION" = "RedOS-7" ]]; then DOCKERFILE="./redos7/cpp.Dockerfile" IMAGE_NAME="redos7-cpp" IMAGE_VERSION="$REDOS7_CPP_VERSION" elif [[ "$OS_VERSION" = "CentOS-7" && "$COMPONENT_TYPE" = "Python" ]]; then DOCKERFILE="./redos7/python.Dockerfile" IMAGE_NAME="centos7-python" IMAGE_VERSION="$CENTOS_PYTHON_VERSION" fi # 导出变量到环境,同时写入dotenv文件让GitLab CI识别 export DOCKERFILE IMAGE_NAME IMAGE_VERSION echo "DOCKERFILE=$DOCKERFILE" >> variables.env echo "IMAGE_NAME=$IMAGE_NAME" >> variables.env echo "IMAGE_VERSION=$IMAGE_VERSION" >> variables.env # 添加artifacts传递dotenv文件 artifacts: reports: dotenv: variables.env
2. 修正子job的冗余配置
去掉子job里重复定义的variables块,同时修正build_image:cpp的笔误:
# 修正后的lint和build子job lint_dockerfile:tests: extends: .lint build_image:tests: extends: .build variables: IMAGE_VERSION: $CENTOS_TESTS_VERSION needs: - job: lint_dockerfile:tests lint_dockerfile:python: extends: .lint build_image:python: extends: .build variables: IMAGE_VERSION: $CENTOS_PYTHON_VERSION needs: - job: lint_dockerfile:python lint_dockerfile:cpp: extends: .lint build_image:cpp: extends: .build variables: IMAGE_VERSION: $CENTOS_CPP_VERSION needs: - job: lint_dockerfile:cpp
3. 关键说明
- dotenv报告:通过
artifacts.reports.dotenv把变量写入文件并传递,后续job就能读取到这些动态赋值的变量。 - Shell语法规范:赋值时不要加空格(
DOCKERFILE=./xxx而不是DOCKERFILE = ./xxx),引用变量时加双引号避免空格问题。 - case语句优化:把嵌套的if-elif改成case,让逻辑更清晰易维护。
内容的提问来源于stack exchange,提问作者Stanislav
相关产品推荐
相关产品推荐

