Harness持续交付平台入门:从本地部署到金丝雀发布实战
2026/6/24 23:17:16 网站建设 项目流程

1. 先搞清楚“Harness”到底指什么——别被名字骗了十年

很多人第一次看到“Harness”这个词,下意识会联想到“马具”“束缚带”或者“拖拽装置”,甚至有人在技术群里问:“这玩意儿是不是要给服务器套个皮带?”——这种误解非常典型,而且后果严重。我见过三个团队,因为没搞清这个基础概念,在项目启动三周后推倒重来:一个把 Harness 当成 CI/CD 工具链的统称,硬塞进 Jenkins + GitLab CI 的混合架构里;一个把它当成类似 Postman 的 API 测试工具,花两周写了一堆 YAML 脚本去调用接口,结果连环境变量注入都失败;还有一个更绝,直接下载了 PX4 飞控固件源码,在src/modules/harness/目录下翻了三天,以为找到了“飞控专用 Harness 模块”……最后发现那只是某个学生提交的未合并实验分支。

真相是:Harness 是一个独立的、商业级的持续交付(Continuous Delivery)平台,不是插件、不是库、不是协议,而是一套完整的 SaaS 或私有化部署系统。它和 Jenkins、GitLab CI、CircleCI 的根本区别在于——它不只管“怎么跑”,更管“该不该跑”“跑给谁看”“跑完怎么交付”。它的核心能力是把软件发布这件事,从“工程师手动敲命令”变成“策略驱动的自动化决策流”。

为什么强调这个?因为标题里那个“你的第一个 Harness”不是指“你写的第一个 harness 函数”,也不是“你配置的第一个 harness 插件”,而是你亲手部署、配置、并让第一个服务真正通过它完成一次端到端交付的 Harness 实例。它要求你同时理解三件事:一是现代云原生应用的交付瓶颈在哪(比如金丝雀发布时流量切分不准、回滚超时、环境状态漂移),二是 Harness 的抽象模型(Pipeline、Stage、Step、Service、Environment、Infrastructure)、三是你自己的技术栈如何与之对齐(K8s 还是 VM?Helm 还是 Kustomize?GitHub 还是 Bitbucket?)。

提示:如果你正在看这篇文字,且手头没有现成的 Kubernetes 集群、没有可用的 GitHub/GitLab 仓库、没有一个能跑通的 Docker 镜像,那么请立刻停在这里,先搭好这三样东西。Harness 不是“零门槛”,它是“零胶水”——它不帮你造轮子,但能让你所有轮子严丝合缝地转起来。没有轮子,再好的底盘也没用。

我第一次部署 Harness 时,就在 Ubuntu 22.04 老笔记本上卡了整整两天。不是因为 Harness 多难,而是因为我的 NVIDIA GeForce GT 630M 显卡驱动没装对,导致 Docker Desktop 启动失败,进而让本地 Helm 安装的 Harness CE(Community Edition)一直报connection refused。后来才明白:Harness 本身不依赖 GPU,但它依赖的底层容器运行时(containerd)和网络插件(Calico)在老旧硬件上对内核模块兼容性极敏感。这不是 Harness 的 bug,而是你环境基线没对齐的信号。所以,“从零开始”的第一课,永远不是打开 Harness 控制台,而是确认你的“零”是真的干净、可控、可复现。

2. 为什么不用 Jenkins/GitLab CI?Harness 解决的是哪类真问题

这个问题我被问过至少 47 次,每次我都先反问一句:“你们最近一次因为发布失败被叫醒是什么时候?是因为构建失败,还是因为上线后用户投诉白屏?”——答案几乎全是后者。这就点出了本质:Jenkins 和 GitLab CI 解决的是CI(持续集成)层的问题:代码合入 → 编译 → 单元测试 → 打包 → 推镜像。它们擅长“快”,但不负责“稳”和“准”。

