本章概述

Helm Chart 仓库是存储和分发 Chart 的中心化平台,类似于 Docker Registry 之于容器镜像。通过 Chart 仓库,我们可以轻松地共享、版本管理和分发 Helm Chart。本章将深入探讨如何创建、管理和使用 Chart 仓库,以及如何构建企业级的 Chart 分发体系。

学习目标

  • 理解 Chart 仓库的概念和架构
  • 掌握公共和私有仓库的使用方法
  • 学会创建和管理自己的 Chart 仓库
  • 了解 Chart 打包和版本管理
  • 掌握 Chart 签名和安全验证
  • 学习企业级仓库的最佳实践
  • 了解 OCI 仓库和新一代分发方式

7.1 Chart 仓库概述

7.1.1 仓库架构

graph TB
    A[Helm Client] --> B[Chart Repository]
    B --> C[Chart Index]
    B --> D[Chart Packages]
    
    subgraph "仓库类型"
        E[Public Repository]
        F[Private Repository]
        G[OCI Registry]
        H[Local Repository]
    end
    
    subgraph "仓库组件"
        I[index.yaml]
        J[Chart Archives]
        K[Provenance Files]
        L[Metadata]
    end
    
    subgraph "分发方式"
        M[HTTP/HTTPS]
        N[Git Repository]
        O[Cloud Storage]
        P[Container Registry]
    end

7.1.2 仓库的优势

  1. 集中管理:统一存储和管理所有 Chart
  2. 版本控制:支持多版本并存和回滚
  3. 访问控制:支持权限管理和安全控制
  4. 自动化:支持 CI/CD 集成和自动发布
  5. 可发现性:便于搜索和发现可用的 Chart

7.2 使用公共仓库

7.2.1 添加官方仓库

# 添加官方稳定仓库
helm repo add stable https://charts.helm.sh/stable

# 添加 Bitnami 仓库
helm repo add bitnami https://charts.bitnami.com/bitnami

# 添加 Prometheus 社区仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# 添加 Ingress Nginx 仓库
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

# 添加 Jetstack 仓库(cert-manager)
helm repo add jetstack https://charts.jetstack.io

# 更新仓库索引
helm repo update

7.2.2 仓库管理命令

# 列出已添加的仓库
helm repo list

# 搜索 Chart
helm search repo nginx
helm search repo database

# 查看仓库中的 Chart 版本
helm search repo bitnami/mysql --versions

# 获取 Chart 信息
helm show chart bitnami/mysql
helm show values bitnami/mysql
helm show readme bitnami/mysql

# 移除仓库
helm repo remove stable

# 更新特定仓库
helm repo update bitnami

7.2.3 仓库配置文件

# ~/.config/helm/repositories.yaml
apiVersion: ""
generated: "2023-01-01T00:00:00Z"
repositories:
- caFile: ""
  certFile: ""
  insecure_skip_tls_verify: false
  keyFile: ""
  name: bitnami
  pass_credentials_all: false
  password: ""
  url: https://charts.bitnami.com/bitnami
  username: ""
- caFile: ""
  certFile: ""
  insecure_skip_tls_verify: false
  keyFile: ""
  name: prometheus-community
  pass_credentials_all: false
  password: ""
  url: https://prometheus-community.github.io/helm-charts
  username: ""

7.3 创建私有仓库

7.3.1 基于 HTTP 服务器的仓库

# 创建仓库目录
mkdir -p ~/helm-repo/charts
cd ~/helm-repo

# 创建 index.yaml
helm repo index charts --url http://localhost:8080/charts

# 启动 HTTP 服务器
python3 -m http.server 8080
# 或使用 nginx
# nginx -p . -c nginx.conf
# nginx.conf
events {
    worker_connections 1024;
}

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    
    server {
        listen 8080;
        server_name localhost;
        
        location /charts/ {
            root /path/to/helm-repo;
            autoindex on;
            autoindex_exact_size off;
            autoindex_localtime on;
        }
        
        location /health {
            access_log off;
            return 200 "healthy\n";
            add_header Content-Type text/plain;
        }
    }
}

7.3.2 使用 ChartMuseum

# 安装 ChartMuseum
curl -LO https://get.helm.sh/chartmuseum-v0.15.0-linux-amd64.tar.gz
tar -xzf chartmuseum-v0.15.0-linux-amd64.tar.gz
sudo mv linux-amd64/chartmuseum /usr/local/bin/

