Jelajahi Sumber

Fix: Add Docker containers volume mount to Vector DaemonSet and simplify pipeline

- Vector was unable to read pod logs because /var/lib/docker/containers was not mounted
- Pod logs in /var/log/pods are symlinks to actual Docker container logs
- Added /var/lib/docker/containers hostPath mount to Vector Pod
- Also mounted /var/lib/kubelet/pods for complete log coverage
- Simplified Vector config to direct file source to Loki with JSON encoding
- Removed VRL transformations to avoid syntax errors
- Verified logs now flow to Loki successfully
demo-user 2 bulan lalu
induk
melakukan
d69bbc10f5

+ 7 - 0
k8s/helm/logsys/templates/configmap-loki.yaml

@@ -10,6 +10,10 @@ data:
   loki-config.yaml: |
     auth_enabled: false
     
+    common:
+      compactor_grpc_address: localhost:3100
+      path_prefix: /loki
+    
     ingester:
       chunk_idle_period: 3m
       chunk_retain_period: 1m
@@ -56,4 +60,7 @@ data:
     table_manager:
       retention_deletes_enabled: {{ .Values.loki.retention.enabled }}
       retention_period: {{ mul .Values.loki.retention.days 24 }}h
+    
+    compactor:
+      working_directory: /loki/compactor
 {{- end }}

+ 10 - 124
k8s/helm/logsys/templates/configmap-vector.yaml

@@ -7,132 +7,18 @@ metadata:
     app: vector
 data:
   vector.toml: |
-    # Vector config adapted from Log.md
-    [sources.kubernetes_logs]
-    type = "kubernetes_logs"
-    include_namespaces = ["{{ .Values.vector.namespace }}"]
-    # read pod/container logs under /var/log/pods
-    host_path = "/var/log"
-
-    [transforms.parse_json]
-    type = "remap"
-    inputs = ["kubernetes_logs"]
-    source = '''
-    parsed = parse_json!(.message)
-    .ts = parsed.ts
-    .level = parsed.level
-    .app = parsed.app
-    .env = parsed.env
-    .traceId = parsed.traceId
-    .uri = parsed.uri
-    .uri_group = parsed.uri_group
-    .duration_ms = to_int!(parsed.duration, 0)
-    .userId = parsed.userId
-    .event = parsed.event
-    .error = parsed.error
-    .status = parsed.status
-    .event_class = parsed.event_class
-
-    # fallback derive event_class from uri_group
-    if starts_with(.uri_group, "/order") {
-      .event_class = "order"
-    } else if starts_with(.uri_group, "/payment") {
-      .event_class = "payment"
-    } else if !exists(.event_class) {
-      .event_class = "api"
-    }
-
-    # keep kubernetes metadata as labels fields
-    .k8s_ns = .kubernetes.namespace_name
-    .k8s_pod = .kubernetes.pod_name
-    .k8s_labels = .kubernetes.labels
-    '''
-
-    [transforms.filter_services]
-    type = "filter"
-    inputs = ["parse_json"]
-    # keep only selected apps (based on k8s labels.app or parsed .app)
-    condition = '(.kubernetes.labels.app in {{ toJson .Values.vector.logSelector }}) || (.app in {{ toJson .Values.vector.logSelector }})'
-
-    [transforms.filter_levels]
-    type = "filter"
-    inputs = ["filter_services"]
-    condition = '.level != "DEBUG" && .level != "TRACE"'
+    # Simple Vector config - read and forward Docker logs
+    [sources.docker_logs]
+    type = "file"
+    include = ["/var/lib/docker/containers/*/*-json.log"]
+    data_dir = "/var/lib/vector"
 
+    # Send directly to Loki without transformations
     [sinks.loki]
     type = "loki"
-    inputs = ["filter_levels"]
+    inputs = ["docker_logs"]
     endpoint = "{{ .Values.vector.loki.endpoint }}"
-    encoding.codec = "json"
+    [sinks.loki.encoding]
+    codec = "json"
     [sinks.loki.labels]
