本章概述

Values 文件是 Helm Chart 的核心配置机制,它提供了一种灵活的方式来管理应用程序的配置参数。本章将深入探讨 Values 文件的结构、使用方法以及配置管理的最佳实践。

学习目标

  • 理解 Values 文件的作用和重要性
  • 掌握 Values 文件的结构和语法
  • 学会使用不同层级的 Values 文件
  • 了解配置优先级和覆盖机制
  • 掌握配置验证和安全管理
  • 学习环境特定配置的管理方法

3.1 Values 文件概述

3.1.1 什么是 Values 文件

Values 文件是 YAML 格式的配置文件,用于定义 Chart 模板中使用的变量值。它们提供了一种将配置与模板分离的机制,使得同一个 Chart 可以在不同环境中使用不同的配置。

graph TB
    A[Chart 模板] --> B[Values 文件]
    B --> C[默认 values.yaml]
    B --> D[环境特定 Values]
    B --> E[命令行 Values]
    C --> F[最终配置]
    D --> F
    E --> F
    F --> G[渲染后的 Kubernetes 资源]

3.1.2 Values 文件的优势

  1. 配置分离:将配置与模板逻辑分离
  2. 环境适配:支持多环境配置管理
  3. 可重用性:同一 Chart 可用于不同场景
  4. 版本控制:配置变更可追踪
  5. 安全性:敏感信息可单独管理

3.2 Values 文件结构

3.2.1 基本结构

# values.yaml
# 应用基本信息
app:
  name: myapp
  version: "1.0.0"
  environment: production

# 镜像配置
image:
  repository: nginx
  tag: "1.21"
  pullPolicy: IfNotPresent
  pullSecrets: []

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

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

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

# 副本数
replicaCount: 1

# 自动扩缩容
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  targetMemoryUtilizationPercentage: 80

# 节点选择器
nodeSelector: {}

# 容忍度
tolerations: []

# 亲和性
affinity: {}

# 安全上下文
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  fsGroup: 2000

# 存储配置
persistence:
  enabled: false
  storageClass: ""
  accessMode: ReadWriteOnce
  size: 8Gi

# 配置映射
configMap:
  enabled: true
  data:
    app.properties: |
      server.port=8080
      logging.level.root=INFO

# 密钥
secrets:
  enabled: false
  data: {}

# 健康检查
healthCheck:
  enabled: true
  livenessProbe:
    httpGet:
      path: /health
      port: 8080
    initialDelaySeconds: 30
    periodSeconds: 10
  readinessProbe:
    httpGet:
      path: /ready
      port: 8080
    initialDelaySeconds: 5
    periodSeconds: 5

3.2.2 嵌套结构示例

# 复杂的嵌套配置
database:
  primary:
    host: db-primary.example.com
    port: 5432
    name: myapp
    credentials:
      username: app_user
      passwordSecret: db-password
  replica:
    enabled: true
    host: db-replica.example.com
    port: 5432

cache:
  redis:
    enabled: true
    cluster:
      enabled: false
    standalone:
      host: redis.example.com
      port: 6379
    auth:
      enabled: true
      passwordSecret: redis-password

monitoring:
  prometheus:
    enabled: true
    scrapeInterval: 30s
    path: /metrics
  grafana:
    enabled: true
    dashboards:
      - name: app-dashboard
        configMap: app-grafana-dashboard

logging:
  level: INFO
  format: json
  outputs:
    - console
    - file
  file:
    path: /var/log/app.log
    maxSize: 100MB
    maxBackups: 5

3.3 Values 文件使用方法

3.3.1 在模板中使用 Values

# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.app.name }}
  labels:
    app: {{ .Values.app.name }}
    version: {{ .Values.app.version }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Values.app.name }}
  template:
    metadata:
      labels:
        app: {{ .Values.app.name }}
        version: {{ .Values.app.version }}
    spec:
      containers:
      - name: {{ .Values.app.name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        ports:
        - containerPort: {{ .Values.service.targetPort }}
        {{- if .Values.healthCheck.enabled }}
        livenessProbe:
          {{- toYaml .Values.healthCheck.livenessProbe | nindent 10 }}
        readinessProbe:
          {{- toYaml .Values.healthCheck.readinessProbe | nindent 10 }}
        {{- end }}
        {{- if .Values.resources }}
        resources:
          {{- toYaml .Values.resources | nindent 10 }}
        {{- end }}
        {{- if .Values.configMap.enabled }}
        volumeMounts:
        - name: config
          mountPath: /etc/config
        {{- end }}
      {{- if .Values.configMap.enabled }}
      volumes:
      - name: config
        configMap:
          name: {{ .Values.app.name }}-config
      {{- 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 }}

3.3.2 条件渲染

# templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ .Values.app.name }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  {{- if .Values.ingress.className }}
  ingressClassName: {{ .Values.ingress.className }}
  {{- end }}
  {{- 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: {{ $.Values.app.name }}
                port:
                  number: {{ $.Values.service.port }}
          {{- end }}
    {{- end }}
{{- end }}

3.3.3 循环和列表处理

# templates/configmap.yaml
{{- if .Values.configMap.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Values.app.name }}-config
data:
  {{- range $key, $value := .Values.configMap.data }}
  {{ $key }}: |
    {{- $value | nindent 4 }}
  {{- end }}
{{- end }}

---
# templates/secrets.yaml
{{- if .Values.secrets.enabled }}
apiVersion: v1
kind: Secret
metadata:
  name: {{ .Values.app.name }}-secret
type: Opaque
data:
  {{- range $key, $value := .Values.secrets.data }}
  {{ $key }}: {{ $value | b64enc }}
  {{- end }}
{{- end }}

3.4 配置优先级和覆盖

3.4.1 优先级顺序

Helm 按以下优先级顺序合并 Values:

  1. 命令行参数 (--set--set-string)
  2. 用户指定的 Values 文件 (-f--values)
  3. Chart 的 values.yaml 文件
  4. 依赖 Chart 的默认值
# 优先级示例
helm install myapp ./mychart \
  -f values-prod.yaml \
  --set image.tag=v2.0.0 \
  --set replicaCount=3

3.4.2 环境特定配置

# values-dev.yaml
app:
  environment: development

image:
  tag: "latest"
  pullPolicy: Always

replicaCount: 1

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

ingress:
  enabled: true
  hosts:
    - host: myapp-dev.example.com
      paths:
        - path: /
          pathType: Prefix

database:
  primary:
    host: db-dev.example.com

logging:
  level: DEBUG
# values-prod.yaml
app:
  environment: production

image:
  tag: "v1.2.3"
  pullPolicy: IfNotPresent

replicaCount: 3

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

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts:
        - myapp.example.com

database:
  primary:
    host: db-prod.example.com
  replica:
    enabled: true
    host: db-replica-prod.example.com

logging:
  level: WARN

3.4.3 部署不同环境

# 开发环境部署
helm install myapp-dev ./mychart \
  -f values-dev.yaml \
  --namespace dev

# 生产环境部署
helm install myapp-prod ./mychart \
  -f values-prod.yaml \
  --namespace prod

# 临时覆盖配置
helm upgrade myapp-prod ./mychart \
  -f values-prod.yaml \
  --set image.tag=v1.2.4 \
  --namespace prod

3.5 配置验证

3.5.1 JSON Schema 验证

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "app": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string",
          "pattern": "^[a-z0-9-]+$"
        },
        "version": {
          "type": "string",
          "pattern": "^v?[0-9]+\\.[0-9]+\\.[0-9]+$"
        },
        "environment": {
          "type": "string",
          "enum": ["development", "staging", "production"]
        }
      },
      "required": ["name", "version"]
    },
    "image": {
      "type": "object",
      "properties": {
        "repository": {
          "type": "string"
        },
        "tag": {
          "type": "string"
        },
        "pullPolicy": {
          "type": "string",
          "enum": ["Always", "IfNotPresent", "Never"]
        }
      },
      "required": ["repository", "tag"]
    },
    "replicaCount": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "resources": {
      "type": "object",
      "properties": {
        "limits": {
          "type": "object",
          "properties": {
            "cpu": {"type": "string"},
            "memory": {"type": "string"}
          }
        },
        "requests": {
          "type": "object",
          "properties": {
            "cpu": {"type": "string"},
            "memory": {"type": "string"}
          }
        }
      }
    }
  },
  "required": ["app", "image"]
}