# 启动 ChartMuseum
chartmuseum --debug --port=8080 \
  --storage="local" \
  --storage-local-rootdir="./charts" \
  --basic-auth-user="admin" \
  --basic-auth-pass="password"
# docker-compose.yml
version: '3.8'

services:
  chartmuseum:
    image: chartmuseum/chartmuseum:v0.15.0
    container_name: chartmuseum
    ports:
      - "8080:8080"
    environment:
      DEBUG: 1
      STORAGE: local
      STORAGE_LOCAL_ROOTDIR: /charts
      BASIC_AUTH_USER: admin
      BASIC_AUTH_PASS: password
      ALLOW_OVERWRITE: true
    volumes:
      - ./charts:/charts
    restart: unless-stopped
# 启动 ChartMuseum
docker-compose up -d

# 添加仓库
helm repo add myrepo http://admin:password@localhost:8080

# 上传 Chart
curl --data-binary "@mychart-1.0.0.tgz" \
     -u admin:password \
     http://localhost:8080/api/charts

7.3.3 基于云存储的仓库

AWS S3 仓库

# 安装 helm-s3 插件
helm plugin install https://github.com/hypnoglow/helm-s3.git

# 创建 S3 bucket
aws s3 mb s3://my-helm-charts

# 初始化仓库
helm s3 init s3://my-helm-charts/charts

# 添加仓库
helm repo add my-s3-repo s3://my-helm-charts/charts

# 上传 Chart
helm s3 push mychart-1.0.0.tgz my-s3-repo
# S3 bucket policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowHelmAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::ACCOUNT-ID:user/helm-user"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-helm-charts",
        "arn:aws:s3:::my-helm-charts/*"
      ]
    }
  ]
}

Google Cloud Storage 仓库

# 安装 helm-gcs 插件
helm plugin install https://github.com/hayorov/helm-gcs.git

# 创建 GCS bucket
gsutil mb gs://my-helm-charts

# 初始化仓库
helm gcs init gs://my-helm-charts

# 添加仓库
helm repo add my-gcs-repo gs://my-helm-charts

# 上传 Chart
helm gcs push mychart-1.0.0.tgz my-gcs-repo

7.3.4 基于 Git 的仓库

# 创建 Git 仓库
mkdir helm-charts
cd helm-charts
git init

# 创建目录结构
mkdir -p charts docs

# 添加 Chart
cp -r ../mychart charts/

# 打包 Chart
helm package charts/mychart -d charts/

# 生成索引
helm repo index charts --url https://username.github.io/helm-charts/charts

# 提交到 Git
git add .
git commit -m "Add mychart"
git push origin main
# .github/workflows/release.yml
name: Release Charts

on:
  push:
    branches:
      - main

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Configure Git
        run: |
          git config user.name "$GITHUB_ACTOR"
          git config user.email "$GITHUB_ACTOR@users.noreply.github.com"

      - name: Install Helm
        uses: azure/setup-helm@v3
        with:
          version: v3.10.0

      - name: Run chart-releaser
        uses: helm/chart-releaser-action@v1.4.1
        env:
          CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

7.4 Chart 打包和发布

7.4.1 Chart 打包

# 基本打包
helm package mychart

# 指定版本
helm package mychart --version 1.2.3

# 指定应用版本
helm package mychart --app-version 2.1.0

# 指定输出目录
helm package mychart -d ./packages

# 更新依赖后打包
helm dependency update mychart
helm package mychart

# 签名打包
helm package mychart --sign --key 'My Key' --keyring ~/.gnupg/secring.gpg

7.4.2 版本管理策略

# Chart.yaml 版本配置
apiVersion: v2
name: mychart
description: A Helm chart for my application

# Chart 版本(遵循 SemVer)
version: 1.2.3

# 应用版本
appVersion: "2.1.0"

# 版本注释
annotations:
  # 变更日志
  artifacthub.io/changes: |
    - kind: added
      description: Support for custom annotations
    - kind: changed
      description: Default replica count changed to 2
    - kind: fixed
      description: Fixed issue with service account creation
  
  # 许可证
  artifacthub.io/license: Apache-2.0
  
  # 维护者
  artifacthub.io/maintainers: |
    - name: John Doe
      email: john@example.com

7.4.3 自动化发布流程

#!/bin/bash
# scripts/release.sh

set -e

CHART_DIR=${1:-"./charts"}
REPO_URL=${2:-"http://localhost:8080"}
VERSION=${3:-""}

