1. 项目概述:codecentric Helm Charts 是什么?

如果你正在 Kubernetes 上部署应用,并且已经厌倦了为每一个服务手动编写和维护那些冗长、复杂的 YAML 文件,那么 Helm 和 Helm Charts 绝对是你工具箱里不可或缺的利器。今天要聊的 codecentric/helm-charts ,就是一个由德国知名 IT 咨询公司 codecentric 维护的 Helm Chart 仓库。简单来说,你可以把它理解为一个经过精心打包和测试的“应用模板”超市,里面提供了像 Jenkins、Keycloak、MailHog 等一系列在云原生环境中非常流行的中间件和工具的标准化部署方案。

我最初接触这个仓库,是因为需要在多个不同的 K8s 集群上快速、一致地部署 Keycloak(一个开源的身份和访问管理解决方案)。自己从头写 Chart,不仅要定义 Deployment、Service、Ingress,还得考虑配置管理、持久化存储、高可用性,甚至版本升级路径,工作量巨大且容易出错。而 codecentric/helm-charts 提供的 keycloak Chart,几乎开箱即用,通过几个简单的配置项就能拉起一个生产可用的 Keycloak 集群,大大提升了效率。这个仓库的价值就在于,它凝聚了 codecentric 团队在大量客户项目中的实战经验,把最佳实践固化成了可复用的 Chart,让我们这些使用者可以直接站在“巨人”的肩膀上。

2. 核心组件与 Chart 选型解析

codecentric/helm-charts 仓库虽然不像官方的 bitnami 仓库那样包罗万象,但其精选的 Chart 在质量和易用性上往往有独到之处。我们结合关键词,重点剖析几个核心 Chart 的设计思路和适用场景。

2.1 Jenkins:不仅仅是 CI/CD 流水线引擎

Jenkins 作为老牌的自动化服务器,在 Kubernetes 环境下的部署有其特殊性。 codecentric 的 Jenkins Chart 没有简单地封装一个 Jenkins 实例,而是充分考虑了云原生下的动态伸缩和资源管理。

为什么选择这个 Chart?

  1. 基于官方镜像的深度定制 :它基于 Jenkins 官方 Docker 镜像构建,确保了核心功能的稳定性和兼容性。同时,它通过 initContainers sidecar 容器的设计,优雅地解决了插件预安装和配置初始化的问题。比如,你可以通过 master.installPlugins 列表在启动时自动安装所需插件,无需手动进入管理界面操作。
  2. 完整的持久化与高可用考量 :Chart 中详细定义了 PVC(PersistentVolumeClaim)模板,用于存储 Jenkins 的 JENKINS_HOME 数据。更重要的是,它提供了与 Jenkins Configuration as Code (JCasC) 插件集成的配置选项。这意味着你可以将 Jenkins 的全局配置、凭据、节点等全部用 YAML 文件定义,并存储在 Git 中,实现真正的不可变基础设施和版本化管理。
  3. Agent 的动态供应集成 :Chart 默认配置了 Kubernetes Cloud 插件,使得 Jenkins Master 可以动态地在同一个 K8s 集群中创建 Pod 作为构建代理(Agent)。这部分的配置(如 Pod 模板、资源限制、镜像等)都可以在 values.yaml 中灵活定义,实现了资源利用的最大化。

注意 :部署后,默认的 Jenkins 管理员密码是以 Secret 形式生成的。务必在首次登录后立即修改,或通过 master.adminPassword master.adminUser 配置项使用自定义的密码/用户。生产环境强烈建议启用 Ingress 并配置 TLS 证书。

2.2 Keycloak:身份管理的云原生实践

Keycloak Chart 是这个仓库的明星产品之一。部署一个功能完整的 Keycloak 集群涉及数据库、缓存、网络等多个组件,该 Chart 将其抽象得非常好。

