使用helm创建属于自己的chart
作为一名运维工作者,学习 Helm 是管理 Kubernetes 应用的关键一步。下面我将为你详细讲解如何使用 helm create 创建自己的 Chart,并逐步将其完善以应用到生产环境中。
⚙️ 理解 Helm Chart 基础
Helm Chart 就像 Kubernetes 应用的“安装包”,它包含了一组预配置的 Kubernetes 资源定义(如 Deployment、Service 等)。使用 Helm 可以让你轻松地打包、配置、部署和管理这些应用。
一个典型的 Helm Chart 目录结构如下所示(以名为 mychart 的 Chart 为例):
mychart/
├── charts/ # 存放其他依赖的 Chart(子 Chart)
├── templates/ # 模板文件目录
│ ├── deployment.yaml # 应用部署模板
│ ├── service.yaml # 服务模板
│ └── NOTES.txt # 安装后提示信息
├── Chart.yaml # Chart 元数据文件
├── values.yaml # 默认配置值文件
└── .helmignore # 忽略文件列表(类似 .gitignore)
🛠️ 第一步:创建 Helm Chart
-
使用
helm create搭建脚手架
打开终端,执行以下命令来创建一个名为myapp的 Chart:$ helm create myapp这个命令会生成一个包含基本目录结构和示例文件的 Chart
$ tree myapp/ myapp/ ├── charts ├── Chart.yaml ├── templates │ ├── deployment.yaml │ ├── _helpers.tpl │ ├── hpa.yaml │ ├── ingress.yaml │ ├── NOTES.txt │ ├── serviceaccount.yaml │ ├── service.yaml │ └── tests │ └── test-connection.yaml └── values.yaml 3 directories, 10 files -
解读生成的文件
创建完成后,你需要了解几个核心文件的作用:Chart.yaml:描述 Chart 的基本信息,如名称、版本、描述等,你需要根据你的应用修改这些内容。values.yaml:这是 Chart 的默认配置值文件。所有在模板中引用的参数(例如镜像名称、副本数等)都可以在这里定义默认值。templates/目录:存放所有 Kubernetes 资源模板文件(如 Deployment、Service 等)。这些文件使用 Go 模板语法,并可以引用values.yaml中定义的参数。
🔧 第二步:定制化你的 Chart
默认生成的 Chart 是一个 Nginx 示例,你需要修改它以部署自己的应用。
-
修改
Chart.yaml
用文本编辑器打开myapp/Chart.yaml,更新其中的元数据,例如:cat Chart.yaml |grep -v '^#'apiVersion: v2 name: myapp description: A Helm chart for Kubernetes type: application version: 0.1.0 appVersion: "1.16.0" -
配置
values.yaml
这是定制应用的核心。用文本编辑器打开myapp/values.yaml,你会看到很多可配置的项。根据你的应用需求修改,例如:replicaCount: 2 # 指定副本数量 image: repository: nginx # 你的应用镜像仓库地址 tag: "latest" # 镜像标签 pullPolicy: IfNotPresent service: type: ClusterIP port: 80 resources: limits: memory: "128Mi" cpu: "500m" requests: memory: "128Mi" cpu: "500m" -
编写或调整
templates/下的模板文件
根据你的应用所需 Kubernetes 资源,在templates/目录下创建或修改相应的 YAML 模板文件。这些模板会使用values.yaml中定义的参数。例如,一个简化的
templates/deployment.yaml长这样:apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-deployment # Helm会替换Release.Name为发布名 labels: app: nginx spec: replicas: {{ .Values.replicaCount }} # 使用values.yaml中的replicaCount值 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: {{ .Values.image.repository }}:{{ .Values.image.tag }} # 使用values.yaml中的镜像信息 ports: - containerPort: 80你可以根据需要,参照 Kubernetes 文档和 Helm 模板指南,在
templates/目录下创建其他资源模板,如service.yaml、ingress.yaml等。
🧪 第三步:调试与测试
在正式部署前,务必进行调试和测试。
-
使用
helm lint检查 Chart 格式
在 Chart 目录(myapp/)的上一级,运行:helm lint ./myapp #结果输出 ==> Linting ./myapp [INFO] Chart.yaml: icon is recommended 1 chart(s) linted, 0 chart(s) failed这个命令会检查 Chart 的语法和结构是否正确。
-
使用
helm template或--dry-run渲染模板
为了预览 Helm 实际会生成哪些 Kubernetes 资源清单,可以使用:helm install my-dry-run ./myapp --dry-run --debug#输出结果如下: install.go:214: [debug] Original chart version: "" install.go:231: [debug] CHART PATH: /root/helm/test/myapp NAME: my-dry-run LAST DEPLOYED: Wed Oct 15 17:13:21 2025 NAMESPACE: default STATUS: pending-install REVISION: 1 USER-SUPPLIED VALUES: {} COMPUTED VALUES: affinity: {} autoscaling: enabled: false maxReplicas: 100 minReplicas: 1 targetCPUUtilizationPercentage: 80 fullnameOverride: "" image: pullPolicy: IfNotPresent repository: nginx tag: "" imagePullSecrets: [] ingress: annotations: {} className: "" enabled: false hosts: - host: chart-example.local paths: - path: / pathType: ImplementationSpecific tls: [] nameOverride: "" nodeSelector: {} podAnnotations: {} podLabels: {} podSecurityContext: {} replicaCount: 1 resources: {} securityContext: {} service: port: 80 type: ClusterIP serviceAccount: annotations: {} automount: true create: true name: "" tolerations: [] volumeMounts: [] volumes: [] HOOKS: --- # Source: myapp/templates/tests/test-connection.yaml apiVersion: v1 kind: Pod metadata: name: "my-dry-run-myapp-test-connection" labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm annotations: "helm.sh/hook": test spec: containers: - name: wget image: busybox command: ['wget'] args: ['my-dry-run-myapp:80'] restartPolicy: Never MANIFEST: --- # Source: myapp/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: my-dry-run-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm automountServiceAccountToken: true --- # Source: myapp/templates/service.yaml apiVersion: v1 kind: Service metadata: name: my-dry-run-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run --- # Source: myapp/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: my-dry-run-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run template: metadata: labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: my-dry-run app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: my-dry-run-myapp securityContext: {} containers: - name: myapp securityContext: {} image: "nginx:1.16.0" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {} NOTES: 1. Get the application URL by running these commands: export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=myapp,app.kubernetes.io/instance=my-dry-run" -o jsonpath="{.items[0].metadata.name}") export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") echo "Visit http://127.0.0.1:8080 to use your application" kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT或者
helm template ./myapp# 输出结果如下: --- # Source: myapp/templates/serviceaccount.yaml apiVersion: v1 kind: ServiceAccount metadata: name: release-name-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm automountServiceAccountToken: true --- # Source: myapp/templates/service.yaml apiVersion: v1 kind: Service metadata: name: release-name-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: type: ClusterIP ports: - port: 80 targetPort: http protocol: TCP name: http selector: app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name --- # Source: myapp/templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: release-name-myapp labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: replicas: 1 selector: matchLabels: app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name template: metadata: labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm spec: serviceAccountName: release-name-myapp securityContext: {} containers: - name: myapp securityContext: {} image: "nginx:1.16.0" imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: / port: http readinessProbe: httpGet: path: / port: http resources: {} --- # Source: myapp/templates/tests/test-connection.yaml apiVersion: v1 kind: Pod metadata: name: "release-name-myapp-test-connection" labels: helm.sh/chart: myapp-0.1.0 app.kubernetes.io/name: myapp app.kubernetes.io/instance: release-name app.kubernetes.io/version: "1.16.0" app.kubernetes.io/managed-by: Helm annotations: "helm.sh/hook": test spec: containers: - name: wget image: busybox command: ['wget'] args: ['release-name-myapp:80'] restartPolicy: Never这不会真正部署应用,而是将渲染后的模板输出到终端,方便你检查。
-
在测试环境安装 Chart
在测试 Kubernetes 集群中,使用helm install命令部署你的 Chart:helm install my-test-release ./myapp查看部署状态:
helm list kubectl get pods -l app=myapp
🚀 第四步:准备生产部署
将 Chart 用于生产环境,需要考虑更多因素。
-
管理不同环境的配置
不要直接修改默认的values.yaml来适应不同环境(如开发、测试、生产)。 推荐的做法是:-
保留
values.yaml作为默认配置。 -
为不同环境创建各自的 values 文件,例如
values-production.yaml。 -
在部署时,使用
-f参数指定特定环境的 values 文件:helm install -f values-production.yaml my-prod-release ./myapp
-
-
打包和版本化管理 Chart
-
打包 Chart:使用
helm package命令将 Chart 打包成一个.tgz压缩文件,便于分发和存储。helm package ./myapp -
版本控制:将你的 Chart 代码(包括
Chart.yaml、values.yaml和templates/)纳入版本控制系统(如 Git)。 -
Chart 版本:每次对 Chart 进行重大更改时,记得在
Chart.yaml中更新version字段。遵循语义化版本控制规范。
-
-
考虑使用 Chart 仓库
对于团队协作和持续集成/持续部署(CI/CD),可以搭建或使用现有的 Helm Chart 仓库来集中存储和管理 Chart。
📝 生产环境 Chart 进阶要点
- 安全性:确保配置文件不包含敏感信息(如密码、密钥)。对于敏感数据,使用 Kubernetes Secrets,并通过 Helm 模板引用。
- 资源管理:在
values.yaml中明确定义容器的资源请求(requests)和限制(limits),这对于生产环境稳定性至关重要。 - 健康检查:在 Deployment 模板中配置 livenessProbe(存活性探针) 和 readinessProbe(就绪性探针),这是生产级应用的必要配置。
- 考虑使用 CI/CD 流水线:结合 Git 和 CI/CD 工具(如 Jenkins、GitLab CI),可以实现 Chart 的自动化测试、打包和部署。
💎 简单总结
使用 Helm 创建并管理应用的基本工作流可以概括为:创建 Chart -> 定制配置与模板 -> 调试验证 -> 管理部署。作为新手,从修改默认 Chart 开始,逐步理解模板和值文件的工作原理,再尝试为不同环境定制配置。
本文来源于我的微信公众号Linux运维小白,我会持续更新文章,欢迎大家关注,互相交流学习。
更多推荐




所有评论(0)