3.5.2 模板中的验证

# templates/_helpers.tpl
{{/*
验证必需的值
*/}}
{{- define "mychart.validateValues" -}}
{{- if not .Values.app.name -}}
{{- fail "app.name is required" -}}
{{- end -}}
{{- if not .Values.image.repository -}}
{{- fail "image.repository is required" -}}
{{- end -}}
{{- if not .Values.image.tag -}}
{{- fail "image.tag is required" -}}
{{- end -}}
{{- if lt (.Values.replicaCount | int) 1 -}}
{{- fail "replicaCount must be at least 1" -}}
{{- end -}}
{{- end -}}

{{/*
验证环境配置
*/}}
{{- define "mychart.validateEnvironment" -}}
{{- $validEnvs := list "development" "staging" "production" -}}
{{- if not (has .Values.app.environment $validEnvs) -}}
{{- fail (printf "Invalid environment '%s'. Must be one of: %s" .Values.app.environment (join ", " $validEnvs)) -}}
{{- end -}}
{{- end -}}
# templates/deployment.yaml
{{- include "mychart.validateValues" . -}}
{{- include "mychart.validateEnvironment" . -}}

apiVersion: apps/v1
kind: Deployment
# ... 其余配置

3.6 安全配置管理

3.6.1 敏感信息处理

# values.yaml - 不包含敏感信息
database:
  primary:
    host: db.example.com
    port: 5432
    name: myapp
    credentials:
      usernameSecret: db-credentials
      usernameKey: username
      passwordSecret: db-credentials
      passwordKey: password

cache:
  redis:
    host: redis.example.com
    port: 6379
    auth:
      enabled: true
      passwordSecret: redis-credentials
      passwordKey: password
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.app.name }}
spec:
  template:
    spec:
      containers:
      - name: {{ .Values.app.name }}
        env:
        - name: DB_HOST
          value: {{ .Values.database.primary.host }}
        - name: DB_PORT
          value: {{ .Values.database.primary.port | quote }}
        - name: DB_NAME
          value: {{ .Values.database.primary.name }}
        - name: DB_USERNAME
          valueFrom:
            secretKeyRef:
              name: {{ .Values.database.primary.credentials.usernameSecret }}
              key: {{ .Values.database.primary.credentials.usernameKey }}
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: {{ .Values.database.primary.credentials.passwordSecret }}
              key: {{ .Values.database.primary.credentials.passwordKey }}
        {{- if .Values.cache.redis.auth.enabled }}
        - name: REDIS_PASSWORD
          valueFrom:
            secretKeyRef:
              name: {{ .Values.cache.redis.auth.passwordSecret }}
              key: {{ .Values.cache.redis.auth.passwordKey }}
        {{- end }}

3.6.2 创建密钥的脚本

#!/bin/bash
# scripts/create-secrets.sh

set -e

NAMESPACE=${1:-default}

echo "Creating secrets in namespace: $NAMESPACE"

# 创建数据库凭据
kubectl create secret generic db-credentials \
  --from-literal=username=myapp_user \
  --from-literal=password=secure_db_password \
  --namespace=$NAMESPACE \
  --dry-run=client -o yaml | kubectl apply -f -