设计亮点解析:

  1. 多模式部署支持 :它支持两种主要部署模式。一种是“嵌入式”模式,使用内置的 H2 数据库,适用于开发和测试,快速轻量。另一种是“生产”模式,可以配置外部的 PostgreSQL 或 MySQL 数据库,并支持数据库连接池、健康检查等高级配置。这种设计清晰地划分了环境边界。
  2. 高可用与缓存配置 :对于生产环境,Chart 可以配置多个 Keycloak 实例组成集群,并通过 extraEnv 注入 JGROUPS 配置实现实例间通信。缓存方面,它支持使用外部 Infinispan 集群或配置本地缓存,这对于大规模用户场景下的性能至关重要。这些高级特性通常需要深入理解 Keycloak 架构才能正确配置,而 Chart 提供了清晰的参数入口。
  3. 灵活的定制化入口 :除了标准的环境变量配置,Chart 提供了 extraInitContainers extraContainers (sidecar) 和 extraVolumes 等配置项。这意味着你可以在不修改 Chart 本身的前提下,轻松地添加自定义的初始化脚本、日志收集 sidecar(如 Fluent Bit)或挂载额外的配置文件,实现了“配置与 Chart 分离”的最佳实践。

2.3 MailHog:开发测试的邮件捕获神器

MailHog 是一个轻量级的邮件测试工具,它会捕获所有发送给它的 SMTP 邮件,并提供 Web UI 查看,而不会真正发送出去。在开发、测试或演示环境中,用它来替代真实的 SMTP 服务器非常方便。

codecentric 的 MailHog Chart 特点:

  1. 极简部署 :Chart 结构非常简单,一个 Deployment 和一个 Service,可能再加一个 Ingress。它的 values.yaml 文件也很简洁,主要配置 Web UI 端口、Ingress 规则等。这符合 MailHog 工具本身的定位——一个即用即抛的辅助服务。
  2. 资源友好 :默认的资源请求(CPU/Memory)设置得非常低,因为它本身不处理复杂逻辑。这提醒我们,在 K8s 中为每个服务设置合理的资源限制是良好习惯,即使对于小型工具也是如此。
  3. 与其他 Chart 的联动 :在微服务架构中,你的应用服务可能需要发送邮件(如注册确认、通知)。在开发环境,你可以通过 Helm 的依赖机制或简单的服务发现(DNS 名称 mailhog ),将应用服务的 SMTP 配置指向这个 MailHog 实例,从而安全地测试邮件发送功能。

2.4 通用 Chart 设计哲学

观察这几个 Chart,我们能总结出 codecentric/helm-charts 的一些通用设计原则:

  • 约定大于配置 :提供了合理的默认值( values.yaml ),让基础部署只需极简配置。
  • 生产就绪 :都考虑了持久化、健康检查(Readiness/Liveness Probe)、资源限制、Pod 反亲和性(避免单点故障)等生产级特性。
  • 可观测性 :通常集成了 Prometheus Metrics 导出(如果应用支持)和合理的日志输出配置。
  • 安全基线 :默认以非 root 用户运行容器,支持配置 Pod 安全上下文(Security Context)。

3. 实操:从添加仓库到部署完整应用栈

理论说了这么多,我们动手部署一个包含 Jenkins 和 MailHog 的简单环境,来看看实际流程和可能遇到的细节。

3.1 前期准备与仓库添加

首先,确保你有一个可用的 Kubernetes 集群(可以是 Minikube、Kind 本地集群,或云服务商的托管集群)并且 Helm 客户端已经安装。

# 1. 验证 Helm 版本(v3.x)
helm version

# 2. 添加 codecentric 的 Helm 仓库
helm repo add codecentric https://codecentric.github.io/helm-charts
helm repo update # 更新本地仓库缓存,获取最新 Chart 信息

# 3. 搜索我们感兴趣的 Chart
helm search repo codecentric

执行 helm search repo codecentric 后,你会看到类似下面的列表,包含了 Chart 名称、最新版本和应用版本。

NAME                            CHART VERSION   APP VERSION   DESCRIPTION
codecentric/jenkins             4.1.0           2.426.3      Jenkins - Build great things at any scale! Th...
codecentric/keycloak            22.0.0          22.0.0       Open Source Identity and Access Management Fo...
codecentric/mailhog             2.0.0           1.0.1        MailHog - Web and API based SMTP testing tool...

3.2 定制化安装 Jenkins

我们不想直接用默认配置安装,而是进行一些定制。最佳实践是创建一个自定义的 values 文件。

