自动配置Helm Chart部署的脚本

wen 实用脚本 1

本文目录导读:

自动配置Helm Chart部署的脚本

  1. 完整的 Helm 部署脚本
  2. 配置文件示例
  3. 使用示例
  4. 注意事项

我来帮你创建一个自动配置和部署 Helm Chart 的脚本,这个脚本将包含完整的部署流程、错误处理和配置管理功能。

完整的 Helm 部署脚本

#!/bin/bash
# =============================================
# 自动配置 Helm Chart 部署脚本
# =============================================
set -euo pipefail
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# =============================================
# 配置变量 - 根据项目修改这些值
# =============================================
# 项目配置
PROJECT_NAME="my-app"
NAMESPACE="default"
CHART_NAME="my-chart"
CHART_VERSION="1.0.0"
RELEASE_NAME="${PROJECT_NAME}-release"
# 环境配置
ENVIRONMENT=${1:-"dev"}  # dev, staging, production
ACTION=${2:-"install"}   # install, upgrade, uninstall, status, rollback
# Helm 仓库配置
HELM_REPO_URL=""
HELM_REPO_NAME="my-repo"
# 配置文件路径
VALUES_DIR="./values"
VALUES_FILE="${VALUES_DIR}/values-${ENVIRONMENT}.yaml"
COMMON_VALUES="${VALUES_DIR}/values-common.yaml"
SECRETS_FILE="${VALUES_DIR}/secrets-${ENVIRONMENT}.yaml"
# 部署配置
DEPLOY_TIMEOUT="300s"
MAX_HISTORY=5
ROLLBACK_VERSION=0
# =============================================
# 函数定义
# =============================================
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}
# 检查依赖
check_dependencies() {
    log_info "检查依赖..."
    # 检查 Helm
    if ! command -v helm &> /dev/null; then
        log_error "Helm 未安装,请运行: curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash"
        exit 1
    fi
    log_success "Helm 版本: $(helm version --short)"
    # 检查 kubectl
    if ! command -v kubectl &> /dev/null; then
        log_error "kubectl 未安装"
        exit 1
    fi
    log_success "kubectl 已安装"
    # 检查 yq (用于 YAML 处理)
    if ! command -v yq &> /dev/null; then
        log_warning "yq 未安装,将使用 grep/sed 进行基本 YAML 处理"
    else
        log_success "yq 已安装"
    fi
}
# 初始化 Helm
initialize_helm() {
    log_info "初始化 Helm..."
    # 添加 Helm 仓库
    if [[ -n "$HELM_REPO_URL" && -n "$HELM_REPO_NAME" ]]; then
        if ! helm repo list | grep -q "$HELM_REPO_NAME"; then
            helm repo add "$HELM_REPO_NAME" "$HELM_REPO_URL"
            log_success "添加 Helm 仓库: $HELM_REPO_NAME"
        else
            log_info "Helm 仓库已存在: $HELM_REPO_NAME"
        fi
    fi
    # 更新仓库
    helm repo update
    log_success "Helm 仓库已更新"
}
# 创建命名空间
create_namespace() {
    log_info "检查命名空间: $NAMESPACE"
    if ! kubectl get namespace "$NAMESPACE" &> /dev/null; then
        kubectl create namespace "$NAMESPACE"
        log_success "创建命名空间: $NAMESPACE"
    else
        log_info "命名空间已存在: $NAMESPACE"
    fi
}
# 准备 values 文件
prepare_values() {
    log_info "准备配置..."
    local temp_values=$(mktemp)
    local final_values="${VALUES_DIR}/final-${ENVIRONMENT}.yaml"
    # 创建 values 目录
    mkdir -p "$VALUES_DIR"
    # 合并 values 文件
    if [[ -f "$COMMON_VALUES" ]]; then
        log_info "使用公共配置: $COMMON_VALUES"
        cp "$COMMON_VALUES" "$temp_values"
    fi
    if [[ -f "$VALUES_FILE" ]]; then
        log_info "使用环境配置: $VALUES_FILE"
        if [[ -f "$temp_values" ]]; then
            yq eval-all '. as $item ireduce ({}; . *+ $item)' "$temp_values" "$VALUES_FILE" > "$final_values" 2>/dev/null || \
            cat "$VALUES_FILE" > "$final_values"
        else
            cp "$VALUES_FILE" "$final_values"
        fi
    else
        log_warning "环境配置文件不存在: $VALUES_FILE"
        # 创建默认配置
        cat > "$VALUES_FILE" << EOF
# ${ENVIRONMENT} 环境配置
replicaCount: 1
image:
  repository: nginx
  tag: latest
  pullPolicy: IfNotPresent
service:
  type: ClusterIP
  port: 80
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi
EOF
        log_info "创建默认配置: $VALUES_FILE"
        cp "$VALUES_FILE" "$final_values"
    fi
    # 处理 secrets
    if [[ -f "$SECRETS_FILE" ]]; then
        log_info "使用加密配置: $SECRETS_FILE"
        # 如果是加密文件,需要解密
        if [[ "$SECRETS_FILE" == *.enc ]]; then
            decrypt_secrets "$SECRETS_FILE" "${SECRETS_FILE%.enc}"
            yq eval-all '. as $item ireduce ({}; . *+ $item)' "$final_values" "${SECRETS_FILE%.enc}" > "${final_values}.tmp"
            mv "${final_values}.tmp" "$final_values"
        else
            yq eval-all '. as $item ireduce ({}; . *+ $item)' "$final_values" "$SECRETS_FILE" > "${final_values}.tmp" 2>/dev/null || \
            cat "$final_values" "$SECRETS_FILE" > "${final_values}.tmp"
            mv "${final_values}.tmp" "$final_values"
        fi
    fi
    # 设置环境变量
    yq eval ".global.environment = \"${ENVIRONMENT}\"" "$final_values" > "${final_values}.tmp" 2>/dev/null || true
    mv "${final_values}.tmp" "$final_values"
    echo "$final_values"
}
# 解密 secrets 文件
decrypt_secrets() {
    local encrypted_file=$1
    local decrypted_file=$2
    log_info "解密配置文件..."
    # 使用 sops 解密
    if command -v sops &> /dev/null; then
        sops -d "$encrypted_file" > "$decrypted_file"
        log_success "使用 sops 解密成功"
    # 使用 helm-secrets 插件
    elif helm plugin list | grep -q "secrets"; then
        helm secrets decrypt "$encrypted_file" > "$decrypted_file"
        log_success "使用 helm-secrets 解密成功"
    else
        log_warning "未找到解密工具,使用原始文件"
        cp "$encrypted_file" "$decrypted_file"
    fi
}
# 安装/升级 Helm Chart
install_or_upgrade() {
    local values_file=$1
    local action=$2
    log_info "${action} Helm Chart..."
    # 构建 Helm 命令
    local helm_cmd="helm ${action} ${RELEASE_NAME} ${CHART_NAME}"
    # 添加命名空间
    helm_cmd+=" --namespace ${NAMESPACE}"
    # 添加 values 文件
    if [[ -n "$values_file" && -f "$values_file" ]]; then
        helm_cmd+=" --values ${values_file}"
    fi
    # 添加额外选项
    helm_cmd+=" --timeout ${DEPLOY_TIMEOUT}"
    helm_cmd+=" --history-max ${MAX_HISTORY}"
    # 如果是升级,添加升级选项
    if [[ "$action" == "upgrade" ]]; then
        helm_cmd+=" --install"  # release 不存在则安装
        helm_cmd+=" --cleanup-on-fail"
        helm_cmd+=" --atomic"    # 失败时自动回滚
        helm_cmd+=" --wait"     # 等待就绪
    fi
    # 如果是安装,添加安装选项
    if [[ "$action" == "install" ]]; then
        helm_cmd+=" --create-namespace"
        helm_cmd+=" --wait"
    fi
    # 添加部署标签
    helm_cmd+=" --set global.deployedBy=\"helm-auto-deploy\""
    helm_cmd+=" --set global.deployedAt=\"$(date -u +%Y-%m-%dT%H:%M:%SZ)\""
    # 执行 Helm 命令
    log_info "执行命令: $helm_cmd"
    if $helm_cmd; then
        log_success "Helm ${action} 成功"
        # 检查部署状态
        sleep 5
        check_deployment_status
    else
        log_error "Helm ${action} 失败"
        return 1
    fi
}
# 检查部署状态
check_deployment_status() {
    log_info "检查部署状态..."
    # 检查 Pod 状态
    echo ""
    log_info "Pod 状态:"
    kubectl get pods -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" --show-labels 2>/dev/null || true
    # 检查 Service
    echo ""
    log_info "Service 状态:"
    kubectl get services -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" 2>/dev/null || true
    # 检查 Ingress
    echo ""
    log_info "Ingress 状态:"
    kubectl get ingress -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" 2>/dev/null || true
    # 检查 HPA
    echo ""
    log_info "HPA 状态:"
    kubectl get hpa -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" 2>/dev/null || true
    # 获取访问信息
    echo ""
    log_info "访问信息:"
    local service_name=$(kubectl get svc -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" -o jsonpath='{.items[0].metadata.name}' 2>/dev/null || echo "")
    if [[ -n "$service_name" ]]; then
        local node_port=$(kubectl get svc -n "$NAMESPACE" "$service_name" -o jsonpath='{.spec.ports[0].nodePort}' 2>/dev/null || echo "")
        local cluster_ip=$(kubectl get svc -n "$NAMESPACE" "$service_name" -o jsonpath='{.spec.clusterIP}' 2>/dev/null || echo "")
        if [[ -n "$node_port" ]]; then
            echo "  NodePort: ${node_port}"
        fi
        if [[ -n "$cluster_ip" ]]; then
            echo "  ClusterIP: ${cluster_ip}"
        fi
    fi
}
# 卸载 Helm Release
uninstall_release() {
    log_info "卸载 Helm Release: $RELEASE_NAME"
    read -p "确认卸载 ${RELEASE_NAME}? (y/N) " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        helm uninstall "$RELEASE_NAME" --namespace "$NAMESPACE"
        log_success "卸载成功"
    else
        log_info "取消卸载"
    fi
}
# 回滚 Helm Release
rollback_release() {
    local version=${1:-0}
    log_info "回滚 Helm Release: $RELEASE_NAME"
    # 获取历史版本
    echo ""
    log_info "发布历史:"
    helm history "$RELEASE_NAME" --namespace "$NAMESPACE" 2>/dev/null || true
    if [[ "$version" -eq 0 ]]; then
        # 如果没有指定版本,回滚到上一个版本
        local revisions=$(helm history "$RELEASE_NAME" --namespace "$NAMESPACE" -o json 2>/dev/null | jq '. | length' 2>/dev/null || echo "0")
        if [[ "$revisions" -gt 1 ]]; then
            version=$((revisions - 1))
        else
            log_error "没有可回滚的版本"
            return 1
        fi
    fi
    echo ""
    read -p "确认回滚到版本 ${version}? (y/N) " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        helm rollback "$RELEASE_NAME" "$version" --namespace "$NAMESPACE" --wait
        log_success "回滚到版本 ${version} 成功"
        check_deployment_status
    else
        log_info "取消回滚"
    fi
}
# 查看部署状态
show_status() {
    log_info "查看部署状态..."
    # 检查 Helm Release 状态
    echo ""
    log_info "Helm Release 状态:"
    helm status "$RELEASE_NAME" --namespace "$NAMESPACE" 2>/dev/null || log_warning "Release 不存在"
    # 列出所有资源
    echo ""
    log_info "所有资源列表:"
    kubectl get all -n "$NAMESPACE" -l "app.kubernetes.io/instance=${RELEASE_NAME}" 2>/dev/null || true
    # 显示历史版本
    echo ""
    log_info "发布历史:"
    helm history "$RELEASE_NAME" --namespace "$NAMESPACE" 2>/dev/null || true
}
# 创建默认 Chart 结构
create_default_chart() {
    if [[ ! -d "$CHART_NAME" ]]; then
        log_info "创建默认 Chart 结构..."
        mkdir -p "$CHART_NAME/templates"
        mkdir -p "$CHART_NAME/charts"
        # 创建 Chart.yaml
        cat > "$CHART_NAME/Chart.yaml" << EOF
apiVersion: v2
name: ${CHART_NAME}
description: A Helm chart for ${PROJECT_NAME}
type: application
version: ${CHART_VERSION}
appVersion: "1.0.0"
EOF
        # 创建默认 values.yaml
        cat > "$CHART_NAME/values.yaml" << EOF
# 默认配置
replicaCount: 1
image:
  repository: nginx
  tag: latest
  pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
  create: true
  annotations: {}
  name: ""
podAnnotations: {}
podSecurityContext: {}
securityContext: {}
service:
  type: ClusterIP
  port: 80
ingress:
  enabled: false
  className: ""
  annotations: {}
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi
autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
EOF
        # 创建默认 Deployment
        cat > "$CHART_NAME/templates/deployment.yaml" << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "chart.fullname" . }}
  labels:
    {{- include "chart.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "chart.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      {{- with .Values.podAnnotations }}
      annotations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      labels:
        {{- include "chart.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      serviceAccountName: {{ include "chart.serviceAccountName" . }}
      securityContext:
        {{- toYaml .Values.podSecurityContext | nindent 8 }}
      containers:
        - name: {{ .Chart.Name }}
          securityContext:
            {{- toYaml .Values.securityContext | nindent 12 }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.port }}
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
      {{- end }}
EOF
        # 创建 Service
        cat > "$CHART_NAME/templates/service.yaml" << 'EOF'
apiVersion: v1
kind: Service
metadata:
  name: {{ include "chart.fullname" . }}
  labels:
    {{- include "chart.labels" . | nindent 4 }}
spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.port }}
      targetPort: http
      protocol: TCP
      name: http
  selector:
    {{- include "chart.selectorLabels" . | nindent 4 }}
EOF
        # 创建 _helpers.tpl
        cat > "$CHART_NAME/templates/_helpers.tpl" << 'EOF'
{{- define "chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.name" . }}-{{ .Chart.Version | replace "+" "_" }}
{{ include "chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{- define "chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{- define "chart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "chart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
EOF
        log_success "创建默认 Chart 结构完成"
    else
        log_info "Chart 目录已存在"
    fi
}
# 主函数
main() {
    echo ""
    echo "=============================================="
    echo "  Helm Chart 自动化部署脚本"
    echo "=============================================="
    echo "  环境: ${ENVIRONMENT}"
    echo "  操作: ${ACTION}"
    echo "  项目: ${PROJECT_NAME}"
    echo "  Release: ${RELEASE_NAME}"
    echo "=============================================="
    echo ""
    # 检查依赖
    check_dependencies
    # 初始化 Helm
    initialize_helm
    # 根据操作执行不同命令
    case "$ACTION" in
        install)
            # 创建默认 Chart
            create_default_chart
            # 创建命名空间
            create_namespace
            # 准备配置
            local values_file
            values_file=$(prepare_values)
            # 安装
            install_or_upgrade "$values_file" "install"
            ;;
        upgrade)
            # 准备配置
            local values_file
            values_file=$(prepare_values)
            # 升级
            install_or_upgrade "$values_file" "upgrade"
            ;;
        uninstall)
            uninstall_release
            ;;
        rollback)
            rollback_release "$ROLLBACK_VERSION"
            ;;
        status)
            show_status
            ;;
        *)
            echo "用法: $0 <environment> <action>"
            echo ""
            echo "环境:"
            echo "  dev        开发环境"
            echo "  staging    预发布环境"
            echo "  production 生产环境"
            echo ""
            echo "操作:"
            echo "  install    安装新的 release"
            echo "  upgrade    升级已有的 release"
            echo "  uninstall  删除 release"
            echo "  rollback   回滚 release"
            echo "  status     查看状态"
            echo ""
            echo "示例:"
            echo "  $0 dev install"
            echo "  $0 production upgrade"
            echo "  $0 staging uninstall"
            echo "  $0 dev rollback"
            echo "  $0 production status"
            exit 1
            ;;
    esac
    echo ""
    log_success "操作完成"
}
# 执行主函数
main "$@"

