常见问题

Jenkinsfile 语法相关问题

Q:不建议继续使用 ci-init

Q:为什么 2019 年 10 月 10 号 之后使用带有 ci-init 的 Jenkinsfile, 创建一个新的 Job 会提示无法拉取代码?

A:2019 年 10 月 10 日 之前创建的构建计划( Job )中的 ci-init 命令会为用户创建一对公私钥,并使其能够拉取项目中的代码仓库。之后创建的构建计划在调用 ci-init 时,将不会创建拉取代码的公私钥对了。

新创建的构建计划, 我们都会为用户内置一个可以用于拉取对应代码仓库的凭据 ID,直接使用 env.CREDENTIALS_ID 作为 userRemoteConfigs 的 credentialsId 即可。

旧的语法:

pipeline {
    agent any
        stages {
        stage('检出') {
            steps {
                // 旧版本的语法含有 ci-init 
                sh 'ci-init'

                checkout([
                    $class: 'GitSCM', 
                    branches: [[name: env.GIT_BUILD_REF]],
                    userRemoteConfigs: [[url: env.GIT_REPO_URL]]
                ])
            }
        }
    }
}

新的语法:

pipeline {
    agent any
        stages {
        stage('检出') {
            steps {
                checkout([
                    $class: 'GitSCM', 
                    branches: [[name: env.GIT_BUILD_REF]],
                    // 请注意新版的检出语法比旧版新增了 credentialsId: env.CREDENTIALS_ID
                    userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]
                ])
            }
        }
    }
}

CODING 目前已经支持了凭据管理,我们强烈建议用户使用更安全的凭据 ID 来代替之前的 ci-init 操作。

关于凭据如果您想了解更多可以参考《凭据管理》

Q:之前创建的构建计划会受到影响么?

A:不会,我们保障了之前创建的构建计划依然能够正常生效,会注入有效的公私钥,但建议用户尽快替换成新的 checkout 语法。

Q:单引号和双引号用法有什么差异

您在使用 CODING 持续集成时,经常需要在 Jenkinsfile 内拼接字符串或使用环境变量作为参数, Jenkinsfile 中的单引号和双引号在使用时,会有些不同的差异, 这里演示一下常用的 echo 与 sh 两个命令的差异。

pipeline {
    agent any
    environment {
        MY_ENV = 'this is my env'
    }
    stages {
        stage('Test') {
            steps {
                script    {
                    def MY_ENV = 'define in script'

                    echo "${env.MY_ENV}"
                    // 输出内容为 this is my env

                    echo "\${env.MY_ENV}"
                    // 输出内容为 ${env.MY_ENV}

                    echo "${MY_ENV}"
                    // 输出内容为 define in script

                    echo '${MY_ENV}'
                    // 输出内容为 ${MY_ENV}

                    sh 'echo ${MY_ENV}'
                    // 输出内容为 this is my env

                    sh "echo ${MY_ENV}"
                    // 输出内容为 define in script

                    sh "echo ${env.MY_ENV}"
                    // 输出内容为 this is my env
                }
            }
        }
    }
}

从上图输出的结果可以看出:

echo 在使用单引号时,并不会解析里面的 $ 符号,而是直接输出原文;在使用双引号时,会打印出环境变量里的 MY_ENV。

sh 在使用单引号时,将原文当作我们平时在终端里 sh 的命令一样执行,所以可以打印出环境变量里的 MY_ENV。

Q:如何在 CODING 持续集成内推送代码

在某些场景下,您可能需要在持续集成阶段推送代码。CODING 的持续集成内置了 Git、SVN 等命令工具,您可以参考如下示例。

Jenkinsfile 配置语法如下:

pipeline {
  agent any
  stages {
    stage('检出') {
      steps {
        checkout([
            $class: 'GitSCM', 
            branches: [[name: env.GIT_BUILD_REF]], 
            userRemoteConfigs: [[url: env.GIT_REPO_URL, credentialsId: env.CREDENTIALS_ID]]])
      }
    }
    stage('修改') {
        steps {
            sh "echo '# Hello CODING' > README.md"
            sh "git add ."
            sh "git commit -m 'add README.md' "

        }
    }
    stage('推送') {
        steps {
            // 使用了 CODING 持续集成系统预置的项目令牌环境变量 PROJECT_TOKEN_GK 和 PROJECT_TOKEN 来推送
            // 若希望推送到非本项目或第三方平台的代码仓库,需要自行换成有效的凭据信息
            sh "git push https://${PROJECT_TOKEN_GK}:${PROJECT_TOKEN}
              @e.coding.net/myteam/myrepo.git HEAD:master"
        }
    }
  }
}