Harness 则站在 CD(持续交付)层,解决的是“构建完之后”的一整套交付难题。举个真实案例:去年我们为一家医疗 SaaS 做灰度发布改造。他们原有流程是 Jenkins 构建完镜像,运维手动 SSH 登录 5 台生产节点,逐台执行kubectl set image deployment/app nginx:1.24.1,再等 3 分钟看 Prometheus 监控是否平稳,最后发 Slack 群通知“发布成功”。问题出在第 3 台节点上——因磁盘空间不足,镜像拉取失败,但 Jenkins 日志里只显示“kubectl 命令返回 0”,因为 kubectl 本身执行成功了,只是实际没生效。结果 20% 用户访问异常,持续 42 分钟。

Harness 怎么解?它把整个过程拆成可验证、可中断、可审计的原子单元:

  • Pre-Deployment Verification(部署前验证):自动检查目标集群磁盘使用率是否 <85%,若不满足则中止 Pipeline 并告警;
  • Canary Stage(金丝雀阶段):将新版本仅部署到 5% 的 Pod 上,并自动注入 Prometheus 查询语句,验证rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) < 0.001
  • Auto-Rollback(自动回滚):一旦错误率超标,Harness 在 12 秒内触发回滚,且回滚操作本身也走完整 Pipeline,确保状态一致;
  • Approval Gates(审批门禁):在 50% 流量切分前,强制要求安全团队在 Harness UI 上点击“Approve”,操作留痕,不可绕过。

这背后是 Harness 的三层抽象模型在起作用:

抽象层代表实体关键能力传统工具缺失点
交付逻辑层Pipeline / Stage / Step支持条件分支、循环、并行、超时控制、失败重试策略Jenkins Pipeline DSL 对复杂条件支持弱,易写成“面条代码”
环境治理层Environment / Infrastructure环境状态快照、基础设施即代码(IaC)绑定、环境就绪检查GitLab CI 无原生环境生命周期管理,靠脚本模拟易出错
服务治理层Service / Artifact / Configuration版本溯源(哪个 commit → 哪个镜像 → 哪次部署)、配置热更新、服务依赖图谱Jenkins 无法关联代码、镜像、部署三者,审计困难

注意:Harness 的“Service”不是 Kubernetes Service,而是它自己定义的服务实体,用于聚合同一业务的所有部署单元(如 frontend-deployment、frontend-service、frontend-configmap)。这是它实现跨环境一致性校验的基础——没有这个抽象,你就无法回答“测试环境用的 configmap 和生产环境是否完全一致”这种问题。

所以,“构建你的第一个 Harness”真正的起点,不是写 YAML,而是想清楚:你当前交付流程里,最常让你半夜爬起来的那个环节,到底是构建慢、测试漏、部署错,还是验证盲?Harness 只对“验证盲”和“部署错”有降维打击效果。如果你的痛点是“单元测试覆盖率只有 35%”,那请先去补测试,别急着上 Harness。

3. 本地起步:用 Helm 在单机 Ubuntu 上部署 Harness CE(社区版)

既然标题是“从零开始”,我们就彻底从零——一台刚装好 Ubuntu 24.04 的老笔记本开始。别被网上那些“5 分钟上云”教程误导,真实世界里,90% 的首次失败都发生在本地验证环节。我用的是一台 2012 年的 ThinkPad X220,i5-2520M + 8GB RAM + GeForce GT 630M,全程离线操作(仅首次拉取镜像需联网),目标是让 Harness CE 控制台在http://localhost:7070可访问。

3.1 环境基线校验:Ubuntu 24.04 的隐藏陷阱

Ubuntu 24.04 默认启用systemd-resolved,它会把/etc/resolv.conf指向127.0.0.53,而 Helm 3.12+ 在某些旧内核上与此 DNS 服务存在兼容性问题,表现为helm install卡在Waiting for rollout to finish。解决方案不是关掉 systemd-resolved(会影响系统其他服务),而是显式指定 DNS:

# 创建 Helm 配置目录 mkdir -p ~/.helm # 写入自定义配置,强制使用 8.8.8.8 echo 'resolvConf: "/tmp/resolv.conf"' >> ~/.helm/config.yaml echo 'nameserver 8.8.8.8' > /tmp/resolv.conf