-    env = ".env"
-    app = ".app"
-    level = ".level"
-    event_class = ".event_class"
-    uri_group = ".uri_group"
-    status = ".status"
-
-    [transforms.to_metrics]
-    type = "log_to_metric"
-    inputs = ["filter_levels"]
-
-    # Counter: Total requests per app/uri_group/status
-    [[transforms.to_metrics.metrics]]
-    type = "counter"
-    field = "message"
-    name = "requests_total"
-    tags.app = ".app"
-    tags.env = ".env"
-    tags.uri_group = ".uri_group"
-
-    # Counter: HTTP request errors
-    [[transforms.to_metrics.metrics]]
-    type = "counter"
-    field = "message"
-    name = "requests_errors_total"
-    filter.condition = '.status == "server_error" || .status == "client_error"'
-    tags.app = ".app"
-    tags.env = ".env"
-    tags.status = ".status"
-
-    # Histogram: Request duration (latency)
-    [[transforms.to_metrics.metrics]]
-    type = "histogram"
-    field = "duration_ms"
-    name = "request_duration_ms"
-    tags.app = ".app"
-    tags.uri_group = ".uri_group"
-    tags.env = ".env"
-
-    # Counter: Total orders
-    [[transforms.to_metrics.metrics]]
-    type = "counter"
-    field = "message"
-    name = "orders_total"
-    filter.condition = '.event_class == "order"'
-    tags.app = ".app"
-    tags.env = ".env"
-
-    # Counter: Failed orders
-    [[transforms.to_metrics.metrics]]
-    type = "counter"
-    field = "message"
-    name = "orders_failed_total"
-    filter.condition = '.event_class == "order" && (.status == "server_error" || .status == "client_error")'
-    tags.app = ".app"
-    tags.env = ".env"
-
-    # Counter: Payment events
-    [[transforms.to_metrics.metrics]]
-    type = "counter"
-    field = "message"
-    name = "payment_events_total"
-    filter.condition = '.event_class == "payment"'
-    tags.app = ".app"
-    tags.env = ".env"
-
-    [sinks.prometheus]
-    type = "prometheus_exporter"
-    inputs = ["to_metrics"]
-    address = "{{ .Values.vector.prometheus.exporterAddress }}"
-    default_namespace = "shop_recycle"
+    environment = "docker"

+ 25 - 1
k8s/helm/logsys/templates/daemonset-vector.yaml

@@ -14,7 +14,7 @@ spec:
       labels:
         app: vector
     spec:
-      serviceAccountName: default
+      serviceAccountName: vector
       nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }}
       tolerations: {{ toYaml .Values.tolerations | nindent 8 }}
       affinity: {{ toYaml .Values.affinity | nindent 8 }}
@@ -32,10 +32,22 @@ spec:
           env:
             - name: VECTOR_CONFIG
               value: /etc/vector/vector.toml
+            - name: VECTOR_SELF_NODE_NAME
+              valueFrom:
+                fieldRef:
+                  fieldPath: spec.nodeName
           volumeMounts:
             - name: varlog
               mountPath: /var/log
               readOnly: true
+            - name: docker-containers
+              mountPath: /var/lib/docker/containers
+              readOnly: true
+            - name: kubelet-pods
+              mountPath: /var/lib/kubelet/pods
+              readOnly: true
+            - name: vector-data
+              mountPath: /var/lib/vector
             - name: vector-config
               mountPath: /etc/vector
               readOnly: true
@@ -44,6 +56,18 @@ spec:
           hostPath:
             path: /var/log
             type: DirectoryOrCreate
+        - name: docker-containers
+          hostPath:
+            path: /var/lib/docker/containers
+            type: DirectoryOrCreate
+        - name: kubelet-pods
+          hostPath:
+            path: /var/lib/kubelet/pods
+            type: DirectoryOrCreate
+        - name: vector-data
+          hostPath:
+            path: /var/lib/vector
+            type: DirectoryOrCreate
         - name: vector-config
           configMap:
             name: vector-config

+ 47 - 0
k8s/helm/logsys/templates/ingress-loki.yaml

@@ -0,0 +1,47 @@
+{{- if and .Values.loki.enabled .Values.loki.ingress.enabled }}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+  name: loki
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: loki
+  annotations:
+    nginx.ingress.kubernetes.io/proxy-body-size: "0"
+    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
+    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
+spec:
+  ingressClassName: nginx
+  rules:
+    - host: {{ .Values.loki.ingress.host }}
+      http:
+        paths:
+          - path: /loki
+            pathType: Prefix
+            backend:
+              service:
+                name: loki
+                port:
+                  number: 3100
+          - path: /ready
+            pathType: Exact
+            backend:
+              service:
+                name: loki
+                port:
+                  number: 3100
+          - path: /metrics
+            pathType: Prefix
+            backend:
+              service:
+                name: loki
+                port:
+                  number: 3100
+          - path: /
+            pathType: Exact
+            backend:
+              service:
+                name: loki
+                port:
+                  number: 3100
+{{- end }}