Jenkinsfile 两种配置来源的区别

在创建构建计划时,你可以设置 Jenkinsfile 的配置来源,使用代码仓库中的 Jenkinsfile使用静态配置的 Jenkinsfile 有什么区别?

使用代码仓库中的 Jenkinsfile 有以下特点:

  1. Jenkinsfile 文件存储在所选择的代码仓库中,修改 Jenkinsfile 的同时也更新代码仓库。

  2. 任务 Job 的构建可由更新代码触发规则定义,若修改 Jenkinsfile 将会自动触发构建。

  3. 在任务 Job 点击立即构建,选择构建目标进行构建时,构建任务的配置将会从所构建目标拉取代码的 Jenkinsfile 进行构建,而不是该任务 Job 里当时配置的 Jenkinsfile。

使用静态配置的 Jenkinsfile 有以下特点:

  1. 静态配置的 Jenkinsfile 将不会保存在代码仓库中,修改 Jenkinsfile 的同时不会更新代码仓库。

  2. 任务 Job 的构建可由更新代码触发规则定义,修改静态配置文件 Jenkinsfile 不会自动触发构建。

  3. 在任务 Job 点击立即构建,选择构建目标进行构建时,构建任务将统一使用该静态配置,不再使用代码仓库中的 Jenkinsfile。

两者区别

  1. 使用代码仓库中的 Jenkinsfile 进行配置,可将 Jenkinsfile 保存到仓库中进行版本记录。而选择使用静态配置的 Jenkinsfile 将不存储在代码版本中,无法进行版本记录。

  2. 使用静态配置的 Jenkinsfile 进行配置,构建时所有的构建任务将统一使用该静态配置,每次代码版本更新时将会执行相同的 Jenkinsfile 进行构建。保障构建流程相同。

构建执行相关问题

Q:构建任务运行失败了怎么办

在遇到构建任务运行失败后,您可以按照下文思路进行排查。

1. 为什么持续集成任务会构建失败

持续集成过程中执行进程的 exit code(退出码)不为 0 就会认为是“构建失败”。

目前主流的计算机操作系统内任何进程的退出,都会留下 exit code, 操作系统可以根据退出码来判断进程是否按照预期运行。通常退出码是 0-255 之间的整数,0 表示正常退出。

CODING 持续集成也根据这一状态码来判断一次构建是否“失败”。用户经常遇到的 exit code 不为 0 有以下几种情况:

持续集成的配置文件语法有错误

与大多数的编程语言一样,Jenkinsfile 也是由特定领域的语言 (DSL) 组成,语法错误,就会导致编译或者运行失败。

测试不通过

大多数主流的测试工具或测试框架,在测试逻辑不通过时,默认都会将退出码设置为非 0。

构建超时或构建配额不足

每一个团队在使用 CODING 持续集成的时候,都会有一定的配额。为防止恶意使用持续集成,每一个构建任务都会有超时的限制,超时或者构建次数超过配额系统将会主动中止构建任务。用户遇到配额不足时,可以在团队管理内进行配额调整,购买满足自己实际需求的配额。

2. 失败了如何排查解决

持续集成过程的本质就是自动地执行一系列任务,这与过去开发者使用脚本编写的自动化任务没有本质上的差异。

查看构建日志与构建快照

CODING 持续集成为用户提供了构建日志,用户可以根据日志内容,判断构建失败的原因。除此之外,CODING 持续集成还提供了每一次构建的配置快照, 用户可以根据快照获取构建使用的配置文件内容和参数,得知是否是配置差异导致的构建失败。

构建日志:

构建快照:

在本地运行自动化任务

用户可以再将自动化的逻辑重新执行一遍(如:在本地重新运行测试代码),本地可以利用 Debug ,或者实时修改代码获得更多的信息反馈,以此来排查问题。

3. 常见其他构建失败原因

使用了交互式命令行程序会导致构建失败

由于持续集成的整个过程中,用户是无法直接使用交互式命令的,若使用了会呼出交互式命令行窗口的程序,会导致构建失败。

常见的有 npm login docker login -u xxx ( CI 内登陆 docker 需要使用 docker -u xx -p xx 的命令)等。