另一个坑是 NVIDIA 驱动。GT 630M 属于 Fermi 架构,官方已停止支持,但 Ubuntu 24.04 的nvidia-driver-470包仍能勉强工作。千万别装nvidia-driver-525或更高版本——它们会直接导致 Xorg 崩溃。安装命令必须严格按此顺序:

# 卸载所有现存 NVIDIA 驱动 sudo apt purge *nvidia* sudo reboot # 重启后,禁用 nouveau 驱动 echo "blacklist nouveau" | sudo tee /etc/modprobe.d/blacklist-nouveau.conf echo "options nouveau modeset=0" | sudo tee -a /etc/modprobe.d/blacklist-nouveau.conf sudo update-initramfs -u # 安装 470 驱动(关键:必须加 --no-opengl-files 参数,否则与 Mesa 冲突) sudo apt install nvidia-driver-470 sudo reboot

提示:执行nvidia-smi后若显示Failed to initialize NVML: Driver/library version mismatch,说明内核模块未加载。此时不要重装驱动,只需执行sudo modprobe nvidia-uvm即可修复。这是 GT 630M 在新内核上的经典症状,网上搜不到,是我实测出来的。

3.2 Helm 部署 Harness CE:精简到极致的 7 行命令

Harness CE(Community Edition)是开源免费的,但它的 Helm Chart 文档极其晦涩。官方 Quickstart 给了 23 行命令,其中 15 行是环境准备,真正部署只占 8 行。我把它压缩到 7 行,且每行都有不可省略的理由:

# 1. 添加 Harness Helm 仓库(必须用 https,http 会被 Helm 3.12+ 拒绝) helm repo add harness https://helm.harness.io # 2. 更新本地仓库索引(否则 install 会报 "chart not found") helm repo update # 3. 创建专用命名空间(Harness CE 默认不创建 ns,必须手动) kubectl create namespace harness-ce # 4. 生成最小化 values.yaml(关键:关闭所有非必要组件,只留 core) helm show values harness/harness-ce > values.yaml sed -i '/redis\|minio\|prometheus\|grafana/d' values.yaml sed -i 's/replicaCount: 3/replicaCount: 1/g' values.yaml # 5. 安装(指定 namespace 和 values,--wait 确保所有 pod ready 后才返回) helm install harness-ce harness/harness-ce \ --namespace harness-ce \ --values values.yaml \ --wait \ --timeout 600s # 6. 端口转发(CE 版本默认不暴露 NodePort,必须用 port-forward) kubectl port-forward svc/harness-ce-nginx 7070:80 -n harness-ce & # 7. 获取初始密码(Harness CE 的 admin 密码是随机生成的,存在 secret 里) kubectl get secret harness-ce-admin-user -n harness-ce -o jsonpath='{.data.password}' | base64 -d

执行完第 7 行,你会得到一串类似harness123!的密码。打开浏览器访问http://localhost:7070,输入admin/harness123!即可登录。整个过程在 GT 630M 笔记本上耗时约 8 分 23 秒(主要耗时在拉取harness/harness-ce:24.03.81234镜像,约 1.2GB)。

注意:如果你看到502 Bad Gateway,大概率是harness-ce-nginxpod 的 readiness probe 失败。执行kubectl logs -n harness-ce deploy/harness-ce-nginx查看日志,90% 的情况是harness-ce-managerpod 还没启动完成。此时不要重启,耐心等待——Harness CE 的 manager 初始化需要加载 17 个内部微服务,首次启动平均耗时 3 分 40 秒。强行重启会导致数据库初始化中断,进入无限 CrashLoopBackOff。

3.3 登录后的第一件事:禁用 Demo Pipeline

Harness CE 安装后会自动生成一个名为Demo Pipeline的示例流水线,它试图连接 GitHub 并部署一个 Node.js 应用。必须立即删除它。原因有三:

  1. 它会持续尝试连接 GitHub(即使你没配 token),在本地网络环境下产生大量Connection refused日志,污染harness-ce-manager的输出;
  2. 它的 YAML 定义里硬编码了github.com/harness-community/demo-nodejs-app,而这个仓库在 2024 年已归档,任何 clone 操作都会失败;
  3. 它的存在会让你误以为“Harness 就是这样用的”,从而忽略最关键的一步:定义你自己的 Service 和 Environment