echo "Starting chart release process..."

# 验证 Chart
echo "Validating charts..."
for chart in $CHART_DIR/*/; do
  if [ -f "$chart/Chart.yaml" ]; then
    echo "Validating $(basename $chart)..."
    helm lint "$chart"
    helm template test "$chart" > /dev/null
  fi
done

# 更新依赖
echo "Updating dependencies..."
for chart in $CHART_DIR/*/; do
  if [ -f "$chart/Chart.yaml" ]; then
    echo "Updating dependencies for $(basename $chart)..."
    helm dependency update "$chart"
  fi
done

# 打包 Chart
echo "Packaging charts..."
mkdir -p packages
for chart in $CHART_DIR/*/; do
  if [ -f "$chart/Chart.yaml" ]; then
    chart_name=$(basename $chart)
    echo "Packaging $chart_name..."
    
    if [ -n "$VERSION" ]; then
      helm package "$chart" -d packages --version "$VERSION"
    else
      helm package "$chart" -d packages
    fi
  fi
done

# 生成索引
echo "Generating repository index..."
helm repo index packages --url "$REPO_URL"

# 上传到仓库(根据仓库类型选择)
echo "Uploading to repository..."
if [[ $REPO_URL == *"chartmuseum"* ]]; then
  # ChartMuseum
  for package in packages/*.tgz; do
    echo "Uploading $(basename $package)..."
    curl --data-binary "@$package" "$REPO_URL/api/charts"
  done
elif [[ $REPO_URL == s3://* ]]; then
  # S3
  aws s3 sync packages/ "$REPO_URL/"
else
  echo "Manual upload required for $REPO_URL"
fi

echo "Chart release completed successfully!"

7.4.4 CI/CD 集成

# .gitlab-ci.yml
stages:
  - validate
  - package
  - release

variables:
  CHART_DIR: "charts"
  REPO_URL: "https://charts.example.com"

validate_charts:
  stage: validate
  image: alpine/helm:3.10.0
  script:
    - |
      for chart in $CHART_DIR/*/; do
        if [ -f "$chart/Chart.yaml" ]; then
          echo "Validating $(basename $chart)..."
          helm lint "$chart"
          helm template test "$chart" --debug
        fi
      done
  only:
    - merge_requests
    - main

