Harness CI/CD 平台实战:从声明式部署到智能化交付的工程实践
在实际企业级软件交付和 DevOps 实践中持续集成与持续部署CI/CD的复杂性常常是团队效率的瓶颈。配置繁琐、环境差异、部署失败后的回滚困难等问题使得从代码提交到生产上线的路径充满不确定性。Harness 作为一款现代化的软件交付平台其核心价值在于通过智能化和自动化的手段将 CI/CD 的复杂性封装起来让开发者能够更专注于业务逻辑本身。然而Harness 本身作为一个功能丰富的平台其概念体系、配置逻辑和底层工作流对于初次接触者而言同样存在一定的学习门槛。很多人尝试后可能只停留在“点按钮触发部署”的层面对其背后的工程逻辑、策略模型以及如何与现有基础设施深度集成知之甚少这导致在遇到复杂场景或需要定制化时无从下手。本文旨在系统性地拆解 Harness 的工程底层逻辑与核心能力。我们将从一个具体的实战场景出发不仅介绍如何配置一个基础的流水线更会深入探讨其设计哲学、关键组件的工作机制以及如何通过代码如 Harness YAML来定义和管理复杂的交付流程。目标是让你理解 Harness 如何将部署抽象为可预测、可验证、可回滚的工程实践从而在真实项目中少走弯路构建出健壮、高效的软件交付体系。1. 理解 Harness 的核心设计哲学一切皆代码与智能自动化在开始动手配置之前理解 Harness 的设计理念至关重要。这决定了你将以何种方式使用它以及如何发挥其最大价值。1.1 从“脚本化”到“声明式”与“智能化”的转变传统的 CI/CD 工具如 Jenkins大多基于脚本Groovy, Shell驱动。这种方式灵活但将大量逻辑和判断如环境差异、部署策略、回滚条件硬编码在脚本中导致流水线脆弱、难以维护和复用。Harness 倡导的是声明式Declarative和策略驱动Policy-driven的模型。声明式配置你通过 YAML 或 UI 定义“期望的状态”例如将服务部署到生产环境并执行金丝雀发布而不是编写“如何达到该状态”的每一步命令。Harness 引擎负责解析你的声明并自动生成和执行必要的步骤。策略驱动部署策略如蓝绿、金丝雀、故障条件、审批流程等都被抽象为独立的策略实体。你可以将这些策略像积木一样应用到不同的服务和环境中实现关注点分离和高度复用。更重要的是Harness 引入了智能化Intelligence层。它通过持续验证Continuous Verification功能在部署后自动分析应用和基础设施的指标来自监控工具如 Prometheus、Datadog、日志和跟踪数据判断部署是否成功。如果检测到异常它可以自动触发回滚将人为判断和干预的滞后性降到最低。1.2 Harness 的核心抽象服务、环境、基础设施与工作流Harness 将软件交付过程抽象为几个核心概念理解它们之间的关系是构建一切的基础。服务Service这是你要部署的软件单元。在 Harness 中一个服务定义了“什么”将被部署。它包含服务定义名称、标识符。制品来源Docker 镜像来自 Docker Hub、ECR、GCR 等、Helm Chart、Kubernetes 清单文件、Terraform 模块等。Harness 并不关心你的构建过程它关注的是如何部署一个已知版本的制品。配置对于容器化应用这主要指 Kubernetes 的 Deployment/Service YAML 清单或 Helm Chart 的 values 文件。Harness 允许你使用“配置覆盖”来为不同环境如测试、生产定制这些配置。环境Environment指部署的目标位置如“开发”、“QA”、“预发布”、“生产”。环境是一个逻辑分组它关联着具体的基础设施定义和部署策略。基础设施定义Infrastructure Definition这是环境的具体化。它定义了在目标环境中“在哪里”运行服务。对于 Kubernetes这可能是一个具体的集群通过连接器 Connector 配置和命名空间Namespace。一个环境如“生产”下可以有多个基础设施定义例如“生产-集群A”、“生产-集群B”。执行Execution这是 Harness 中承载部署流程的核心实体。在早期版本中称为“工作流Workflow”现在更普遍的概念是流水线Pipeline。一个流水线由一系列阶段Stage组成每个阶段又包含一系列步骤Step。步骤是原子操作如“获取制品”、“运行 Shell 脚本”、“部署”、“人工审批”、“发送通知”等。这些概念的关系可以概括为流水线将某个服务的特定版本通过指定的部署策略部署到目标环境的基础设施上。2. 环境准备与 Harness 平台配置在编写任何代码或 YAML 之前我们需要准备好 Harness 平台和外部依赖。本节将引导你完成初始设置。2.1 创建 Harness 账户与组织/项目结构注册与登录访问 Harness 官网注册一个账户。Harness 提供免费社区版CE功能对于学习和中小型项目足够。理解层级结构Harness 采用Account - Organization - Project的层级结构来管理资源和权限。账户Account顶级实体通常对应你的公司或团队。组织Organization用于在账户内对项目进行逻辑分组如按业务线、部门。项目Project实际开展工作的地方。服务、环境、连接器、流水线等资源都创建在项目内。初始设置建议对于学习你可以在账户下创建一个组织例如Learning然后在该组织下创建一个项目例如FirstPipeline。2.2 配置连接器Connector打通外部系统连接器是 Harness 与外部系统如代码仓库、镜像仓库、云平台、监控工具通信的桥梁。这是配置中最关键的一环。我们将配置两个最常用的连接器1. Docker Registry 连接器用于拉取镜像假设我们使用 Docker Hub 的公共镜像或私有仓库。连接器类型选择Docker Registry。提供商选择Docker Hub。认证方式对于公共镜像选择Anonymous。对于私有镜像选择Username and Password并填写你的 Docker Hub 用户名和访问令牌建议使用 Access Token 而非密码。测试连接配置完成后务必点击“Test”验证连接是否成功。2. Kubernetes 集群连接器用于部署目标假设我们有一个可访问的 Kubernetes 集群可以是 Minikube、Kind 本地集群或云上的 EKS/GKE/AKS。连接器类型选择Kubernetes Cluster。认证方式根据你的集群类型选择。对于学习Master URL和Service Account Token是最直接的方式。Master URL通过kubectl cluster-info命令获取。Service Account Token在目标集群中创建一个具有足够权限的 ServiceAccount并获取其 Token。# 创建命名空间和 ServiceAccount kubectl create namespace harness-deploy kubectl create serviceaccount harness-deploy-sa -n harness-deploy # 绑定集群管理员角色仅用于学习生产环境需按需授权 kubectl create clusterrolebinding harness-deploy-sa-admin \ --clusterrolecluster-admin \ --serviceaccountharness-deploy:harness-deploy-sa # 获取 Token kubectl get secret $(kubectl get serviceaccount harness-deploy-sa -n harness-deploy -o jsonpath{.secrets[0].name}) -n harness-deploy -o jsonpath{.data.token} | base64 --decode将获取的 Token 粘贴到 Harness 连接器配置中。测试连接保存前进行测试确保 Harness 可以连接到你的集群。2.3 定义部署目标环境与基础设施在项目中我们开始定义部署的“目的地”。创建环境在Project-Environments下点击New Environment。名称dev类型Non-Production(用于开发、测试环境)。在环境中创建基础设施定义进入刚创建的dev环境点击Infrastructure Definitions-Add Infrastructure Definition。名称dev-k8s-cluster部署类型Kubernetes连接器选择上一步创建的 Kubernetes 集群连接器。命名空间输入harness-deploy即我们之前创建的命名空间。你也可以使用表达式如infra.namespace在运行时动态指定。至此Harness 平台的基础配置完成。它现在知道了从哪里获取镜像Docker Hub以及部署到哪里你的 Kubernetes 集群的指定命名空间。3. 构建第一个声明式部署流水线从 YAML 开始虽然 Harness UI 非常直观但“一切皆代码”的理念鼓励我们使用 YAML 来定义和管理流水线。这种方式便于版本控制、代码审查和批量管理。我们将创建一个最简单的流水线部署一个 Nginx 镜像到开发环境。3.1 流水线 YAML 结构概览一个基本的 Harness 流水线 YAML 包含以下顶层字段pipeline: name: Deploy Nginx to Dev identifier: deploy_nginx_to_dev projectIdentifier: FirstPipeline orgIdentifier: Learning tags: {} stages: - stage: name: Deploy identifier: Deploy description: type: Deployment spec: ... # 阶段详细配置 tags: {}3.2 定义部署阶段Deployment Stage部署阶段是核心它需要关联服务、环境和执行策略。spec: serviceConfig: serviceRef: nginx_service # 引用之前创建的服务标识符 serviceDefinition: type: Kubernetes spec: artifacts: primary: primaryArtifactRef: input # 允许运行时选择镜像标签 sources: - spec: connectorRef: account.dockerhub_connector # 你的Docker连接器标识符 imagePath: library/nginx tag: input # 运行时输入的镜像标签如 latest, 1.21 identifier: nginx_image type: DockerRegistry infrastructure: environmentRef: dev # 引用之前创建的环境标识符 infrastructureDefinition: type: KubernetesDirect spec: connectorRef: account.k8s_cluster_connector # 你的K8s连接器标识符 namespace: harness-deploy releaseName: release-INFRA_KEY allowSimultaneousDeployments: false execution: steps: - step: type: K8sRollingDeploy name: Rollout Deployment identifier: rolloutDeployment spec: skipDryRun: false pruningEnabled: false rollbackSteps: - step: type: K8sRollingRollback name: Rollback Deployment identifier: rollbackDeployment spec: pruningEnabled: false关键点解释serviceRef: 这里我们假设你已通过 UI 或 YAML 创建了一个名为nginx_service的服务。服务的 YAML 定义会包含更详细的 Kubernetes 清单。input: 这是 Harness 的运行时表达式。input表示在执行流水线时会弹出输入框让用户填写具体的镜像标签。这提供了灵活性。execution.steps: 这里只定义了一个K8sRollingDeploy步骤这是 Harness 为 Kubernetes 滚动更新提供的内置步骤。它会执行kubectl apply并等待 Pod 就绪。rollbackSteps: 定义了如果部署失败或后续验证失败自动执行的回滚步骤。K8sRollingRollback会自动回滚到上一个成功的版本。3.3 创建服务定义 YAML服务定义可以独立于流水线。一个基本的 Kubernetes 服务定义如下service: name: nginx_service identifier: nginx_service serviceDefinition: type: Kubernetes spec: variables: [] artifacts: primary: primaryArtifactRef: nginx_image sources: - spec: connectorRef: account.dockerhub_connector imagePath: library/nginx tag: input identifier: nginx_image type: DockerRegistry manifests: - manifest: identifier: nginx_manifest type: K8sManifest spec: store: type: Harness spec: files: - /templates/deployment.yaml # 指向存储库中的K8s清单文件 valuesPaths: [] skipResourceVersioning: false这里的关键是manifests部分。它指向了一个存储在 Harness 文件存储或 Git 仓库中的 Kubernetes Deployment YAML 文件。例如/templates/deployment.yaml的内容可能是apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: infra.namespace spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: artifact.image # Harness 表达式会被替换为实际镜像地址 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: nginx-service namespace: infra.namespace spec: selector: app: nginx ports: - protocol: TCP port: 80 targetPort: 80 type: ClusterIP表达式说明infra.namespace: 运行时会被替换为基础设施定义中指定的命名空间harness-deploy。artifact.image: 运行时会被替换为流水线执行时选定的完整镜像地址如library/nginx:1.21。3.4 运行与验证流水线创建流水线在 Harness UI 的Pipelines页面点击Create a Pipeline选择YAML方式将完整的流水线 YAML 粘贴进去并保存。执行流水线点击Run。系统会提示你为tag输入一个值例如latest或1.21。观察执行过程Harness 会展示一个可视化的执行图。你可以看到它执行了“Rollout Deployment”步骤。验证部署在 Harness 执行结果中查看输出。使用kubectl命令在本地验证kubectl get pods -n harness-deploy kubectl get svc -n harness-deploy你应该能看到 Nginx 的 Pod 正在运行并且服务已创建。4. 深入核心能力策略、变量与高级步骤掌握了基础部署后我们来探索 Harness 如何通过高级功能应对复杂场景。4.1 部署策略蓝绿与金丝雀发布Harness 将部署策略抽象为“执行策略”在部署阶段中配置。以下是一个金丝雀发布Canary的配置示例片段execution: steps: - step: type: K8sCanaryDeploy name: Canary Deployment identifier: canaryDeploy spec: instanceSelection: type: Count spec: count: 1 # 第一期先部署1个Pod实例 skipDryRun: false - step: type: K8sCanaryDelete name: Delete Canary identifier: deleteCanary spec: skipDryRun: false when: stageStatus: Success # 仅在成功后删除金丝雀负载金丝雀发布流程先部署一小部分流量如 1 个 Pod作为“金丝雀”经过人工验证或自动分析后再全量部署并删除金丝雀负载。K8sCanaryDeploy和K8sCanaryDelete步骤协同工作实现了这一流程。4.2 变量与表达式实现动态配置Harness 表达式...是其动态性的核心。它们可以在运行时被解析和替换。内置变量pipeline.sequenceId: 流水线执行序列号。stage.name: 当前阶段名称。service.name: 服务名称。env.name: 环境名称。引用其他实体的输出steps.[step_id].output.[output_variable]: 引用某个步骤的输出。在配置中覆盖值在服务定义或环境配置中你可以使用变量来使配置环境差异化。例如在环境dev中设置一个变量replicaCount: 2在prod中设置为5。然后在 Deployment YAML 中使用env.variables.replicaCount来引用它。4.3 条件执行、循环与人工干预流水线步骤支持丰富的控制逻辑。条件执行when如上例金丝雀删除步骤中的when: stageStatus: Success可以基于上一步状态、变量值等条件决定是否执行。- step: type: ShellScript name: Notify on Failure identifier: notifyOnFailure spec: ... when: stageStatus: Failure # 仅在阶段失败时执行人工审批Harness Approval在关键部署如生产环境前加入人工审批步骤。- step: type: HarnessApproval name: Production Approval identifier: productionApproval spec: approvalMessage: Please approve deployment to production includePipelineExecutionHistory: true approvers: userGroups: - account._account_all_users # 审批用户组需提前配置 minimumCount: 1 disallowPipelineExecutor: false5. 常见问题排查与调试指南即使配置正确在实际运行中也可能遇到问题。以下是基于 Harness 特性的排查路径。5.1 部署失败通用排查清单问题现象可能原因检查点与命令解决方案连接器测试失败凭证错误、网络不通、权限不足1. 在 Harness UI 中重新测试连接器。2. 检查网络策略如防火墙。3. 对于 K8s用kubectl手动测试 Token 和 URL。修正凭证、开通网络、调整 RBAC 权限。流水线启动时“Input Required”报错必需的运行时输入input未提供或引用变量不存在。检查流水线 YAML 中所有input和变量引用。确保服务、环境等引用标识符正确。在执行时提供所有必需输入或为变量设置默认值。“ImagePullBackOff” 错误镜像拉取失败。镜像不存在、标签错误、私有仓库无权限。1. 查看 Harness 部署步骤日志。2. 用kubectl describe pod pod-name查看 Pod 事件。3. 手动docker pull测试镜像。检查镜像路径和标签确保 Docker 连接器有拉取权限。“CrashLoopBackOff” 错误容器启动后立即退出。应用本身配置错误如启动命令、环境变量、依赖。1.kubectl logs pod-name --previous查看上次崩溃日志。2. 检查应用配置和 Harness 服务配置中的覆盖项。修正应用配置在本地或测试环境先验证容器能独立运行。部署步骤卡住或超时资源不足CPU/内存、就绪探针Readiness Probe未通过、目标实例数未达到。1. 查看 Harness 步骤日志通常会有等待 Pod 就绪的提示。2.kubectl get pods查看 Pod 状态。3.kubectl describe deployment查看事件。调整资源请求/限制检查并修正就绪探针配置或调整超时时间。回滚未自动触发回滚步骤配置错误、部署步骤未标记为“失败”、连续验证未启用或配置不当。1. 检查流水线 YAML 中rollbackSteps配置。2. 检查部署阶段的“失败策略”。3. 确认连续验证CV配置并检查其日志。确保回滚步骤正确关联配置失败策略为“在阶段失败后执行”正确设置 CV。5.2 日志与调试技巧Harness 执行日志这是第一现场。在流水线执行详情页面点击每个步骤可以展开查看详细日志。日志会显示 Harness 执行引擎发出的命令如kubectl apply及其输出。Kubernetes 集群日志当 Harness 步骤显示成功但应用行为异常时需要查看集群内资源状态。# 查看 Pod 状态和事件 kubectl get pods -n namespace -o wide kubectl describe pod pod-name -n namespace # 查看 Pod 日志 kubectl logs pod-name -n namespace kubectl logs pod-name -n namespace --previous # 查看上次崩溃日志 # 查看 Deployment 状态 kubectl describe deployment deployment-name -n namespace启用 Debug 模式在某些 Shell 脚本步骤或复杂场景下可以在步骤配置中启用“调试模式”来输出更详细的信息。检查表达式解析不确定表达式...是否被正确解析可以在步骤中插入一个Shell Script步骤使用echo命令打印出变量值。- step: type: ShellScript name: Debug Variables identifier: debugVariables spec: shell: Bash onDelegate: true source: type: Inline spec: script: | echo Image Path: artifact.image echo Namespace: infra.namespace echo Pipeline ID: pipeline.sequenceId environmentVariables: [] outputVariables: []6. 从学习到生产最佳实践与扩展方向将 Harness 用于个人学习与用于支撑企业生产环境关注点有显著不同。以下是一些关键的最佳实践。6.1 基础设施即代码与 Git 集成将所有配置 YAML 存入 Git服务、环境、连接器敏感信息除外、流水线、模板等所有 Harness 实体的 YAML 定义都应存储在 Git 仓库中。这提供了版本历史、审计追踪和协作基础。使用 Harness Git Experience在项目设置中启用 Git 同步可以将 Harness 实体直接与 Git 仓库分支关联。任何在 Harness UI 上的更改都会生成提交反之亦然。敏感信息管理永远不要将密码、令牌、密钥等硬编码在 YAML 或脚本中。使用 Harness 的机密Secrets管理功能。在 YAML 中通过表达式secrets.getValue(secret_identifier)引用机密。6.2 模块化与复用模板与管道库步骤模板Step Templates将常用的、复杂的步骤逻辑如一个自定义的数据库迁移脚本封装成模板。可以在多个流水线中复用统一维护。阶段模板Stage Templates将一整套部署阶段如标准的 K8s 蓝绿发布流程封装成模板。适用于跨项目标准化部署流程。管道库Pipeline Library在组织级别创建可复用的流水线片段或完整流水线供所有项目引用。6.3 安全与治理基于角色的访问控制RBAC精细配置用户和用户组在项目、环境、服务等资源上的权限查看、执行、编辑等。遵循最小权限原则。资源限制在服务定义的 Kubernetes 清单中务必为容器设置resources.requests和resources.limits防止单个应用耗尽集群资源。部署策略审批为生产环境部署配置强制的人工审批步骤并可能结合聊天工具如 Slack、MS Teams通知。6.4 监控与可观测性集成连续验证Continuous Verification这是 Harness 的智能化核心。将其与你的 APMApplication Performance Monitoring工具如 New Relic, AppDynamics或监控系统如 Prometheus集成。配置验证指标如错误率、响应时间、CPU 使用率让 Harness 在部署后自动判断成功与否并决定是否回滚。通知集成将流水线成功、失败、需要审批等事件发送到团队沟通渠道。6.5 扩展方向多云/混合云部署Harness 可以统一管理部署到不同云提供商AWS, GCP, Azure或私有数据中心的 Kubernetes 集群。通过配置不同的基础设施定义和连接器即可实现。自定义步骤开发如果 Harness 内置步骤无法满足需求你可以使用 Harness SDK 开发自定义步骤Custom Step封装特定的业务逻辑或工具调用。特性标志Feature Flags与 Harness 的特性标志模块集成实现更细粒度的发布控制和渐进式交付。Harness 的强大之处在于它将软件交付中的最佳实践如不可变基础设施、声明式配置、渐进式交付、自动化验证产品化、流程化。开始时应聚焦于核心概念和基础流水线的搭建确保能够可靠地完成从代码到部署的闭环。随着对平台理解的深入再逐步引入策略、模板、GitOps、连续验证等高级功能最终构建出一个完全自动化、智能化且受控的软件交付平台。避免一开始就追求复杂配置从一个小而确定的部署开始验证每个环节积累的实践经验将是你应对更复杂场景最可靠的依据。