Skip to content
清晨的一缕阳光
返回

Spring Boot Helm Chart 打包部署

前言

Helm 是 Kubernetes 的包管理工具,通过 Chart 可以方便地打包和部署应用。本文将介绍 Spring Boot Helm Chart 的完整方案。

Helm 基础

1. 安装 Helm

# macOS
brew install helm

# Linux
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Windows
choco install kubernetes-helm

2. 验证安装

# 查看版本
helm version

# 查看帮助
helm --help

# 添加仓库
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami

# 搜索 Chart
helm search repo nginx
helm search hub wordpress

3. 常用命令

# 创建 Chart
helm create demo

# 打包 Chart
helm package ./demo

# 安装 Chart
helm install demo ./demo

# 升级 Chart
helm upgrade demo ./demo

# 卸载 Chart
helm uninstall demo

# 查看状态
helm list
helm status demo

# 回滚
helm rollback demo 1

# 查看历史
helm history demo

Chart 结构

1. 目录结构

demo/
├── Chart.yaml          # Chart 元数据
├── values.yaml         # 默认配置值
├── values-prod.yaml    # 生产环境配置
├── Chart.lock          # 依赖锁定文件
├── templates/          # 模板目录
│   ├── NOTES.txt       # 安装说明
│   ├── _helpers.tpl    # 辅助模板
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── configmap.yaml
│   ├── ingress.yaml
│   └── hpa.yaml
├── charts/             # 子 Chart 依赖
└── .helmignore         # 忽略文件

2. Chart.yaml

apiVersion: v2
name: demo
description: Spring Boot Demo Application
type: application

# Chart 版本
version: 1.0.0

# 应用版本
appVersion: "1.0.0"

# 关键词
keywords:
  - spring-boot
  - java
  - web

# 维护者
maintainers:
  - name: Your Name
    email: your-email@example.com

# 依赖
dependencies:
  - name: mysql
    version: 9.0.0
    repository: https://charts.bitnami.com/bitnami
    condition: mysql.enabled
  - name: redis
    version: 17.0.0
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled

3. values.yaml

# 副本数
replicaCount: 3

# 镜像配置
image:
  repository: demo
  pullPolicy: IfNotPresent
  tag: "1.0.0"

# 镜像拉取密钥
imagePullSecrets: []

# 服务名称
nameOverride: ""
fullnameOverride: ""

# 服务账号
serviceAccount:
  create: true
  annotations: {}
  name: ""

# Pod 注解
podAnnotations: {}

# Pod 安全上下文
podSecurityContext: {}

# 容器安全上下文
securityContext: {}

# 服务配置
service:
  type: ClusterIP
  port: 80
  targetPort: 8080

# Ingress 配置
ingress:
  enabled: false
  className: nginx
  annotations: {}
  hosts:
    - host: demo.example.com
      paths:
        - path: /
          pathType: Prefix
  tls: []

# 资源限制
resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 1Gi

# 自动扩缩容
autoscaling:
  enabled: false
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80
  targetMemoryUtilizationPercentage: 80

# 健康检查
livenessProbe:
  httpGet:
    path: /actuator/health/liveness
    port: 8080
  initialDelaySeconds: 30
  periodSeconds: 10

readinessProbe:
  httpGet:
    path: /actuator/health/readiness
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5

# 环境变量
env:
  SPRING_PROFILES_ACTIVE: prod
  JAVA_OPTS: "-Xms512m -Xmx512m"

# 配置映射
configMap:
  application: |
    server:
      port: 8080
    spring:
      datasource:
        url: jdbc:mysql://mysql:3306/demo
        username: root
      redis:
        host: redis
        port: 6379

# 敏感信息
secret:
  enabled: true
  data:
    DB_PASSWORD: ""
    JWT_SECRET: ""

# 子 Chart 配置
mysql:
  enabled: true
  auth:
    rootPassword: "root-password"
    database: demo
  primary:
    persistence:
      enabled: true
      size: 8Gi

redis:
  enabled: true
  auth:
    enabled: true
    password: "redis-password"
  master:
    persistence:
      enabled: true
      size: 8Gi

模板语法