Q:持续集成支持 SVN 仓库么

在默认的持续集成计划的配置过程中,所运行的代码源默认是 Git 类型仓库。如果希望通过 SVN 代码仓库运行持续集成,您需要按照以下指引作出相应的设置。

参考阅读:在 CODING 中创建并使用 SVN 代码仓库

在开始之前,请先创建项目令牌与申请用户名+密码凭据。

  1. 创建项目令牌

前往【项目设置】->【开发者选项】->【项目令牌】中新建项目令牌。设置过期时间后并勾选持续集成所有的权限。

创建完成后会给出用户名及密码。

  1. 申请用户名+密码凭据

前往【项目设置】->【开发者选项】->【凭据管理】中录入用户名+密码凭据。用户名和密码需要填写在创建项目令牌时给出的用户名及密码。

创建完成后会给出凭据 ID,稍后需要将此 ID 录入至构建计划的流程配置中。

  1. 配置构建计划

在【持续集成】->【构建计划】中点击【新建构建计划配置】,选择基础栏中的空白模板,这样可以自定义流程配置。

命名构建计划后,代码源选择【不使用】。

完成后在流程配置中填写相应的配置。

pipeline {
  agent any
  stages {
    stage('检出 SVN 代码') {
      steps {
        checkout([$class: 'SubversionSCM',
                  // 此处可以添加额外认证
                  additionalCredentials: [],
                  excludedCommitMessages: '',
                  excludedRegions: '',
                  excludedRevprop: '',
                  excludedUsers: '',
                  filterChangelog: false,
                  ignoreDirPropChanges: false,
                  includedRegions: '',
                  locations: [[
                               // 输入上文中创建的凭据 ID
                               credentialsId: '5e25f6a9-675c-4b38-97b0-e907b5fe27cd',
                               // 检出代码时所取出代码的范围
                               depthOption: 'infinity',
                               // 是否将 SVN 上的外部引用一并检出
                               ignoreExternalsOption: true,
                               // SVN 的检出目录,此目录是该 Job 工作目录的相对路径
                               local: '.',
                               // SVN 代码仓库地址
                               remote: "svn://subversion.e.coding.net/StrayBirds/svn"]],
                  workspaceUpdater: [$class: 'UpdateUpdater']])
      }
    }
  }
}
  1. 添加环境变量

在变量与缓存中添加环境变量,类别选择 CODING 凭据里的用户名 + 密码。

  1. 触发构建

您可以选择手动构建或配置触发方式进行自动构建,构建成功后如图所示。

Q:如何在持续集成中检出(克隆)Git Submodule 的代码

在持续集成中用户可以通过流程配置检出(克隆) Git 子模块代码,在执行构建计划的代码源中添加带有子模块的代码仓库。

在了解如何检出 Git Submodule 之前,请先熟悉 Git Submodule 的基本命令。

如何添加子模块

可以在 git submodule add 后面命令后面加上拟跟踪项目里的仓库地址来添加新的子模块。下面是在父仓库 git-parent-module 仓库中添加了子仓库 git-sub-module 作为其子模块的示例代码。

git-parent-module user$ git submodule add https://e.coding.net/test/git-sub-module.git
Cloning into 'git-parent-module/git-sub-module'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 10 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (10/10), done.

如何克隆带有子模块的代码仓库并更新子模块

在运行 git clone 克隆带有子模块的项目后,默认会包含该子模块目录,但其中还没有任何文件:

user$ git clone https://e.coding.net/test/git-parent-module.git
Cloning into 'git-parent-module'...
remote: Enumerating objects: 10, done.
remote: Counting objects: 100% (10/10), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 10 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (10/10), done.
user$ cd git-parent-module
user$ ls
README.md    git-sub-module
user$ ls git-sub-module
user$

此时需要运行两个命令:git submodule init 用来初始化本地配置文件;git submodule update 是从子项目中抓取对应版本的提交。

