深入理解Helm Charts:Kubernetes应用打包的艺术

深入理解Helm Charts:Kubernetes应用打包的艺术

【免费下载链接】helm Helm 是一个开源的 Kubernetes 包管理器,用于部署和管理 Kubernetes 应用程序。 * Kubernetes 包管理器、部署和管理 Kubernetes 应用程序 * 有什么特点:支持多种 Kubernetes 应用程序和库、易于使用、用于云原生应用程序的开发和管理 【免费下载链接】helm 项目地址: https://gitcode.com/GitHub_Trending/hel/helm

本文全面解析Helm Chart的核心结构与组件,深入探讨Chart.yaml元数据文件的配置规范,详细讲解Helm模板引擎与Go模板语法,并提供Values文件与参数化配置的最佳实践。文章系统性地介绍了Helm Chart的目录结构、核心组件功能、模板渲染流程以及多环境配置管理策略,为开发者创建高质量、可维护的Kubernetes应用包提供完整指导。

Helm Chart结构与组件详解

Helm Chart是Kubernetes应用程序的打包格式,它采用标准化的目录结构和配置文件来定义复杂的应用部署。一个完整的Helm Chart包含多个核心组件,每个组件都有其特定的作用和格式要求。

Chart目录结构

一个标准的Helm Chart包含以下目录和文件结构:

mychart/
├── Chart.yaml          # Chart元数据文件
├── values.yaml         # 默认配置值
├── charts/             # 依赖的子Chart目录
├── templates/          # 模板文件目录
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── _helpers.tpl    # 模板助手函数
│   └── tests/          # 测试文件目录
├── crds/               # 自定义资源定义
└── .helmignore         # 忽略文件模式

核心组件详解

1. Chart.yaml - 元数据定义

Chart.yaml是Chart的元数据文件,定义了Chart的基本信息和依赖关系:

apiVersion: v2
name: myapp
description: A Helm chart for Kubernetes
type: application
version: 1.2.3
appVersion: 2.1.0

dependencies:
  - name: postgresql
    version: "~10.0.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled

关键字段说明:

字段描述必需
apiVersionChart API版本(v1或v2)
nameChart名称
versionChart版本(遵循SemVer)
descriptionChart描述
typeChart类型(application或library)
appVersion应用程序版本
dependenciesChart依赖列表
2. values.yaml - 配置值管理

values.yaml文件定义了Chart的默认配置值,采用YAML格式:

replicaCount: 3

image:
  repository: nginx
  tag: "1.21.0"
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  className: "nginx"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: Prefix

配置值支持层级结构,可以通过模板中的.Values对象访问。

3. templates/ - 模板文件

templates目录包含Kubernetes清单文件的Go模板:

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "mychart.fullname" . }}
  labels:
    {{- include "mychart.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "mychart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "mychart.selectorLabels" . | nindent 8 }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}

模板语法支持变量替换、条件判断、循环等高级功能。

4. _helpers.tpl - 模板助手

_helpers.tpl文件包含可重用的模板函数:

{{/*
生成应用的完整名称
*/}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
通用标签定义
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
5. charts/ - 依赖管理

charts目录用于存放依赖的子Chart,支持两种方式:

  • 手动放置Chart压缩包(.tgz文件)
  • 通过helm dependency update自动下载

依赖关系在Chart.yaml中定义:

dependencies:
  - name: redis
    version: "16.0.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: redis.enabled
    tags:
      - database
      - cache
6. crds/ - 自定义资源定义

crds目录用于存放Custom Resource Definitions:

# crds/my-crd.yaml
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: myresources.example.com
spec:
  group: example.com
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              properties:
                size:
                  type: integer
                image:
                  type: string
  scope: Namespaced
  names:
    plural: myresources
    singular: myresource
    kind: MyResource
    shortNames:
    - mr

CRD文件会在安装Chart时首先被应用,确保自定义资源类型可用。

7. .helmignore - 文件排除

.helmignore文件用于指定在打包Chart时应忽略的文件模式:

# 忽略版本控制文件
.git/
.gitignore

# 忽略编辑器文件
*.swp
*.bak
.idea/

# 忽略日志文件
*.log

# 忽略临时文件
/temp/
/build/

Chart类型比较

Helm支持两种类型的Chart:

类型描述特点
Application应用Chart包含可部署的模板,可以独立运行
Library库Chart不包含模板,提供可重用的函数和定义

模板渲染流程

Helm Chart的模板渲染遵循以下流程:

mermaid

最佳实践

  1. 命名规范:Chart名称应使用小写字母、数字和连字符
  2. 版本管理:遵循语义化版本控制(SemVer)
  3. 值验证:使用values.schema.json进行配置值验证
  4. 模板组织:将相关资源组织在同一个模板文件中
  5. 依赖管理:明确指定依赖版本和条件

通过深入了解Helm Chart的结构和组件,开发者可以创建出更加健壮、可维护的Kubernetes应用包,实现真正的基础设施即代码。

Chart.yaml元数据文件配置指南

Chart.yaml是Helm Chart的核心配置文件,它定义了Chart的元数据信息、依赖关系以及各种配置选项。这个文件不仅提供了Chart的基本描述信息,还决定了Chart在Helm生态系统中的行为和兼容性。正确配置Chart.yaml对于创建高质量、可维护的Helm Chart至关重要。

基本结构解析

每个Chart.yaml文件都必须包含三个核心字段:apiVersionnameversion。这些字段构成了Chart的基本身份标识:

apiVersion: v2
name: my-awesome-chart
version: 1.2.3

apiVersion字段指定了Chart的API版本,目前主要支持v1和v2两个版本。v2版本引入了对依赖项的本地管理,取代了传统的requirements.yaml文件。选择正确的apiVersion至关重要,因为它决定了Chart的兼容性和功能特性。

必需字段详解

名称规范 (name)

Chart名称必须遵循特定的命名约定:

  • 只能包含小写字母、数字和连字符(-)
  • 必须以字母开头和结尾
  • 不能包含大写字母或下划线
  • 长度应保持简洁且具有描述性
name: nginx-ingress  # 正确
name: Nginx_Ingress  # 错误:包含大写字母和下划线
版本管理 (version)

版本号必须遵循语义化版本控制(SemVer 2.0)规范:

  • 格式:主版本号.次版本号.修订号 (MAJOR.MINOR.PATCH)
  • 可以包含预发布版本标识符:1.2.3-alpha.1
  • 必须大于0.0.0
version: "1.0.0"        # 稳定版本
version: "2.1.0-rc.1"   # 发布候选版本
version: "0.1.0"        # 初始开发版本

可选字段配置指南

应用版本 (appVersion)

appVersion字段用于指定Chart包装的应用程序版本,这与Chart本身的版本是分开的:

appVersion: "v1.23.0"

这个字段对于用户了解Chart中包含的应用程序版本非常有用,特别是在进行版本升级或故障排除时。

描述信息 (description)

提供清晰、简洁的Chart描述,帮助用户快速理解Chart的用途:

description: A Helm chart for deploying the NGINX Ingress Controller
关键字标签 (keywords)

使用关键字可以提高Chart在仓库中的可发现性:

keywords:
  - nginx
  - ingress
  - load-balancer
  - reverse-proxy
维护者信息 (maintainers)

维护者信息建立了Chart的责任链和联系渠道:

maintainers:
  - name: John Doe
    email: john.doe@example.com
    url: https://github.com/johndoe
  - name: Jane Smith
    email: jane.smith@example.com

依赖管理配置

在apiVersion v2中,依赖项直接在Chart.yaml中定义,这简化了依赖管理:

dependencies:
  - name: postgresql
    version: "12.1.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled
    tags:
      - database
    alias: db

依赖项配置选项:

  • condition: 基于值的条件表达式,控制依赖是否启用
  • tags: 标签组,用于批量启用/禁用相关依赖
  • alias: 为依赖项提供别名,避免命名冲突
  • import-values: 导入子Chart的值到父Chart

高级配置选项

类型指定 (type)

Chart可以是两种类型之一:

type: application    # 默认类型,用于部署应用程序
type: library       # 库Chart,包含可重用的模板片段
Kubernetes版本约束 (kubeVersion)

指定Chart所需的Kubernetes版本范围:

kubeVersion: ">=1.19.0-0"
注解信息 (annotations)

添加额外的元数据注解,供其他工具使用:

annotations:
  category: Infrastructure
  license: Apache-2.0
  supported-os: linux

验证和最佳实践

Helm提供了内置的lint工具来验证Chart.yaml的合法性:

helm lint ./mychart

最佳实践建议:

  1. 始终使用最新的apiVersion(v2)
  2. 遵循语义化版本控制规范
  3. 提供完整且准确的维护者信息
  4. 使用有意义的描述和关键字
  5. 明确指定Kubernetes版本要求
  6. 定期更新依赖项版本

配置示例模板

以下是一个完整的Chart.yaml配置示例,展示了所有重要字段的使用:

apiVersion: v2
name: web-application
description: A complete web application stack with frontend and database
version: 2.1.0
appVersion: "v3.4.2"
type: application
kubeVersion: ">=1.20.0-0"

home: https://github.com/myorg/web-app
sources:
  - https://github.com/myorg/web-app
icon: https://example.com/icon.png

keywords:
  - web
  - application
  - fullstack
  - database

maintainers:
  - name: Web Team
    email: web-team@example.com
    url: https://github.com/orgs/myorg/teams/web-team

dependencies:
  - name: nginx
    version: "1.0.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: nginx.enabled
  - name: postgresql
    version: "12.1.0"
    repository: "https://charts.bitnami.com/bitnami"
    condition: postgresql.enabled
    tags:
      - database

annotations:
  category: Web Application
  architecture: "microservices"
  required-cpu: "2"
  required-memory: "4Gi"

通过精心配置Chart.yaml文件,您可以创建出专业级、易于维护且用户友好的Helm Chart,为Kubernetes应用程序的部署和管理提供坚实的基础。

模板引擎与Go模板语法精讲

Helm的核心能力之一是其强大的模板引擎,它基于Go语言的text/template包构建,为Kubernetes资源配置提供了灵活的动态生成能力。理解Helm模板引擎的工作原理和Go模板语法,是掌握Helm高级用法的关键。

Helm模板引擎架构

Helm的模板引擎采用分层架构设计,将标准Go模板功能与Helm特有的扩展功能完美结合:

mermaid

核心模板语法详解

变量与值引用

Helm模板使用点号.来访问当前作用域的值,这是Go模板的基础语法:

# values.yaml
app:
  name: my-app
  replicas: 3
  image: nginx:1.20

# template.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.app.name }}-deployment
spec:
  replicas: {{ .Values.app.replicas }}
  template:
    spec:
      containers:
      - name: {{ .Values.app.name }}
        image: {{ .Values.app.image }}
控制结构

Helm模板支持完整的控制流语句,包括条件判断、循环和范围操作:

条件判断 (if/else)

{{- if .Values.app.enabled }}
apiVersion: apps/v1
kind: Deployment
{{- else }}
# Deployment disabled
{{- end }}

范围循环 (range)

{{- range .Values.app.containers }}
- name: {{ .name }}
  image: {{ .image }}
  {{- if .ports }}
  ports:
  {{- range .ports }}
  - containerPort: {{ . }}
  {{- end }}
  {{- end }}
{{- end }}
管道操作

管道操作符|允许将前一个操作的结果传递给下一个函数,这是函数式编程风格的体现:

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-config
data:
  config.json: |-
    {{- .Values.config | toJson | indent 4 }}
  app-name: {{ .Values.app.name | upper }}
  timestamp: {{ now | date "2006-01-02T15:04:05Z07:00" }}

Helm特有的模板函数

Helm在标准Go模板基础上扩展了多个专用函数,这些函数极大增强了模板的表达能力:

include函数

include函数允许在模板中嵌套其他已定义的命名模板:

# _helpers.tpl
{{- define "app.labels" -}}
app: {{ .Chart.Name }}
version: {{ .Chart.Version }}
release: {{ .Release.Name }}
{{- end -}}

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    {{- include "app.labels" . | nindent 4 }}
tpl函数

tpl函数用于动态解析和执行模板字符串,支持运行时模板生成:

# values.yaml
app:
  annotationTemplate: |
    deployed-by: {{ .Release.Name }}
    timestamp: {{ now | date "2006-01-02T15:04:05Z" }}

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    {{- tpl .Values.app.annotationTemplate . | nindent 4 }}
required函数

required函数用于强制要求某个值必须存在,否则渲染失败:

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-secret
stringData:
  password: {{ required "A password is required!" .Values.secrets.password }}

数据处理与转换函数

Helm集成了丰富的数据处理函数,主要来自Sprig函数库:

函数类别示例函数描述
字符串处理upper, lower, trim, replace字符串大小写转换和清理
数学运算add, sub, mul, div, mod基本数学计算操作
列表操作list, first, last, append, prepend列表创建和操作
字典操作dict, get, set, unset, hasKey字典数据管理
类型转换toString, toInt, toFloat, toBool数据类型转换
# 复杂数据处理示例
data:
  # 字符串处理
  normalized-name: {{ .Values.app.name | lower | replace "_" "-" }}
  
  # 数学计算
  calculated-replicas: {{ mul (.Values.app.replicas | default 1) 2 }}
  
  # 列表操作
  environment: |-
    {{- range $index, $item := .Values.app.env }}
    - name: {{ $item.name }}
      value: {{ $item.value | quote }}
    {{- end }}

模板调试与错误处理

Helm提供了完善的模板调试机制,帮助开发者快速定位问题:

严格模式 (Strict Mode)

# 启用严格模式,缺失值会导致渲染失败
engine := engine.Engine{Strict: true}

常见错误处理模式

# 使用default值避免空值错误
replicas: {{ .Values.replicas | default 1 }}

# 使用coalesce处理多个可能的空值
image: {{ coalesce .Values.image .Chart.AppVersion "latest" }}

# 使用fail函数自定义错误消息
{{- if not (hasKey .Values "database") }}
{{- fail "Database configuration is required" }}
{{- end }}

高级模板技巧

模板继承与组合

通过命名模板和块操作实现模板的继承和重写:

# _base.tpl
{{- define "base.deployment" -}}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Release.Name }}-deployment
spec:
  template:
    spec:
      containers:
      - name: {{ .Chart.Name }}
        {{- block "container.spec" . }}
        image: {{ .Values.image }}
        {{- end }}
{{- end -}}

