如何在Helm升级阶段限制用户修改特定配置字段?
禁止Helm Upgrade修改特定字段的实现方案
下面提供几种可行的实现方式,按可靠性和约束强度排序:
一、预升级钩子(Pre-Upgrade Hook)强制验证
这是最可靠的方案,通过Helm钩子在升级前自动执行验证逻辑,一旦检测到非法修改就终止升级。
步骤1:存储不可修改字段到K8s资源
首先在Chart模板中,将id这类不可修改字段存入ConfigMap(或Secret),确保部署后能通过K8s API获取到原值:
# templates/configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: {{ .Release.Name }}-app-config data: id: {{ .Values.id | quote }}
步骤2:创建验证用的预升级Job
编写一个Job作为预升级钩子,对比现有ConfigMap中的id和新values中的id,不一致则报错退出:
# templates/pre-upgrade-validate-id.yaml apiVersion: batch/v1 kind: Job metadata: name: {{ .Release.Name }}-validate-id annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "-5" "helm.sh/hook-delete-policy": hook-succeeded spec: template: spec: serviceAccountName: {{ .Release.Name }}-validator-sa restartPolicy: Never containers: - name: validator image: busybox:1.36 command: ['sh', '-c', ' EXISTING_ID=$(kubectl get configmap {{ .Release.Name }}-app-config -o jsonpath="{.data.id}"); NEW_ID="{{ .Values.id }}"; if [ "$EXISTING_ID" != "$NEW_ID" ]; then echo "Error: 字段id不允许在升级时修改,当前值: $EXISTING_ID,新值: $NEW_ID"; exit 1; fi ']
步骤3:配置权限允许钩子访问K8s API
由于钩子需要读取ConfigMap,需创建对应的ServiceAccount和RBAC规则:
# templates/validator-rbac.yaml apiVersion: v1 kind: ServiceAccount metadata: name: {{ .Release.Name }}-validator-sa annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "-6" --- apiVersion: rbac.authorization.k8s.io/v1 kind: Role metadata: name: {{ .Release.Name }}-validator-role annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "-6" rules: - apiGroups: [""] resources: ["configmaps"] verbs: ["get"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: RoleBinding metadata: name: {{ .Release.Name }}-validator-binding annotations: "helm.sh/hook": pre-upgrade "helm.sh/hook-weight": "-6" roleRef: apiGroup: rbac.authorization.k8s.io kind: Role name: {{ .Release.Name }}-validator-role subjects: - kind: ServiceAccount name: {{ .Release.Name }}-validator-sa
当用户执行helm upgrade时,钩子会先运行,若检测到id被修改,Job会失败,Helm会终止升级流程并返回错误信息。
二、模板内使用lookup函数验证
在核心资源(如Deployment)的模板中,通过Helm内置的lookup函数读取现有资源的id值,与新values对比,不一致则生成无效YAML触发升级失败:
# templates/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ .Release.Name }}-app annotations: {{- if .Release.IsUpgrade }} {{- $existingConfig := lookup "v1" "ConfigMap" .Release.Namespace (printf "%s-app-config" .Release.Name) }} {{- if ne $existingConfig.data.id (.Values.id | quote) }} "validation-error": "字段id不允许修改,当前值: {{ $existingConfig.data.id }},新值: {{ .Values.id }}" {{- end }} {{- end }} spec: replicas: 1 selector: matchLabels: app: {{ .Release.Name }}-app template: metadata: labels: app: {{ .Release.Name }}-app spec: containers: - name: app image: nginx:alpine
这种方式无需额外钩子资源,但验证失败时的错误信息相对不够直观,且依赖Helm模板渲染逻辑。
三、客户端脚本前置验证
适合内部团队场景,要求用户在执行helm upgrade前先运行验证脚本,对比现有Release的id和新values的id:
#!/bin/bash RELEASE_NAME="your-release-name" NEW_VALUES_FILE="new-values.yaml" # 获取现有Release的id值 EXISTING_ID=$(helm get values $RELEASE_NAME -o jsonpath='{.id}') # 获取新values中的id值 NEW_ID=$(yq eval '.id' $NEW_VALUES_FILE) if [ "$EXISTING_ID" != "$NEW_ID" ]; then echo "错误:字段id不允许在升级时修改" exit 1 fi # 验证通过后执行升级 helm upgrade $RELEASE_NAME . -f $NEW_VALUES_FILE
这种方式依赖用户自觉执行脚本,无法强制约束外部用户。
内容的提问来源于stack exchange,提问作者Saran
相关产品推荐
相关产品推荐

