**如何在 DevOps 中使用 Harness Continuous Integration** **翻译说明:** * **How to**:译为“如何”,符合中文技术文章标题的常用句式。 * **Harness Continuous Integration**:作为产品名保留英文原文。 * **devops**:译为中文技术圈最常用的“DevOps”(通常在中文语境下直接使用原词比硬翻成“开发运维”更自然、更口语化)。

devops入门12 分钟阅读2026/7/8

我的团队以前简直是被 Jenkins 淹没了。我们的构建服务器就像个摇摇欲坠的老古董——跑一次流水线要 40 分钟,XML 配置文件满天飞,而且每次一有插件更新,总有东西会挂掉。我花在“伺候” CI 服务器上的时间,比真正写代码的时间还要多。在某个特别让人崩溃的下午,那已经是那周我第三次去调试 Groovy 流水线的语法错误了,我下定决心:我们得换个现代化的工具。就在那时,我开始研究 Harness Continuous Integration (CI)。

与我用惯了的那些老牌工具相比,Harness 在 CI 的思路上有着根本性的不同。它把 CI 和 CD 拆分成了独立且专门构建的模块,这乍一看挺奇怪的——为什么要拆开呢?但用过之后我就明白了。CI 和 CD 关注点不同,优化的侧重点也不同,把它们当成独立又相连的模块来处理,反而让整个系统变得更清爽。下面就来分享一下我是如何上手的,以及这一路上学到的经验。

搭建我的第一条 Harness CI 流水线

注册了 Harness 账号后,它引导上手的体验立刻让我眼前一亮,感觉完全不一样。不需要安装服务器、配置插件,我直接就在云托管环境里操作了。使用 Harness,你首先要理解它的层级结构:项目包含流水线,流水线包含阶段,阶段包含步骤。当你实际操作时,就会发现这个逻辑非常清晰。

我创建了一个名为“TeamBackend”的新项目,并开始为一个简单的 Node.js API 搭建流水线。可视化流水线编辑器是你初期最常打交道的地方。你可以拖拽各个阶段,但有一点让我挺惊喜:可视化编辑器里的所有内容都有对应的 YAML,而且你可以在两者之间自由切换。第一天过后,我发现自己反而更喜欢 YAML 视图了,因为我可以直接复制粘贴,还能用 Git 进行版本控制。

下面是一个基本的 CI 流水线在 Harness YAML 中的样子:

pipeline:
  name: backend-api-ci
  identifier: backend_api_ci
  projectIdentifier: TeamBackend
  orgIdentifier: default
  tags: {}
  stages:
    - stage:
        name: build-and-test
        identifier: build_and_test
        type: CI
        spec:
          cloneCodebase: true
          infrastructure:
            type: KubernetesDirect
            spec:
              connectorRef: account.harness_k8s_connector
              namespace: harness-ci-builds
          execution:
            steps:
              - step:
                  type: Run
                  name: install_deps
                  identifier: install_deps
                  spec:
                    command: npm ci
              - step:
                  type: Run
                  name: run_lint
                  identifier: run_lint
                  spec:
                    command: npm run lint
              - step:
                  type: Run
                  name: run_tests
                  identifier: run_tests
                  spec:
                    command: npm test

infrastructure 这部分让我迎来了第一个“顿悟”时刻。Harness 没有把构建绑定在某一台特定的静态服务器上,而是在你的 Kubernetes 集群里启动临时的构建 Pod。构建一结束,Pod 就消失了。再也不用纠结“在我的 Jenkins Agent 上明明没问题”这种事了。

基础设施之问:构建到底跑在哪?

这就是我踩第一个坑的地方。我一开始想图省事,用了 Harness 的托管基础设施——也就是他们基于云的构建运行器,但没仔细看关于网络访问的细则。我们的私有 npm 仓库从 Harness 的托管运行器根本访问不到,所以构建立马报了鉴权错误。

我有两个选择:要么把我们的仓库对 Harness 的 IP 段开放,要么把我们自己的 Kubernetes 集群接入,作为构建基础设施。我选了后者,而且出人意料地简单。你只需要在集群里装一个 Harness Delegate——这是一个轻量级代理,负责处理你的基础设施和 Harness 控制面之间的通信。Delegate 的 YAML 可以直接在界面上生成:

kubectl apply -f harness-delegate.yaml

Delegate 跑起来之后,我创建了一个指向我集群的 Kubernetes 连接器。现在,所有的 CI 构建都跑在我们自己的基础设施上,在我们的内网里,可以完全访问私有仓库和内部服务。这些构建依然在临时的 Pod 中执行,几秒钟就能拉起,跑完就自动销毁。

测试智能:真正立竿见影的功能

Harness 对他们的“测试智能”功能吹捧得很厉害,声称可以只跑那些关键的测试,从而将测试周期缩短 80%。我一开始是持怀疑态度的——这种说辞通常意味着“我们会跳过一些测试”,这可不是什么好主意。但测试智能的工作原理不同。它会分析你的代码改动,找出哪些测试受这些特定改动的影响,然后只运行这小部分测试。

实际效果如何呢?我们的 Node.js 项目大约有 1200 个单元测试,全量跑一次需要 18 分钟。开启了测试智能后,一个典型的 PR 如果改动了三个源文件,大概只会运行 80-150 个相关测试,而不是全部 1200 个。测试步骤的时间从 18 分钟骤降到了 2-3 分钟。按一周 40 多个 PR 来算,这省下了开发者大量的等待时间。