# my-jenkins-values.yaml
jenkins:
  master:
    # 启用 JCasC 配置
    JCasC:
      enabled: true
      configScripts:
        welcome-message: |
          jenkins:
            systemMessage: "欢迎使用由 Helm Chart 部署的 Jenkins!"
    # 预安装常用插件
    installPlugins:
      - kubernetes:3916.vdfa_a_7a_4a_42a
      - workflow-aggregator:596.v8c21c963d92d
      - git:5.0.1
      - configuration-as-code:1670.v564dc8b_982d0
    # 资源限制
    resources:
      requests:
        memory: "1Gi"
        cpu: "500m"
      limits:
        memory: "2Gi"
        cpu: "1000m"
    # 使用持久化存储
    persistence:
      enabled: true
      size: 10Gi
  # 配置 Kubernetes Cloud 用于动态创建 Agent
  agent:
    enabled: true
    podTemplates:
      jnlp:
        name: "jnlp"
        label: "jnlp-agent"
        containers:
          - name: jnlp
            image: jenkins/inbound-agent:latest
            resources:
              requests:
                memory: "256Mi"
                cpu: "200m"
              limits:
                memory: "512Mi"
                cpu: "500m"
# 配置 Ingress,以便通过域名访问
ingress:
  enabled: true
  hostName: jenkins.my-domain.local
  annotations:
    kubernetes.io/ingress.class: "nginx"

保存文件后,使用 helm install 命令进行安装。 -f 指定自定义 values 文件, -n 指定命名空间(建议为不同应用创建独立命名空间)。

# 创建命名空间(如果不存在)
kubectl create namespace ci-cd

# 安装 Jenkins
helm install my-jenkins codecentric/jenkins -f my-jenkins-values.yaml -n ci-cd

# 安装后,查看 Pod 状态和获取初始密码
kubectl get pods -n ci-cd -w # 使用 -w 观察启动过程
kubectl get svc -n ci-cd # 查看服务类型和端口

# 获取初始管理员密码(如果未在 values 中自定义)
kubectl exec -n ci-cd --namespace ci-cd svc/my-jenkins -c jenkins -- cat /run/secrets/chart-admin-password && echo

3.3 并行部署 MailHog 作为辅助服务

在另一个终端,我们快速部署 MailHog 到同一个或不同的命名空间。

# 创建一个开发测试用的命名空间
kubectl create namespace dev-tools

# 使用极简配置安装 MailHog
helm install my-mailhog codecentric/mailhog \
  --set ingress.enabled=true \
  --set ingress.hosts[0].host=mailhog.my-domain.local \
  --set ingress.hosts[0].paths[0].path=/ \
  --namespace dev-tools

这里我们使用了 --set 参数进行行内配置,对于简单的 Chart 这很便捷。安装后,访问 http://mailhog.my-domain.local 就能看到 MailHog 的 Web UI。

3.4 验证与连接测试

  1. 验证 Jenkins :等待所有 Pod 状态变为 Running READY 。通过 Ingress 域名 http://jenkins.my-domain.local 访问,用之前获取的密码登录。你应该能看到我们通过 JCasC 配置的欢迎信息。
  2. 验证 MailHog :访问其 Web UI,界面应该是空的,因为还没有邮件发送过来。
  3. 联动测试 :在 Jenkins 中创建一个简单的 Pipeline 任务,在脚本中添加一个发送邮件的步骤(使用 Jenkins 的 mail 插件或 sh 命令调用 curl 发送到 my-mailhog.dev-tools.svc.cluster.local:1025 )。执行任务后,刷新 MailHog 的 Web UI,应该能看到被捕获的邮件。这证明了服务间可以通过 K8s 内部 DNS ( <service-name>.<namespace>.svc.cluster.local ) 正常通信。

4. 高级配置与生产环境考量

对于生产环境,仅仅安装是远远不够的。我们需要关注安全性、可维护性和可靠性。

4.1 密钥与敏感信息管理

Chart 中通常需要数据库密码、管理员密码、API Token 等敏感信息。 绝对不要 将这些信息明文写在 values.yaml --set 命令中。

正确做法是使用 Kubernetes Secrets:

  1. 通过 helm install 传递 Secret :先创建 Secret,然后在 values 文件中引用。
    # 创建 Secret
    kubectl create secret generic my-db-secret -n production \
      --from-literal=postgres-password='YourSuperStrongPassword!'
    
    # 在 values 文件中引用
    # keycloak-values-prod.yaml
    postgresql:
      enabled: false # 使用外部数据库
    externalDatabase:
      host: "postgresql.production.svc.cluster.local"
      password:
        existingSecret: "my-db-secret"
        passwordKey: "postgres-password"
    
  2. 使用 Helm Secrets 或类似工具 :对于更复杂的场景,可以使用 helm-secrets (集成 sops vals )对包含敏感信息的 values 文件进行加密,并将其安全地存储在版本控制系统中。