package_charts:
  stage: package
  image: alpine/helm:3.10.0
  script:
    - mkdir -p packages
    - |
      for chart in $CHART_DIR/*/; do
        if [ -f "$chart/Chart.yaml" ]; then
          helm dependency update "$chart"
          helm package "$chart" -d packages
        fi
      done
    - helm repo index packages --url "$REPO_URL"
  artifacts:
    paths:
      - packages/
    expire_in: 1 hour
  only:
    - main

release_charts:
  stage: release
  image: alpine/helm:3.10.0
  script:
    - |
      for package in packages/*.tgz; do
        echo "Uploading $(basename $package)..."
        curl -u "$REPO_USERNAME:$REPO_PASSWORD" \
             --data-binary "@$package" \
             "$REPO_URL/api/charts"
      done
  dependencies:
    - package_charts
  only:
    - main
  when: manual

7.5 Chart 签名和安全

7.5.1 GPG 密钥管理

# 生成 GPG 密钥
gpg --full-generate-key

# 列出密钥
gpg --list-keys
gpg --list-secret-keys

# 导出公钥
gpg --armor --export user@example.com > public.key

# 导出私钥
gpg --armor --export-secret-keys user@example.com > private.key

# 导入密钥
gpg --import public.key
gpg --import private.key

7.5.2 Chart 签名

# 签名打包
helm package mychart --sign --key 'user@example.com' --keyring ~/.gnupg/secring.gpg

# 验证签名
helm verify mychart-1.0.0.tgz

# 安装时验证
helm install myrelease mychart-1.0.0.tgz --verify

7.5.3 Provenance 文件

# mychart-1.0.0.tgz.prov
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

name: mychart
description: A Helm chart for my application
version: 1.0.0
appVersion: 1.0.0
home: https://example.com
sources:
- https://github.com/example/mychart
maintainers:
- name: John Doe
  email: john@example.com
engine: gotpl
icon: https://example.com/icon.png
files:
  mychart-1.0.0.tgz: sha256:1234567890abcdef...
-----BEGIN PGP SIGNATURE-----

iQEzBAEBCAAdFiEE...
-----END PGP SIGNATURE-----

7.5.4 仓库安全配置

# ChartMuseum 安全配置
version: '3.8'

services:
  chartmuseum:
    image: chartmuseum/chartmuseum:v0.15.0
    environment:
      # 启用认证
      BASIC_AUTH_USER: admin
      BASIC_AUTH_PASS: ${CHARTMUSEUM_PASSWORD}
      
      # 启用 TLS
      TLS_CERT: /certs/tls.crt
      TLS_KEY: /certs/tls.key
      
      # 启用 CORS
      CORS_ALLOW_ORIGIN: "https://example.com"
      
      # 禁用覆盖
      ALLOW_OVERWRITE: false
      
      # 启用多租户
      MULTITENANT: true
      
      # 存储配置
      STORAGE: s3
      STORAGE_AMAZON_BUCKET: my-secure-charts
      STORAGE_AMAZON_PREFIX: charts
      STORAGE_AMAZON_REGION: us-west-2
      
    volumes:
      - ./certs:/certs:ro
    ports:
      - "443:8080"

7.6 OCI 仓库支持

7.6.1 OCI 仓库概述

Helm 3.8+ 支持将 Chart 存储在 OCI(Open Container Initiative)兼容的容器注册表中,如 Docker Hub、Harbor、AWS ECR 等。

# 启用 OCI 支持
export HELM_EXPERIMENTAL_OCI=1

# 登录到 OCI 注册表
helm registry login registry.example.com -u username

# 推送 Chart 到 OCI 注册表
helm push mychart-1.0.0.tgz oci://registry.example.com/charts

# 从 OCI 注册表拉取 Chart
helm pull oci://registry.example.com/charts/mychart --version 1.0.0

# 安装来自 OCI 注册表的 Chart
helm install myrelease oci://registry.example.com/charts/mychart --version 1.0.0

7.6.2 Harbor 集成

# harbor-values.yaml
expose:
  type: ingress
  tls:
    enabled: true
    certSource: secret
    secret:
      secretName: harbor-tls
  ingress:
    hosts:
      core: harbor.example.com
    annotations:
      kubernetes.io/ingress.class: nginx
      cert-manager.io/cluster-issuer: letsencrypt-prod

externalURL: https://harbor.example.com

persistence:
  enabled: true
  resourcePolicy: "keep"
  persistentVolumeClaim:
    registry:
      size: 100Gi
    chartmuseum:
      size: 10Gi
    database:
      size: 10Gi
    redis:
      size: 1Gi

chartmuseum:
  enabled: true
  absoluteUrl: true
# 安装 Harbor
helm repo add harbor https://helm.goharbor.io
helm install harbor harbor/harbor -f harbor-values.yaml

# 配置 Harbor 项目
# 1. 创建项目 "charts"
# 2. 启用 Helm Chart 支持
# 3. 配置访问权限

# 推送 Chart 到 Harbor
helm registry login harbor.example.com -u admin
helm push mychart-1.0.0.tgz oci://harbor.example.com/charts

7.6.3 AWS ECR 集成

# 创建 ECR 仓库
aws ecr create-repository --repository-name charts/mychart

# 获取登录令牌
aws ecr get-login-password --region us-west-2 | \
  helm registry login --username AWS --password-stdin \
  123456789012.dkr.ecr.us-west-2.amazonaws.com

# 推送 Chart
helm push mychart-1.0.0.tgz \
  oci://123456789012.dkr.ecr.us-west-2.amazonaws.com/charts

# 拉取 Chart
helm pull oci://123456789012.dkr.ecr.us-west-2.amazonaws.com/charts/mychart \
  --version 1.0.0

7.7 企业级仓库管理

7.7.1 多环境仓库策略

# 仓库配置管理
# config/repositories.yaml
repositories:
  development:
    url: https://charts-dev.example.com
    username: dev-user
    password: ${DEV_PASSWORD}
    
  staging:
    url: https://charts-staging.example.com
    username: staging-user
    password: ${STAGING_PASSWORD}
    
  production:
    url: https://charts-prod.example.com
    username: prod-user
    password: ${PROD_PASSWORD}
    verify: true
    
  public:
    - name: bitnami
      url: https://charts.bitnami.com/bitnami
    - name: prometheus-community
      url: https://prometheus-community.github.io/helm-charts
#!/bin/bash
# scripts/setup-repos.sh

ENV=${1:-development}
CONFIG_FILE="config/repositories.yaml"

echo "Setting up repositories for environment: $ENV"

# 解析配置文件并添加仓库
yq eval ".repositories.$ENV" $CONFIG_FILE | while read -r repo; do
  if [ "$repo" != "null" ]; then
    name=$(echo $repo | yq eval '.name' -)
    url=$(echo $repo | yq eval '.url' -)
    username=$(echo $repo | yq eval '.username' -)
    password=$(echo $repo | yq eval '.password' -)
    
    if [ "$username" != "null" ] && [ "$password" != "null" ]; then
      helm repo add $name $url --username $username --password $password
    else
      helm repo add $name $url
    fi
  fi
done

# 添加公共仓库
yq eval '.repositories.public[]' $CONFIG_FILE | while read -r repo; do
  name=$(echo $repo | yq eval '.name' -)
  url=$(echo $repo | yq eval '.url' -)
  helm repo add $name $url
done

helm repo update
echo "Repository setup completed for $ENV environment"

7.7.2 访问控制和权限管理

# RBAC 配置示例
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: helm-charts
  name: chart-manager
rules:
- apiGroups: [""]
  resources: ["configmaps", "secrets"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "create", "update", "patch", "delete"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: chart-manager-binding
  namespace: helm-charts
subjects:
- kind: User
  name: chart-admin
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: chart-manager
  apiGroup: rbac.authorization.k8s.io

7.7.3 仓库监控和审计

# 监控配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: chartmuseum-monitoring
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
    
    scrape_configs:
    - job_name: 'chartmuseum'
      static_configs:
      - targets: ['chartmuseum:8080']
      metrics_path: /metrics
      scrape_interval: 30s
    
    - job_name: 'helm-exporter'
      static_configs:
      - targets: ['helm-exporter:9571']
      scrape_interval: 60s

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: helm-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helm-exporter
  template:
    metadata:
      labels:
        app: helm-exporter
    spec:
      containers:
      - name: helm-exporter
        image: sstarcher/helm-exporter:latest
        ports:
        - containerPort: 9571
        env:
        - name: HELM_EXPORTER_NAMESPACES
          value: "default,kube-system,monitoring"

7.7.4 备份和灾难恢复

#!/bin/bash
# scripts/backup-repository.sh

BACKUP_DIR="/backup/helm-charts"
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="$BACKUP_DIR/charts-backup-$DATE.tar.gz"

echo "Starting repository backup..."

# 创建备份目录
mkdir -p $BACKUP_DIR

# 备份 Chart 文件
echo "Backing up chart files..."
tar -czf $BACKUP_FILE /var/lib/chartmuseum/charts

# 备份索引文件
echo "Backing up index files..."
cp /var/lib/chartmuseum/index.yaml $BACKUP_DIR/index-$DATE.yaml

# 备份配置文件
echo "Backing up configuration..."
cp /etc/chartmuseum/config.yaml $BACKUP_DIR/config-$DATE.yaml

# 上传到云存储
if [ "$CLOUD_BACKUP" = "true" ]; then
  echo "Uploading to cloud storage..."
  aws s3 cp $BACKUP_FILE s3://my-backup-bucket/helm-charts/
  aws s3 cp $BACKUP_DIR/index-$DATE.yaml s3://my-backup-bucket/helm-charts/
fi

# 清理旧备份(保留30天)
find $BACKUP_DIR -name "charts-backup-*.tar.gz" -mtime +30 -delete
find $BACKUP_DIR -name "index-*.yaml" -mtime +30 -delete

echo "Backup completed: $BACKUP_FILE"
#!/bin/bash
# scripts/restore-repository.sh

BACKUP_FILE=${1}
RESTORE_DIR="/var/lib/chartmuseum"

if [ -z "$BACKUP_FILE" ]; then
  echo "Usage: $0 <backup-file>"
  exit 1
fi

echo "Starting repository restore from $BACKUP_FILE..."

# 停止 ChartMuseum 服务
echo "Stopping ChartMuseum service..."
systemctl stop chartmuseum

# 备份当前数据
echo "Backing up current data..."
mv $RESTORE_DIR $RESTORE_DIR.backup.$(date +%Y%m%d-%H%M%S)

# 恢复数据
echo "Restoring data..."
mkdir -p $RESTORE_DIR
tar -xzf $BACKUP_FILE -C /

# 重新生成索引
echo "Regenerating index..."
helm repo index $RESTORE_DIR/charts --url http://localhost:8080/charts

# 启动 ChartMuseum 服务
echo "Starting ChartMuseum service..."
systemctl start chartmuseum

# 验证恢复
echo "Verifying restore..."
sleep 5
curl -f http://localhost:8080/health

if [ $? -eq 0 ]; then
  echo "Repository restore completed successfully"
else
  echo "Repository restore failed"
  exit 1
fi

7.8 实践练习

7.8.1 练习1:创建私有仓库

# 1. 使用 ChartMuseum 创建私有仓库
docker run -d \
  --name chartmuseum \
  -p 8080:8080 \
  -e DEBUG=1 \
  -e STORAGE=local \
  -e STORAGE_LOCAL_ROOTDIR=/charts \
  -v $(pwd)/charts:/charts \
  chartmuseum/chartmuseum:latest

# 2. 创建并打包一个 Chart
helm create myapp
helm package myapp

# 3. 上传到私有仓库
curl --data-binary "@myapp-0.1.0.tgz" http://localhost:8080/api/charts

# 4. 添加仓库并安装
helm repo add myrepo http://localhost:8080
helm repo update
helm install test myrepo/myapp

7.8.2 练习2:设置 CI/CD 自动发布

# .github/workflows/chart-release.yml
name: Chart Release

on:
  push:
    tags:
      - 'v*'

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v3
    
    - name: Setup Helm
      uses: azure/setup-helm@v3
    
    - name: Package and Release
      run: |
        helm package charts/myapp
        curl --data-binary "@myapp-*.tgz" \
             -u "${{ secrets.REPO_USERNAME }}:${{ secrets.REPO_PASSWORD }}" \
             ${{ secrets.REPO_URL }}/api/charts

7.8.3 练习3:实现 Chart 签名验证

# 1. 生成 GPG 密钥
gpg --batch --full-generate-key <<EOF
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: Chart Signer
Name-Email: charts@example.com
Expire-Date: 1y
%no-protection
%commit
EOF

# 2. 签名打包
helm package myapp --sign --key 'charts@example.com'

# 3. 验证签名
helm verify myapp-0.1.0.tgz

# 4. 配置仓库验证
helm repo add --verify myrepo http://localhost:8080

7.9 故障排除

7.9.1 常见仓库问题

# 仓库连接问题
helm repo update --debug

# 检查仓库状态
curl -I http://localhost:8080/index.yaml

# 清理仓库缓存
rm -rf ~/.cache/helm/repository
helm repo update

# 检查认证问题
helm repo add myrepo http://localhost:8080 --username admin --password password --debug

7.9.2 索引文件问题

# 重新生成索引
helm repo index charts --url http://localhost:8080/charts

# 验证索引文件
yaml-lint charts/index.yaml

# 检查索引内容
yq eval '.entries' charts/index.yaml

7.9.3 权限问题

# 检查文件权限
ls -la /var/lib/chartmuseum/

# 修复权限
chown -R chartmuseum:chartmuseum /var/lib/chartmuseum/
chmod -R 755 /var/lib/chartmuseum/

7.10 本章小结

核心概念回顾

  1. Chart 仓库:存储和分发 Helm Chart 的中心化平台
  2. 仓库类型:公共仓库、私有仓库、OCI 仓库、Git 仓库
  3. Chart 打包:将 Chart 打包成 .tgz 文件进行分发
  4. 版本管理:使用语义化版本控制 Chart 和应用版本
  5. 安全机制:GPG 签名、访问控制、TLS 加密

技术要点总结

  • 仓库通过 index.yaml 文件管理 Chart 元数据
  • 支持多种存储后端(本地、S3、GCS 等)
  • OCI 仓库提供了新的分发方式
  • 企业级部署需要考虑高可用、备份、监控
  • CI/CD 集成可以实现自动化发布流程

最佳实践

  1. 版本策略:采用语义化版本管理
  2. 安全控制:启用认证、授权和签名验证
  3. 高可用性:部署多副本和负载均衡
  4. 监控告警:监控仓库健康状态和使用情况
  5. 备份恢复:定期备份仓库数据和配置
  6. 文档管理:维护完整的 Chart 文档和变更日志

下一章预告

下一章我们将学习「高级模板技巧」,探讨 Helm 模板的高级用法,包括复杂的条件逻辑、循环处理、自定义函数、模板继承、调试技巧等内容,帮助您编写更加灵活和强大的 Helm Chart。