You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

错误原因

  1. 混淆YAML与Shell语法:在Shell脚本里写了YAML格式的variables:块,Shell根本不认识这个语法,直接抛出variables:: not found错误。
  2. 变量传递问题:即使Shell赋值正确,默认情况下before_script里的变量只在当前Shell进程有效,不会自动传递到后续job步骤;子job里重复定义DOCKERFILE: $DOCKERFILE属于无效操作,还可能覆盖变量。
  3. 笔误问题: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 00:00:58