本文目录导读:

- 项目结构
- Chart.yaml
- values.yaml
- templates/_helpers.tpl
- templates/deployment.yaml
- templates/service.yaml
- templates/configmap.yaml
- templates/secrets.yaml
- templates/hpa.yaml
- templates/ingress.yaml
- templates/serviceaccount.yaml
- templates/pvc.yaml
- templates/NOTES.txt
- values-dev.yaml
- values-prod.yaml
- 使用方法
- Dockerfile 示例
我将为您提供一个完整的Java应用Helm chart案例,包括详细的配置和使用说明。
项目结构
java-app-chart/
├── Chart.yaml
├── values.yaml
├── values-dev.yaml
├── values-prod.yaml
├── templates/
│ ├── NOTES.txt
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── configmap.yaml
│ ├── secrets.yaml
│ ├── serviceaccount.yaml
│ ├── hpa.yaml
│ └── pvc.yaml
└── charts/
Chart.yaml
apiVersion: v2
name: java-app
description: A Helm chart for Java Spring Boot application
type: application
version: 1.0.0
appVersion: "1.0.0"
# 依赖项(如果需要)
dependencies:
- name: mysql
version: 9.4.0
repository: https://charts.bitnami.com/bitnami
condition: mysql.enabled
- name: redis
version: 17.3.7
repository: https://charts.bitnami.com/bitnami
condition: redis.enabled
values.yaml
# 默认配置
replicaCount: 2
image:
repository: your-registry/java-app
tag: latest
pullPolicy: Always
# 指定镜像拉取密钥
pullSecrets:
- name: registry-secret
nameOverride: ""
fullnameOverride: ""
# 环境变量配置
env:
normal:
- name: JAVA_OPTS
value: "-Xms256m -Xmx512m"
- name: SPRING_PROFILES_ACTIVE
value: "prod"
- name: TZ
value: "Asia/Shanghai"
# 引用ConfigMap的配置
fromConfigMap:
- configMapRef:
name: java-app-config
# 引用Secret的配置
fromSecret:
- secretRef:
name: java-app-secret
# 容器端口配置
ports:
- name: http
containerPort: 8080
protocol: TCP
# 健康检查
livenessProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 60
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /actuator/health
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 资源限制
resources:
limits:
cpu: "1"
memory: 1Gi
requests:
cpu: "500m"
memory: 512Mi
# 自动扩缩容
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 80
targetMemoryUtilizationPercentage: 80
# Service配置
service:
type: ClusterIP
port: 80
targetPort: http
annotations: {}
# Ingress配置
ingress:
enabled: true
className: "nginx"
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
hosts:
- host: app.example.com
paths:
- path: /
pathType: Prefix
backend:
serviceName: java-app
servicePort: 80
tls:
- secretName: java-app-tls
hosts:
- app.example.com
# ConfigMap配置
configMap:
enabled: true
data:
application.yml: |
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://mysql:3306/java_app
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
redis:
host: redis
port: 6379
logging:
level:
root: INFO
com.example: DEBUG
# Secret配置
secrets:
enabled: true
data:
DB_PASSWORD: UGFzc3dvcmQxMjM= # Base64编码
REDIS_PASSWORD: UGFzc3dvcmQxMjM=$
# 持久化存储
persistence:
enabled: true
storageClass: ""
accessMode: ReadWriteOnce
size: 10Gi
existingClaim: ""
annotations: {}
# ServiceAccount
serviceAccount:
create: true
name: ""
annotations: {}
# 其他配置
nodeSelector: {}
tolerations: []
affinity: {}
# 滚动更新策略
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
# 自定义标签
labels:
app.kubernetes.io/name: java-app
app.kubernetes.io/managed-by: helm
templates/_helpers.tpl
{{- define "java-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- define "java-app.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 "java-app.labels" -}}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
{{ include "java-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- with .Values.labels }}
{{ toYaml . }}
{{- end }}
{{- end -}}
{{- define "java-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "java-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end -}}
{{- define "java-app.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "java-app.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}
templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "java-app.fullname" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
strategy:
{{- toYaml .Values.strategy | nindent 4 }}
selector:
matchLabels:
{{- include "java-app.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
{{- include "java-app.selectorLabels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "java-app.serviceAccountName" . }}
{{- with .Values.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
{{- toYaml .Values.ports | nindent 12 }}
env:
{{- toYaml .Values.env.normal | nindent 12 }}
{{- if .Values.env.fromConfigMap }}
{{- toYaml .Values.env.fromConfigMap | nindent 12 }}
{{- end }}
{{- if .Values.env.fromSecret }}
{{- toYaml .Values.env.fromSecret | nindent 12 }}
{{- end }}
livenessProbe:
{{- toYaml .Values.livenessProbe | nindent 12 }}
readinessProbe:
{{- toYaml .Values.readinessProbe | nindent 12 }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
{{- if .Values.configMap.enabled }}
- name: config
mountPath: /app/config
readOnly: true
{{- end }}
{{- if .Values.persistence.enabled }}
- name: data
mountPath: /app/data
{{- end }}
volumes:
{{- if .Values.configMap.enabled }}
- name: config
configMap:
name: {{ include "java-app.fullname" . }}-config
{{- end }}
{{- if .Values.persistence.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ if .Values.persistence.existingClaim }}{{ .Values.persistence.existingClaim }}{{ else }}{{ include "java-app.fullname" . }}{{ end }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "java-app.fullname" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
{{- with .Values.service.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort }}
protocol: TCP
name: http
selector:
{{- include "java-app.selectorLabels" . | nindent 4 }}
templates/configmap.yaml
{{- if .Values.configMap.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "java-app.fullname" . }}-config
labels:
{{- include "java-app.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.configMap.data }}
{{ $key }}: |
{{ $value | indent 4 }}
{{- end }}
{{- end }}
templates/secrets.yaml
{{- if .Values.secrets.enabled }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "java-app.fullname" . }}-secret
labels:
{{- include "java-app.labels" . | nindent 4 }}
type: Opaque
data:
{{- range $key, $value := .Values.secrets.data }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}
templates/hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "java-app.fullname" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "java-app.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
templates/ingress.yaml
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "java-app.fullname" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.className }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- toYaml .Values.ingress.tls | nindent 4 }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
pathType: {{ .pathType }}
backend:
service:
name: {{ include "java-app.fullname" $ }}
port:
number: {{ .backend.servicePort }}
{{- end }}
{{- end }}
{{- end }}
templates/serviceaccount.yaml
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "java-app.serviceAccountName" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
templates/pvc.yaml
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: {{ include "java-app.fullname" . }}
labels:
{{- include "java-app.labels" . | nindent 4 }}
{{- with .Values.persistence.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
{{- if .Values.persistence.storageClass }}
storageClassName: {{ .Values.persistence.storageClass }}
{{- end }}
resources:
requests:
storage: {{ .Values.persistence.size }}
{{- end }}
templates/NOTES.txt
Get the application URL:
{{- if .Values.ingress.enabled }}
http://{{ .Values.ingress.hosts[0].host }}
{{- else if eq .Values.service.type "ClusterIP" }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "java-app.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:8080
{{- else if eq .Values.service.type "NodePort" }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "java-app.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Visit http://$NODE_IP:$NODE_PORT to use your application"
{{- end }}
values-dev.yaml
replicaCount: 1
image:
repository: your-registry/java-app
tag: dev-latest
pullPolicy: Always
env:
normal:
- name: SPRING_PROFILES_ACTIVE
value: "dev"
- name: JAVA_OPTS
value: "-Xms128m -Xmx256m"
resources:
limits:
cpu: "500m"
memory: 512Mi
requests:
cpu: "250m"
memory: 256Mi
autoscaling:
enabled: false
ingress:
enabled: false
service:
type: ClusterIP
values-prod.yaml
replicaCount: 3
image:
repository: your-registry/java-app
tag: stable
pullPolicy: IfNotPresent
resources:
limits:
cpu: "2"
memory: 2Gi
requests:
cpu: "1"
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
ingress:
enabled: true
hosts:
- host: prod-app.example.com
paths:
- path: /
pathType: Prefix
backend:
servicePort: 80
tls:
- secretName: prod-tls
hosts:
- prod-app.example.com
使用方法
安装chart
# 基本安装 helm install java-app ./java-app-chart # 指定环境 helm install java-app ./java-app-chart -f values-dev.yaml helm install java-app ./java-app-chart -f values-prod.yaml # 指定命名空间 helm install java-app ./java-app-chart -n my-namespace --create-namespace
升级
# 升级release helm upgrade java-app ./java-app-chart -f values-prod.yaml # 指定版本 helm upgrade java-app ./java-app-chart --set image.tag=1.0.1
回滚
# 查看历史版本 helm history java-app # 回滚到指定版本 helm rollback java-app 2
卸载
helm uninstall java-app -n my-namespace
调试和测试
# 渲染模板 helm template java-app ./java-app-chart -f values-dev.yaml # 检查语法 helm lint ./java-app-chart # 渲染并调试 helm install java-app ./java-app-chart --dry-run --debug
Dockerfile 示例
# 多阶段构建 FROM maven:3.8.4-openjdk-17 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline COPY src ./src RUN mvn clean package -DskipTests # 运行时镜像 FROM openjdk:17-jdk-alpine WORKDIR /app COPY --from=build /app/target/*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java", "-jar", "app.jar"]
这个完整的Helm chart案例包含了Java应用部署所需的所有资源,可以根据实际需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播