How to use Harness Continuous Integration for devops

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

My team was drowning in Jenkins. Our build server was a creaking relic—pipelines took 40 minutes to run, XML configs were scattered everywhere, and every time a plugin updated, something broke. I spent more time nursing the CI server than actually writing code. After one particularly frustrating afternoon debugging a Groovy pipeline syntax error for the third time that week, I decided we needed a modern alternative. That's when I started exploring Harness Continuous Integration (CI).

Harness takes a fundamentally different approach to CI than the legacy tools I was used to. It separates CI from CD into distinct, purpose-built modules, which initially seemed odd—why split them? But after using it, I get it. The concerns are different, the optimization levers are different, and treating them as separate but connected modules actually makes the whole system cleaner. Here's how I got started and what I learned along the way.

Setting Up My First Harness CI Pipeline

I signed up for a Harness account and was immediately struck by how different the onboarding felt. Instead of installing a server and configuring plugins, I was working in a cloud-hosted environment right away. The first thing you need to understand about Harness is its hierarchy: Projects contain Pipelines, Pipelines contain Stages, and Stages contain Steps. It's logical once you see it in action.

I created a new Project called "TeamBackend" and started building a pipeline for a simple Node.js API. The visual pipeline editor is where you'll spend most of your time initially. You can drag and drop stages, but here's the thing that surprised me: everything in the visual editor has a YAML equivalent, and you can toggle between them. I actually found myself preferring the YAML view after the first day because I could copy-paste and version-control it in Git.

Here's what a basic CI pipeline looks like in 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

The infrastructure section was my first "aha" moment. Instead of tying builds to a specific static server, Harness spins up ephemeral build pods in your Kubernetes cluster. When the build finishes, the pod disappears. No more "works on my Jenkins agent" problems.

The Infrastructure Question: Where Do Builds Actually Run?

This is where I made my first mistake. I initially tried to use Harness's hosted infrastructure—their cloud-based build runners—without reading the fine print about network access. Our private npm registry wasn't accessible from Harness's hosted runners, so builds failed immediately with authentication errors.

I had two options: open up our registry to Harness's IP ranges or connect our own Kubernetes cluster as the build infrastructure. I went with the latter, and it was surprisingly straightforward. You install a Harness delegate in your cluster—a lightweight agent that handles communication between your infrastructure and Harness's control plane. The delegate YAML is generated for you in the UI:

kubectl apply -f harness-delegate.yaml

Once the delegate was running, I created a Kubernetes connector pointing to my cluster. Now all CI builds run on our infrastructure, inside our network, with full access to private registries and internal services. The builds still execute in ephemeral pods that spin up in seconds and tear down after completion.

Test Intelligence: The Feature That Actually Delivered

Harness makes a big deal about their "Test Intelligence" feature, claiming it can accelerate test cycles by 80% by only running tests that matter. I was skeptical—these kinds of claims usually mean "we skip tests," which is a terrible idea. But Test Intelligence works differently. It analyzes your code changes and identifies which tests are impacted by those specific changes, then runs only that subset.

Here's what happened in practice. Our Node.js project had about 1,200 unit tests. A full test run took 18 minutes. After enabling Test Intelligence, a typical PR that touched three source files would run roughly 80-150 related tests instead of all 1,200. The test step dropped from 18 minutes to about 2-3 minutes. Over a week with 40+ PRs, that saved hours of developer waiting time.

To enable it, I added a Test Intelligence step instead of a standard Run step for tests:

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

The runOnlySelectedTests: true flag is what activates Test Intelligence. The first few runs still execute all tests because Harness is learning the mapping between source files and tests. After about 5-6 full runs, it has enough data to start intelligently selecting tests. I'd recommend letting it run in "all tests" mode for at least a week before trusting the selection.

Smart Caching: Where the Real Speed Gains Come From

The other performance feature that genuinely impressed me was Harness's caching. Build caching isn't new—every CI tool has some caching mechanism—but Harness handles it more transparently. You can cache at multiple levels: dependency caches (npm, Maven, Gradle), Docker layer caches, and even arbitrary file caches.

For our Node.js builds, I set up dependency caching and saw build times drop from about 8 minutes to under 2 minutes for incremental builds. The configuration is minimal:

- 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" }}
# ... build steps happen here ...
- 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

The {{ checksum "package-lock.json" }} template variable is key—it means the cache key changes whenever your dependencies change, so you never get stale caches. I initially forgot to include the save step and wondered why caching wasn't working. You need both restore and save steps, and the save step should only run on success (which is the default behavior).

Connecting CI to CD: The Bigger Picture

Since Harness separates CI and CD into distinct modules, connecting them is done through artifacts. My CI pipeline builds a Docker image, pushes it to our container registry, and publishes the image tag as a build artifact. Then the CD pipeline picks up that artifact and deploys it.

In the CI pipeline, the final build step looks like this:

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

The <+pipeline.sequenceId> is a Harness built-in variable that gives you an incrementing build number. The CD pipeline then references this artifact in its service definition. It's clean and decoupled—CI doesn't need to know anything about where the code is deploying.

Practical Tips and Honest Limitations

After running Harness CI in production for several months, here's what I wish someone had told me upfront:

Start with the YAML editor. The visual editor is nice for exploring, but YAML is faster once you understand the structure. You can also store pipeline YAML in Git using Harness's Git Experience feature, which gives you proper version control and PR-based pipeline changes.

The delegate is critical. If your delegate goes down, builds stop. Run at least two replicas in your cluster, and set up monitoring on the delegate pods. This bit us once during a cluster upgrade.

Test Intelligence needs calibration. Don't blindly trust it from day one. Run it in parallel with full test suites for a while and compare results. We caught two instances early on where it missed relevant tests after major refactors.

The learning curve is real. Harness's abstraction model—connectors, delegates, pipelines, stages, steps—takes time to internalize. Budget a couple of weeks for your team to get comfortable before migrating critical pipelines.

Cost can be unpredictable. If you're using Harness's hosted infrastructure, you pay by build minute. Long-running integration tests can get expensive fast. Running on your own Kubernetes cluster with the delegate is more cost-effective for heavy workloads.

Documentation is hit-or-miss. Some features are well-documented with clear examples. Others require digging through community forums or opening support tickets. The YAML schema reference is helpful but not always complete.

Would I make the same choice again? Yes. Our builds are faster, our pipelines are version-controlled, and I haven't touched a Jenkins plugin in months. Harness CI isn't perfect, but it's a genuine step forward from the legacy CI tools that were making our team less productive. If you're stuck on Jenkins or similar tools, it's worth the migration effort—just go in with realistic expectations about the learning curve.

相关 Agent

D

Devin

Cognition AI 的自主 AI 软件工程师

了解更多 →