# 创建 Redis 凭据
kubectl create secret generic redis-credentials \
  --from-literal=password=secure_redis_password \
  --namespace=$NAMESPACE \
  --dry-run=client -o yaml | kubectl apply -f -

echo "Secrets created successfully"

3.7 高级配置技巧

3.7.1 动态配置生成

# templates/_config.tpl
{{- define "mychart.config" -}}
{{- $config := dict -}}
{{- $_ := set $config "server.port" .Values.service.targetPort -}}
{{- $_ := set $config "logging.level.root" .Values.logging.level -}}
{{- $_ := set $config "app.name" .Values.app.name -}}
{{- $_ := set $config "app.version" .Values.app.version -}}
{{- $_ := set $config "app.environment" .Values.app.environment -}}

{{- if .Values.database.primary.host -}}
{{- $_ := set $config "spring.datasource.url" (printf "jdbc:postgresql://%s:%d/%s" .Values.database.primary.host (.Values.database.primary.port | int) .Values.database.primary.name) -}}
{{- end -}}

{{- if .Values.cache.redis.enabled -}}
{{- $_ := set $config "spring.redis.host" .Values.cache.redis.standalone.host -}}
{{- $_ := set $config "spring.redis.port" .Values.cache.redis.standalone.port -}}
{{- end -}}

{{- if .Values.monitoring.prometheus.enabled -}}
{{- $_ := set $config "management.endpoints.web.exposure.include" "health,info,metrics,prometheus" -}}
{{- $_ := set $config "management.endpoint.prometheus.enabled" true -}}
{{- end -}}

{{- range $key, $value := $config }}
{{ $key }}={{ $value }}
{{- end -}}
{{- end -}}

3.7.2 条件配置合并

# templates/_helpers.tpl
{{/*
合并默认配置和用户配置
*/}}
{{- define "mychart.mergeConfig" -}}
{{- $defaultConfig := dict "timeout" 30 "retries" 3 "debug" false -}}
{{- $userConfig := .Values.config | default dict -}}
{{- $finalConfig := merge $userConfig $defaultConfig -}}
{{- toYaml $finalConfig -}}
{{- end -}}

3.7.3 多环境配置模板

# values-template.yaml
app:
  name: myapp
  version: "${APP_VERSION}"
  environment: "${ENVIRONMENT}"

image:
  repository: "${IMAGE_REPOSITORY}"
  tag: "${IMAGE_TAG}"

replicaCount: ${REPLICA_COUNT}

resources:
  limits:
    cpu: "${CPU_LIMIT}"
    memory: "${MEMORY_LIMIT}"
  requests:
    cpu: "${CPU_REQUEST}"
    memory: "${MEMORY_REQUEST}"

database:
  primary:
    host: "${DB_HOST}"
    port: ${DB_PORT}
    name: "${DB_NAME}"
#!/bin/bash
# scripts/generate-values.sh

ENVIRONMENT=$1
VALUES_TEMPLATE="values-template.yaml"
VALUES_OUTPUT="values-${ENVIRONMENT}.yaml"

case $ENVIRONMENT in
  "dev")
    export APP_VERSION="latest"
    export IMAGE_REPOSITORY="myapp"
    export IMAGE_TAG="dev"
    export REPLICA_COUNT=1
    export CPU_LIMIT="200m"
    export MEMORY_LIMIT="256Mi"
    export CPU_REQUEST="100m"
    export MEMORY_REQUEST="128Mi"
    export DB_HOST="db-dev.example.com"
    export DB_PORT=5432
    export DB_NAME="myapp_dev"
    ;;
  "prod")
    export APP_VERSION="v1.0.0"
    export IMAGE_REPOSITORY="myapp"
    export IMAGE_TAG="v1.0.0"
    export REPLICA_COUNT=3
    export CPU_LIMIT="1000m"
    export MEMORY_LIMIT="1Gi"
    export CPU_REQUEST="500m"
    export MEMORY_REQUEST="512Mi"
    export DB_HOST="db-prod.example.com"
    export DB_PORT=5432
    export DB_NAME="myapp_prod"
    ;;
  *)
    echo "Unknown environment: $ENVIRONMENT"
    exit 1
    ;;
