Exemples Helm Chart

Exemples complets de Helm charts avec templates, valeurs, dépendances et configurations de gestion de paquets

💻 Helm Chart d'Application Web de Base

🟢 simple ⭐⭐

Structure complète de Helm chart pour application web avec deployment, service et ingress configurables

⏱️ 15 min 🏷️ helm, chart, kubernetes, templates
Prerequisites: Kubernetes basics, Helm fundamentals, YAML syntax
# Basic Web Application Helm Chart Structure

# 1. Chart.yaml - Chart Metadata
apiVersion: v2
name: web-app
description: A Helm chart for web application deployment
type: application
version: 1.0.0
appVersion: "1.0.0"
home: https://github.com/example/web-app
sources:
  - https://github.com/example/web-app
maintainers:
  - name: DevOps Team
    email: [email protected]
keywords:
  - web
  - application
  - nginx
annotations:
  category: WebApplication
  licenses: MIT

# 2. values.yaml - Default Configuration
replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  tag: "1.21-alpine"

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext:
  fsGroup: 2000

securityContext:
  # capabilities:
  #   drop:
  #   - ALL
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  runAsUser: 1000

service:
  type: ClusterIP
  port: 80
  targetPort: 80
  annotations: {}

ingress:
  enabled: false
  className: "nginx"
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: web-app.local
      paths:
        - path: /
          pathType: Prefix
  tls: []
  #  - secretName: web-app-tls
  #    hosts:
  #      - web-app.local

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

# Application specific configuration
app:
  env: production
  logLevel: info
  features:
    - authentication
    - monitoring
    - caching

# Database configuration
database:
  enabled: false
  host: ""
  port: 5432
  name: webapp
  user: webapp
  password: ""
  sslMode: require

# Redis configuration
redis:
  enabled: false
  host: ""
  port: 6379
  password: ""
  database: 0

# Monitoring configuration
monitoring:
  enabled: false
  serviceMonitor:
    enabled: false
    namespace: ""
    labels: {}
    annotations: {}
    interval: 30s
    scrapeTimeout: 10s

# 3. templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "web-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
        checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
        {{- with .Values.podAnnotations }}
        {{- toYaml . | nindent 8 }}
        {{- end }}
      labels:
        {{- include "web-app.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "web-app.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
            timeoutSeconds: 3
            failureThreshold: 3
          env:
            - name: APP_ENV
              value: {{ .Values.app.env | quote }}
            - name: LOG_LEVEL
              value: {{ .Values.app.logLevel | quote }}
            - name: FEATURES
              value: {{ join "," .Values.app.features | quote }}
            {{- if .Values.database.enabled }}
            - name: DATABASE_HOST
              value: {{ .Values.database.host | quote }}
            - name: DATABASE_PORT
              value: {{ .Values.database.port | quote }}
            - name: DATABASE_NAME
              value: {{ .Values.database.name | quote }}
            - name: DATABASE_USER
              value: {{ .Values.database.user | quote }}
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: {{ include "web-app.fullname" . }}
                  key: database-password
            - name: DATABASE_SSL_MODE
              value: {{ .Values.database.sslMode | quote }}
            {{- end }}
            {{- if .Values.redis.enabled }}
            - name: REDIS_HOST
              value: {{ .Values.redis.host | quote }}
            - name: REDIS_PORT
              value: {{ .Values.redis.port | quote }}
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: {{ include "web-app.fullname" . }}
                  key: redis-password
            - name: REDIS_DATABASE
              value: {{ .Values.redis.database | quote }}
            {{- end }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          volumeMounts:
            - name: config
              mountPath: /app/config
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: {{ include "web-app.fullname" . }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}

# 4. templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.labels" . | nindent 4 }}
  {{- with .Values.service.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "web-app.selectorLabels" . | nindent 4 }}

# 5. templates/ingress.yaml
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.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 }}
            {{- if .pathType }}
            pathType: {{ .pathType }}
            {{- end }}
            backend:
              service:
                name: {{ include "web-app.fullname" $ }}
                port:
                  number: {{ $.Values.service.port }}
          {{- end }}
    {{- end }}
{{- end }}

# 6. templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.labels" . | nindent 4 }}
data:
  app.json: |
    {
      "environment": "{{ .Values.app.env }}",
      "logLevel": "{{ .Values.app.logLevel }}",
      "features": {{ .Values.app.features | toJson }}
    }

  {{- if .Values.database.enabled }}
  database.json: |
    {
      "host": "{{ .Values.database.host }}",
      "port": {{ .Values.database.port }},
      "name": "{{ .Values.database.name }}",
      "user": "{{ .Values.database.user }}",
      "sslMode": "{{ .Values.database.sslMode }}"
    }
  {{- end }}

  nginx.conf: |
    server {
        listen 80;
        server_name localhost;

        location / {
            root /usr/share/nginx/html;
            index index.html index.htm;
        }

        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }

        location /ready {
            access_log off;
            return 200 "ready\n";
            add_header Content-Type text/plain;
        }
    }

# 7. templates/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.labels" . | nindent 4 }}
type: Opaque
data:
  {{- if .Values.database.enabled }}
  database-password: {{ .Values.database.password | b64enc | quote }}
  {{- end }}
  {{- if .Values.redis.enabled }}
  redis-password: {{ .Values.redis.password | b64enc | quote }}
  {{- end }}