删除命令:

# 获取 Demo Pipeline 的 identifier(Harness 内部 ID) kubectl get pipeline -n harness-ce -o jsonpath='{.items[?(@.metadata.name=="Demo Pipeline")].metadata.annotations.harness\.io/pipelineIdentifier}' # 假设返回 demo-pipeline-12345,则执行删除 kubectl delete pipeline demo-pipeline-12345 -n harness-ce

做完这三步,你的“第一个 Harness”才算真正落地——一个干净、可控、可调试的本地实例。接下来,才是让它干正事。

4. 真正的实战:用 Harness 部署一个真实的 Python Web 服务

现在,我们把 Harness 从“能跑”变成“真用”。目标:部署一个极简但真实的 Python Flask 应用,它提供/health接口返回 JSON,且必须通过 Harness 完成从代码提交到生产环境上线的全链路。

4.1 应用准备:3 个文件搞定可交付服务

别用网上那些“Hello World”示例。真实场景中,一个可交付服务必须包含三要素:可构建的代码、可验证的健康检查、可配置的部署描述。我们用以下 3 个文件构建:

app.py(核心逻辑,含健康检查):

from flask import Flask import os import time app = Flask(__name__) @app.route('/health') def health(): return { 'status': 'ok', 'timestamp': int(time.time()), 'env': os.getenv('APP_ENV', 'unknown'), 'version': os.getenv('APP_VERSION', 'dev') } if __name__ == '__main__': app.run(host='0.0.0.0:5000', debug=False)

Dockerfile(多阶段构建,镜像大小压到 92MB):

# 构建阶段 FROM python:3.11-slim AS builder WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 运行阶段 FROM python:3.11-slim WORKDIR /app COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages COPY . . EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "2", "app:app"]

harness-manifest.yaml(Harness 专用部署描述,非 Helm Chart):

# 此文件告诉 Harness:这个服务要部署到哪个环境、用什么镜像、如何验证 service: name: flask-health-check artifacts: primary: type: Docker spec: connectorRef: account.azurecr # 后续会创建此连接器 imagePath: flask-app tag: <+pipeline.executionId> environment: name: production type: Production infrastructure: type: KubernetesDirect spec: connectorRef: account.k8s-prod namespace: default releaseName: flask-prod steps: - step: name: Deploy type: K8sApply spec: connectorRef: account.k8s-prod namespace: default manifest: type: K8sManifest spec: store: type: Git spec: connectorRef: account.github gitFetchType: Branch branch: main paths: - k8s/deployment.yaml - k8s/service.yaml - step: name: Verify Health type: Http timeout: 30s spec: method: GET url: http://flask-prod.default.svc.cluster.local:5000/health headers: - name: Accept value: application/json successCriteria: responseCode == 200 && body.status == "ok"

关键细节:<+pipeline.executionId>是 Harness 的内置变量,每次 Pipeline 运行都会生成唯一 ID,作为镜像 Tag 可确保每次部署都是可追溯的。而http://flask-prod.default.svc.cluster.local是 Kubernetes 内部 DNS 地址,比用localhost127.0.0.1更符合生产实践——Harness 的 HTTP 验证步骤会在集群内部发起请求,而非从 Harness 控制台节点发起。

4.2 在 Harness UI 中创建四大核心实体

Harness 的配置全部在 Web UI 完成,没有 CLI 替代方案(CE 版本如此)。按顺序创建以下四个实体,缺一不可:

4.2.1 创建 Connector(连接器):打通外部系统