esac

envsubst < $VALUES_TEMPLATE > $VALUES_OUTPUT
echo "Generated $VALUES_OUTPUT for $ENVIRONMENT environment"

3.8 实践练习

3.8.1 练习1:创建多环境配置

创建一个 Web 应用的 Chart,包含以下配置:

  1. 基础 values.yaml
  2. 开发环境配置 values-dev.yaml
  3. 生产环境配置 values-prod.yaml
  4. 配置验证逻辑
# 创建 Chart
helm create webapp
cd webapp

# 编辑 values.yaml
vim values.yaml

# 创建环境特定配置
vim values-dev.yaml
vim values-prod.yaml

# 验证配置
helm template . -f values-dev.yaml
helm template . -f values-prod.yaml

# 部署测试
helm install webapp-dev . -f values-dev.yaml --dry-run
helm install webapp-prod . -f values-prod.yaml --dry-run

3.8.2 练习2:配置安全管理

实现敏感信息的安全管理:

  1. 创建密钥管理模板
  2. 实现配置验证
  3. 编写部署脚本
# 创建密钥
kubectl create secret generic app-secrets \
  --from-literal=db-password=secret123 \
  --from-literal=api-key=abc123

# 验证模板
helm template . --set secrets.enabled=true

# 部署应用
helm install myapp . --set secrets.enabled=true

3.8.3 练习3:动态配置生成

创建一个可以根据环境动态生成配置的 Chart:

# 练习目标配置结构
config:
  database:
    connections: 10
    timeout: 30
  cache:
    ttl: 3600
    maxSize: 1000
  features:
    enableMetrics: true
    enableTracing: false

3.9 故障排除

3.9.1 常见配置问题

  1. YAML 语法错误 “`bash

    验证 YAML 语法

    yaml-lint values.yaml

使用 Helm 验证

helm template . -f values.yaml


2. **配置覆盖不生效**
```bash
# 检查配置合并结果
helm template . -f values.yaml --debug

# 查看最终配置
helm get values RELEASE_NAME
  1. 模板渲染错误 “`bash

    调试模板

    helm template . –debug

检查特定模板

helm template . –show-only templates/deployment.yaml


### 3.9.2 调试技巧

```yaml
# 在模板中添加调试信息
{{- if .Values.debug }}
# DEBUG: Current values
# {{- toYaml .Values | nindent 2 }}
{{- end }}
# 启用调试模式
helm install myapp . --set debug=true --debug

# 查看渲染结果
helm template myapp . --set debug=true

3.10 本章小结

核心概念回顾

  1. Values 文件:Helm Chart 的配置管理核心
  2. 配置层次:默认值、环境配置、命令行覆盖
  3. 模板集成:在模板中使用 Values 的方法
  4. 安全管理:敏感信息的安全处理
  5. 配置验证:确保配置的正确性和安全性

技术要点总结

  • Values 文件使用 YAML 格式,支持嵌套结构
  • 配置优先级:命令行 > 用户文件 > 默认文件
  • 模板中通过 .Values 对象访问配置
  • 支持条件渲染和循环处理
  • 可以实现配置验证和安全管理

最佳实践

  1. 结构化配置:使用清晰的层次结构组织配置
  2. 环境分离:为不同环境创建专门的配置文件
  3. 安全优先:敏感信息使用 Secret 管理
  4. 配置验证:实现必要的配置验证逻辑
  5. 文档完善:为配置项提供清晰的注释和说明

下一章预告

下一章我们将学习「依赖管理与子图表」,探讨如何管理 Chart 之间的依赖关系,以及如何使用子图表构建复杂的应用架构。我们将深入了解依赖声明、版本管理、子图表配置等高级主题。