user$ git submodule init
Submodule 'git-sub-module' (https://e.coding.net/test/git-sub-module.git) 
registered for path 'git-sub-module'
user$ git submodule update
Cloning into '/Users/DianYu/Documents/Projects/git-parent-module/git-sub-module'...
Submodule path 'git-sub-module': checked out '96120312315396d1e9245f435c40c662f0933cfc'
user$ ls git-sub-module
README.md
user$

如何在创建构建计划时检出 Git Submodule

  1. 在【凭据管理】中录入父、子代码仓库的用户名+密码,生成凭据 ID。

  1. 在构建计划页面,新建构建计划,选择自定义构建过程。

  1. 选择代码源后进入流程配置,流程配置代码如下:
pipeline {
  agent any
  stages {
    stage('检出') {
      steps {
        checkout([
          $class: 'GitSCM',
          branches: [[name: env.GIT_BUILD_REF]],
          doGenerateSubmoduleConfigurations: false,
          // 此处配置 Submodule 的检出规则
          extensions: [[
            $class: 'SubmoduleOption',
            // 是否禁用检出 Submodule
            disableSubmodules: false,
            // 是否允许检出时使用 Parent Project 的用户凭据
            parentCredentials: false,
            // 是否递归检出所有 Submodule 的更新
            recursiveSubmodules: true,
            // 指定参考仓库的路径
            reference: '',
            // 是否追踪 .gitmodules 文件中配置的分支的最新提交
            trackingSubmodules: false
          ]],
          submoduleCfg: [
          ],
          // 此处配置远程 Parent Project 和 Submodules的检出信息
          userRemoteConfigs: [
            [
              credentialsId: env.PARENT_CREDENTIALS_ID,
              url: env.PARENT_REPO_URL
            ],

            [
              credentialsId: env.SUB_CREDENTIALS_ID,
              url: env.SUB_REPO_URL
            ]

            // 如果有更多的Submodules,可以在这里增加配置
          ]

        ])
        sh 'ls'
        sh 'ls git-sub-module'
      }
    }
  }
}

参考环境变量

序号 变量名 变量含义
1 GIT_BUILD_REF 构建对应的 Git 修订版本号
2 PARENT_CREDENTIALS_ID 父仓库用户凭据
3 SUB_CREDENTIALS_ID 子仓库用户凭据
4 PARENT_REPO_URL 父仓库 SSH 地址
5 SUB_REPO_URL 子仓库 SSH 地址

Q:如何在 CODING 持续集成中检出其它 CODING 项目的仓库

在持续集成中,您可以通过项目令牌的方式检出其它项目内的 CODING 仓库代码。

为了方便您区分即将要操作的两个不同项目,我们统一将:

  • 需要被检出的代码仓库所在项目称为 “项目 A”
  • 执行检出持续集成任务所在的项目称为 “项目 B”
步骤一:在项目 A 内创建项目令牌
  1. 进入项目 A【项目设置】->【开发者选项】->【项目令牌】,点击 “新建项目令牌” 。

  1. 选择需要检出的代码仓库,按需求配置操作权限。

  1. 点击确定后创建成功。
步骤二:在项目 B 创建凭据
  1. 进入项目 B 进入【项目设置】->【开发者选项】->【凭据管理】,点击 “录入凭据”。

  1. 回到之前创建好的项目 A 项目令牌页面,点击 “查看密码”。

  1. 在项目 B 的 “录入凭据” 窗口选择 “用户名 + 密码” 类型凭据,粘贴项目令牌对应信息。

  1. 选择授权的持续集成项目,点击 “保存”。

步骤三:在项目 B 持续集成任务中配置对应的环境变量
  1. 进入持续集成设置 -> 【流程配置】,添加 “从代码仓库检出” 步骤,点击 “环境变量”。

也可以在添加检出流程之后,进入持续集成设置 ->【变量与缓存】中添加环境变量。

  1. 分别添加以下两个环境变量:
变量名 默认值
GIT_REPO_URL 需要检出的仓库克隆地址(HTTPS)
CREDENTIALS_ID 在步骤二录入的凭据 ID


填好后的环境变量:

步骤四:开始构建任务,成功检出代码

Q:如何在 CODING 持续集成中检出使用 Git LFS 管理的仓库

在持续集成中用户可以通过流程配置检出使用 Git LFS (Large File Storage) 插件管理的代码仓库,实现带有大文件的 Git 仓库持续集成。

Git LFS 简介

Git LFS 插件加速了带有频繁变动的大文件(例如图片、视频等)的 git clonegit fetch 操作。

每当您在仓库中添加了大文件时,Git LFS 插件会将它储存在本地的 Git LFS cache 中,同时将代码仓库中的大文件内容代替为指向缓存地址的引用。当您提交代码时,本次提交所涵盖的所有大文件会被提交到远程 Git LFS cache 中,该缓存和您的远程仓库相关联。当您检出带有大文件引用的提交时,插件会将其替换为缓存中的文件实际内容。

因此,通过 Git LFS 插件的管理,大文件只会在 git checkout 的时候被加载。

如何在构建计划中检出使用 Git LFS 管理的代码

在【构建计划设置】->【流程配置】页面,添加 “从代码仓库检出” 步骤,添加 Git-LFS-Pull 插件。

流程配置代码
pipeline {
  agent any
  stages {
    stage('检出') {
      steps {
        checkout([
          $class: 'GitSCM',
          branches: [[name: env.GIT_BUILD_REF]],
          extensions: [
            // 添加 GitLFSPull 插件
            [$class: 'GitLFSPull'],
          ],
          userRemoteConfigs: [[
            url: env.GIT_REPO_URL,
            credentialsId: env.CREDENTIALS_ID
          ]]
        ])
      }
    }
  }
}

Q:如何在自定义构建节点访问本地 Jenkins

步骤一:访问 Jenkins
  1. 首先需要将您的设备作为自定义构建节点接入,具体操作步骤可以点击查看

  2. 为了避免对外暴露端口,CODING CI 自定义节点默认启动的 Jenkins 只会监听本地回环地址(127.0.0.1),默认的监听端口为 15740,此时,您只能在构建节点机器通过 localhost 或者 127.0.0.1 进行访问,具体的访问地址为 http://localhost:15740

  3. 如果无法访问,可以通过命令 cat ~/.coding/cci-agent.yml 查看端口 (publicPort)

  4. 如果您希望在构建节点外部访问 Jenkins,可以在执行 up 命令启动程序时添加 --jserver 0.0.0.0 参数,同时也可以使用 --jport 指定监听端口,假设构建节点 ip 为 NODE_IP,指定的监听端口为 PORT 此时的访问地址为 http://NODE_IP:PORT

步骤二:Jenkins 登录令牌

在浏览器中输入 Jenkins 访问地址,会看到登录页面。

Jenkins 登录用户名和密码分别为 coding11bf48c0403ec88231b530b5f98a113cad,您可以执行 ./cci-agent up -h 命令,在帮助文档中查看更多命令

Q:如何在自定义构建节点安装插件

自定义构建节点是以开源软件 Jenkins 为引擎进行构建的,Jenkins 提供了超过 1000 个插件支持构建、部署、自动化。CODING CI 自定义节点默认提供的 Jenkins 仅内置了最常用的部分插件,如果不能满足您项目的需求,您可以自行安装需要的插件。

  1. 首先需要您登陆 Jenkins,详见上一问的答案。

  2. 登录到 Jenkins 后,可以看到 Jenkins 管理界面,依次点击 【系统管理】–> 【插件管理】,即可进入插件管理页面。

  3. 左侧菜单栏中点击【系统管理】。

  1. 下拉页面,点击【插件管理】。

  1. 打开插件管理页面。

  1. 在插件管理页面,找到【可选插件】选项页,搜索并勾选需要安装的插件,点击页面下方的【下载待重启后安装】,在弹出的【更新中心】页面勾选 安装完成后重启 Jenkins,等待 Jenkins 安装完成后自动重启,即可使用。

Q:为什么关联的工蜂仓库无法同步至外部仓库列表

目前需在工蜂授权时选择 “当前帐号” 的授权范围才能成功同步到外部仓库列表,并在持续集成构建任务重被检出,如果您选择的授权范围是 “项目组” 或 “项目”,则无法成功同步。

Q:如何 Debug 构建任务

如果您需要 Debug 构建运行过程,可以通过在构建过程中添加以下步骤的方式提供 ssh:

steps {
  sh 'apt-get update'
  sh 'apt-get install -y tmate openssh-client'
  sh '''echo -e \'y
\'|ssh-keygen -q -t rsa -N "" -f ~/.ssh/id_rsa'''
  sh 'tmate -S /tmp/tmate.sock new-session -d'
  sh 'tmate -S /tmp/tmate.sock wait tmate-ready'
  sh '''
tmate -S /tmp/tmate.sock display -p \'#{tmate_ssh}\'
tmate -S /tmp/tmate.sock display -p \'#{tmate_web}\'
echo "WebURL: ${tmateWeb}"
echo "SSH: ${tmateSSH}"
'''
  sh 'sleep 3600'
}

上一篇在持续集成中使用 SSH
最近更新
感谢反馈有用
感谢反馈没用