# 8. templates/hpa.yaml
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ include "web-app.fullname" . }}
  labels:
    {{- include "web-app.labels" . | nindent 4 }}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ include "web-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 }}

# 9. templates/_helpers.tpl - Helper Templates
{{/*
Expand the name of the chart.
*/}}
{{- define "web-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "web-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 }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "web-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "web-app.labels" -}}
helm.sh/chart: {{ include "web-app.chart" . }}
{{ include "web-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "web-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "web-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "web-app.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "web-app.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

# 10. templates/NOTES.txt - Installation Notes
{{- /*
Notes displayed after chart installation
*/}}
{{- if .Values.ingress.enabled }}
Your web application has been deployed!

{{- range .Values.ingress.hosts }}
Access your application at: {{- if .tls }}https{{ else }}http{{- end }}://{{ .host | quote }}
{{- end }}

{{- else }}
Your web application has been deployed!

Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "web-app.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

💻 Helm Chart d'Application Microservices

🟡 intermediate ⭐⭐⭐⭐

Configuration complète de microservices avec services multiples, dépendances partagées et configurations avancées

⏱️ 30 min 🏷️ helm, microservices, kubernetes, dependencies
Prerequisites: Helm basics, Kubernetes services, Microservices architecture
# Microservices Application Helm Chart
# Complete setup for multiple interconnected services

# 1. Chart.yaml
apiVersion: v2
name: microservices-app
description: A Helm chart for microservices application
type: application
version: 2.0.0
appVersion: "2.0.0"
dependencies:
  - name: postgresql
    version: 12.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled
  - name: redis
    version: 17.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled
  - name: elasticsearch
    version: 19.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: elasticsearch.enabled

# 2. values.yaml
global:
  imageRegistry: ""
  imagePullSecrets: []
  storageClass: ""

# Common configurations
common:
  annotations: {}
  labels: {}
  resources:
    limits:
      cpu: 500m
      memory: 512Mi
    requests:
      cpu: 250m
      memory: 256Mi

# API Gateway Configuration
gateway:
  enabled: true
  replicaCount: 2
  image:
    repository: myregistry/api-gateway
    tag: "2.0.0"
    pullPolicy: IfNotPresent
  service:
    type: LoadBalancer
    port: 80
    targetPort: 8080
  ingress:
    enabled: true
    className: nginx
    annotations:
      nginx.ingress.kubernetes.io/rewrite-target: /
    hosts:
      - host: api.example.com
        paths:
          - path: /
            pathType: Prefix
    tls:
      - secretName: api-tls
        hosts:
          - api.example.com
  env:
    - name: LOG_LEVEL
      value: "INFO"
    - name: RATE_LIMIT
      value: "100"
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 10
    targetCPUUtilizationPercentage: 70
  nodeSelector:
    node-type: edge
  tolerations: []

# User Service
userService:
  enabled: true
  replicaCount: 2
  image:
    repository: myregistry/user-service
    tag: "2.0.0"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 3001
    targetPort: 3001
  env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: postgres-secret
          key: url
    - name: REDIS_URL
      valueFrom:
        secretKeyRef:
          name: redis-secret
          key: url
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 8
    targetCPUUtilizationPercentage: 75

# Order Service
orderService:
  enabled: true
  replicaCount: 2
  image:
    repository: myregistry/order-service
    tag: "2.0.0"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 3002
    targetPort: 3002
  env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: postgres-secret
          key: url
    - name: USER_SERVICE_URL
      value: "http://user-service:3001"
    - name: NOTIFICATION_SERVICE_URL
      value: "http://notification-service:3003"
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 6
    targetCPUUtilizationPercentage: 70

# Payment Service
paymentService:
  enabled: true
  replicaCount: 2
  image:
    repository: myregistry/payment-service
    tag: "2.0.0"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 3004
    targetPort: 3004
  env:
    - name: DATABASE_URL
      valueFrom:
        secretKeyRef:
          name: postgres-secret
          key: url
    - name: STRIPE_API_KEY
      valueFrom:
        secretKeyRef:
          name: payment-secrets
          key: stripe-key
  resources:
    limits:
      cpu: 200m
      memory: 256Mi
    requests:
      cpu: 100m
      memory: 128Mi

# Notification Service
notificationService:
  enabled: true
  replicaCount: 1
  image:
    repository: myregistry/notification-service
    tag: "2.0.0"
    pullPolicy: IfNotPresent
  service:
    type: ClusterIP
    port: 3003
    targetPort: 3003
  env:
    - name: SMTP_HOST
      value: "smtp.example.com"
    - name: SMTP_USER
      valueFrom:
        secretKeyRef:
          name: smtp-secrets
          key: username
    - name: SMTP_PASSWORD
      valueFrom:
        secretKeyRef:
          name: smtp-secrets
          key: password

# PostgreSQL Configuration
postgresql:
  enabled: true
  auth:
    postgresPassword: "postgres123"
    username: "microservices"
    password: "microservices123"
    database: "microservices"
  primary:
    persistence:
      enabled: true
      size: 20Gi
      storageClass: fast-ssd
    resources:
      limits:
        cpu: 1000m
        memory: 2Gi
      requests:
        cpu: 500m
        memory: 1Gi
  readReplicas:
    replicaCount: 2
    persistence:
      enabled: true
      size: 20Gi

# Redis Configuration
redis:
  enabled: true
  auth:
    enabled: true
    password: "redis123"
  master:
    persistence:
      enabled: true
      size: 8Gi
    resources:
      limits:
        cpu: 500m
        memory: 512Mi
  replica:
    replicaCount: 2
    persistence:
      enabled: true
      size: 8Gi

# Elasticsearch Configuration
elasticsearch:
  enabled: false
  replicas: 3
  minimumMasterNodes: 2
  volumeClaimTemplate:
    accessModes: ["ReadWriteOnce"]
    resources:
      requests:
        storage: 30Gi
  resources:
    limits:
      cpu: 1000m
      memory: 2Gi
    requests:
      cpu: 500m
      memory: 1Gi

# Monitoring Configuration
monitoring:
  enabled: true
  prometheus:
    enabled: true
    serviceMonitor:
      enabled: true
      namespace: monitoring
      labels:
        release: prometheus
      interval: 30s
      scrapeTimeout: 10s
  grafana:
    enabled: false
    service:
      type: LoadBalancer
      port: 3000

# Jaeger Tracing
jaeger:
  enabled: false
  provisionDataStore:
    cassandra: false
    elasticsearch: true
  elasticsearch:
    client:
      url: "http://elasticsearch:9200"

# Service Mesh (Istio)
istio:
  enabled: false
  gateways:
    enabled: true
    hosts:
      - api.example.com
  virtualServices:
    enabled: true
  destinationRules:
    enabled: true

# 3. templates/_helpers.tpl - Extended Helper Templates
{{/*
Common labels for microservices
*/}}
{{- define "microservices-app.labels" -}}
helm.sh/chart: {{ include "microservices-app.chart" . }}
{{ include "microservices-app.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels for microservices
*/}}
{{- define "microservices-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "microservices-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: {{ .component | default "service" }}
{{- end }}

{{/*
Service name for microservices
*/}}
{{- define "microservices-app.serviceName" -}}
{{- $component := .component -}}
{{- $fullName := include "microservices-app.fullname" . -}}
{{- if eq $component "gateway" -}}
{{- $fullName -}}
{{- else -}}
{{- printf "%s-%s" $fullName $component -}}
{{- end -}}
{{- end }}

{{/*
Database connection URL
*/}}
{{- define "microservices-app.databaseURL" -}}
{{- if .Values.postgresql.enabled -}}
postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ .Release.Name }}-postgresql.{{ .Release.Namespace }}.svc.cluster.local:5432/{{ .Values.postgresql.auth.database }}
{{- else -}}
{{- .Values.externalDatabase.url | default "" -}}
{{- end -}}
{{- end }}

{{/*
Redis connection URL
*/}}
{{- define "microservices-app.redisURL" -}}
{{- if .Values.redis.enabled -}}
redis://:{{ .Values.redis.auth.password }}@{{ .Release.Name }}-redis-master.{{ .Release.Namespace }}.svc.cluster.local:6379/{{ .Values.redis.database | default "0" }}
{{- else -}}
{{- .Values.externalRedis.url | default "" -}}
{{- end -}}
{{- end }}

# 4. templates/gateway/deployment.yaml
{{- if .Values.gateway.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "microservices-app.fullname" . }}-gateway
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
    app.kubernetes.io/component: gateway
spec:
  replicas: {{ .Values.gateway.replicaCount }}
  selector:
    matchLabels:
      {{- include "microservices-app.selectorLabels" . | nindent 6 }}
      app.kubernetes.io/component: gateway
  template:
    metadata:
      labels:
        {{- include "microservices-app.selectorLabels" . | nindent 8 }}
        app.kubernetes.io/component: gateway
      annotations:
        checksum/config: {{ include (print $.Template.BasePath "/gateway/configmap.yaml") . | sha256sum }}
    spec:
      containers:
        - name: gateway
          image: "{{ .Values.gateway.image.repository }}:{{ .Values.gateway.image.tag }}"
          imagePullPolicy: {{ .Values.gateway.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5
          env:
            {{- range .Values.gateway.env }}
            - name: {{ .name }}
              value: {{ .value | quote }}
            {{- end }}
            - name: USER_SERVICE_URL
              value: "http://{{ include "microservices-app.serviceName" (dict "component" "userService" "context" $) }}:{{ .Values.userService.service.port }}"
            - name: ORDER_SERVICE_URL
              value: "http://{{ include "microservices-app.serviceName" (dict "component" "orderService" "context" $) }}:{{ .Values.orderService.service.port }}"
            - name: PAYMENT_SERVICE_URL
              value: "http://{{ include "microservices-app.serviceName" (dict "component" "paymentService" "context" $) }}:{{ .Values.paymentService.service.port }}"
            - name: NOTIFICATION_SERVICE_URL
              value: "http://{{ include "microservices-app.serviceName" (dict "component" "notificationService" "context" $) }}:{{ .Values.notificationService.service.port }}"
          resources:
            {{- toYaml .Values.common.resources | nindent 12 }}
          volumeMounts:
            - name: config
              mountPath: /app/config
              readOnly: true
      volumes:
        - name: config
          configMap:
            name: {{ include "microservices-app.fullname" . }}-gateway
{{- end }}

# 5. templates/gateway/service.yaml
{{- if .Values.gateway.enabled }}
apiVersion: v1
kind: Service
metadata:
  name: {{ include "microservices-app.serviceName" (dict "component" "gateway" "context" .) }}
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
    app.kubernetes.io/component: gateway
  {{- with .Values.gateway.service.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  type: {{ .Values.gateway.service.type }}
  ports:
    - port: {{ .Values.gateway.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "microservices-app.selectorLabels" . | nindent 4 }}
    app.kubernetes.io/component: gateway
{{- end }}

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

# 7. templates/shared/secrets.yaml
apiVersion: v1
kind: Secret
metadata:
  name: postgres-secret
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
type: Opaque
data:
  url: {{ include "microservices-app.databaseURL" . | b64enc | quote }}

---
apiVersion: v1
kind: Secret
metadata:
  name: redis-secret
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
type: Opaque
data:
  url: {{ include "microservices-app.redisURL" . | b64enc | quote }}

---
apiVersion: v1
kind: Secret
metadata:
  name: payment-secrets
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
type: Opaque
data:
  stripe-key: {{ .Values.paymentService.stripeApiKey | default "" | b64enc | quote }}

---
apiVersion: v1
kind: Secret
metadata:
  name: smtp-secrets
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
type: Opaque
data:
  username: {{ .Values.notificationService.smtpUsername | default "" | b64enc | quote }}
  password: {{ .Values.notificationService.smtpPassword | default "" | b64enc | quote }}

# 8. templates/monitoring/servicemonitor.yaml
{{- if .Values.monitoring.enabled }}
{{- range $service := list "gateway" "userService" "orderService" "paymentService" "notificationService" }}
{{- if (index $.Values $service "enabled") }}
---
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: {{ include "microservices-app.fullname" $ }}-{{ $service }}
  labels:
    {{- include "microservices-app.labels" $ | nindent 4 }}
    app.kubernetes.io/component: {{ $service }}
  {{- with $.Values.monitoring.prometheus.serviceMonitor.labels }}
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
  selector:
    matchLabels:
      {{- include "microservices-app.selectorLabels" $ | nindent 6 }}
      app.kubernetes.io/component: {{ $service }}
  namespaceSelector:
    any: true
  endpoints:
    - port: http
      interval: {{ $.Values.monitoring.prometheus.serviceMonitor.interval }}
      scrapeTimeout: {{ $.Values.monitoring.prometheus.serviceMonitor.scrapeTimeout }}
      path: /metrics
{{- end }}
{{- end }}
{{- end }}

# 9. templates/istio/gateway.yaml (if Istio enabled)
{{- if .Values.istio.enabled }}
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: {{ include "microservices-app.fullname" . }}-gateway
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    {{- range .Values.istio.gateways.hosts }}
    - {{ . }}
    {{- end }}
  - port:
      number: 443
      name: https
      protocol: HTTPS
    tls:
      mode: SIMPLE
      credentialName: {{ include "microservices-app.fullname" . }}-tls
    hosts:
    {{- range .Values.istio.gateways.hosts }}
    - {{ . }}
    {{- end }}

---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: {{ include "microservices-app.fullname" . }}
  labels:
    {{- include "microservices-app.labels" . | nindent 4 }}
spec:
  hosts:
  {{- range .Values.istio.gateways.hosts }}
  - {{ . }}
  {{- end }}
  gateways:
  - {{ include "microservices-app.fullname" . }}-gateway
  http:
  - match:
    - uri:
        prefix: /api/users
    rewrite:
      uri: /
    route:
    - destination:
        host: {{ include "microservices-app.serviceName" (dict "component" "userService" "context" .) }}
        port:
          number: {{ .Values.userService.service.port }}
  - match:
    - uri:
        prefix: /api/orders
    rewrite:
      uri: /
    route:
    - destination:
        host: {{ include "microservices-app.serviceName" (dict "component" "orderService" "context" .) }}
        port:
          number: {{ .Values.orderService.service.port }}
  - match:
    - uri:
        prefix: /api/payments
    rewrite:
      uri: /
    route:
    - destination:
        host: {{ include "microservices-app.serviceName" (dict "component" "paymentService" "context" .) }}
        port:
          number: {{ .Values.paymentService.service.port }}
{{- end }}

# 10. Chart.lock (dependency lock file)
dependencies:
- name: postgresql
  version: 12.1.9
  repository: https://charts.bitnami.com/bitnami
  condition: postgresql.enabled
- name: redis
  version: 17.3.7
  repository: https://charts.bitnami.com/bitnami
  condition: redis.enabled
- name: elasticsearch
  version: 19.5.0
  repository: https://charts.bitnami.com/bitnami
  condition: elasticsearch.enabled
digest: sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

💻 Helm Chart d'Entreprise Avancé

🔴 complex ⭐⭐⭐⭐⭐

Helm chart prêt pour production avec sécurité, conformité, monitoring et support multi-environnement

⏱️ 45 min 🏷️ helm, enterprise, security, compliance, production
Prerequisites: Advanced Helm, Enterprise security, Compliance standards, Multi-environment deployment
# Enterprise-Grade Helm Chart
# Production-ready with security, compliance, and multi-environment support

# 1. Chart.yaml
apiVersion: v2
name: enterprise-app
description: Production-ready enterprise application Helm chart
type: application
version: 3.0.0
appVersion: "3.0.0"
home: https://github.company.com/enterprise-app
sources:
  - https://github.company.com/enterprise-app
dependencies:
  - name: postgresql
    version: 12.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: postgresql.enabled
  - name: redis
    version: 17.x.x
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled
  - name: keycloak
    version: 18.x.x
    repository: https://codecentric.github.io/helm-charts
    condition: keycloak.enabled
  - name: prometheus-operator
    version: 45.x.x
    repository: https://prometheus-community.github.io/helm-charts
    condition: monitoring.prometheus.enabled
  - name: elasticsearch
    version: 19.x.x
    repository: https://helm.elastic.co
    condition: logging.elasticsearch.enabled

# 2. values.yaml
# Global settings
global:
  # Environment (dev, staging, prod)
  environment: production

  # Image registry and pull policy
  imageRegistry: "registry.company.com"
  imagePullSecrets:
    - name: registry-secret
  imagePullPolicy: IfNotPresent

  # Common labels and annotations
  labels:
    team: platform
    cost-center: engineering
    compliance-level: high

  annotations:
    contact: [email protected]
    cost-optimization: enabled

  # Resource defaults
  resources:
    default:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 512Mi
    small:
      requests:
        cpu: 50m
        memory: 64Mi
      limits:
        cpu: 200m
        memory: 256Mi
    medium:
      requests:
        cpu: 250m
        memory: 256Mi
      limits:
        cpu: 1000m
        memory: 1Gi
    large:
      requests:
        cpu: 500m
        memory: 512Mi
      limits:
        cpu: 2000m
        memory: 2Gi

# Application Configuration
app:
  name: enterprise-app

  # Repository and image configuration
  image:
    repository: enterprise-app
    tag: "3.0.0"
    pullPolicy: IfNotPresent

  # Deployment configuration
  replicaCount: 3

  # Resource class (small, medium, large)
  resourceClass: medium

  # Environment-specific configurations
  environments:
    dev:
      replicaCount: 1
      resourceClass: small
      debug: true
    staging:
      replicaCount: 2
      resourceClass: medium
      debug: false
    prod:
      replicaCount: 5
      resourceClass: large
      debug: false
      priorityClassName: high-priority

# Security Configuration
security:
  # Pod Security Standards
  podSecurityPolicy:
    enabled: true
    privileged: false
    allowPrivilegeEscalation: false
    readOnlyRootFilesystem: true
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    capabilities:
      drop:
      - ALL

  # Network policies
  networkPolicy:
    enabled: true
    ingress:
    - from:
      - namespaceSelector:
          matchLabels:
            name: ingress-nginx
    - from:
      - namespaceSelector:
          matchLabels:
            name: monitoring
    egress:
    - to: []
    - to: []
      ports:
      - protocol: TCP
        port: 53
      - protocol: UDP
        port: 53

  # RBAC
  rbac:
    enabled: true
    serviceAccount:
      create: true
      name: ""
      annotations:
        iam.amazonaws.com/role: "arn:aws:iam::123456789012:role/enterprise-app-role"

  # Admission controllers
  admissionWebhooks:
    enabled: true
    validatePodSecurity: true
    enforceResourceQuotas: true

# High Availability
highAvailability:
  # Pod disruption budget
  podDisruptionBudget:
    enabled: true
    minAvailable: 2
    maxUnavailable: 1

  # Anti-affinity rules
  antiAffinity:
    enabled: true
    type: hard  # soft or hard
    topologyKey: kubernetes.io/hostname

  # Zone distribution
  zoneDistribution:
    enabled: true
    zones:
    - us-west-2a
    - us-west-2b
    - us-west-2c

# Autoscaling
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70
  targetMemoryUtilizationPercentage: 80
  behavior:
    scaleDown:
      stabilizationWindowSeconds: 300
      policies:
      - type: Percent
        value: 10
        periodSeconds: 60
    scaleUp:
      stabilizationWindowSeconds: 0
      policies:
      - type: Percent
        value: 100
        periodSeconds: 15
      - type: Pods
        value: 4
        periodSeconds: 15
      selectPolicy: Max

# Database Configuration
postgresql:
  enabled: true
  auth:
    postgresPassword: ""  # Use external secret
    username: enterpriseapp
    password: ""  # Use external secret
    database: enterpriseapp
  primary:
    persistence:
      enabled: true
      size: 100Gi
      storageClass: ssd-fast
      accessModes: ["ReadWriteOnce"]
    resources:
      requests:
        cpu: 1000m
        memory: 4Gi
      limits:
        cpu: 2000m
        memory: 8Gi
    configuration: |
      max_connections = 200
      shared_buffers = 1GB
      effective_cache_size = 3GB
      maintenance_work_mem = 256MB
      checkpoint_completion_target = 0.9
      wal_buffers = 16MB
      default_statistics_target = 100
      random_page_cost = 1.1
      effective_io_concurrency = 200
  readReplicas:
    replicaCount: 2
    persistence:
      enabled: true
      size: 100Gi
      storageClass: ssd-fast
    resources:
      requests:
        cpu: 500m
        memory: 2Gi
      limits:
        cpu: 1000m
        memory: 4Gi
  backup:
    enabled: true
    schedule: "0 2 * * *"  # Daily at 2 AM
    retention: "30d"
    storageClass: backup

# Redis Configuration
redis:
  enabled: true
  auth:
    enabled: true
    password: ""  # Use external secret
  master:
    persistence:
      enabled: true
      size: 20Gi
      storageClass: ssd-fast
    resources:
      requests:
        cpu: 500m
        memory: 1Gi
      limits:
        cpu: 1000m
        memory: 2Gi
    configuration: |
      maxmemory 1gb
      maxmemory-policy allkeys-lru
      save 900 1
      save 300 10
      save 60 10000
  replica:
    replicaCount: 2
    persistence:
      enabled: true
      size: 20Gi
      storageClass: ssd-fast

# Authentication (Keycloak)
keycloak:
  enabled: true
  auth:
    adminUser: admin
    adminPassword: ""  # Use external secret
  postgresql:
    enabled: false
    externalDatabase:
      host: "{{ .Release.Name }}-postgresql"
      port: 5432
      user: "{{ .Values.postgresql.auth.username }}"
      password: "{{ .Values.postgresql.auth.password }}"
      database: keycloak
  resources:
    requests:
      cpu: 500m
      memory: 1Gi
    limits:
      cpu: 1000m
      memory: 2Gi
  extraEnv: |
    - name: JAVA_OPTS
      value: >-
        -Xms512m -Xmx1024m
        -XX:+UseG1GC
        -XX:+UseContainerSupport
        -XX:MaxRAMPercentage=75.0

# Monitoring
monitoring:
  prometheus:
    enabled: true
    serviceMonitor:
      enabled: true
      namespace: monitoring
      interval: 30s
      scrapeTimeout: 10s
      labels:
        team: platform
        environment: "{{ .Values.global.environment }}"
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/path: "/metrics"
        prometheus.io/port: "9090"
    rules:
      enabled: true
      alertingRules:
        - name: app-down
          expr: up{job="{{ .Release.Name }}"} == 0
          for: 1m
          labels:
            severity: critical
            team: platform
          annotations:
            summary: "{{ .Release.Name }} is down"
            description: "{{ .Release.Name }} has been down for more than 1 minute."

  grafana:
    enabled: true
    service:
      type: LoadBalancer
      port: 3000
    adminPassword: ""  # Use external secret
    dashboards:
      enabled: true
      default:
        - enterprise-app-overview
        - enterprise-app-performance

  jaeger:
    enabled: true
    provisionDataStore:
      cassandra: false
      elasticsearch: true
    elasticsearch:
      client:
        url: "http://elasticsearch:9200"
    agent:
      enabled: true
    collector:
      enabled: true
      resources:
        requests:
          cpu: 100m
          memory: 256Mi
        limits:
          cpu: 500m
          memory: 1Gi

# Logging
logging:
  elasticsearch:
    enabled: true
    replicas: 3
    volumeClaimTemplate:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 50Gi
    resources:
      requests:
        cpu: 1000m
        memory: 2Gi
      limits:
        cpu: 2000m
        memory: 4Gi
    minimumMasterNodes: 2

  kibana:
    enabled: true
    resources:
      requests:
        cpu: 250m
        memory: 512Mi
      limits:
        cpu: 500m
        memory: 1Gi
    elasticsearchHosts: "http://elasticsearch:9200"

  logstash:
    enabled: false
    replicas: 1
    resources:
      requests:
        cpu: 250m
        memory: 512Mi
      limits:
        cpu: 500m
        memory: 1Gi

  fluentd:
    enabled: true
    resources:
      requests:
        cpu: 100m
        memory: 200Mi
      limits:
        cpu: 200m
        memory: 400Mi

# Cost Optimization
costOptimization:
  # Spot instances (for non-critical workloads)
  spotInstances:
    enabled: false
    tolerations:
    - key: "spot-instance"
      operator: "Equal"
      value: "true"
      effect: "NoSchedule"
    nodeSelector:
      node-lifecycle: spot

  # Resource requests optimization
  rightSizing:
    enabled: true
    recommendations: true
    autoApply: false  # Manual review required

  # Scaledown for non-working hours
  scheduledScaling:
    enabled: false
    timezone: "America/Los_Angeles"
    schedules:
    - name: business-hours
      start: "08:00"
      end: "18:00"
      days: ["monday", "tuesday", "wednesday", "thursday", "friday"]
      minReplicas: 2
      maxReplicas: 10
    - name: after-hours
      start: "18:01"
      end: "07:59"
      days: ["monday", "tuesday", "wednesday", "thursday", "friday"]
      minReplicas: 1
      maxReplicas: 3

# Backup and Disaster Recovery
backup:
  enabled: true
  schedule: "0 2 * * *"  # Daily at 2 AM
  retention: "30d"
  storage:
    type: s3
    s3:
      bucket: "company-backups"
      region: "us-west-2"
      prefix: "enterprise-app"
      storageClass: "STANDARD_IA"
  encryption:
    enabled: true
    type: AES256

  disasterRecovery:
    enabled: true
    crossRegion:
      enabled: true
      sourceRegion: "us-west-2"
      targetRegion: "us-east-1"
      targetBucket: "company-backups-dr"

# Compliance and Auditing
compliance:
  # PCI DSS compliance
  pci:
    enabled: true
    encryptionAtRest: true
    encryptionInTransit: true
    accessControl: true
    auditLogging: true

  # GDPR compliance
  gdpr:
    enabled: true
    dataRetention: "2555d"  # 7 years
    rightToErasure: true
    consentManagement: true

  # SOX compliance
  sox:
    enabled: true
    auditTrail: true
    changeManagement: true
    segregationOfDuties: true

  # HIPAA compliance (if applicable)
  hipaa:
    enabled: false
    phiEncryption: true
    accessLogs: true
    businessAssociateAgreement: true

# Environment-specific values
environments:
  dev:
    global:
      environment: dev
    app:
      replicaCount: 1
      resourceClass: small
    postgresql:
      primary:
        persistence:
          size: 10Gi
      readReplicas:
        replicaCount: 0
    monitoring:
      prometheus:
        enabled: false
    backup:
      enabled: false
    compliance:
      pci:
        enabled: false
      gdpr:
        enabled: false
      sox:
        enabled: false

  staging:
    global:
      environment: staging
    app:
      replicaCount: 2
      resourceClass: medium
    postgresql:
      primary:
        persistence:
          size: 50Gi
      readReplicas:
        replicaCount: 1
    backup:
      enabled: true
      schedule: "0 3 * * *"
    compliance:
      pci:
        enabled: true
      gdpr:
        enabled: true
      sox:
        enabled: false

  prod:
    global:
      environment: prod
    app:
      replicaCount: 5
      resourceClass: large
    postgresql:
      primary:
        persistence:
          size: 500Gi
      readReplicas:
        replicaCount: 3
    highAvailability:
      podDisruptionBudget:
        minAvailable: 3
      antiAffinity:
        type: hard
      zoneDistribution:
        enabled: true
    backup:
      enabled: true
      schedule: "0 1 * * *"
      retention: "90d"
    compliance:
      pci:
        enabled: true
      gdpr:
        enabled: true
      sox:
        enabled: true
    costOptimization:
      spotInstances:
        enabled: false
      scheduledScaling:
        enabled: true

# 3. Chart Templates (examples)
# templates/_helpers.tpl - Advanced helper functions
{{/*
Get resource limits based on class and environment
*/}}
{{- define "enterprise-app.resources" -}}
{{- $resourceClass := .Values.app.resourceClass | default "default" -}}
{{- $env := .Values.global.environment | default "dev" -}}
{{- $baseResources := index .Values.global.resources $resourceClass -}}
{{- $envConfig := index .Values.app.environments $env -}}
{{- $envResourceClass := $envConfig.resourceClass | default $resourceClass -}}
{{- $envResources := index .Values.global.resources $envResourceClass -}}
{{- $finalResources := dict -}}
{{- range $key, $value := $baseResources.requests -}}
{{- $_ := set $finalResources "requests" (dict $key (max ($value | int) (index ($envResources.requests | default dict) $key | int))) -}}
{{- end -}}
{{- range $key, $value := $baseResources.limits -}}
{{- $_ := set $finalResources "limits" (dict $key (max ($value | int) (index ($envResources.limits | default dict) $key | int))) -}}
{{- end -}}
{{- toYaml $finalResources -}}
{{- end }}

{{/*
Generate security context based on compliance requirements
*/}}
{{- define "enterprise-app.securityContext" -}}
{{- $securityContext := .Values.security.podSecurityPolicy -}}
{{- if .Values.compliance.pci.enabled -}}
{{- $_ := set $securityContext "readOnlyRootFilesystem" true -}}
{{- $_ := set $securityContext "runAsNonRoot" true -}}
{{- $_ := set $securityContext "capabilities" (dict "drop" (list "ALL")) -}}
{{- end -}}
{{- toYaml $securityContext -}}
{{- end }}

{{/*
Generate affinity rules for high availability
*/}}
{{- define "enterprise-app.affinity" -}}
{{- if .Values.highAvailability.antiAffinity.enabled -}}
{{- $antiAffinity := .Values.highAvailability.antiAffinity -}}
{{- if eq $antiAffinity.type "hard" -}}
podAntiAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
  - labelSelector:
      matchLabels:
        {{- include "enterprise-app.selectorLabels" . | nindent 8 }}
    topologyKey: {{ $antiAffinity.topologyKey | default "kubernetes.io/hostname" }}
{{- else -}}
podAntiAffinity:
  preferredDuringSchedulingIgnoredDuringExecution:
  - weight: 100
    podAffinityTerm:
      labelSelector:
        matchLabels:
          {{- include "enterprise-app.selectorLabels" . | nindent 10 }}
      topologyKey: {{ $antiAffinity.topologyKey | default "kubernetes.io/hostname" }}
{{- end -}}
{{- if .Values.highAvailability.zoneDistribution.enabled -}}
nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchExpressions:
      - key: topology.kubernetes.io/zone
        operator: In
        values: {{ .Values.highAvailability.zoneDistribution.zones | toYaml }}
{{- end -}}
{{- end -}}
{{- end }}

{{/*
Generate compliance annotations
*/}}
{{- define "enterprise-app.complianceAnnotations" -}}
{{- $annotations := dict -}}
{{- if .Values.compliance.pci.enabled -}}
{{- $_ := set $annotations "pci-dss.compliance" "enabled" -}}
{{- $_ := set $annotations "pci-dss.version" "4.0" -}}
{{- end -}}
{{- if .Values.compliance.gdpr.enabled -}}
{{- $_ := set $annotations "gdpr.compliance" "enabled" -}}
{{- $_ := set $annotations "data-retention.days" .Values.compliance.gdpr.dataRetention -}}
{{- end -}}
{{- if .Values.compliance.sox.enabled -}}
{{- $_ := set $annotations "sox.compliance" "enabled" -}}
{{- $_ := set $annotations "audit-trail" "enabled" -}}
{{- end -}}
{{- toYaml $annotations -}}
{{- end }}

# 4. Templates for advanced features
# templates/security/networkpolicy.yaml
{{- if .Values.security.networkPolicy.enabled }}
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: {{ include "enterprise-app.fullname" . }}
  labels:
    {{- include "enterprise-app.labels" . | nindent 4 }}
spec:
  podSelector:
    matchLabels:
      {{- include "enterprise-app.selectorLabels" . | nindent 6 }}
  policyTypes:
  - Ingress
  - Egress
  ingress:
  {{- range .Values.security.networkPolicy.ingress }}
  - from:
    {{- toYaml .from | nindent 6 }}
  {{- if .ports }}
    ports:
    {{- toYaml .ports | nindent 6 }}
  {{- end }}
  {{- end }}
  egress:
  {{- range .Values.security.networkPolicy.egress }}
  - to:
    {{- toYaml .to | nindent 6 }}
  {{- if .ports }}
    ports:
    {{- toYaml .ports | nindent 6 }}
  {{- end }}
  {{- end }}
{{- end }}

# templates/cost-optimization/scheduled-scaling.yaml
{{- if .Values.costOptimization.scheduledScaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: {{ include "enterprise-app.fullname" . }}-scheduled
  labels:
    {{- include "enterprise-app.labels" . | nindent 4 }}
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: {{ include "enterprise-app.fullname" . }}
  minReplicas: {{ .Values.costOptimization.scheduledScaling.schedules[0].minReplicas }}
  maxReplicas: {{ .Values.costOptimization.scheduledScaling.schedules[0].maxReplicas }}
  metrics:
  - type: External
    external:
      metric:
        name: scheduled_replicas
      target:
        type: AverageValue
        averageValue: "1"
{{- end }}

# templates/compliance/audit-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ include "enterprise-app.fullname" . }}-audit-config
  labels:
    {{- include "enterprise-app.labels" . | nindent 4 }}
  annotations:
    {{- include "enterprise-app.complianceAnnotations" . | nindent 4 }}
data:
  audit.conf: |
    # Audit configuration
    log_level: {{ .Values.global.environment | default "production" }}
    audit_enabled: {{ .Values.compliance.sox.auditTrail | default "true" }}
    encryption_at_rest: {{ .Values.compliance.pci.encryptionAtRest | default "true" }}
    data_retention_days: {{ .Values.compliance.gdpr.dataRetention | default "2555" }}

    # PCI DSS requirements
    pci_compliance: {{ .Values.compliance.pci.enabled | default "false" }}
    encryption_in_transit: {{ .Values.compliance.pci.encryptionInTransit | default "true" }}

    # Access control
    rbac_enabled: {{ .Values.security.rbac.enabled | default "true" }}
    mfa_required: {{ .Values.compliance.sox.segregationOfDuties | default "true" }}

# templates/disaster-recovery/restore-job.yaml
{{- if .Values.backup.disasterRecovery.enabled }}
apiVersion: batch/v1
kind: Job
metadata:
  name: {{ include "enterprise-app.fullname" . }}-disaster-recovery
  labels:
    {{- include "enterprise-app.labels" . | nindent 4 }}
    app.kubernetes.io/component: disaster-recovery
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-weight": "1"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    metadata:
      labels:
        {{- include "enterprise-app.selectorLabels" . | nindent 8 }}
        app.kubernetes.io/component: disaster-recovery
    spec:
      restartPolicy: Never
      containers:
      - name: disaster-recovery
        image: "registry.company.com/disaster-recovery:latest"
        command:
        - /bin/bash
        - -c
        - |
          echo "Starting disaster recovery process..."

          # Restore from cross-region backup
          aws s3 sync s3://{{ .Values.backup.storage.s3.bucket }}-dr/enterprise-app/             s3://{{ .Values.backup.storage.s3.bucket }}/enterprise-app/             --region {{ .Values.backup.storage.s3.region }}

          # Restore database
          pg_restore -h {{ .Release.Name }}-postgresql             -U {{ .Values.postgresql.auth.username }}             -d {{ .Values.postgresql.auth.database }}             /tmp/latest-backup.sql

          echo "Disaster recovery completed successfully!"
        env:
        - name: AWS_DEFAULT_REGION
          value: {{ .Values.backup.storage.s3.region | quote }}
        resources:
          requests:
            cpu: 500m
            memory: 1Gi
          limits:
            cpu: 1000m
            memory: 2Gi
{{- end }}

# 5. Environment-specific values files
# values-dev.yaml
global:
  environment: dev
  imagePullPolicy: Always

app:
  replicaCount: 1
  resourceClass: small

postgresql:
  primary:
    persistence:
      size: 10Gi
  readReplicas:
    replicaCount: 0

monitoring:
  prometheus:
    enabled: false

backup:
  enabled: false

compliance:
  pci:
    enabled: false
  gdpr:
    enabled: false
  sox:
    enabled: false

# values-prod.yaml
global:
  environment: prod
  imagePullPolicy: IfNotPresent

app:
  replicaCount: 5
  resourceClass: large

highAvailability:
  podDisruptionBudget:
    minAvailable: 3
  antiAffinity:
    type: hard
  zoneDistribution:
    enabled: true
    zones:
    - us-west-2a
    - us-west-2b
    - us-west-2c

postgresql:
  primary:
    persistence:
      size: 500Gi
  readReplicas:
    replicaCount: 3

backup:
  enabled: true
  schedule: "0 1 * * *"
  retention: "90d"

compliance:
  pci:
    enabled: true
  gdpr:
    enabled: true
  sox:
    enabled: true

costOptimization:
  spotInstances:
    enabled: false
  scheduledScaling:
    enabled: true