要启用它,只需把测试的标准 Run 步骤换成测试智能步骤:

- step:
    type: RunTests
    name: run_unit_tests
    identifier: run_unit_tests
    spec:
      language: Javascript
      buildTool: Mocha
      args:
        testReports: /harness/reports/*.xml
      runOnlySelectedTests: true

runOnlySelectedTests: true 这个标志就是开启测试智能的开关。最开始的几次运行依然会执行所有测试,因为 Harness 还在学习源文件和测试之间的映射关系。大概经过 5-6 次全量运行后,它积累了足够的数据,就可以开始智能挑选测试了。我建议在信任它的挑选结果之前,至少让它在“全量测试”模式下跑上一周。

智能缓存:速度飙升的真正秘诀

另一个让我心服口服的性能功能是 Harness 的缓存机制。构建缓存不算什么新鲜事——每个 CI 工具都有缓存机制——但 Harness 处理起来更加透明。你可以在多个层面做缓存:依赖缓存(npm、Maven、Gradle)、Docker 层缓存,甚至任意文件缓存。

对于我们的 Node.js 构建,我设置了依赖缓存,增量构建的时间直接从大约 8 分钟降到了 2 分钟以内。配置也非常简单:

- step:
    type: RestoreCacheS3
    name: restore_npm_cache
    identifier: restore_npm_cache
    spec:
      connectorRef: account.aws_s3_connector
      bucket: harness-ci-cache
      key: npm-{{ checksum "package-lock.json" }}
# ... 这里执行构建步骤 ...
- step:
    type: SaveCacheS3
    name: save_npm_cache
    identifier: save_npm_cache
    spec:
      connectorRef: account.aws_s3_connector
      bucket: harness-ci-cache
      key: npm-{{ checksum "package-lock.json" }}
      sourcePaths:
        - node_modules

{{ checksum "package-lock.json" }} 这个模板变量是关键——它意味着只要依赖变了,缓存 key 就会变,所以你永远不会用到过期的缓存。一开始我忘了加保存缓存的步骤,还纳闷为什么缓存不起作用。恢复和保存步骤缺一不可,而且保存步骤默认只在构建成功时运行。

连接 CI 与 CD:大局观

既然 Harness 把 CI 和 CD 分成了独立的模块,那它们之间就是通过制品来衔接的。我的 CI 流水线构建出 Docker 镜像,推送到我们的容器仓库,并把镜像标签作为构建制品发布出去。然后 CD 流水线会拿走这个制品并进行部署。

在 CI 流水线中,最后的构建步骤长这样:

- step:
    type: BuildAndPushDockerRegistry
    name: build_and_push
    identifier: build_and_push
    spec:
      connectorRef: account.dockerhub_connector
      repo: myorg/backend-api
      tags:
        - "<+pipeline.sequenceId>"

<+pipeline.sequenceId> 是 Harness 的内置变量,会给你一个递增的构建号。接着,CD 流水线会在它的服务定义中引用这个制品。整个过程非常干净且解耦——CI 完全不需要知道代码要部署到哪里。

实用建议与实话实说的局限性

在生产环境跑了几个月的 Harness CI 后,有些话我真希望一开始就有人告诉我:

从 YAML 编辑器入手。 可视化编辑器用来探索挺不错的,但一旦你熟悉了结构,YAML 会快得多。你还可以用 Harness 的 Git Experience 功能把流水线 YAML 存到 Git 里,这样就能实现正经的版本控制,流水线的改动也能走 PR 流程。

Delegate 至关重要。 如果 Delegate 挂了,构建也就停了。在集群里至少跑两个副本,并且给 Delegate Pod 配上监控。我们就因为在一次集群升级时没注意,在这上面栽过跟头。

测试智能需要校准。 别从第一天起就盲目信任它。先让它和全量测试并行跑一段时间,对比一下结果。我们就曾在大重构后,提早发现了两次它漏选相关测试的情况。

学习曲线是真实存在的。 Harness 的抽象模型——连接器、Delegate、流水线、阶段、步骤——需要时间来消化。多预留个一两周的时间,让团队熟悉了之后再迁移关键流水线。

成本可能不太好预估。 如果你用的是 Harness 的托管基础设施,他们是按构建分钟数收费的。长时间运行的集成测试很快就会产生高昂的费用。对于繁重的工作负载,用 Delegate 跑在自己的 Kubernetes 集群上性价比更高。

文档质量参差不齐。 有些功能文档写得很棒,示例清晰;有些则得到处翻社区论坛,或者提工单才能弄明白。YAML Schema 参考挺有用的,但有时也不够全面。

如果重来一次,我还会做同样的选择吗?会的。我们的构建变快了,流水线实现了版本控制,我也好几个月没碰过 Jenkins 插件了。Harness CI 并不完美,但相比那些拖累团队效率的老牌 CI 工具,它确确实实向前迈进了一步。如果你还受困于 Jenkins 或类似的工具,这波迁移是值得的——只是对学习曲线要有现实的预期。

相关 Agent

D

Docker

Docker 是一个容器化平台,允许开发者将应用及其依赖项打包成轻量级、可移植的容器。它简化了跨环境的开发、测试和部署过程。该描述强调它最适合容器化和开发环境,提供免费方案和团队方案,团队方案从每用户每月5美元起。

了解更多 →