配置文件示例

公共配置 (values/values-common.yaml)

# 公共配置
global:
  environment: ""
  registry: "registry.example.com"
imagePullSecrets:
  - name: registry-credentials
ingress:
  enabled: true
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi

开发环境配置 (values/values-dev.yaml)

# 开发环境配置
replicaCount: 1
image:
  repository: registry.example.com/my-app
  tag: dev-latest
  pullPolicy: Always
ingress:
  enabled: false
service:
  type: NodePort
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 250m
    memory: 256Mi
autoscaling:
  enabled: false

生产环境配置 (values/values-production.yaml)

# 生产环境配置
replicaCount: 3
image:
  repository: registry.example.com/my-app
  tag: stable
  pullPolicy: IfNotPresent
ingress:
  enabled: true
  hosts:
    - host: app.example.com
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls:
    - hosts:
        - app.example.com
      secretName: app-tls
resources:
  limits:
    cpu: 1
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi
autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70

加密 Secrets (values/secrets-production.yaml.enc)

# 加密的敏感信息
env:
  DATABASE_URL: postgresql://user:password@localhost:5432/dbname
  REDIS_PASSWORD: your-redis-password
  API_KEY: your-api-key
# 注意:实际使用时,需要使用 sops 或 helm-secrets 进行加密