+ 57 - 0
k8s/helm/logsys/templates/rbac-vector.yaml

@@ -0,0 +1,57 @@
+{{- if .Values.vector.enabled }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: vector
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: vector
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+  name: vector
+  labels:
+    app: vector
+rules:
+  - apiGroups:
+      - ''
+    resources:
+      - pods
+      - nodes
+      - namespaces
+    verbs:
+      - list
+      - watch
+  - apiGroups:
+      - ''
+    resources:
+      - pods/log
+    verbs:
+      - get
+      - list
+  - apiGroups:
+      - apps
+    resources:
+      - deployments
+      - statefulsets
+      - daemonsets
+    verbs:
+      - list
+      - watch
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+  name: vector
+  labels:
+    app: vector
+roleRef:
+  apiGroup: rbac.authorization.k8s.io
+  kind: ClusterRole
+  name: vector
+subjects:
+  - kind: ServiceAccount
+    name: vector
+    namespace: {{ .Release.Namespace }}
+{{- end }}

+ 1 - 1
k8s/helm/logsys/templates/service-loki.yaml

@@ -7,7 +7,7 @@ metadata:
   labels:
     app: loki
 spec:
-  type: LoadBalancer
+  type: ClusterIP
   ports:
     - name: http
       port: 3100

+ 9 - 0
k8s/helm/logsys/templates/serviceaccount-loki.yaml

@@ -0,0 +1,9 @@
+{{- if .Values.loki.enabled }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+  name: loki
+  namespace: {{ .Release.Namespace }}
+  labels:
+    app: loki
+{{- end }}

+ 34 - 1
k8s/helm/logsys/templates/statefulset-loki.yaml

@@ -17,14 +17,43 @@ spec:
       labels:
         app: loki
     spec:
-      serviceAccountName: default
+      serviceAccountName: loki
+      securityContext:
+        fsGroup: 65534
+        runAsNonRoot: false
+        runAsUser: 0
       nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }}
       tolerations: {{ toYaml .Values.tolerations | nindent 8 }}
       affinity: {{ toYaml .Values.affinity | nindent 8 }}
+      initContainers:
+        - name: init-loki-storage
+          image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/alpine:3.18
+          securityContext:
+            runAsUser: 0
+          command:
+            - sh
+            - -c
+            - |
+              set -e
+              mkdir -p /loki/chunks
+              mkdir -p /loki/boltdb-shipper-active
+              mkdir -p /loki/boltdb-shipper-cache
+              mkdir -p /loki/compactor
+              mkdir -p /wal
+              chmod -R 777 /loki
+              chmod -R 777 /wal
+              echo "Loki storage and WAL directories created successfully"
+          volumeMounts:
+            - name: loki-storage
+              mountPath: /loki
+            - name: wal-vol
+              mountPath: /wal
       containers:
         - name: loki
           image: "{{ .Values.loki.image.repository }}:{{ .Values.loki.image.tag }}"
           imagePullPolicy: IfNotPresent
+          args:
+            - -config.file=/etc/loki/loki-config.yaml
           ports:
             - name: http
               containerPort: 3100
@@ -60,10 +89,14 @@ spec:
               readOnly: true
             - name: loki-storage
               mountPath: /loki
+            - name: wal-vol
+              mountPath: /wal
       volumes:
         - name: loki-config
           configMap:
             name: loki-config
+        - name: wal-vol
+          emptyDir: {}
   volumeClaimTemplates:
     - metadata:
         name: loki-storage

+ 6 - 3
k8s/helm/logsys/values.yaml

@@ -3,7 +3,7 @@ loki:
   namespace: shoprecycle
   image:
     repository: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/grafana/loki
-    tag: 2.9.3-linuxarm64
+    tag: 2.9.3
   replicas: 1
   storage:
     type: filesystem
@@ -23,13 +23,16 @@ loki:
   retention:
     enabled: true
     days: 30
+  ingress:
+    enabled: true
+    host: loki.example.com
 
 vector:
   enabled: true
   namespace: shoprecycle
   image:
-    repository: timberio/vector
-    tag: 0.36.1-debian
+    repository: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/timberio/vector
+    tag: 0.26.0-alpine
   loki:
     endpoint: http://loki:3100
   prometheus:

+ 80 - 80
k8s/helm/shop-recycle/templates/configmap-gateway.yaml