# deployment.yaml
{{- template "base.deployment" . }}
{{- define "container.spec" }}
image: {{ .Values.image }}
resources:
  {{- toYaml .Values.resources | nindent 10 }}
{{- end }}
动态模板生成

利用Go模板的元编程能力生成动态内容:

# 动态生成环境变量
env:
{{- range $key, $value := .Values.config }}
- name: {{ $key | upper | replace "." "_" }}
  value: {{ $value | quote }}
{{- end }}

# 条件性包含配置片段
{{- if .Values.metrics.enabled }}
- name: METRICS_PORT
  value: "{{ .Values.metrics.port }}"
{{- end }}

Helm的模板引擎通过深度集成Go模板语法和丰富的扩展函数,为Kubernetes应用部署提供了强大的配置管理能力。掌握这些模板技术,能够显著提升Helm Chart的开发效率和应用部署的灵活性。

Values文件与参数化配置最佳实践

Helm的核心价值在于其强大的参数化配置能力,通过Values文件实现应用配置的灵活管理。Values文件是Helm Chart的配置中心,允许用户在不修改Chart模板的情况下定制化部署应用。

Values文件的多层级管理策略

Helm支持多层次的Values文件配置,遵循特定的优先级顺序:

mermaid

Values文件结构设计规范

良好的Values文件结构应该遵循以下原则:

# values.yaml 标准结构示例
global:
  # 全局配置,所有子Chart共享
  imageRegistry: "registry.example.com"
  storageClass: "standard"
  domain: "example.com"

# 主应用配置
app:
  replicaCount: 3
  image:
    repository: nginx
    tag: "1.21.0"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 80
  resources:
    requests:
      memory: "256Mi"
      cpu: "250m"
    limits:
      memory: "512Mi"
      cpu: "500m"

# 子Chart配置(如果存在)
subchart:
  enabled: true
  config:
    key: value

# 环境特定配置(通过不同values文件覆盖)
environment: "production"

参数化配置的最佳实践

1. 合理的默认值设置

为所有配置项提供合理的默认值,确保Chart在没有额外配置的情况下也能正常运行:

# 良好的默认值示例
database:
  enabled: true
  host: "localhost"
  port: 5432
  username: "appuser"
  password: ""  # 必须由用户提供
  sslMode: "prefer"
2. 类型安全的配置验证

利用Helm的Schema验证功能确保配置数据的正确性:

# values.schema.json 配置验证
{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "replicaCount": {
      "type": "integer",
      "minimum": 1,
      "maximum": 10
    },
    "image": {
      "type": "object",
      "properties": {
        "repository": {"type": "string"},
        "tag": {"type": "string", "pattern": "^[a-zA-Z0-9._-]+$"}
      },
      "required": ["repository", "tag"]
    }
  },
  "required": ["replicaCount", "image"]
}
3. 环境特定的配置管理

为不同环境创建专门的Values文件:

# 环境特定的values文件结构
charts/
├── myapp/
│   ├── values.yaml          # 基础配置
│   ├── values-dev.yaml      # 开发环境
│   ├── values-staging.yaml  # 预发布环境
│   └── values-prod.yaml     # 生产环境

各环境文件内容示例:

# values-dev.yaml - 开发环境
replicaCount: 1
resources:
  requests:
    cpu: "100m"
    memory: "128Mi"
  limits:
    cpu: "200m"
    memory: "256Mi"