4.2 持久化存储策略

生产环境的持久化存储需要仔细规划。

  • 存储类(StorageClass) :在 values.yaml 中,通常可以指定 persistence.storageClass 。你需要根据集群环境选择,例如 gp2 (AWS)、 standard (GCP) 或 rook-ceph-block (自建 Ceph)。
  • 访问模式与大小 :根据应用读写特性选择 ReadWriteOnce (RWO) 或 ReadWriteMany (RWX)。容量( size )要预留足够的增长空间,避免频繁扩容的麻烦。
  • 备份 :仅仅有持久化卷还不够,必须建立定期备份机制。可以利用 Velero 等工具对整个命名空间或特定 PVC 进行备份。

4.3 高可用与滚动更新配置

以 Keycloak 为例,实现高可用需要调整多个参数:

# keycloak-values-ha.yaml
replicas: 3 # 启动多个实例

affinity:
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - keycloak
        topologyKey: kubernetes.io/hostname # 尽量将 Pod 分散到不同节点

readinessProbe:
  path: /auth/realms/master # 使用一个轻量级端点做就绪检查
  initialDelaySeconds: 60
  periodSeconds: 10

livenessProbe:
  path: /auth/realms/master
  initialDelaySeconds: 180
  periodSeconds: 30

strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 1 # 滚动更新时,最多可以比期望副本数多出1个Pod
    maxUnavailable: 0 # 滚动更新时,最多允许0个Pod不可用(确保全时可用)

这些配置确保了服务在节点故障或版本升级时,能保持可用性和性能。

4.4 监控与日志集成

  1. 监控(Metrics) :许多 Chart(如 Keycloak)默认暴露了 Prometheus 格式的指标。你需要确保集群中部署了 Prometheus Operator 或类似方案,并正确配置 ServiceMonitor 或 PodMonitor 来抓取这些指标。
  2. 日志 :确保应用容器将日志输出到标准输出(stdout/stderr),这是 Kubernetes 的惯例。然后通过 DaemonSet 部署 Fluentd 或 Filebeat 等日志收集器,将日志转发到 Elasticsearch、Loki 或云服务商的日志服务中。在 Chart 的 values.yaml 中,通常可以通过 extraVolumes extraVolumeMounts 来挂载日志收集器需要的 sidecar 容器或配置文件。

5. 常见问题排查与运维心得

即使使用了成熟的 Chart,在实际运维中也会遇到各种问题。下面是一些典型场景和解决思路。

5.1 Pod 启动失败:CrashLoopBackOff

这是最常见的问题之一。Pod 反复启动后立即崩溃。

排查步骤:

  1. 查看 Pod 描述 kubectl describe pod <pod-name> -n <namespace> 。重点关注 Events 部分,看是否有镜像拉取失败、调度失败(资源不足、节点选择器不匹配)、或初始化容器失败的信息。
  2. 查看 Pod 日志 kubectl logs <pod-name> -n <namespace> --previous (如果当前容器没起来,查看上一次的日志)。对于多容器 Pod,用 -c <container-name> 指定容器。
  3. 常见原因
    • 配置错误 values.yaml 中某个配置项格式错误或值非法(如将字符串 "true" 写成了布尔值 true )。使用 helm template . helm install --dry-run --debug 命令可以渲染出最终的 Kubernetes 资源清单,便于检查。
    • 依赖服务未就绪 :例如,Keycloak Chart 如果使用内置的 PostgreSQL,但 PostgreSQL 的 Pod 因为存储问题没能启动,Keycloak 就会因连接不上数据库而崩溃。检查依赖服务的状态。
    • 权限问题 :容器以非 root 用户运行,但挂载的持久化卷目录没有写权限。在 values.yaml 中检查 securityContext 和持久化卷的挂载点。
    • 资源不足 :Pod 请求的资源(CPU/Memory)超过节点可用资源,或者超过了 LimitRange 的限制。

5.2 Helm 升级失败:如何回滚?