使用示例

基本使用

# 赋予执行权限
chmod +x deploy.sh
# 安装到开发环境
./deploy.sh dev install
# 升级生产环境
./deploy.sh production upgrade
# 查看状态
./deploy.sh dev status
# 回滚到上一个版本
./deploy.sh staging rollback
# 卸载
./deploy.sh dev uninstall

高级用法

# 使用自定义值文件
VALUES_DIR=custom-values ./deploy.sh dev install
# 设置超时时间
DEPLOY_TIMEOUT=600s ./deploy.sh production upgrade
# 指定回滚到特定版本
ROLLBACK_VERSION=3 ./deploy.sh production rollback
# 使用不同的命名空间
NAMESPACE=my-custom-ns ./deploy.sh dev install

CI/CD 集成 (GitLab CI)

# .gitlab-ci.yml
deploy-dev:
  stage: deploy
  script:
    - chmod +x deploy.sh
    - ./deploy.sh dev install
  only:
    - develop
deploy-production:
  stage: deploy
  script:
    - chmod +x deploy.sh
    - ./deploy.sh production upgrade
  only:
    - tags
  environment:
    name: production
    url: https://app.example.com

GitHub Actions

# .github/workflows/deploy.yml
name: Deploy to Kubernetes
on:
  push:
    branches: [main]
    tags: ['v*']
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Install Helm
        uses: azure/setup-helm@v3
      - name: Deploy
        run: |
          chmod +x deploy.sh
          ./deploy.sh production upgrade
        env:
          KUBECONFIG: ${{ secrets.KUBECONFIG }}

注意事项

  1. 安全性

    • 不要在脚本中硬编码密码
    • 使用 sopshelm-secrets 加密敏感信息
    • 限制脚本执行权限
  2. 配置管理

    • 维护不同环境的值文件
    • 使用版本控制管理配置
    • 定期审核配置文件
  3. 错误处理

    • 脚本包含基本的错误处理
    • 生产环境建议添加更严格的验证
    • 实现部署前检查
  4. 监控和日志

    • 记录所有部署操作
    • 集成监控告警
    • 保存部署历史
  5. 回滚策略

    • 保留足够的发布历史
    • 测试回滚流程
    • 文档化回滚步骤

这个脚本提供了一个完整、可扩展的 Helm Chart 部署解决方案,可以根据实际需求进行定制和扩展。

抱歉,评论功能暂时关闭!