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

Jenkins持续部署流水线:如何每日仅执行特定步骤一次

这个场景确实是持续部署流程里的典型痛点,我来分享几个经过验证的可行方案,覆盖Jenkins原生能力、插件工具和业界常用实践:

1. Jenkins原生归档+历史构建检索(无额外依赖)

这是你提到的思路的具体落地方式,完全依赖Jenkins自身能力,不需要外部资源:

  • 部署标记:当部署成功后,生成一个带环境+日期的标记文件(比如deployed-TestA-20240520.txt),用archiveArtifacts步骤归档到构建记录中。
  • 历史检查:后续构建时,遍历当前Job的近期历史构建(限制在24小时内避免性能问题),检查是否存在对应当日环境的归档标记。

示例代码(声明式流水线的script块中):

script {
    def today = new Date().format('yyyyMMdd')
    def targetEnv = ''
    // 时段判断逻辑
    def currentHour = new Date().getHours()
    if (currentHour >= 11 && currentHour < 14) {
        targetEnv = 'TestA'
    } else if (currentHour >=14 && currentHour <18) {
        targetEnv = 'TestB'
    } else {
        echo "当前时段不在部署窗口,跳过部署"
        return
    }

    // 检查当日是否已部署
    def deployedToday = false
    def recentBuilds = currentBuild.rawBuild.parent.builds.findAll {
        it.timestamp.time >= System.currentTimeMillis() - 24*60*60*1000
    }
    recentBuilds.each { build ->
        try {
            if (build.getArtifacts().any { it.fileName == "deployed-${targetEnv}-${today}.txt" }) {
                deployedToday = true
                return // 找到标记后终止遍历
            }
        } catch (Exception e) {
            echo "检查构建${build.number}时出错: ${e.message}"
        }
    }

    if (!deployedToday) {
        echo "开始部署到${targetEnv}..."
        // 这里写入你的部署逻辑(比如ssh、kubectl命令等)
        
        // 部署成功后归档标记文件
        writeFile file: "deployed-${targetEnv}-${today}.txt", text: "Deployed at ${new Date()}"
        archiveArtifacts artifacts: "deployed-${targetEnv}-${today}.txt", fingerprint: true
    } else {
        echo "${targetEnv}今日已完成部署,跳过"
    }
}
  • 优点:零外部依赖,配置简单;缺点:如果Job历史量极大,遍历会有轻微性能损耗,限制遍历范围即可解决。

2. 利用Jenkins全局属性存储状态

通过Jenkins的全局节点属性来存储部署记录,跨节点共享状态:

  • 借助Groovy脚本读写全局属性,注意加上@NonCPS注解避免序列化问题,同时需要确保流水线有足够权限。

示例代码:

@NonCPS
def checkDeployedToday(String envName) {
    def today = new Date().format('yyyyMMdd')
    def key = "${env.JOB_NAME}:${envName}:${today}"
    def globalProps = Jenkins.instance.getGlobalNodeProperties().get(GlobalStringProperty.class)
    return globalProps.any { it.key == key && it.value == 'true' }
}

@NonCPS
def markDeployedToday(String envName) {
    def today = new Date().format('yyyyMMdd')
    def key = "${env.JOB_NAME}:${envName}:${today}"
    def globalProps = Jenkins.instance.getGlobalNodeProperties().get(GlobalStringProperty.class)
    // 先移除旧记录(如果存在)
    globalProps.removeAll { it.key == key }
    globalProps.add(new GlobalStringProperty(key, 'true'))
    Jenkins.instance.save()
}

// 流水线中调用
script {
    // 时段判断逻辑...
    if (!checkDeployedToday(targetEnv)) {
        // 部署逻辑...
        markDeployedToday(targetEnv)
    }
}
  • 优点:查询速度快,跨节点共享;缺点:需要管理员权限配置,且全局属性是全Jenkins可见,要通过Job名称前缀做隔离。

3. 专用插件简化实现

有几个插件可以直接封装这类逻辑,减少自定义代码量:

  • Lockable Resources Plugin:把每个环境+每日窗口当成一个可锁定的资源。比如定义TestA-Daily和TestB-Daily资源,部署前尝试锁定,若已被锁定(当日已部署)则跳过。还可以配合定时Job每日0点自动释放锁。
    示例流水线步骤:
    stage('Deploy') {
        when {
            expression {
                def h = new Date().getHours()
                return (h >=11 && h<14) || (h>=14 && h<18)
            }
        }
        steps {
            script {
                def lockName = new Date().getHours() >=11 && new Date().getHours()<14 ? 'TestA-Daily' : 'TestB-Daily'
                lock(resource: lockName, skipIfLocked: true) {
                    echo "部署到${lockName.replace('-Daily', '')}..."
                    // 部署逻辑
                }
            }
        }
    }
    
  • Pipeline Utility Steps Plugin:可以更方便地检索历史归档文件,简化findFiles、readFileFromWorkspace等操作。

4. 外部存储方案(业界常用的轻量选项)

如果团队有现成的基础设施,外部存储是更灵活的选择:

  • Redis:用键值对存储部署状态,键格式为${JobName}:${Env}:${Date},值设为true并设置24小时过期。流水线中通过sh调用redis-cli读写。
  • 共享存储标记文件:比如NFS共享目录,部署成功后创建TestA-20240520文件,后续构建通过sh 'ls /shared/deploy/TestA-$(date +%Y%m%d)'判断是否存在。
  • 数据库:用轻量数据库(如SQLite、MySQL)存储部署日志,查询当日是否有对应环境的部署记录。

业界实践总结

  • 中小团队优先选择Jenkins原生归档+历史检索或Lockable Resources Plugin,无需额外运维成本;
  • 大型团队或有统一运维平台的场景,会用Redis/数据库做全局状态管理,方便跨系统查询和统计;
  • 很多团队会把时段-环境的对应规则放到配置中心(如内部配置平台),而非硬编码在流水线中,方便随时调整部署窗口。

内容的提问来源于stack exchange,提问作者ami

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:49:40