// LokiDeployer — k8s-yaml 模式 manifest 生成(StatefulSet/PVC/ConfigMap/Service)。 package services import ( "crypto/sha256" "encoding/base64" "fmt" ) func (d *LokiDeployer) generateManifest(ns string) string { version := d.effectiveVersion() image := ResolveImage("docker.io/grafana/loki:" + version) replicas := d.deployment.Replicas if replicas < 1 { replicas = 1 } storageSize := d.deployment.StorageSize if storageSize == "" { storageSize = "10Gi" } cpu := d.deployment.ResourcesCPU mem := d.deployment.ResourcesMem if cpu == "" { cpu = "1000m" } if mem == "" { mem = "1Gi" } configData := d.generateLokiConfig() secretManifest := "" configExpandArg := "" storageEnvBlock := "" if sc := d.deployment.StorageConfig; sc != nil { switch sc.StorageType { case "s3", "oss", "minio", "azure": secretManifest = fmt.Sprintf(`--- apiVersion: v1 kind: Secret metadata: name: loki-storage-credentials namespace: %s type: Opaque data: accessKey: %s secretKey: %s`, ns, base64.StdEncoding.EncodeToString([]byte(sc.AccessKey)), base64.StdEncoding.EncodeToString([]byte(sc.SecretKey))) configExpandArg = "\n - -config.expand-env=true" storageEnvBlock = ` env: - name: LOKI_STORAGE_ACCESS_KEY valueFrom: secretKeyRef: name: loki-storage-credentials key: accessKey - name: LOKI_STORAGE_SECRET_KEY valueFrom: secretKeyRef: name: loki-storage-credentials key: secretKey` } } // ConfigMap/Secret 更新本身不会重建 Pod。把内容摘要写入 Pod 模板以触发滚动更新。 configHash := sha256.Sum256([]byte(configData + "\n" + secretManifest)) manifest := fmt.Sprintf(`apiVersion: v1 kind: Namespace metadata: name: %s --- apiVersion: v1 kind: ConfigMap metadata: name: loki-config namespace: %s data: loki.yaml: | %s %s --- apiVersion: v1 kind: Service metadata: name: loki namespace: %s labels: app: loki spec: type: ClusterIP ports: - name: http port: 3100 targetPort: 3100 protocol: TCP - name: grpc port: 9095 targetPort: 9095 protocol: TCP selector: app: loki --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: loki-data namespace: %s spec: accessModes: - ReadWriteOnce resources: requests: storage: %s --- apiVersion: apps/v1 kind: StatefulSet metadata: name: loki namespace: %s labels: app: loki spec: serviceName: loki replicas: %d selector: matchLabels: app: loki template: metadata: labels: app: loki annotations: checksum/loki-config: "%x" spec: securityContext: runAsUser: 0 runAsGroup: 0 fsGroup: 0 containers: - name: loki image: grafana/loki:%s imagePullPolicy: IfNotPresent args: - -config.file=/etc/loki/loki.yaml%s%s ports: - name: http containerPort: 3100 protocol: TCP - name: grpc containerPort: 9095 protocol: TCP resources: limits: cpu: "%s" memory: "%s" requests: cpu: "200m" memory: "256Mi" securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: false capabilities: drop: - ALL livenessProbe: httpGet: path: /ready port: http initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 6 readinessProbe: httpGet: path: /ready port: http initialDelaySeconds: 10 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3 startupProbe: httpGet: path: /ready port: http initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 30 volumeMounts: - name: config mountPath: /etc/loki readOnly: true - name: data mountPath: /var/lib/loki - name: wal mountPath: /var/lib/loki/wal volumes: - name: config configMap: name: loki-config - name: data persistentVolumeClaim: claimName: loki-data - name: wal emptyDir: {} `, ns, ns, indentYAML(configData, 4), secretManifest, ns, ns, storageSize, ns, replicas, configHash, image, configExpandArg, storageEnvBlock, cpu, mem) // 多副本:追加 Headless Service(clusterIP: None + selector app:loki), // 使 memberlist 的 join_members (loki-headless..svc.cluster.local) 能解析到所有 Pod IP。 if replicas >= 2 { manifest += fmt.Sprintf(` --- apiVersion: v1 kind: Service metadata: name: loki-headless namespace: %s labels: app: loki spec: clusterIP: None ports: - name: http port: 3100 targetPort: 3100 protocol: TCP - name: grpc port: 9095 targetPort: 9095 protocol: TCP - name: memberlist port: 7946 targetPort: 7946 protocol: TCP selector: app: loki `, ns) } return manifest } // ==================== Loki 本地配置生成 (text/template) ====================