当你修改了 values.yaml 并执行 helm upgrade 后,发现应用异常。

安全操作流程:

# 1. 首先查看本次升级的发布历史
helm history my-jenkins -n ci-cd

# 2. 回滚到上一个稳定版本
helm rollback my-jenkins 1 -n ci-cd # 回滚到版本1

# 3. (如果回滚后仍不正常) 仔细对比 values 文件
# 可以使用 helm get values 获取当前配置
helm get values my-jenkins -n ci-cd -o yaml > current-values.yaml
# 与你的新 values 文件做对比

心得 :对于生产环境的重大变更,强烈建议先在预发布(Staging)环境进行 helm upgrade 测试。同时,利用 Helm 的 --atomic 参数,可以在升级失败时自动回滚。

5.3 Ingress 配置后无法访问

部署了 Ingress,但通过域名访问不到服务。

排查链条:

  1. 确认 Ingress 资源状态 kubectl get ingress -n <namespace> 。查看 ADDRESS 字段是否分配了 IP(云环境)或主机名。
  2. 检查 Ingress Controller :确保集群中已经安装了 Ingress Controller(如 Nginx Ingress Controller、Traefik),并且其 Pod 正在运行。 kubectl get pods -n ingress-nginx
  3. 检查 Ingress 规则 kubectl describe ingress <ingress-name> -n <namespace> 。检查规则是否正确地映射到了后端的 Service 和端口。
  4. 检查 Service 和 Endpoints kubectl get svc,ep -n <namespace> 。确保 Service 背后的 Pod 是 Ready 状态,并且 Endpoints 列表不为空。
  5. 本地 Hosts 或 DNS :在开发环境,你可能需要修改本地的 /etc/hosts 文件,将域名(如 jenkins.my-domain.local )指向 Ingress Controller 的 IP 地址(通常是 localhost 或 Minikube IP)。

5.4 自定义配置不生效

通过 extraEnv extraInitContainers 添加的配置似乎没起作用。

可能原因与解决:

  1. 配置项路径错误 :仔细阅读 Chart 的 values.yaml 默认文件或官方文档。 codecentric 的 Chart 通常有良好的注释。确保你添加的配置项在正确的层级下。例如,给 Keycloak 添加环境变量,应该是在 keycloak.extraEnv ,而不是顶层的 extraEnv
  2. 配置冲突 :你通过 extraEnv 设置的环境变量,可能被 Chart 中其他地方定义的默认值覆盖。检查渲染后的 Deployment 配置: kubectl get deployment <deploy-name> -n <namespace> -o yaml ,搜索你的环境变量名。
  3. 初始化顺序 extraInitContainers 会在主容器启动前运行。如果它失败了,主容器不会启动。检查 Init Container 的日志: kubectl logs <pod-name> -n <namespace> -c <init-container-name>

5.5 性能问题与调优

应用部署后运行缓慢。

排查方向:

  1. 资源瓶颈 :使用 kubectl top pods -n <namespace> 查看 Pod 的实际 CPU/内存使用量。对比 values.yaml 中设置的 resources.requests/limits 。如果使用量持续接近或超过 limits,会导致 Pod 被限流(Throttling)甚至被杀死(OOMKilled)。需要适当调高 limits。
  2. 持久化存储 I/O :如果应用是数据库或频繁读写磁盘的,存储性能可能是瓶颈。检查 PVC 使用的 StorageClass 的 IOPS/吞吐量规格。在云环境下,可以考虑升级到更高性能的磁盘类型。
  3. 应用本身配置 :Chart 的默认配置通常是中庸的。例如,Jenkins 的 JVM 堆内存参数( master.javaOpts )、Keycloak 的数据库连接池大小,都需要根据实际负载进行调整。这些参数通常在 values.yaml 中以 extraEnv 或特定配置项的形式提供。
  4. 网络延迟 :如果应用需要频繁访问集群外部的服务(如外部数据库、API),网络延迟可能成为问题。考虑将依赖服务也迁移到集群内,或使用服务网格(如 Istio)来优化连接池和重试策略。

经过这些步骤,你不仅能将 codecentric/helm-charts 用起来,更能理解其背后的设计,并具备排查和解决实际问题的能力。记住,好的工具能提升效率,但深入理解其原理和运维细节,才是保证系统长期稳定运行的关键。

更多推荐