diff --git a/deploy/README.md b/deploy/README.md new file mode 100644 index 0000000..519af0f --- /dev/null +++ b/deploy/README.md @@ -0,0 +1,231 @@ +# S3 Balance 部署指南 + +本目录包含 S3 Balance 服务的各种部署方案,从简单的 Docker Compose 到生产级的 Kubernetes 部署。 + +## 目录结构 + +``` +deploy/ +├── docker/ # Docker 和 Docker Compose 部署 +│ ├── docker-compose.yml # Docker Compose 配置 +│ ├── Dockerfile # Docker 镜像构建文件 +│ ├── start-monitoring.sh # 一键启动脚本 +│ └── config.docker.yaml # Docker 环境配置 +├── kubernetes/ # Kubernetes 原生部署 +│ ├── namespace.yaml # 命名空间 +│ ├── configmap.yaml # 配置映射 +│ ├── deployment.yaml # 部署配置 +│ ├── service.yaml # 服务暴露 +│ └── ingress.yaml # 入口配置 +├── helm/ # HELM Chart 部署 +│ └── s3-balance/ # HELM Chart 目录 +└── monitoring/ # 监控系统配置 + ├── prometheus.yml # Prometheus 配置 + ├── s3_balance_alerts.yml # 告警规则 + └── grafana/ # Grafana 配置和仪表板 +``` + +## 🐳 Docker Compose 部署(推荐开发环境) + +### 快速启动(含完整监控栈) +```bash +cd deploy/docker +./start-monitoring.sh +``` + +### 手动启动 +```bash +cd deploy/docker +docker-compose up -d +``` + +### 访问地址 +- S3 Balance API: http://localhost:8080 +- Grafana 面板: http://localhost:3000 (admin/admin123) +- Prometheus: http://localhost:9090 +- 监控指标: http://localhost:8080/metrics + +### 配置文件 +编辑 `config.docker.yaml` 来自定义: +- 存储桶配置 +- 负载均衡策略 +- 监控指标设置 + +## ☸️ Kubernetes 部署(推荐生产环境) + +### 基础部署 +```bash +cd deploy/kubernetes +kubectl apply -f namespace.yaml +kubectl apply -f configmap.yaml +kubectl apply -f deployment.yaml +kubectl apply -f service.yaml +``` + +### 高可用部署 +```bash +kubectl apply -f hpa.yaml # 水平自动扩缩容 +kubectl apply -f pdb.yaml # Pod 中断预算 +``` + +### 外部访问 +```bash +kubectl apply -f ingress.yaml +``` + +### 配置说明 +- 使用 ConfigMap 管理配置文件 +- 支持 HPA 自动扩缩容 +- 集成集群 DNS 服务发现 +- 支持多环境配置(dev/test/prod) + +## 📊 HELM Chart 部署(推荐企业环境) + +### 安装 Chart +```bash +cd deploy/helm +helm install s3-balance ./s3-balance +``` + +### 自定义参数 +```bash +helm install s3-balance ./s3-balance -f custom-values.yaml +``` + +### 升级版本 +```bash +helm upgrade s3-balance ./s3-balance +``` + +### HELM 优势 +- 参数化配置 +- 多环境管理 +- 版本控制 +- 依赖管理 + +## 🔧 监控集成 + +所有的部署方案都集成了完整的监控系统: + +### Prometheus 指标 +- S3 Balance 业务指标 +- 系统资源指标 +- 自定义应用指标 + +### Grafana 仪表板 +- 服务概览面板 +- 性能分析面板 +- 容量监控面板 +- 错误率跟踪面板 + +### 告警规则 +- 存储桶健康状态告警 +- 高错误率告警 +- 高延迟告警 +- 容量使用率告警 + +## 🚨 部署要求 + +### 系统要求 +- Docker & Docker Compose(开发环境) +- Kubernetes 1.19+(生产环境) +- HELM 3.0+(企业环境) + +### 资源要求 +- CPU: 0.5-2 core +- Memory: 512MB-2GB +- Storage: 1GB-100GB(根据使用情况) +- Network: 内网访问存储桶 + +### 网络要求 +- 访问后端 S3 存储桶 +- Prometheus Pushgateway(可选) +- 外部监控系统(可选) + +## 📋 环境变量 + +### S3 Balance +- `CONFIG_FILE`: 配置文件路径 +- `LOG_LEVEL`: 日志级别 (debug/info/warn/error) +- `TZ`: 时区设置 + +### Prometheus +- `STORAGE_TSDB_RETENTION_TIME`: 数据保留时间 +- `WEB_ENABLE_LIFECYCLE`: 启用生命周期管理 + +### Grafana +- `GF_SECURITY_ADMIN_USER`: 管理员用户名 +- `GF_SECURITY_ADMIN_PASSWORD`: 管理员密码 +- `GF_USERS_ALLOW_SIGN_UP`: 是否允许注册 + +## 🎯 最佳实践 + +### 生产环境建议 +1. **资源限制**: 设置合理的CPU/内存限制 +2. **健康检查**: 配置完整的探针检查 +3. **持久化**: 重要数据使用持久化存储 +4. **备份**: 定期备份配置和数据库 +5. **监控**: 集成现有监控系统 + +### 高可用建议 +1. **多副本**: 部署多个实例 +2. **负载均衡**: 集群内负载均衡 +3. **自动扩缩容**: 基于负载自动扩缩容 +4. **多区域**: 跨可用区部署 + +### 安全建议 +1. **镜像安全**: 使用官方基础镜像 +2. **访问控制**: 配置RBAC权限 +3. **网络隔离**: 使用网络策略 +4. **敏感信息**: 使用Secret管理凭证 + +## 🔧 故障排除 + +### 常见问题 + +**Pod 启动失败** +```bash +kubectl describe pod +kubectl logs +``` + +**配置错误** +```bash +kubectl get configmap s3-balance-config -o yaml +``` + +**服务无法访问** +```bash +kubectl get service s3-balance-service +kubectl get ingress s3-balance-ingress +``` + +### 性能调优 +- 调整负载均衡策略 +- 优化数据库连接池 +- 配置合理的缓存策略 +- 监控资源使用情况 + +## 🔗 集成外部系统 + +### 已有 Prometheus +在外部 Prometheus 配置中添加: +```yaml +scrape_configs: + - job_name: 's3-balance' + static_configs: + - targets: ['s3-balance-service.default.svc.cluster.local:8080'] +``` + +### 现有监控系统 +- 通过 exporters 暴露指标 +- 使用统一的日志格式 +- 集成告警通知渠道 + +## 📖 参考文献 + +- [Docker Compose 文档](https://docs.docker.com/compose/) +- [Kubernetes 官方文档](https://kubernetes.io/docs/) +- [HELM 官方文档](https://helm.sh/docs/) +- [Prometheus 最佳实践](https://prometheus.io/docs/practices/) +- [Grafana 文档](https://grafana.com/docs/) \ No newline at end of file diff --git a/deploy/docker/Dockerfile b/deploy/docker/Dockerfile new file mode 100644 index 0000000..c018a8e --- /dev/null +++ b/deploy/docker/Dockerfile @@ -0,0 +1,45 @@ +# 多阶段构建用于减小镜像大小 +FROM golang:1.24-alpine AS builder + +# 安装构建依赖(包括CGO支持的sqlite3) +RUN apk add --no-cache gcc musl-dev sqlite-dev git ca-certificates tzdata + +# 设置工作目录 +WORKDIR /build + +# 复制 Go 模块文件 +COPY go.mod go.sum ./ +RUN go mod download && go mod tidy + +# 复制源码 +COPY . . + +# 构建应用(启用CGO) +RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build \ + -ldflags='-w -s -X main.version=$(git describe --tags --always)' \ + -o s3-balance \ + cmd/s3-balance/main.go + +# 运行时镜像 +FROM alpine:latest + +# 安装运行时依赖(包括sqlite库) +RUN apk --no-cache add ca-certificates tzdata sqlite-libs + +# 设置时区 +ENV TZ=Asia/Shanghai + +WORKDIR /app + +# 复制二进制文件 +COPY --from=builder /build/s3-balance /app/s3-balance + +# 创建配置和数据目录 +RUN mkdir -p /app/config /app/data + +# 暴露端口 +EXPOSE 8080 + +# 运行应用 +ENTRYPOINT ["/app/s3-balance"] +CMD ["-config", "/app/config/config.yaml"] \ No newline at end of file diff --git a/deploy/docker/config.docker.yaml b/deploy/docker/config.docker.yaml new file mode 100644 index 0000000..fd34866 --- /dev/null +++ b/deploy/docker/config.docker.yaml @@ -0,0 +1,62 @@ +# Docker 配置 - 启用监控 +server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30s + write_timeout: 30s + idle_timeout: 60s + +database: + type: "sqlite" + dsn: "data/s3-balance.db" + max_open_conns: 25 + max_idle_conns: 5 + conn_max_lifetime: 300 + log_level: "info" + auto_migrate: true + +# 示例存储桶配置 - 请根据实际情况修改 +buckets: + - name: "minio-bucket" + endpoint: "http://minio:9000" + region: "us-east-1" + access_key_id: "minioadmin" + secret_access_key: "minioadmin" + max_size: "1GB" + weight: 10 + enabled: true + use_ssl: false + path_style: true + virtual: false + + - name: "user-data" + endpoint: "" + region: "us-east-1" + access_key_id: "" + secret_access_key: "" + max_size: "1GB" + weight: 10 + enabled: true + use_ssl: true + path_style: false + virtual: true + +balancer: + strategy: "least-space" + health_check_period: 30s + update_stats_period: 60s + retry_attempts: 3 + retry_delay: 1s + +# 监控指标 - 启用状态 +metrics: + enabled: true + path: "/metrics" + port: 9090 + +s3api: + access_key: "AKIAIOSFODNN7EXAMPLE" + secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + virtual_host: false + proxy_mode: false + auth_required: false \ No newline at end of file diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml new file mode 100644 index 0000000..33f4ba5 --- /dev/null +++ b/deploy/docker/docker-compose.yml @@ -0,0 +1,90 @@ +version: '3.8' + +services: + # S3 Balance 服务 + s3-balance: + build: + context: ../.. + dockerfile: deploy/docker/Dockerfile + container_name: s3-balance + ports: + - "8080:8080" + volumes: + - ../docker/config.docker.yaml:/app/config/config.yaml + - ../docker/data:/app/data + environment: + - TZ=Asia/Shanghai + networks: + - monitoring + restart: unless-stopped + command: ["/app/s3-balance", "-config", "/app/config/config.yaml"] + + # Prometheus 监控 + prometheus: + image: prom/prometheus:latest + container_name: prometheus + ports: + - "9090:9090" + volumes: + - ../monitoring/prometheus.yml:/etc/prometheus/prometheus.yml + - ../monitoring/s3_balance_alerts.yml:/etc/prometheus/s3_balance_alerts.yml + - prometheus_data:/prometheus + command: + - '--config.file=/etc/prometheus/prometheus.yml' + - '--storage.tsdb.path=/prometheus' + - '--web.console.libraries=/etc/prometheus/console_libraries' + - '--web.console.templates=/etc/prometheus/consoles' + - '--storage.tsdb.retention.time=200h' + - '--web.enable-lifecycle' + networks: + - monitoring + restart: unless-stopped + + # Grafana 可视化 + grafana: + image: grafana/grafana:latest + container_name: grafana + ports: + - "3000:3000" + volumes: + - grafana_data:/var/lib/grafana + - ../monitoring/grafana/provisioning:/etc/grafana/provisioning + - ../monitoring/grafana/dashboards:/var/lib/grafana/dashboards + environment: + - GF_SECURITY_ADMIN_USER=admin + - GF_SECURITY_ADMIN_PASSWORD=admin123 + - GF_USERS_ALLOW_SIGN_UP=false + - GF_INSTALL_PLUGINS=grafana-clock-panel,grafana-simple-json-datasource + networks: + - monitoring + restart: unless-stopped + depends_on: + - prometheus + + # Node Exporter (可选,监控宿主机) + node-exporter: + image: prom/node-exporter:latest + container_name: node-exporter + ports: + - "9100:9100" + volumes: + - /proc:/host/proc:ro + - /sys:/host/sys:ro + - /:/rootfs:ro + command: + - '--path.procfs=/host/proc' + - '--path.sysfs=/host/sys' + - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)' + networks: + - monitoring + restart: unless-stopped + +volumes: + prometheus_data: + driver: local + grafana_data: + driver: local + +networks: + monitoring: + driver: bridge \ No newline at end of file diff --git a/deploy/docker/start-monitoring.sh b/deploy/docker/start-monitoring.sh new file mode 100644 index 0000000..c27097d --- /dev/null +++ b/deploy/docker/start-monitoring.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# S3 Balance + 监控栈 一键启动(修复版) + +set -e + +echo "🚀 正在启动 S3 Balance + 监控栈(修复CGO版本)..." + +# 检查 Docker 和 Docker Compose +if ! command -v docker &> /dev/null; then + echo "❌ Docker 未安装,请先安装 Docker" + exit 1 +fi + +if ! command -v docker-compose &> /dev/null; then + echo "❌ Docker Compose 未安装,请先安装 Docker Compose" + exit 1 +fi + +# 创建必要目录 +echo "📁 创建必要目录..." +mkdir -p data grafana/provisioning/datasources grafana/provisioning/dashboards + +# 构建 S3 Balance 镜像(使用固定 Go 版本) +echo "🔨 构建 S3 Balance 镜像..." +docker build -t s3-balance:latest -f ../docker/Dockerfile ../.. + +# 停止已有容器(如果存在) +echo "🛑 清理已有容器..." +docker-compose down 2>/dev/null || true + +# 启动服务 +echo "🐳 启动 Docker 容器..." +docker-compose up -d + +# 等待服务启动 +echo "⏳ 等待服务启动..." +sleep 25 + +# 检查服务状态 +echo "🔍 检查服务状态..." +if docker-compose ps | grep -q "Up"; then + echo "" + echo "✅ 服务启动完成!" +else + echo "" + echo "❌ 服务启动可能失败,检查日志:" + echo "docker-compose logs" + exit 1 +fi + +# 输出访问信息 +echo "" +echo "🔗 访问地址:" +echo " 📊 Grafana 面板: http://localhost:3000 (用户名: admin, 密码: admin123)" +echo " 🔥 Prometheus: http://localhost:9090" +echo " 📈 指标端点: http://localhost:8080/metrics" +echo " 🐳 Node 指标: http://localhost:9100/metrics" +echo "" +echo "🔧 管理命令:" +echo " docker-compose logs -f s3-balance # 查看 S3 Balance 日志" +echo " docker-compose logs -f prometheus # 查看 Prometheus 日志" +echo " docker-compose logs -f grafana # 查看 Grafana 日志" +echo " docker-compose down # 停止所有服务" +echo " docker-compose restart s3-balance # 重启 S3 Balance" +echo "" +echo "📊 指标查询示例:" +echo " - 存储桶健康: s3_balance_bucket_healthy" +echo " - QPS: rate(s3_balance_s3_operations_total[1m])" +echo " - 延迟: histogram_quantile(0.95, s3_balance_s3_operation_duration_seconds_bucket)" +echo "" +echo "🎉 享受完整的 S3 Balance 监控体验!" \ No newline at end of file diff --git a/deploy/helm/s3-balance-servicemonitor/Chart.yaml b/deploy/helm/s3-balance-servicemonitor/Chart.yaml new file mode 100644 index 0000000..a5cf747 --- /dev/null +++ b/deploy/helm/s3-balance-servicemonitor/Chart.yaml @@ -0,0 +1,9 @@ +apiVersion: v2 +name: s3-balance-servicemonitor +description: A Helm chart for ServiceMonitor to monitor S3 Balance +type: application +version: 0.1.0 +appVersion: "1.0.0" + +# Usage: +# helm install s3-balance-monitoring ./s3-balance-servicemonitor -n monitoring \ No newline at end of file diff --git a/deploy/helm/s3-balance/Chart.yaml b/deploy/helm/s3-balance/Chart.yaml new file mode 100644 index 0000000..220c33a --- /dev/null +++ b/deploy/helm/s3-balance/Chart.yaml @@ -0,0 +1,20 @@ +apiVersion: v2 +name: s3-balance +description: A Helm chart for S3 Balance load balancing service +type: application +version: 0.1.0 +appVersion: "1.0.0" +icon: https://helm.sh/img/helm.svg +keywords: + - s3 + - storage + - load-balancer + - object-storage + - minio + - aws-s3 +home: https://github.com/example/s3-balance +sources: + - https://github.com/example/s3-balance +maintainers: + - name: S3 Balance Team + email: admin@example.com \ No newline at end of file diff --git a/deploy/helm/s3-balance/production-values.yaml b/deploy/helm/s3-balance/production-values.yaml new file mode 100644 index 0000000..ae429c7 --- /dev/null +++ b/deploy/helm/s3-balance/production-values.yaml @@ -0,0 +1,155 @@ +# HELM Values 生产环境配置 +replicaCount: 3 + +image: + repository: your-registry.com/s3-balance + tag: v1.0.0 + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 8080 + annotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: s3-balance.your-domain.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: s3-balance-tls + hosts: + - s3-balance.your-domain.com + +resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 200m + memory: 256Mi + +autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 20 + targetCPUUtilizationPercentage: 70 + targetMemoryUtilizationPercentage: 80 + +config: + configYaml: | + # 生产环境配置 + server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30s + write_timeout: 30s + idle_timeout: 60s + + database: + type: "sqlite" + dsn: "/app/data/s3-balance.db" + max_open_conns: 100 + max_idle_conns: 20 + conn_max_lifetime: 600 + log_level: "warn" + auto_migrate: true + + buckets: + # 生产存储桶配置 + - name: "prod-minio" + endpoint: "https://your-minio-endpoint.com" + region: "us-east-1" + access_key_id: "CHANGEME" + secret_access_key: "CHANGEME" + max_size: "500GB" + weight: 10 + enabled: true + use_ssl: true + path_style: true + virtual: false + + balancer: + strategy: "least-space" + health_check_period: 30s + update_stats_period: 60s + + metrics: + enabled: true + path: "/metrics" + port: 8080 + + s3api: + access_key: "your-access-key" + secret_key: "your-secret-key" + virtual_host: false + proxy_mode: false + auth_required: true + +persistence: + enabled: true + storageClass: "fast-ssd" + accessMode: ReadWriteOnce + size: 20Gi + +monitoring: + enabled: true + serviceMonitor: + enabled: true + namespace: monitoring + interval: 30s + scrapeTimeout: 10s + labels: + release: prometheus + +prometheusRule: + enabled: true + namespace: monitoring + labels: + release: prometheus + rules: + - alert: BucketDown + expr: up{job="s3-balance"} == 0 + for: 5m + labels: + severity: critical + annotations: + summary: "S3 Balance 服务不可用" + description: "S3 Balance 服务已经连续5分钟不可用" + - alert: HighErrorRate + expr: rate(s3_balance_s3_operations_total{status="error"}[5m]) > 0.05 + for: 2m + labels: + severity: warning + annotations: + summary: "高错误率告警" + description: "错误率超过5%,操作类型: {{ $labels.operation }}" + +nodeSelector: + disktype: ssd + +tolerations: + - key: "highcpu" + operator: "Equal" + value: "true" + effect: "NoSchedule" + +affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - s3-balance + topologyKey: kubernetes.io/hostname \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/_helpers.tpl b/deploy/helm/s3-balance/templates/_helpers.tpl new file mode 100644 index 0000000..8774b81 --- /dev/null +++ b/deploy/helm/s3-balance/templates/_helpers.tpl @@ -0,0 +1,34 @@ +{{/* +Return the proper s3-balance image name +*/}} +{{- define "s3-balance.image" -}} +{{- $registryName := .Values.image.repository -}} +{{- $tag := .Values.image.tag | default .Chart.AppVersion -}} +{{- printf "%s:%s" $registryName $tag -}} +{{- end -}} + +{{/* +Return the chart name +*/}} +{{- define "s3-balance.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the full name +*/}} +{{- define "s3-balance.fullname" -}} +{{- $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 -}} + +{{/* +Return the service account name +*/}} +{{- define "s3-balance.serviceAccountName" -}} +{{- default (include "s3-balance.fullname" .) .Values.serviceAccount.name -}} +{{- end -}} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/_labels.tpl b/deploy/helm/s3-balance/templates/_labels.tpl new file mode 100644 index 0000000..56a28da --- /dev/null +++ b/deploy/helm/s3-balance/templates/_labels.tpl @@ -0,0 +1,26 @@ +{{/* +Labels +*/}} +{{- define "s3-balance.labels" -}} +helm.sh/chart: {{ include "s3-balance.chart" . }} +{{ include "s3-balance.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "s3-balance.selectorLabels" -}} +app.kubernetes.io/name: {{ include "s3-balance.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Chart name and version as used by the chart label. +*/}} +{{- define "s3-balance.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end -}} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/configmap.yaml b/deploy/helm/s3-balance/templates/configmap.yaml new file mode 100644 index 0000000..3930352 --- /dev/null +++ b/deploy/helm/s3-balance/templates/configmap.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "s3-balance.fullname" . }}-config + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} +data: + config.yaml: |{{ .Values.config.configYaml | nindent 4 }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/deployment.yaml b/deploy/helm/s3-balance/templates/deployment.yaml new file mode 100644 index 0000000..7e9bc4d --- /dev/null +++ b/deploy/helm/s3-balance/templates/deployment.yaml @@ -0,0 +1,93 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + selector: + matchLabels: + {{- include "s3-balance.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "s3-balance.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "s3-balance.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + image: {{ include "s3-balance.image" . }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + env: + - name: TZ + value: "Asia/Shanghai" + livenessProbe: + httpGet: + path: /metrics + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /metrics + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + resources: + {{- toYaml .Values.resources | nindent 10 }} + volumeMounts: + - name: config + mountPath: /app/config + readOnly: true + - name: data + mountPath: /app/data + volumes: + - name: config + configMap: + name: {{ include "s3-balance.fullname" . }}-config + - name: data + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ include "s3-balance.fullname" . }}-data + {{- else }} + emptyDir: {} + {{- 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 }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/hpa.yaml b/deploy/helm/s3-balance/templates/hpa.yaml new file mode 100644 index 0000000..cefeca1 --- /dev/null +++ b/deploy/helm/s3-balance/templates/hpa.yaml @@ -0,0 +1,33 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "s3-balance.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 }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/ingress.yaml b/deploy/helm/s3-balance/templates/ingress.yaml new file mode 100644 index 0000000..34c5400 --- /dev/null +++ b/deploy/helm/s3-balance/templates/ingress.yaml @@ -0,0 +1,32 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ include "s3-balance.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/prometheusrule.yaml b/deploy/helm/s3-balance/templates/prometheusrule.yaml new file mode 100644 index 0000000..9ad6b69 --- /dev/null +++ b/deploy/helm/s3-balance/templates/prometheusrule.yaml @@ -0,0 +1,21 @@ +{{- if .Values.monitoring.enabled }} +{{- if .Values.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Values.prometheusRule.namespace | default .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} + {{- with .Values.prometheusRule.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + groups: + - name: {{ include "s3-balance.name" . }} + rules: +{{- with .Values.prometheusRule.rules }} +{{ toYaml . | indent 6 }} +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/pvc.yaml b/deploy/helm/s3-balance/templates/pvc.yaml new file mode 100644 index 0000000..a1ece29 --- /dev/null +++ b/deploy/helm/s3-balance/templates/pvc.yaml @@ -0,0 +1,21 @@ +{{/* +Persistent Volume Claim template +*/}} +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "s3-balance.fullname" . }}-data + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} +spec: + accessModes: + - {{ .Values.persistence.accessMode }} + resources: + requests: + storage: {{ .Values.persistence.size }} + {{- if .Values.persistence.storageClass }} + storageClassName: {{ .Values.persistence.storageClass }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/service.yaml b/deploy/helm/s3-balance/templates/service.yaml new file mode 100644 index 0000000..7c0a7cf --- /dev/null +++ b/deploy/helm/s3-balance/templates/service.yaml @@ -0,0 +1,41 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.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 "s3-balance.selectorLabels" . | nindent 4 }}- name: metrics + port: 8080 + targetPort: http + protocol: TCP +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "s3-balance.fullname" . }}-metrics + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} + service-type: metrics +spec: + type: ClusterIP + ports: + - name: metrics + port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + selector: + {{- include "s3-balance.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/serviceaccount.yaml b/deploy/helm/s3-balance/templates/serviceaccount.yaml new file mode 100644 index 0000000..220c001 --- /dev/null +++ b/deploy/helm/s3-balance/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "s3-balance.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/templates/servicemonitor.yaml b/deploy/helm/s3-balance/templates/servicemonitor.yaml new file mode 100644 index 0000000..a09609c --- /dev/null +++ b/deploy/helm/s3-balance/templates/servicemonitor.yaml @@ -0,0 +1,24 @@ +{{- if .Values.monitoring.enabled }} +{{- if .Values.monitoring.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "s3-balance.fullname" . }} + namespace: {{ .Values.monitoring.serviceMonitor.namespace | default .Release.Namespace }} + labels: + {{- include "s3-balance.labels" . | nindent 4 }} + {{- with .Values.monitoring.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "s3-balance.selectorLabels" . | nindent 6 }} + service-type: metrics + endpoints: + - port: metrics + interval: {{ .Values.monitoring.serviceMonitor.interval }} + scrapeTimeout: {{ .Values.monitoring.serviceMonitor.scrapeTimeout }} + path: /metrics +{{- end }} +{{- end }} \ No newline at end of file diff --git a/deploy/helm/s3-balance/values.yaml b/deploy/helm/s3-balance/values.yaml new file mode 100644 index 0000000..be27ebb --- /dev/null +++ b/deploy/helm/s3-balance/values.yaml @@ -0,0 +1,174 @@ +# 默认值 +replicaCount: 3 + +image: + repository: s3-balance + tag: latest + pullPolicy: IfNotPresent + +imagePullSecrets: [ ] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: { } + name: "" + +podAnnotations: { } + +podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 2000 + +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + runAsNonRoot: true + runAsUser: 1000 + +service: + type: ClusterIP + port: 8080 + targetPort: 8080 + annotations: { } + +ingress: + enabled: false + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" + nginx.ingress.kubernetes.io/rewrite-target: / + hosts: + - host: s3-balance.local + paths: + - path: / + pathType: Prefix + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 10 + targetCPUUtilizationPercentage: 70 + targetMemoryUtilizationPercentage: 80 + +nodeSelector: { } + +tolerations: [ ] + +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - s3-balance + topologyKey: kubernetes.io/hostname + +config: + # S3 Balance 配置 + configYaml: | + # HELM 配置的 S3 Balance + server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30s + write_timeout: 30s + idle_timeout: 60s + + database: + type: "sqlite" + dsn: "/app/data/s3-balance.db" + max_open_conns: 50 + max_idle_conns: 10 + conn_max_lifetime: 600 + log_level: "info" + auto_migrate: true + + buckets: + # 示例配置 - 请根据实际情况修改 + - name: "minio-bucket" + endpoint: "http://minio:9000" + region: "us-east-1" + access_key_id: "minioadmin" + secret_access_key: "minioadmin" + max_size: "50GB" + weight: 10 + enabled: true + use_ssl: false + path_style: true + virtual: false + + balancer: + strategy: "least-space" + health_check_period: 30s + update_stats_period: 60s + + metrics: + enabled: true + path: "/metrics" + port: 8080 + + s3api: + access_key: "AKIAIOSFODNN7EXAMPLE" + secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + virtual_host: false + proxy_mode: false + auth_required: false + +# 监控配置 +monitoring: + enabled: true + serviceMonitor: + enabled: true + namespace: "" + interval: 30s + scrapeTimeout: 10s + labels: { } + +# PrometheusRule 配置 +prometheusRule: + enabled: true + namespace: "" + labels: { } + rules: + - alert: HighErrorRate + expr: rate(s3_balance_s3_operations_total{status="error"}[5m]) > 0.1 + for: 2m + labels: + severity: critical + annotations: + summary: "S3 Balance 错误率过高" + description: "S3 Balance 错误率超过10%: {{ $labels.operation }}" + - alert: HighLatency + expr: histogram_quantile(0.95, rate(s3_balance_s3_operation_duration_seconds_bucket[5m])) > 1 + for: 5m + labels: + severity: warning + annotations: + summary: "操作延迟过高" + description: "操作延迟 P95 超过1秒" + +# 持久化存储 +persistence: + enabled: true + storageClass: "" + accessMode: ReadWriteOnce + size: 5Gi \ No newline at end of file diff --git a/deploy/kubernetes/configmap.yaml b/deploy/kubernetes/configmap.yaml new file mode 100644 index 0000000..8e683b9 --- /dev/null +++ b/deploy/kubernetes/configmap.yaml @@ -0,0 +1,56 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: s3-balance-config + namespace: s3-balance + labels: + app: s3-balance +data: + config.yaml: | + # Kubernetes 生产环境配置 + server: + host: "0.0.0.0" + port: 8080 + read_timeout: 30s + write_timeout: 30s + idle_timeout: 60s + + database: + type: "sqlite" + dsn: "/app/data/s3-balance.db" + max_open_conns: 50 + max_idle_conns: 10 + conn_max_lifetime: 600 + log_level: "info" + auto_migrate: true + + buckets: + # 示例配置 - 请替换为实际存储桶 + - name: "prod-bucket-1" + endpoint: "http://minio-svc:9000" + region: "us-east-1" + access_key_id: "minioadmin" + secret_access_key: "minioadmin" + max_size: "100GB" + weight: 10 + enabled: true + use_ssl: false + path_style: true + virtual: false + + balancer: + strategy: "least-space" + health_check_period: 30s + update_stats_period: 60s + + metrics: + enabled: true + path: "/metrics" + port: 8080 + + s3api: + access_key: "AKIAIOSFODNN7EXAMPLE" + secret_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY" + virtual_host: false + proxy_mode: false + auth_required: false \ No newline at end of file diff --git a/deploy/kubernetes/deployment.yaml b/deploy/kubernetes/deployment.yaml new file mode 100644 index 0000000..53fe7d2 --- /dev/null +++ b/deploy/kubernetes/deployment.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: s3-balance-deployment + namespace: s3-balance + labels: + app: s3-balance + tier: backend +spec: + replicas: 3 + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 1 + maxSurge: 1 + selector: + matchLabels: + app: s3-balance + template: + metadata: + labels: + app: s3-balance + tier: backend + spec: + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app + operator: In + values: + - s3-balance + topologyKey: kubernetes.io/hostname + containers: + - name: s3-balance + image: s3-balance:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 8080 + name: http + env: + - name: TZ + value: "Asia/Shanghai" + volumeMounts: + - name: config + mountPath: /app/config + readOnly: true + - name: data + mountPath: /app/data + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + livenessProbe: + httpGet: + path: /health + port: 8080 + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /ready + port: 8080 + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + securityContext: + runAsNonRoot: true + runAsUser: 1000 + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + volumes: + - name: config + configMap: + name: s3-balance-config + - name: data + emptyDir: {} + restartPolicy: Always + terminationGracePeriodSeconds: 30 \ No newline at end of file diff --git a/deploy/kubernetes/hpa.yaml b/deploy/kubernetes/hpa.yaml new file mode 100644 index 0000000..ab8c88c --- /dev/null +++ b/deploy/kubernetes/hpa.yaml @@ -0,0 +1,40 @@ +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: s3-balance-hpa + namespace: s3-balance + labels: + app: s3-balance +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: s3-balance-deployment + minReplicas: 3 + maxReplicas: 10 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: 80 + behavior: + scaleUp: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 50 + periodSeconds: 60 + scaleDown: + stabilizationWindowSeconds: 300 + policies: + - type: Percent + value: 10 + periodSeconds: 60 \ No newline at end of file diff --git a/deploy/kubernetes/ingress.yaml b/deploy/kubernetes/ingress.yaml new file mode 100644 index 0000000..22c5278 --- /dev/null +++ b/deploy/kubernetes/ingress.yaml @@ -0,0 +1,22 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: s3-balance-ingress + namespace: s3-balance + annotations: + nginx.ingress.kubernetes.io/rewrite-target: / + nginx.ingress.kubernetes.io/ssl-redirect: "false" + nginx.ingress.kubernetes.io/backend-protocol: "HTTP" +spec: + ingressClassName: nginx + rules: + - host: s3-balance.local + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: s3-balance-service + port: + number: 8080 \ No newline at end of file diff --git a/deploy/kubernetes/namespace.yaml b/deploy/kubernetes/namespace.yaml new file mode 100644 index 0000000..c5b4176 --- /dev/null +++ b/deploy/kubernetes/namespace.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: s3-balance + labels: + app: s3-balance + tier: backend \ No newline at end of file diff --git a/deploy/kubernetes/service.yaml b/deploy/kubernetes/service.yaml new file mode 100644 index 0000000..22948d7 --- /dev/null +++ b/deploy/kubernetes/service.yaml @@ -0,0 +1,34 @@ +apiVersion: v1 +kind: Service +metadata: + name: s3-balance-service + namespace: s3-balance + labels: + app: s3-balance +spec: + selector: + app: s3-balance + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: http + type: ClusterIP +--- +apiVersion: v1 +kind: Service +metadata: + name: s3-balance-metrics-service + namespace: s3-balance + labels: + app: s3-balance + service-type: metrics +spec: + selector: + app: s3-balance + ports: + - port: 8080 + targetPort: 8080 + protocol: TCP + name: metrics + type: ClusterIP \ No newline at end of file diff --git a/deploy/monitoring/grafana/dashboards/s3-balance-dashboard.json b/deploy/monitoring/grafana/dashboards/s3-balance-dashboard.json new file mode 100644 index 0000000..a4ead41 --- /dev/null +++ b/deploy/monitoring/grafana/dashboards/s3-balance-dashboard.json @@ -0,0 +1,279 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "description": "S3 Balance 负载均衡服务监控 Dashboard", + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 1, + "links": [], + "panels": [ + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "reqps" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 10, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "expr": "rate(s3_balance_s3_operations_total[5m])", + "legendFormat": "{{operation}} - {{bucket}} - {{status}}", + "refId": "A" + } + ], + "title": "QPS (操作/秒)", + "type": "timeseries" + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "mappings": [ + { + "options": { + "0": { + "color": "red", + "index": 0, + "text": "Unhealthy" + }, + "1": { + "color": "green", + "index": 1, + "text": "Healthy" + } + }, + "type": "value" + } + ], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "colorMode": "background", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "text": {}, + "textMode": "auto" + }, + "pluginVersion": "8.0.0", + "targets": [ + { + "expr": "s3_balance_bucket_healthy", + "legendFormat": "{{bucket}}", + "refId": "A" + } + ], + "title": "存储桶健康状态", + "type": "stat" + }, + { + "datasource": "Prometheus", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "vis": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": true, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "s" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": ["avg"], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "single" + } + }, + "targets": [ + { + "expr": "histogram_quantile(0.50, s3_balance_s3_operation_duration_seconds_bucket)", + "legendFormat": "P50 - {{operation}}", + "refId": "A" + }, + { + "expr": "histogram_quantile(0.95, s3_balance_s3_operation_duration_seconds_bucket)", + "legendFormat": "P95 - {{operation}}", + "refId": "B" + }, + { + "expr": "histogram_quantile(0.99, s3_balance_s3_operation_duration_seconds_bucket)", + "legendFormat": "P99 - {{operation}}", + "refId": "C" + } + ], + "title": "操作延迟 (秒)", + "type": "timeseries" + } + ], + "refresh": "5s", + "schemaVersion": 30, + "style": "dark", + "tags": ["s3-balance", "monitoring"], + "templating": { + "list": [] + }, + "time": { + "from": "now-1h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "S3 Balance 监控面板", + "uid": "s3-balance-monitoring", + "version": 1 +} \ No newline at end of file diff --git a/deploy/monitoring/grafana/provisioning/dashboards/s3-balance.yml b/deploy/monitoring/grafana/provisioning/dashboards/s3-balance.yml new file mode 100644 index 0000000..66e1acb --- /dev/null +++ b/deploy/monitoring/grafana/provisioning/dashboards/s3-balance.yml @@ -0,0 +1,13 @@ +# Grafana 仪表板提供者配置 +apiVersion: 1 + +providers: + - name: 'S3 Balance' + orgId: 1 + folder: '' + type: file + disableDeletion: false + updateIntervalSeconds: 10 + allowUiUpdates: true + options: + path: /var/lib/grafana/dashboards \ No newline at end of file diff --git a/deploy/monitoring/grafana/provisioning/datasources/prometheus.yml b/deploy/monitoring/grafana/provisioning/datasources/prometheus.yml new file mode 100644 index 0000000..d8c225d --- /dev/null +++ b/deploy/monitoring/grafana/provisioning/datasources/prometheus.yml @@ -0,0 +1,11 @@ +# Grafana 数据源配置 +apiVersion: 1 + +datasources: + - name: Prometheus + type: prometheus + access: proxy + url: http://prometheus:9090 + isDefault: true + jsonData: + timeInterval: 5s \ No newline at end of file diff --git a/deploy/monitoring/prometheus.yml b/deploy/monitoring/prometheus.yml new file mode 100644 index 0000000..7b447de --- /dev/null +++ b/deploy/monitoring/prometheus.yml @@ -0,0 +1,30 @@ +# Prometheus 配置 - 抓取 S3 Balance 指标 +global: + scrape_interval: 15s # 抓取间隔 + evaluation_interval: 15s # 评估间隔 + +# 告警规则文件 +rule_files: + - "s3_balance_alerts.yml" + +# 抓取配置 +scrape_configs: + # S3 Balance 服务指标 + - job_name: 's3-balance' + static_configs: + - targets: ['s3-balance:8080'] + metrics_path: '/metrics' + scrape_interval: 15s + scrape_timeout: 10s + + # Node Exporter (系统指标) + - job_name: 'node-exporter' + static_configs: + - targets: ['node-exporter:9100'] + scrape_interval: 15s + +# 告警配置 +alerting: + alertmanagers: + - static_configs: + - targets: [] # 可以添加 AlertManager 地址 \ No newline at end of file diff --git a/deploy/monitoring/s3_balance_alerts.yml b/deploy/monitoring/s3_balance_alerts.yml new file mode 100644 index 0000000..18540d3 --- /dev/null +++ b/deploy/monitoring/s3_balance_alerts.yml @@ -0,0 +1,73 @@ +# S3 Balance 告警规则 +groups: + - name: s3_balance_alerts + rules: + # 存储桶不健康告警 + - alert: BucketUnhealthy + expr: s3_balance_bucket_healthy == 0 + for: 5m + labels: + severity: warning + annotations: + summary: "存储桶 {{ $labels.bucket }} 不健康" + description: "存储桶 {{ $labels.bucket }} ({{ $labels.endpoint }}) 已经连续5分钟不可用" + + # 错误率过高告警 + - alert: HighErrorRate + expr: rate(s3_balance_s3_operations_total{status="error"}[5m]) > 0.1 + for: 2m + labels: + severity: critical + annotations: + summary: "存储桶 {{ $labels.bucket }} 错误率过高" + description: "存储桶 {{ $labels.bucket }} 错误率超过10%,操作: {{ $labels.operation }}" + + # 操作延迟过高告警 + - alert: HighLatency + expr: histogram_quantile(0.95, rate(s3_balance_s3_operation_duration_seconds_bucket[5m])) > 1 + for: 5m + labels: + severity: warning + annotations: + summary: "{{ $labels.operation }} 操作延迟过高" + description: "{{ $labels.operation }} 操作95%分位数延迟超过1秒" + + # 存储桶使用率告警 + - alert: BucketUsageHigh + expr: s3_balance_bucket_usage_bytes / s3_balance_bucket_capacity_bytes > 0.9 + for: 5m + labels: + severity: warning + annotations: + summary: "存储桶 {{ $labels.bucket }} 使用率过高" + description: "存储桶 {{ $labels.bucket }} 使用率超过90%" + + # 存储桶满告警 + - alert: BucketFull + expr: s3_balance_bucket_usage_bytes / s3_balance_bucket_capacity_bytes >= 0.95 + for: 1m + labels: + severity: critical + annotations: + summary: "存储桶 {{ $labels.bucket }} 即将满了" + description: "存储桶 {{ $labels.bucket }} 使用率达到95%" + + # QPS过低告警 (可能服务异常) + - alert: LowQPS + expr: rate(s3_balance_s3_operations_total[5m]) == 0 + for: 10m + labels: + severity: warning + annotations: + summary: "QPS异常低" + description: "系统QPS为0,可能服务异常无请求" + + # 负载均衡失败告警 + - alert: BalancerDecisionFailure + expr: increase(s3_balance_balancer_decisions_total[5m]) == 0 + for: 5m + labels: + severity: warning + annotations: + summary: "负载均衡决策异常" + description: "5分钟内没有负载均衡决策,可能存储桶全部不可用" \ No newline at end of file diff --git a/deploy/start.sh b/deploy/start.sh new file mode 100755 index 0000000..16a5cee --- /dev/null +++ b/deploy/start.sh @@ -0,0 +1,309 @@ +#!/bin/bash + +# S3 Balance 快速部署脚本 +# 支持 Docker、Docker Compose、Kubernetes、HELM 四种部署方式 + +set -e + +# 显示帮助信息 +show_help() { + echo "S3 Balance 快速部署脚本" + echo "" + echo "用法: ./start.sh [选项]" + echo "" + echo "选项:" + echo " -m, --mode MODE 部署模式: docker|compose|kubernetes|helm" + echo " -e, --env ENV 环境: dev|test|prod (默认: dev)" + echo " -b, --build 构建镜像" + echo " -p, --port PORT 服务端口 (默认: 8080)" + echo " -h, --help 显示帮助信息" + echo "" + echo "示例:" + echo " ./start.sh -m compose -e prod" + echo " ./start.sh -m kubernetes --build" + echo " ./start.sh -m helm -e test" +} + +# 默认参数 +MODE="compose" +ENV="dev" +BUILD=false +PORT="8080" + +# 解析命令行参数 +while [[ $# -gt 0 ]]; do + case $1 in + -m|--mode) + MODE="$2" + shift 2 + ;; + -e|--env) + ENV="$2" + shift 2 + ;; + -b|--build) + BUILD=true + shift + ;; + -p|--port) + PORT="$2" + shift 2 + ;; + -h|--help) + show_help + exit 0 + ;; + *) + echo "未知选项: $1" + show_help + exit 1 + ;; + esac +done + +# 输出配置信息 +echo "🚀 S3 Balance 快速部署开始..." +echo "📋 配置信息:" +echo " 部署模式: $MODE" +echo " 环境: $ENV" +echo " 构建镜像: $BUILD" +echo " 服务端口: $PORT" +echo "" + +# 检查必要工具 +check_requirements() { + local tool=$1 + local tool_name=$2 + if ! command -v $tool &> /dev/null; then + echo "❌ $tool_name 未安装" + return 1 + fi + echo "✅ $tool_name 已安装" +} + +# Docker 模式部署 +deploy_docker() { + echo "📦 Docker 单容器部署..." + + check_requirements docker "Docker" || exit 1 + + if [ "$BUILD" = true ]; then + echo "🔨 构建 Docker 镜像..." + docker build -t s3-balance:$MODE-$ENV -f deploy/docker/Dockerfile . + fi + + echo "🚀 启动容器..." + docker run -d \ + --name s3-balance-$ENV \ + -p $PORT:8080 \ + -v $(pwd)/deploy/docker/config.docker.yaml:/app/config/config.yaml \ + -v s3-balance-data:/app/data \ + -e TZ=Asia/Shanghai \ + --restart unless-stopped \ + s3-balance:$MODE-$ENV + + echo "✅ Docker 容器已启动" +} + +# Docker Compose 模式部署 +deploy_compose() { + echo "🐳 Docker Compose 部署..." + + check_requirements docker "Docker" || exit 1 + check_requirements docker-compose "Docker Compose" || exit 1 + + if [ "$BUILD" = true ]; then + echo "🔨 构建 Docker 镜像..." + cd deploy/docker + docker build -t s3-balance:$MODE-$ENV -f Dockerfile ../.. + fi + + echo "🚀 启动服务栈..." + cd deploy/docker + + # 修改 docker-compose.yml 中的端口 + if [ "$PORT" != "8080" ]; then + sed -i.bak "s/8080:8080/$PORT:8080/" docker-compose.yml + fi + + docker-compose up -d + + # 恢复配置文件 + if [ "$PORT" != "8080" ]; then + mv docker-compose.yml.bak docker-compose.yml + fi + + cd ../.. + echo "✅ Docker Compose 服务已启动" +} + +# Kubernetes 模式部署 +deploy_kubernetes() { + echo "☸️ Kubernetes 部署..." + + check_requirements kubectl "kubectl" || exit 1 + check_requirements kubectl "Kubernetes 集群连接" || exit 1 + + echo "🚀 应用 Kubernetes 配置..." + cd deploy/kubernetes + + # 替换环境变量 + if [ "$ENV" != "dev" ]; then + # 根据环境替换镜像标签 + sed -i.bak 's/image: s3-balance:latest/image: s3-balance:'"$ENV"'/' deployment.yaml + fi + + kubectl apply -f namespace.yaml + kubectl apply -f configmap.yaml + kubectl apply -f deployment.yaml + kubectl apply -f service.yaml + kubectl apply -f ingress.yaml + + # 如果是生产环境,应用 HPA + if [ "$ENV" = "prod" ]; then + kubectl apply -f hpa.yaml + echo "📊 已启用水平自动扩缩容" + fi + + # 恢复配置文件 + if [ -f deployment.yaml.bak ]; then + mv deployment.yaml.bak deployment.yaml + fi + + cd ../.. + echo "✅ Kubernetes 部署完成" +} + +# HELM 模式部署 +deploy_helm() { + echo "🔧 HELM Chart 部署..." + + check_requirements helm "HELM" || exit 1 + check_requirements kubectl "kubectl" || exit 1 + + echo "🚀 部署 HELM Chart..." + cd deploy/helm + + # 根据环境选择 values 文件 + VALUES_FILE="values.yaml" + if [ "$ENV" = "prod" ] && [ -f "production-values.yaml" ]; then + VALUES_FILE="production-values.yaml" + fi + + # 安装或升级 Chart + if helm status s3-balance-$ENV 2>/dev/null; then + echo "⬆️ 升级现有 HELM 发布..." + helm upgrade s3-balance-$ENV s3-balance -f $VALUES_FILE \ + --namespace s3-balance-$ENV \ + --create-namespace \ + --wait + else + echo "📦 安装新的 HELM Chart..." + helm install s3-balance-$ENV s3-balance -f $VALUES_FILE \ + --namespace s3-balance-$ENV \ + --create-namespace \ + --wait + fi + + cd ../.. + echo "✅ HELM Chart 部署完成" +} + +# 通用后处理 +post_deploy() { + echo "" + echo "⏳ 等待服务启动..." + sleep 10 + + case $MODE in + docker) + echo "" + echo "✅ Docker 部署完成!" + echo "🔗 访问地址:" + echo " 📊 指标端点: http://localhost:$PORT/metrics" + echo "" + echo "📝 Docker 命令:" + echo " docker logs -f s3-balance-$ENV # 查看日志" + echo " docker stop s3-balance-$ENV # 停止服务" + echo " docker rm s3-balance-$ENV # 删除容器" + ;; + + compose) + echo "" + echo "✅ Docker Compose 部署完成!" + echo "🔗 访问地址:" + echo " 📊 Grafana 面板: http://localhost:3000 (admin/admin123)" + echo " 🔥 Prometheus: http://localhost:9090" + echo " 📈 指标端点: http://localhost:$PORT/metrics" + echo "" + echo "📝 Compose 命令:" + echo " cd deploy/docker && docker-compose logs -f # 查看日志" + echo " cd deploy/docker && docker-compose down # 停止服务" + ;; + + kubernetes) + echo "" + echo "✅ Kubernetes 部署完成!" + echo "🔗 检查状态:" + echo " kubectl get pods -n s3-balance" + echo " kubectl get svc -n s3-balance" + echo " kubectl get ingress -n s3-balance" + echo "" + echo "📋 常用命令:" + echo " kubectl logs -f deployment/s3-balance-deployment -n s3-balance" + echo " kubectl scale deployment s3-balance-deployment --replicas=5 -n s3-balance" + ;; + + helm) + echo "" + echo "✅ HELM Chart 部署完成!" + echo "🔗 检查状态:" + echo " helm status s3-balance-$ENV -n s3-balance-$ENV" + echo " kubectl get pods -n s3-balance-$ENV" + echo " kubectl get svc -n s3-balance-$ENV" + echo "" + echo "🔧 HELM 命令:" + echo " helm uninstall s3-balance-$ENV -n s3-balance-$ENV" + echo " helm list -A" + ;; + esac + + echo "" + echo "📊 监控指标查询:" + echo " - 存储桶健康: s3_balance_bucket_healthy" + echo " - QPS: rate(s3_balance_s3_operations_total[1m])" + echo " - 延迟: histogram_quantile(0.95, s3_balance_s3_operation_duration_seconds_bucket)" + echo "" + echo "🎉 部署完成!享受 S3 Balance 服务!" +} + +# 主执行逻辑 +main() { + echo "🚀 开始部署 S3 Balance..." + + # 根据模式执行部署 + case $MODE in + docker) + deploy_docker + ;; + compose) + deploy_compose + ;; + kubernetes) + deploy_kubernetes + ;; + helm) + deploy_helm + ;; + *) + echo "❌ 未知部署模式: $MODE" + show_help + exit 1 + ;; + esac + + post_deploy +} + +# 执行主函数 +main \ No newline at end of file diff --git a/go.mod b/go.mod index 2becded..5979f00 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/aws/aws-sdk-go-v2/credentials v1.18.5 github.com/aws/aws-sdk-go-v2/service/s3 v1.87.0 github.com/gorilla/mux v1.8.1 + github.com/prometheus/client_golang v1.23.2 gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/mysql v1.6.0 gorm.io/driver/postgres v1.6.0 @@ -31,6 +32,8 @@ require ( github.com/aws/aws-sdk-go-v2/service/ssooidc v1.33.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.37.1 // indirect github.com/aws/smithy-go v1.22.5 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect @@ -40,8 +43,15 @@ require ( github.com/jinzhu/now v1.1.5 // indirect github.com/kr/text v0.2.0 // indirect github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.66.1 // indirect + github.com/prometheus/procfs v0.16.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/crypto v0.31.0 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/text v0.28.0 // indirect + google.golang.org/protobuf v1.36.8 // indirect ) diff --git a/go.sum b/go.sum index c93136c..3d94c36 100644 --- a/go.sum +++ b/go.sum @@ -36,12 +36,18 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.37.1 h1:ssCHKyNJqTnqRH4Vlf+jI0brtGQY github.com/aws/aws-sdk-go-v2/service/sts v1.37.1/go.mod h1:JdeBDPgpJfuS6rU/hNglmOigKhyEZtBmbraLE4GK1J8= github.com/aws/smithy-go v1.22.5 h1:P9ATCXPMb2mPjYBgueqJNCA5S9UfktsW0tTxi+a7eqw= github.com/aws/smithy-go v1.22.5/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -56,27 +62,49 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= +github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= +github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= +google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=