常见问题
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 有以下特点:
Jenkinsfile 文件存储在所选择的代码仓库中,修改 Jenkinsfile 的同时也更新代码仓库。
任务 Job 的构建可由更新代码触发规则定义,若修改 Jenkinsfile 将会自动触发构建。
在任务 Job 点击立即构建,选择构建目标进行构建时,构建任务的配置将会从所构建目标拉取代码的 Jenkinsfile 进行构建,而不是该任务 Job 里当时配置的 Jenkinsfile。
使用静态配置的 Jenkinsfile 有以下特点:
静态配置的 Jenkinsfile 将不会保存在代码仓库中,修改 Jenkinsfile 的同时不会更新代码仓库。
任务 Job 的构建可由更新代码触发规则定义,修改静态配置文件 Jenkinsfile 不会自动触发构建。
在任务 Job 点击立即构建,选择构建目标进行构建时,构建任务将统一使用该静态配置,不再使用代码仓库中的 Jenkinsfile。
两者区别
使用代码仓库中的 Jenkinsfile 进行配置,可将 Jenkinsfile 保存到仓库中进行版本记录。而选择使用静态配置的 Jenkinsfile 将不存储在代码版本中,无法进行版本记录。
使用静态配置的 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 代码仓库。
在开始之前,请先创建项目令牌与申请用户名+密码凭据。
- 创建项目令牌
前往【项目设置】->【开发者选项】->【项目令牌】中新建项目令牌。设置过期时间后并勾选持续集成所有的权限。
创建完成后会给出用户名及密码。
- 申请用户名+密码凭据
前往【项目设置】->【开发者选项】->【凭据管理】中录入用户名+密码凭据。用户名和密码需要填写在创建项目令牌时给出的用户名及密码。
创建完成后会给出凭据 ID,稍后需要将此 ID 录入至构建计划的流程配置中。
- 配置构建计划
在【持续集成】->【构建计划】中点击【新建构建计划配置】,选择基础栏中的空白模板,这样可以自定义流程配置。
命名构建计划后,代码源选择【不使用】。
完成后在流程配置中填写相应的配置。
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']])
}
}
}
}
- 添加环境变量
在变量与缓存中添加环境变量,类别选择 CODING 凭据里的用户名 + 密码。
- 触发构建
您可以选择手动构建或配置触发方式进行自动构建,构建成功后如图所示。
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
- 在【凭据管理】中录入父、子代码仓库的用户名+密码,生成凭据 ID。
- 在构建计划页面,新建构建计划,选择自定义构建过程。
- 选择代码源后进入流程配置,流程配置代码如下:
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 内创建项目令牌
- 进入项目 A【项目设置】->【开发者选项】->【项目令牌】,点击 “新建项目令牌” 。
- 选择需要检出的代码仓库,按需求配置操作权限。
- 点击确定后创建成功。
步骤二:在项目 B 创建凭据
- 进入项目 B 进入【项目设置】->【开发者选项】->【凭据管理】,点击 “录入凭据”。
- 回到之前创建好的项目 A 项目令牌页面,点击 “查看密码”。
- 在项目 B 的 “录入凭据” 窗口选择 “用户名 + 密码” 类型凭据,粘贴项目令牌对应信息。
- 选择授权的持续集成项目,点击 “保存”。
步骤三:在项目 B 持续集成任务中配置对应的环境变量
- 进入持续集成设置 -> 【流程配置】,添加 “从代码仓库检出” 步骤,点击 “环境变量”。
也可以在添加检出流程之后,进入持续集成设置 ->【变量与缓存】中添加环境变量。
- 分别添加以下两个环境变量:
变量名 | 默认值 |
---|---|
GIT_REPO_URL | 需要检出的仓库克隆地址(HTTPS) |
CREDENTIALS_ID | 在步骤二录入的凭据 ID |
填好后的环境变量:
步骤四:开始构建任务,成功检出代码
Q:如何在 CODING 持续集成中检出使用 Git LFS 管理的仓库
在持续集成中用户可以通过流程配置检出使用 Git LFS (Large File Storage) 插件管理的代码仓库,实现带有大文件的 Git 仓库持续集成。
Git LFS 简介
Git LFS 插件加速了带有频繁变动的大文件(例如图片、视频等)的 git clone
和 git 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
首先需要将您的设备作为自定义构建节点接入,具体操作步骤可以点击查看。
为了避免对外暴露端口,CODING CI 自定义节点默认启动的 Jenkins 只会监听本地回环地址(127.0.0.1),默认的监听端口为
15740
,此时,您只能在构建节点机器通过 localhost 或者 127.0.0.1 进行访问,具体的访问地址为 http://localhost:15740如果无法访问,可以通过命令
cat ~/.coding/cci-agent.yml
查看端口 (publicPort)如果您希望在构建节点外部访问 Jenkins,可以在执行
up
命令启动程序时添加--jserver 0.0.0.0
参数,同时也可以使用--jport
指定监听端口,假设构建节点 ip 为NODE_IP
,指定的监听端口为PORT
此时的访问地址为 http://NODE_IP:PORT
步骤二:Jenkins 登录令牌
在浏览器中输入 Jenkins 访问地址,会看到登录页面。
Jenkins 登录用户名和密码分别为 coding
和 11bf48c0403ec88231b530b5f98a113cad
,您可以执行 ./cci-agent up -h 命令,在帮助文档中查看更多命令。
Q:如何在自定义构建节点安装插件
自定义构建节点是以开源软件 Jenkins 为引擎进行构建的,Jenkins 提供了超过 1000 个插件支持构建、部署、自动化。CODING CI 自定义节点默认提供的 Jenkins 仅内置了最常用的部分插件,如果不能满足您项目的需求,您可以自行安装需要的插件。
首先需要您登陆 Jenkins,详见上一问的答案。
登录到 Jenkins 后,可以看到 Jenkins 管理界面,依次点击 【系统管理】–> 【插件管理】,即可进入插件管理页面。
左侧菜单栏中点击【系统管理】。
- 下拉页面,点击【插件管理】。
- 打开插件管理页面。
- 在插件管理页面,找到【可选插件】选项页,搜索并勾选需要安装的插件,点击页面下方的【下载待重启后安装】,在弹出的【更新中心】页面勾选
安装完成后重启 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'
}