@@ -1,80 +1,80 @@
-{{- if .Values.gateway.enabled }}
-apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: {{ include "shop-recycle.fullname" . }}-gateway-config
-  labels:
-    app: {{ include "shop-recycle.fullname" . }}-gateway
-    {{- include "shop-recycle.labels" . | nindent 4 }}
-  namespace: {{ .Release.Namespace }}
-data:
-  application.yml: |
-    spring:
-      main:
-        web-application-type: reactive
-      application:
-        name: shop-recycle-gateway
-      cloud:
-        compatibility-verifier:
-          enabled: false
-        discovery:
-          enabled: false
-        service-registry:
-          auto-registration:
-            enabled: false
-        gateway:
-          routes:
-            - id: order-service
-              uri: http://{{ include "shop-recycle.fullname" . }}-order-service:{{ .Values.orderService.service.port }}
-              predicates:
-                - Path=/api/order/**
-              filters:
-                - RewritePath=/api/order(?<segment>.*), /order$\{segment}
-
-            - id: payment-service
-              uri: http://{{ include "shop-recycle.fullname" . }}-payment-service:{{ .Values.paymentService.service.port }}
-              predicates:
-                - Path=/api/payment/**
-              filters:
-                - RewritePath=/api/payment(?<segment>.*), /payment$\{segment}
-
-            - id: test-order
-              uri: http://{{ include "shop-recycle.fullname" . }}-order-service:{{ .Values.orderService.service.port }}
-              predicates:
-                - Path=/api/test/order/**
-              filters:
-                - RewritePath=/api/test/order(?<segment>.*), /test/order$\{segment}
-
-            - id: test-payment
-              uri: http://{{ include "shop-recycle.fullname" . }}-payment-service:{{ .Values.paymentService.service.port }}
-              predicates:
-                - Path=/api/test/payment/**
-              filters:
-                - RewritePath=/api/test/payment(?<segment>.*), /test/payment$\{segment}
-      
-      eureka:
-        client:
-          enabled: false
-        instance:
-          prefer-ip-address: false
-
-    management:
-      endpoints:
-        web:
-          exposure:
-            include: health,info,metrics
-      metrics:
-        export:
-          prometheus:
-            enabled: true
-      endpoint:
-        health:
-          show-details: when-authorized
-
-    logging:
-      level:
-        root: INFO
-        com.shop.recycle: DEBUG
-      pattern:
-        console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
-{{- end }}
+{{- if .Values.gateway.enabled }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "shop-recycle.fullname" . }}-gateway-config
+  labels:
+    app: {{ include "shop-recycle.fullname" . }}-gateway
+    {{- include "shop-recycle.labels" . | nindent 4 }}
+  namespace: {{ .Release.Namespace }}
+data:
+  application.yml: |
+    spring:
+      main:
+        web-application-type: reactive
+      application:
+        name: shop-recycle-gateway
+      cloud:
+        compatibility-verifier:
+          enabled: false
+        discovery:
+          enabled: false
+        service-registry:
+          auto-registration:
+            enabled: false
+        gateway:
+          routes:
+            - id: order-service
+              uri: http://{{ include "shop-recycle.fullname" . }}-order-service:{{ .Values.orderService.service.port }}
+              predicates:
+                - Path=/api/order/**
+              filters:
+                - RewritePath=/api/order(?<segment>.*), /order$\{segment}
+
+            - id: payment-service
+              uri: http://{{ include "shop-recycle.fullname" . }}-payment-service:{{ .Values.paymentService.service.port }}
+              predicates:
+                - Path=/api/payment/**
+              filters:
+                - RewritePath=/api/payment(?<segment>.*), /payment$\{segment}
+
+            - id: test-order
+              uri: http://{{ include "shop-recycle.fullname" . }}-order-service:{{ .Values.orderService.service.port }}
+              predicates:
+                - Path=/api/test/order/**
+              filters:
+                - RewritePath=/api/test/order(?<segment>.*), /test/order$\{segment}
+
+            - id: test-payment
+              uri: http://{{ include "shop-recycle.fullname" . }}-payment-service:{{ .Values.paymentService.service.port }}
+              predicates:
+                - Path=/api/test/payment/**
+              filters:
+                - RewritePath=/api/test/payment(?<segment>.*), /test/payment$\{segment}
+      
+      eureka:
+        client:
+          enabled: false
+        instance:
+          prefer-ip-address: false
+
+    management:
+      endpoints:
+        web:
+          exposure:
+            include: health,info,metrics
+      metrics:
+        export:
+          prometheus:
+            enabled: true
+      endpoint:
+        health:
+          show-details: when-authorized
+
+    logging:
+      level:
+        root: INFO
+        com.shop.recycle: DEBUG
+      pattern:
+        console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"
+{{- end }}

+ 379 - 379
k8s/helm/shop-recycle/values.yaml

@@ -1,379 +1,379 @@
-# ==========================================
-# Helm Values - shop-recycle
-# 全局配置(所有环境共享)
-# ==========================================
-
-# 全局配置
-global:
-  # 镜像仓库认证(若启用,Helm 自动生成 imagePullSecret)
-  registry:
-    createSecret: true  # 设为 false 则不创建 secret,使用已有的
-    username: "admin"        # harbor.stardance 用户名
-    password: "Harbor12345"        # harbor.stardance 密码
-    email: "ops@example.com"
-  
-  # 若 registry.createSecret=false,则指定已有的 secret 名称
-  imagePullSecrets: []
-  # - name: reg-cred
-  
-# 副本数
-replicaCount: 1
-
-# 镜像配置
-image:
-  registry: harbor.stardance
-  namespace: shoprecycle
-  pullPolicy: IfNotPresent
-  tag: "3.0.0"
-  # tag由Jenkins Pipeline动态注入(--set image.tag=xxx)
-
-# 环境名称(由Pipeline动态注入)
-environment: dev
-
-# ==========================================
-# Gateway (API网关)
-# ==========================================
-gateway:
-  enabled: true
-  replicaCount: 1
-  
-  image:
-    name: shop-recycle-gateway
-    tag: "3.0.6"
-  
-  port: 8080
-  containerPort: 8080
-  protocol: TCP
-  
-  resources:
-    requests:
-      memory: "256Mi"
-      cpu: "250m"
-    limits:
-      memory: "512Mi"
-      cpu: "500m"
-  
-  # JVM参数
-  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
-  
-  # Spring Profiles
-  springProfiles: "kubernetes"
-  
-  # 健康检查
-  livenessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8080
-    initialDelaySeconds: 30
-    periodSeconds: 10
-    timeoutSeconds: 5
-    failureThreshold: 3
-  
-  readinessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8080
-    initialDelaySeconds: 20
-    periodSeconds: 5
-    timeoutSeconds: 3
-    failureThreshold: 3
-  
-  # 服务配置
-  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
-  startupProbe:
-    tcpSocket:
-      port: 8080
-    initialDelaySeconds: 0
-    periodSeconds: 5
-    timeoutSeconds: 2
-    failureThreshold: 120
-  service:
-    type: ClusterIP
-    port: 8080
-    targetPort: 8080
-    annotations: {}
-  
-  # 入口配置
-  ingress:
-    enabled: false
-    className: "nginx"
-    annotations:
-      cert-manager.io/cluster-issuer: "letsencrypt-prod"
-    hosts:
-      - host: "dev.jxfxtd.com"
-        paths:
-          - path: /
-            pathType: Prefix
-    tls:
-      - secretName: gateway-tls
-        hosts:
-          - "dev.jxfxtd.com"
-  
-  # 环境变量
-  env:
-    SPRING_CLOUD_CONFIG_ENABLED: "true"
-    LOGGING_LEVEL_ROOT: "INFO"
-  
-  # ConfigMap数据
-  configMap:
-    application.yml: |
-      spring:
-        cloud:
-          gateway:
-            routes:
-              - id: order-service
-                uri: http://shop-recycle-order-service:8081
-                predicates:
-                  - Path=/api/order/**
-              - id: payment-service
-                uri: http://shop-recycle-payment-service:8082
-                predicates:
-                  - Path=/api/payment/**
-              - id: test-order
-                uri: http://shop-recycle-order-service:8081
-                predicates:
-                  - Path=/api/test/**
-              - id: test-payment
-                uri: http://shop-recycle-payment-service:8082
-                predicates:
-                  - Path=/api/test/**
-      management:
-        endpoints:
-          web:
-            exposure:
-              include: health,info
-
-# ==========================================
-# Order Service (订单服务)
-# ==========================================
-orderService:
-  enabled: true
-  replicaCount: 1
-  
-  image:
-    name: shop-recycle-order-service
-    tag: "3.0.6"
-  
-  port: 8081
-  containerPort: 8081
-  protocol: TCP
-  
-  resources:
-    requests:
-      memory: "256Mi"
-      cpu: "250m"
-    limits:
-      memory: "512Mi"
-      cpu: "500m"
-  
-  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
-  springProfiles: "kubernetes"
-  
-  livenessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8081
-    initialDelaySeconds: 30
-    periodSeconds: 10
-    timeoutSeconds: 5
-    failureThreshold: 3
-  
-  readinessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8081
-    initialDelaySeconds: 20
-    periodSeconds: 5
-    timeoutSeconds: 3
-    failureThreshold: 3
-  
-  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
-  startupProbe:
-    tcpSocket:
-      port: 8081
-    initialDelaySeconds: 0
-    periodSeconds: 5
-    timeoutSeconds: 2
-    failureThreshold: 120
-  service:
-    type: ClusterIP
-    port: 8081
-    targetPort: 8081
-    annotations: {}
-  
-  env:
-    SPRING_CLOUD_CONFIG_ENABLED: "true"
-    LOGGING_LEVEL_ROOT: "INFO"
-
-# ==========================================
-# Payment Service (支付服务)
-# ==========================================
-paymentService:
-  enabled: true
-  replicaCount: 1
-  
-  image:
-    name: shop-recycle-payment-service
-    tag: "3.0.6"
-  
-  port: 8082
-  containerPort: 8082
-  protocol: TCP
-  
-  resources:
-    requests:
-      memory: "256Mi"
-      cpu: "250m"
-    limits:
-      memory: "512Mi"
-      cpu: "500m"
-  
-  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
-  springProfiles: "kubernetes"
-  
-  livenessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8082
-    initialDelaySeconds: 30
-    periodSeconds: 10
-    timeoutSeconds: 5
-    failureThreshold: 3
-  
-  readinessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 8082
-    initialDelaySeconds: 20
-    periodSeconds: 5
-    timeoutSeconds: 3
-    failureThreshold: 3
-  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
-  startupProbe:
-    tcpSocket:
-      port: 8082
-    initialDelaySeconds: 0
-    periodSeconds: 5
-    timeoutSeconds: 2
-    failureThreshold: 120
-  service:
-    type: ClusterIP
-    port: 8082
-    targetPort: 8082
-    annotations: {}
-  
-  env:
-    SPRING_CLOUD_CONFIG_ENABLED: "true"
-    LOGGING_LEVEL_ROOT: "INFO"
-
-# ==========================================
-# Web Frontend (前端应用)
-# ==========================================
-webFrontend:
-  enabled: true
-  replicaCount: 1
-  
-  image:
-    name: shop-recycle-web
-    tag: "3.0.6"
-  
-  port: 80
-  containerPort: 80
-  protocol: TCP
-  
-  resources:
-    requests:
-      memory: "128Mi"
-      cpu: "100m"
-    limits:
-      memory: "256Mi"
-      cpu: "500m"
-  
-  livenessProbe:
-    httpGet:
-      path: /actuator/health
-      port: 80
-    initialDelaySeconds: 10
-    periodSeconds: 10
-    timeoutSeconds: 5
-    failureThreshold: 3
-  
-  readinessProbe:
-    httpGet:
-      path: /
-      port: 80
-    initialDelaySeconds: 5
-    periodSeconds: 5
-    timeoutSeconds: 3
-    failureThreshold: 3
-  
-  service:
-    type: LoadBalancer
-    port: 80
-    targetPort: 80
-    annotations: {}
-  
-  ingress:
-    enabled: true
-    className: "nginx"
-    annotations:
-      cert-manager.io/cluster-issuer: "letsencrypt-prod"
-    hosts:
-      - host: "dev.jxfxtd.com"
-        paths:
-          - path: /
-            pathType: Prefix
-    tls:
-      - secretName: web-tls
-        hosts:
-          - "dev.jxfxtd.com"
-  
-  env:
-    VUE_APP_API_BASE: "http://shop-recycle-gateway:8080"
-    LOGGING_LEVEL: "info"
-
-# ==========================================
-# 网络策略
-# ==========================================
-networkPolicy:
-  enabled: false
-  policyTypes:
-    - Ingress
-    - Egress
-
-# ==========================================
-# Pod安全策略
-# ==========================================
-podSecurityPolicy:
-  enabled: false
-
-# ==========================================
-# RBAC配置
-# ==========================================
-rbac:
-  create: true
-  # 指定已有的ServiceAccount
-  serviceAccountName: ""
-
-# ==========================================
-# 节点亲和性与污点容限
-# ==========================================
-affinity: {}
-
-tolerations: []
-
-# ==========================================
-# 监控和日志
-# ==========================================
-monitoring:
-  enabled: false
-  # Prometheus ServiceMonitor
-  serviceMonitor:
-    enabled: false
-    interval: 30s
-
-logging:
-  # 日志级别
-  level: INFO
-  # 日志输出格式
-  format: json
+# ==========================================
+# Helm Values - shop-recycle
+# 全局配置(所有环境共享)
+# ==========================================
+
+# 全局配置
+global:
+  # 镜像仓库认证(若启用,Helm 自动生成 imagePullSecret)
+  registry:
+    createSecret: true  # 设为 false 则不创建 secret,使用已有的
+    username: "admin"        # harbor.stardance 用户名
+    password: "Harbor12345"        # harbor.stardance 密码
+    email: "ops@example.com"
+  
+  # 若 registry.createSecret=false,则指定已有的 secret 名称
+  imagePullSecrets: []
+  # - name: reg-cred
+  
+# 副本数
+replicaCount: 1
+
+# 镜像配置
+image:
+  registry: harbor.stardance
+  namespace: shoprecycle
+  pullPolicy: IfNotPresent
+  tag: "3.0.0"
+  # tag由Jenkins Pipeline动态注入(--set image.tag=xxx)
+
+# 环境名称(由Pipeline动态注入)
+environment: dev
+
+# ==========================================
+# Gateway (API网关)
+# ==========================================
+gateway:
+  enabled: true
+  replicaCount: 1
+  
+  image:
+    name: shop-recycle-gateway
+    tag: "3.0.6"
+  
+  port: 8080
+  containerPort: 8080
+  protocol: TCP
+  
+  resources:
+    requests:
+      memory: "256Mi"
+      cpu: "250m"
+    limits:
+      memory: "512Mi"
+      cpu: "500m"
+  
+  # JVM参数
+  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
+  
+  # Spring Profiles
+  springProfiles: "kubernetes"
+  
+  # 健康检查
+  livenessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8080
+    initialDelaySeconds: 30
+    periodSeconds: 10
+    timeoutSeconds: 5
+    failureThreshold: 3
+  
+  readinessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8080
+    initialDelaySeconds: 20
+    periodSeconds: 5
+    timeoutSeconds: 3
+    failureThreshold: 3
+  
+  # 服务配置
+  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
+  startupProbe:
+    tcpSocket:
+      port: 8080
+    initialDelaySeconds: 0
+    periodSeconds: 5
+    timeoutSeconds: 2
+    failureThreshold: 120
+  service:
+    type: ClusterIP
+    port: 8080
+    targetPort: 8080
+    annotations: {}
+  
+  # 入口配置
+  ingress:
+    enabled: false
+    className: "nginx"
+    annotations:
+      cert-manager.io/cluster-issuer: "letsencrypt-prod"
+    hosts:
+      - host: "dev.jxfxtd.com"
+        paths:
+          - path: /
+            pathType: Prefix
+    tls:
+      - secretName: gateway-tls
+        hosts:
+          - "dev.jxfxtd.com"
+  
+  # 环境变量
+  env:
+    SPRING_CLOUD_CONFIG_ENABLED: "true"
+    LOGGING_LEVEL_ROOT: "INFO"
+  
+  # ConfigMap数据
+  configMap:
+    application.yml: |
+      spring:
+        cloud:
+          gateway:
+            routes:
+              - id: order-service
+                uri: http://shop-recycle-order-service:8081
+                predicates:
+                  - Path=/api/order/**
+              - id: payment-service
+                uri: http://shop-recycle-payment-service:8082
+                predicates:
+                  - Path=/api/payment/**
+              - id: test-order
+                uri: http://shop-recycle-order-service:8081
+                predicates:
+                  - Path=/api/test/**
+              - id: test-payment
+                uri: http://shop-recycle-payment-service:8082
+                predicates:
+                  - Path=/api/test/**
+      management:
+        endpoints:
+          web:
+            exposure:
+              include: health,info
+
+# ==========================================
+# Order Service (订单服务)
+# ==========================================
+orderService:
+  enabled: true
+  replicaCount: 1
+  
+  image:
+    name: shop-recycle-order-service
+    tag: "3.0.6"
+  
+  port: 8081
+  containerPort: 8081
+  protocol: TCP
+  
+  resources:
+    requests:
+      memory: "256Mi"
+      cpu: "250m"
+    limits:
+      memory: "512Mi"
+      cpu: "500m"
+  
+  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
+  springProfiles: "kubernetes"
+  
+  livenessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8081
+    initialDelaySeconds: 30
+    periodSeconds: 10
+    timeoutSeconds: 5
+    failureThreshold: 3
+  
+  readinessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8081
+    initialDelaySeconds: 20
+    periodSeconds: 5
+    timeoutSeconds: 3
+    failureThreshold: 3
+  
+  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
+  startupProbe:
+    tcpSocket:
+      port: 8081
+    initialDelaySeconds: 0
+    periodSeconds: 5
+    timeoutSeconds: 2
+    failureThreshold: 120
+  service:
+    type: ClusterIP
+    port: 8081
+    targetPort: 8081
+    annotations: {}
+  
+  env:
+    SPRING_CLOUD_CONFIG_ENABLED: "true"
+    LOGGING_LEVEL_ROOT: "INFO"
+
+# ==========================================
+# Payment Service (支付服务)
+# ==========================================
+paymentService:
+  enabled: true
+  replicaCount: 1
+  
+  image:
+    name: shop-recycle-payment-service
+    tag: "3.0.6"
+  
+  port: 8082
+  containerPort: 8082
+  protocol: TCP
+  
+  resources:
+    requests:
+      memory: "256Mi"
+      cpu: "250m"
+    limits:
+      memory: "512Mi"
+      cpu: "500m"
+  
+  javaOpts: "-Xms256m -Xmx512m -XX:+UseG1GC"
+  springProfiles: "kubernetes"
+  
+  livenessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8082
+    initialDelaySeconds: 30
+    periodSeconds: 10
+    timeoutSeconds: 5
+    failureThreshold: 3
+  
+  readinessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 8082
+    initialDelaySeconds: 20
+    periodSeconds: 5
+    timeoutSeconds: 3
+    failureThreshold: 3
+  # 启动探针 - 给 Java 应用充分的启动时间(5分钟才开始检查)
+  startupProbe:
+    tcpSocket:
+      port: 8082
+    initialDelaySeconds: 0
+    periodSeconds: 5
+    timeoutSeconds: 2
+    failureThreshold: 120
+  service:
+    type: ClusterIP
+    port: 8082
+    targetPort: 8082
+    annotations: {}
+  
+  env:
+    SPRING_CLOUD_CONFIG_ENABLED: "true"
+    LOGGING_LEVEL_ROOT: "INFO"
+
+# ==========================================
+# Web Frontend (前端应用)
+# ==========================================
+webFrontend:
+  enabled: true
+  replicaCount: 1
+  
+  image:
+    name: shop-recycle-web
+    tag: "3.0.6"
+  
+  port: 80
+  containerPort: 80
+  protocol: TCP
+  
+  resources:
+    requests:
+      memory: "128Mi"
+      cpu: "100m"
+    limits:
+      memory: "256Mi"
+      cpu: "500m"
+  
+  livenessProbe:
+    httpGet:
+      path: /actuator/health
+      port: 80
+    initialDelaySeconds: 10
+    periodSeconds: 10
+    timeoutSeconds: 5
+    failureThreshold: 3
+  
+  readinessProbe:
+    httpGet:
+      path: /
+      port: 80
+    initialDelaySeconds: 5
+    periodSeconds: 5
+    timeoutSeconds: 3
+    failureThreshold: 3
+  
+  service:
+    type: LoadBalancer
+    port: 80
+    targetPort: 80
+    annotations: {}
+  
+  ingress:
+    enabled: true
+    className: "nginx"
+    annotations:
+      cert-manager.io/cluster-issuer: "letsencrypt-prod"
+    hosts:
+      - host: "dev.jxfxtd.com"
+        paths:
+          - path: /
+            pathType: Prefix
+    tls:
+      - secretName: web-tls
+        hosts:
+          - "dev.jxfxtd.com"
+  
+  env:
+    VUE_APP_API_BASE: "http://shop-recycle-gateway:8080"
+    LOGGING_LEVEL: "info"
+
+# ==========================================
+# 网络策略
+# ==========================================
+networkPolicy:
+  enabled: false
+  policyTypes:
+    - Ingress
+    - Egress
+
+# ==========================================
+# Pod安全策略
+# ==========================================
+podSecurityPolicy:
+  enabled: false
+
+# ==========================================
+# RBAC配置
+# ==========================================
+rbac:
+  create: true
+  # 指定已有的ServiceAccount
+  serviceAccountName: ""
+
+# ==========================================
+# 节点亲和性与污点容限
+# ==========================================
+affinity: {}
+
+tolerations: []
+
+# ==========================================
+# 监控和日志
+# ==========================================
+monitoring:
+  enabled: false
+  # Prometheus ServiceMonitor
+  serviceMonitor:
+    enabled: false
+    interval: 30s
+
+logging:
+  # 日志级别
+  level: INFO
+  # 日志输出格式
+  format: json