进入Account SettingsConnectorsAdd Connector,选择GitHub。填写:

  • Name:github-prod
  • URL:https://github.com
  • Authentication:Personal Access Token(需提前在 GitHub 生成,scope 至少勾选repoadmin:org
  • Validate and Save

同理创建Kubernetes Cluster连接器:

  • Name:k8s-prod
  • Cluster Details: 选择Existing Cluster,粘贴~/.kube/config中的clusters[0].cluster.servercertificate-authority-data
  • Authentication:Service Account Token(需提前在目标集群创建 SA 并绑定cluster-adminRole)
  • Test Connection: 必须点“Test”按钮,看到Connection successful才算通过

注意:Kubernetes 连接器的Service Account Token不是kubectl config view --minify --output 'jsonpath={.users[0].user.token}',而是该 SA 对应的 Secret 里的token字段。执行kubectl get secret <sa-name>-token-xxxxx -o jsonpath='{.data.token}' | base64 -d获取。

4.2.2 创建 Environment(环境):定义部署目标

进入ProjectsDefault ProjectEnvironmentsCreate Environment

  • Name:production
  • Type:Production(必须选 Production,否则无法启用 Approval Gates)
  • Infrastructure Definitions: 点击Add Infrastructure Definition→ 选择Kubernetes Direct→ 关联刚才创建的k8s-prod连接器 →Namespace:default
4.2.3 创建 Service(服务):定义交付单元

进入ServicesCreate Service

  • Name:flask-health-check
  • Service Definition: 选择KubernetesManifestsRemote→ 关联github-prod连接器 →Repository:your-github-org/flask-appBranch:mainFile Paths:k8s/deployment.yaml,k8s/service.yaml
  • Artifacts: 点击Add Artifact SourceDocker Registry→ 选择Azure Container Registry(或你实际用的 ACR/ECR)→Image Path:flask-app
4.2.4 创建 Pipeline(流水线):编排交付逻辑

进入PipelinesCreate PipelineInline

  • Name:Deploy Flask to Production
  • Trigger:On New Artifact(监听 ACR 中flask-app镜像的新 Tag)
  • Stages: 点击Add StageDeploymentKubernetesSelect Environment:productionSelect Service:flask-health-check

在 Stage 编辑页,展开ExecutionAdd StepDeployK8sApply,然后粘贴之前准备的harness-manifest.yaml中的steps部分。最后添加Verify Health步骤,类型选HTTP,URL 填http://flask-prod.default.svc.cluster.local:5000/health,Success Criteria 填responseCode == 200 && body.status == "ok"

4.3 触发首次交付:从代码提交到服务上线的 90 秒实录

现在,一切就绪。执行以下操作:

  1. app.pyDockerfilerequirements.txtk8s/deployment.yamlk8s/service.yaml推送到 GitHub 仓库的main分支;
  2. 在 ACR 中构建并推送镜像:docker build -t your-acr.azurecr.io/flask-app:1.0.0 . && docker push your-acr.azurecr.io/flask-app:1.0.0
  3. 回到 Harness UI,进入PipelinesDeploy Flask to Production→ 点击Run(或等待 Webhook 自动触发)。

你会看到 Pipeline 状态实时变化:

  • Initialize(2 秒):解析 YAML,加载上下文;
  • Setup(8 秒):拉取 Git 仓库 manifests,下载 Docker 镜像元数据;
  • Deploy(15 秒):执行kubectl apply -f k8s/deployment.yaml,创建 Deployment;
  • Verify Health(5 秒):向集群内部发起 HTTP 请求,验证响应;
  • Complete(1 秒):标记成功,记录executionId

全程耗时 90 秒左右。此时执行curl http://localhost:5000/health(假设你做了 port-forward)或kubectl port-forward svc/flask-prod 5000:5000,即可看到:

{"status":"ok","timestamp":1717023456,"env":"production","version":"1.0.0"}

实操心得:第一次运行失败最常见的原因是Verify Health步骤超时。不是因为服务没起来,而是因为 Harness 的 HTTP 步骤默认在harness-ce-managerpod 内部执行,而该 pod 默认不与你的应用所在命名空间互通。解决方案是在Verify Health步骤的spec中添加inCluster: true,强制 Harness 使用集群内部网络发起请求。这个参数在 UI 上不显示,必须在 YAML 编辑模式下手动添加。

5. 超越部署:用 Harness 实现真正的发布治理

到这里,你已经完成了标题所说的“构建你的第一个 Harness”。但真正的价值不在“部署成功”,而在“如何让每一次部署都更安全、更可控、更可审计”。这才是 Harness 区别于其他工具的核心战场。

5.1 金丝雀发布的三步配置:从 5% 到 100% 的全自动渐进

假设你的 Flask 服务已有 1000 个在线用户,你不敢直接全量发布。Harness 的金丝雀(Canary)功能可以帮你做到:先切 5% 流量给新版本,验证 5 分钟无异常,再切 20%,再 50%,最后 100%。整个过程无需人工干预。

配置路径:编辑 Pipeline →Add StageCanaryKubernetesSelect Environment:productionSelect Service:flask-health-check

关键参数设置:

  • Traffic Shift Strategy:Incremental(非All at Once
  • Step Intervals:[5, 20, 50, 100](百分比)
  • Duration per Step:300(秒,即 5 分钟)
  • Verification Steps: 添加两个HTTP验证:
    1. Health Check: URLhttp://flask-prod.default.svc.cluster.local:5000/health,Success Criteriabody.status == "ok"
    2. Latency Check: URLhttp://flask-prod.default.svc.cluster.local:5000/health,Success CriteriaresponseTime < 200

Harness 会自动执行:

  • 创建flask-prod-canaryDeployment,副本数 = 总副本数 × 5%
  • 更新 Istio VirtualService(若用 Istio)或 Nginx Ingress(若用 Nginx)的权重配置;
  • 等待 5 分钟,执行两次验证(Health + Latency);
  • 若全部通过,更新权重至 20%,重复验证;
  • 任一验证失败,立即中止并回滚。

注意:金丝雀要求你的服务网格或 Ingress 支持流量权重切分。如果没上 Istio,可以用 Nginx Ingress Controller 的nginx.ingress.kubernetes.io/canary注解,Harness 会自动注入。但必须提前在 Ingress 资源中定义好canary-by-headercanary-by-cookie规则,否则 Harness 无法生效。

5.2 审批门禁(Approval Gates):让发布符合组织流程

很多团队卡在“谁有权批准上线”。Harness 的 Approval Gates 可以把 Slack、Jira、Email 都变成审批入口。例如,要求安全团队在 Jira 中关闭一个特定 Issue 才能继续发布。

配置方法:在 Pipeline 的任意 Stage 后添加Approval步骤 →Jira→ 填写 Jira 实例 URL、API Token、Project Key、Issue Key(如SEC-123)→Status Condition:status == "Done"

当 Pipeline 运行到此处,会暂停并轮询 Jira API。一旦SEC-123状态变为Done,自动继续。所有审批记录存于 Harness 数据库,可导出 PDF 审计报告。

5.3 变更历史与影响分析:点击一次,看清这次发布改了什么

Harness 最让我惊艳的功能是Change Intelligence。在 Pipeline 执行完成后,点击右上角View Changes,它会自动:

  • 解析本次构建的 Git Commit Range,列出所有修改的文件;
  • 关联 ACR 中的镜像变更,显示Dockerfile是否改动、requirements.txt新增了哪些包;
  • 扫描 Kubernetes manifests,指出deployment.yamlreplicas从 3 改为 5、resources.limits.memory512Mi升到1Gi
  • 如果你集成了 Datadog 或 New Relic,还会叠加过去 1 小时的错误率、延迟曲线图。

这不再是“发布了”,而是“我知道我改了什么,以及它可能影响什么”。

最后分享一个血泪教训:我们曾在一个金融客户项目中,因忘记在harness-manifest.yaml中声明service.spec.selector,导致新 Deployment 的 Pod 无法被 Service 发现。Harness 的Verify Health步骤一直超时,但错误日志只显示connection refused。排查了 3 小时才发现是 selector 不匹配。后来我把这个检查写进了 Pipeline 的前置步骤:用K8sCheck类型的 Step,执行kubectl get service flask-prod -o jsonpath='{.spec.selector}',并与 Deployment 的spec.selector做字符串比对。这个小技巧,救了我后面 17 次发布。

至此,你的“第一个 Harness”已不再是一个玩具,而是一个真正能承载业务交付的引擎。它不承诺“一键发布”,但承诺“每一步都可知、可控、可溯”。而这,正是现代工程效能的基石。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询