1. 基础模板

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      {{- include "demo.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "demo.selectorLabels" . | nindent 8 }}
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "demo.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
              protocol: TCP
          livenessProbe:
            {{- toYaml .Values.livenessProbe | nindent 12 }}
          readinessProbe:
            {{- toYaml .Values.readinessProbe | nindent 12 }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          env:
            {{- range $key, $value := .Values.env }}
            - name: {{ $key }}
              value: {{ $value | quote }}
            {{- end }}

2. 辅助模板

# templates/_helpers.tpl
{{/*
扩展名称
*/}}
{{- define "demo.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
创建完整的名称
*/}}
{{- define "demo.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 }}

{{/*
创建 Chart 标签
*/}}
{{- define "demo.labels" -}}
helm.sh/chart: {{ include "demo.chart" . }}
{{ include "demo.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
通用选择器标签
*/}}
{{- define "demo.selectorLabels" -}}
app.kubernetes.io/name: {{ include "demo.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
创建服务账号名称
*/}}
{{- define "demo.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "demo.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{/*
创建 Chart 版本
*/}}
{{- define "demo.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

3. 条件渲染

# templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "demo.fullname" . }}
  labels:
    {{- include "demo.labels" . | nindent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  ingressClassName: {{ .Values.ingress.className }}
  {{- if .Values.ingress.tls }}
  tls:
    {{- range .Values.ingress.tls }}
    - hosts:
        {{- range .hosts }}
        - {{ . | quote }}
        {{- end }}
      secretName: {{ .secretName }}
    {{- end }}
  {{- end }}
  rules:
    {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
          {{- range .paths }}
          - path: {{ .path }}
            pathType: {{ .pathType }}
            backend:
              service:
                name: {{ include "demo.fullname" $ }}
                port:
                  number: {{ $.Values.service.port }}
          {{- end }}
    {{- end }}
{{- end }}

4. 循环渲染

# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "demo.fullname" . }}-config
  labels:
    {{- include "demo.labels" . | nindent 4 }}
data:
  application.yml: |
    {{- toYaml .Values.configMap.application | nindent 4 }}
  
  {{- range $key, $value := .Values.extraConfig }}
  {{ $key }}: {{ $value | quote }}
  {{- end }}

多环境管理

1. 多 values 文件

# values-dev.yaml
replicaCount: 1

image:
  tag: "latest"

resources:
  requests:
    cpu: 100m
    memory: 256Mi
  limits:
    cpu: 200m
    memory: 512Mi

mysql:
  primary:
    persistence:
      size: 2Gi

# values-test.yaml
replicaCount: 2

image:
  tag: "1.0.0"

resources:
  requests:
    cpu: 250m
    memory: 512Mi
  limits:
    cpu: 500m
    memory: 1Gi

# values-prod.yaml
replicaCount: 3

image:
  tag: "1.0.0"
  pullPolicy: Always

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10

ingress:
  enabled: true
  hosts:
    - host: demo.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: demo-tls
      hosts:
        - demo.example.com

2. 安装命令

# 开发环境
helm install demo ./demo -f values-dev.yaml -n dev

# 测试环境
helm install demo ./demo -f values-test.yaml -n test

# 生产环境
helm install demo ./demo -f values-prod.yaml -n prod

# 覆盖单个值
helm install demo ./demo --set replicaCount=5

3. 环境升级

# 升级 Chart
helm upgrade demo ./demo -f values-prod.yaml -n prod

# 回滚到上一个版本
helm rollback demo -n prod

# 回滚到指定版本
helm rollback demo 2 -n prod

# 查看历史
helm history demo -n prod

私有仓库

1. 创建仓库

# 打包 Chart
helm package ./demo

# 创建仓库索引
helm repo index . --url https://charts.example.com

# 上传到服务器
# 使用 FTP、SCP 或云存储

2. 添加仓库

# 添加仓库
helm repo add myrepo https://charts.example.com

# 添加认证仓库
helm repo add myrepo https://charts.example.com \
  --username admin \
  --password secret

# 更新仓库
helm repo update

# 搜索 Chart
helm search repo demo

3. Chart Museum

# 启动 Chart Museum
docker run -d --name chartmuseum \
  -p 8080:8080 \
  -v $(pwd)/charts:/charts \
  chartmuseum/chartmuseum:latest \
  --storage local \
  --storage-local-rootdir /charts

# 上传 Chart
curl --data-binary "@demo-1.0.0.tgz" \
  http://localhost:8080/api/charts

最佳实践

1. Chart 规范

# ✅ 推荐
apiVersion: v2
name: demo
version: 1.0.0
appVersion: "1.0.0"
description: 清晰的描述
keywords:
  - spring-boot
  - java
maintainers:
  - name: Team
    email: team@example.com

# ❌ 不推荐
apiVersion: v1  # 使用旧版本
version: 1  # 缺少 minor 和 patch

2. 模板规范

# ✅ 推荐
{{- include "demo.labels" . | nindent 4 }}
{{- if .Values.ingress.enabled }}
{{- end }}
{{- range .Values.hosts }}
{{- end }}

# ❌ 不推荐
{{include "demo.labels" .}}  # 缺少空格
{{ if .Values.ingress.enabled }}  # 缺少 -

3. 值文件规范

# ✅ 推荐
# 分组配置
image:
  repository: demo
  tag: "1.0.0"

# 清晰的注释
# 副本数
replicaCount: 3

# ❌ 不推荐
# 没有分组
repository: demo
tag: "1.0.0"
replicaCount: 3

4. 测试 Chart

# 语法检查
helm lint ./demo

# 模板渲染测试
helm template demo ./demo

# 空运行
helm install demo ./demo --dry-run --debug

# 单元测试(使用 helm-unittest 插件)
helm unittest ./demo

5. CI/CD 集成

# .github/workflows/helm.yml
name: Helm Chart CI

on:
  push:
    tags:
      - 'chart-v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Helm
        uses: azure/setup-helm@v3
      
      - name: Lint Chart
        run: helm lint ./demo
      
      - name: Package Chart
        run: helm package ./demo
      
      - name: Upload Chart
        run: |
          curl --data-binary "@demo-*.tgz" \
            https://charts.example.com/api/charts

总结

Helm Chart 要点:

Helm 是 Kubernetes 应用部署的标准工具。


分享这篇文章到:

上一篇文章
Comparator 与 Comparable 详解
下一篇文章
Kafka 集成