debug: true

# values-prod.yaml - 生产环境
replicaCount: 3
resources:
  requests:
    cpu: "500m"
    memory: "512Mi"
  limits:
    cpu: "1000m"
    memory: "1Gi"
debug: false
monitoring:
  enabled: true

高级参数化技巧

1. 条件配置与功能开关

使用布尔值控制功能的启用和禁用:

# 功能开关配置
features:
  monitoring: true
  logging: true
  autoscaling: false
  ingress: true

# 模板中使用条件判断
{{- if .Values.features.monitoring }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ .Chart.Name }}
spec:
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
  endpoints:
  - port: web
{{- end }}
2. 配置继承与覆盖机制

利用Helm的合并策略实现配置的继承:

# 基础配置 (base-values.yaml)
app:
  config:
    timeout: 30
    retries: 3
    environment: production

# 环境特定覆盖 (env-override.yaml)
app:
  config:
    environment: development
    debug: true

# 最终合并结果
app:
  config:
    timeout: 30        # 从基础配置继承
    retries: 3         # 从基础配置继承
    environment: development  # 被覆盖
    debug: true        # 新增配置
3. 敏感数据的安全管理

对于敏感信息,使用Kubernetes Secret而不是明文存储:

# values.yaml - 只包含非敏感配置
database:
  host: "db.example.com"
  port: 5432
  name: "appdb"
  # 密码通过外部Secret提供

# 通过--set或外部文件提供敏感数据
helm install myapp . \
  --set database.password=$DB_PASSWORD \
  --set apiKey=$API_KEY

Values文件的组织与管理策略

1. 模块化配置结构

将大型配置分解为逻辑模块:

# 模块化values结构
networking:
  service:
    type: ClusterIP
    ports:
    - name: http
      port: 80
      targetPort: 8080
  ingress:
    enabled: true
    hosts:
    - host: app.example.com
      paths:
      - path: /
        pathType: Prefix

database:
  enabled: true
  type: postgresql
  connection:
    poolSize: 10
    timeout: 30s

cache:
  enabled: true
  type: redis
  size: 1Gi
2. 配置版本控制与变更管理

为Values文件实现版本控制和变更跟踪:

# 包含元数据的values文件
_metadata:
  version: "1.2.0"
  lastUpdated: "2024-01-15"
  changelog:
    - version: "1.2.0"
      changes:
        - "Added support for Redis clustering"
        - "Updated resource limits"
    - version: "1.1.0"
      changes:
        - "Added monitoring configuration"

# 应用配置
app:
  version: "v2.1.0"
  config: ...

性能优化与最佳实践

1. 避免过度参数化

只在必要的地方使用参数化,保持模板的可读性:

# 适当的参数化
app:
  # 这些应该参数化(可能经常变化)
  replicaCount: 3
  imageTag: "latest"
  environment: "production"
  
  # 这些可能不需要参数化(相对固定)
  livenessProbe:
    path: /healthz
    port: 8080
    initialDelaySeconds: 30
2. 配置验证与错误处理

在模板中添加配置验证:

# 模板中的配置验证
{{- if not .Values.database.password }}
{{- fail "Database password is required. Please set database.password value" }}
{{- end }}

{{- if and .Values.ingress.enabled (not .Values.ingress.host) }}
{{- fail "Ingress host is required when ingress is enabled" }}
{{- end }}

通过遵循这些Values文件与参数化配置的最佳实践,您可以创建出既灵活又可靠的Helm Chart,实现真正的"配置即代码"理念,确保应用在不同环境中的一致性和可维护性。

总结

通过本文的深入探讨,我们可以看到Helm Charts作为Kubernetes应用打包的标准解决方案,提供了强大的参数化配置能力和灵活的模板引擎。从Chart的基础结构到高级的模板技巧,从简单的值文件管理到复杂的环境配置策略,Helm为云原生应用部署提供了完整的工具链。掌握Helm Chart的开发最佳实践,不仅能够提升应用部署的效率和可靠性,还能实现真正的基础设施即代码,为现代化云原生应用的持续交付奠定坚实基础。

【免费下载链接】helm Helm 是一个开源的 Kubernetes 包管理器,用于部署和管理 Kubernetes 应用程序。 * Kubernetes 包管理器、部署和管理 Kubernetes 应用程序 * 有什么特点:支持多种 Kubernetes 应用程序和库、易于使用、用于云原生应用程序的开发和管理 【免费下载链接】helm 项目地址: https://gitcode.com/GitHub_Trending/hel/helm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值