前言:高效的 Kubernetes 应用程序部署

到目前为止,我们已经学习了 Kubernetes 的各种资源和配置方法。但在实际生产环境中,需要管理数十甚至数百个 YAML 文件,并且需要为不同环境应用不同的配置。为了解决这种复杂性,Helm 包管理器应运而生。

此外,在现代软件开发中,自动化从代码变更到生产部署的整个过程的 CI/CD 流水线 是必不可少的。本篇将详细介绍 Helm 的使用方法和基于 GitOps 的 CI/CD 流水线构建方法。

1. 什么是 Helm?

1.1 Helm 概述

Helm 是 Kubernetes 的包管理器。就像 Linux 的 apt、yum 或 macOS 的 Homebrew 一样,Helm 可以轻松地安装、升级和管理 Kubernetes 应用程序。

Helm 的核心概念:

  • Chart:定义 Kubernetes 应用程序的文件集合
  • Release:安装在集群中的 Chart 实例
  • Repository:存储和共享 Chart 的仓库
  • Values:用于自定义 Chart 默认设置的值

1.2 为什么使用 Helm

问题 Helm 的解决方案
管理大量 YAML 文件 打包为单个 Chart
环境间配置差异 使用 values.yaml 覆盖
部署历史管理 发布版本管理和回滚
复杂的依赖关系 Chart 依赖管理
缺乏可重用性 模板和可共享的 Chart

2. Helm 安装和基本用法

2.1 Helm 安装

# macOS
brew install helm

# Linux(脚本)
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# Windows (Chocolatey)
choco install kubernetes-helm

# 验证安装
helm version

2.2 Repository 管理

# 添加官方 Helm Chart 仓库
helm repo add stable https://charts.helm.sh/stable
helm repo add bitnami https://charts.bitnami.com/bitnami

# 查看仓库列表
helm repo list

# 更新仓库
helm repo update

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

# 从 Hub 搜索
helm search hub prometheus

2.3 基本命令

# 安装 Chart
helm install my-release bitnami/nginx

# 安装到特定命名空间
helm install my-release bitnami/nginx -n my-namespace --create-namespace

# 使用 values 文件安装
helm install my-release bitnami/nginx -f custom-values.yaml

# 在命令行指定值
helm install my-release bitnami/nginx --set replicaCount=3

# 查看发布列表
helm list
helm list -A  # 所有命名空间

# 查看发布状态
helm status my-release

# 升级发布
helm upgrade my-release bitnami/nginx --set replicaCount=5

# 回滚发布
helm rollback my-release 1  # 回滚到修订版 1

# 查看发布历史
helm history my-release

# 删除发布
helm uninstall my-release

3. 理解 Chart 结构

3.1 Chart 目录结构

my-chart/
├── Chart.yaml          # Chart 元数据
├── values.yaml         # 默认配置值
├── charts/             # 依赖 Chart
├── templates/          # Kubernetes 清单模板
│   ├── deployment.yaml
│   ├── service.yaml
│   ├── ingress.yaml
│   ├── configmap.yaml
│   ├── secret.yaml
│   ├── _helpers.tpl    # 模板辅助函数
│   ├── NOTES.txt       # 安装后输出的消息
│   └── tests/          # 测试文件
│       └── test-connection.yaml
├── .helmignore         # 打包时排除的文件
└── README.md           # 文档

3.2 Chart.yaml

# Chart.yaml
apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 1.0.0          # Chart 版本
appVersion: "2.0.0"     # 应用程序版本

# 依赖定义
dependencies:
  - name: mysql
    version: "9.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: mysql.enabled
  - name: redis
    version: "17.x.x"
    repository: https://charts.bitnami.com/bitnami
    condition: redis.enabled

# 关键词和元数据
keywords:
  - web
  - application
home: https://example.com
sources:
  - https://github.com/example/my-app
maintainers:
  - name: DevOps Team
    email: devops@example.com

3.3 values.yaml

# values.yaml
# 默认配置值定义

# 应用程序设置
replicaCount: 2

image:
  repository: myregistry/my-app
  tag: "latest"
  pullPolicy: IfNotPresent

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

# 服务设置
service:
  type: ClusterIP
  port: 80
  targetPort: 8080

# Ingress 设置
ingress:
  enabled: true
  className: nginx
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
  hosts:
    - host: myapp.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myapp-tls
      hosts:
        - myapp.example.com

# 资源限制
resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

# 自动扩缩
autoscaling:
  enabled: true
  minReplicas: 2
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80

# 环境变量
env:
  - name: APP_ENV
    value: production
  - name: LOG_LEVEL
    value: info

# 依赖启用
mysql:
  enabled: true
  auth:
    database: myapp
    username: appuser

redis:
  enabled: false

3.4 模板编写

templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "my-app.fullname" . }}
  labels:
    {{- include "my-app.labels" . | nindent 4 }}
spec:
  {{- if not .Values.autoscaling.enabled }}
  replicas: {{ .Values.replicaCount }}
  {{- end }}
  selector:
    matchLabels:
      {{- include "my-app.selectorLabels" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "my-app.selectorLabels" . | nindent 8 }}
    spec:
      {{- with .Values.imagePullSecrets }}
      imagePullSecrets:
        {{- toYaml . | nindent 8 }}
      {{- end }}
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.service.targetPort }}
              protocol: TCP
          {{- if .Values.env }}
          env:
            {{- toYaml .Values.env | nindent 12 }}
          {{- end }}
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /ready
              port: http
            initialDelaySeconds: 5
            periodSeconds: 5

templates/_helpers.tpl

{{/*
生成应用程序名称
*/}}
{{- define "my-app.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
生成完整名称(包含发布名称)
*/}}
{{- define "my-app.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 "my-app.labels" -}}
helm.sh/chart: {{ include "my-app.chart" . }}
{{ include "my-app.selectorLabels" . }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
选择器标签
*/}}
{{- define "my-app.selectorLabels" -}}
app.kubernetes.io/name: {{ include "my-app.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Chart 名称和版本
*/}}
{{- define "my-app.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

4. values.yaml 自定义

4.1 环境特定的 values 文件

# 环境特定的 values 文件结构
values/
├── values.yaml           # 默认值
├── values-dev.yaml       # 开发环境
├── values-staging.yaml   # 预发布环境
└── values-prod.yaml      # 生产环境

values-prod.yaml

# values-prod.yaml - 生产环境设置
replicaCount: 5

image:
  tag: "1.2.3"  # 固定特定版本

resources:
  limits:
    cpu: 1000m
    memory: 1Gi
  requests:
    cpu: 500m
    memory: 512Mi

autoscaling:
  enabled: true
  minReplicas: 5
  maxReplicas: 20
  targetCPUUtilizationPercentage: 70

ingress:
  hosts:
    - host: api.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: api-prod-tls
      hosts:
        - api.example.com

env:
  - name: APP_ENV
    value: production
  - name: LOG_LEVEL
    value: warn
  - name: DB_HOST
    valueFrom:
      secretKeyRef:
        name: db-credentials
        key: host
# 组合多个 values 文件
helm install my-app ./my-chart \
  -f values.yaml \
  -f values-prod.yaml \
  --set image.tag=1.2.4

4.2 模板渲染验证

# 查看渲染后的模板(不实际部署)
helm template my-release ./my-chart -f values-prod.yaml

# 仅查看特定模板
helm template my-release ./my-chart -s templates/deployment.yaml

# 调试模式
helm install my-release ./my-chart --dry-run --debug

5. 实用 Helm Charts

5.1 Prometheus 栈安装

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

# 安装 kube-prometheus-stack(Prometheus + Grafana + AlertManager)
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --create-namespace \
  --set grafana.adminPassword=admin123

自定义 values 文件

# prometheus-values.yaml
prometheus:
  prometheusSpec:
    retention: 15d
    resources:
      requests:
        memory: 2Gi
        cpu: 500m
      limits:
        memory: 4Gi
        cpu: 1000m
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: standard
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 50Gi

grafana:
  adminPassword: "secure-password"
  persistence:
    enabled: true
    size: 10Gi
  ingress:
    enabled: true
    hosts:
      - grafana.example.com
    tls:
      - secretName: grafana-tls
        hosts:
          - grafana.example.com

alertmanager:
  alertmanagerSpec:
    storage:
      volumeClaimTemplate:
        spec:
          storageClassName: standard
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 10Gi

5.2 Grafana 单独安装

# 添加 Grafana 仓库
helm repo add grafana https://grafana.github.io/helm-charts

# 安装 Grafana
helm install grafana grafana/grafana \
  --namespace monitoring \
  --set persistence.enabled=true \
  --set adminPassword='admin123'

5.3 其他实用 Charts

# Nginx Ingress Controller
helm install nginx-ingress ingress-nginx/ingress-nginx \
  --namespace ingress-nginx --create-namespace

# cert-manager(TLS 证书自动化)
helm install cert-manager jetstack/cert-manager \
  --namespace cert-manager --create-namespace \
  --set installCRDs=true

# Redis
helm install redis bitnami/redis \
  --set auth.password=mypassword

# PostgreSQL
helm install postgresql bitnami/postgresql \
  --set auth.postgresPassword=mypassword

# Elasticsearch
helm install elasticsearch elastic/elasticsearch \
  --set replicas=3

6. CI/CD 概念回顾

6.1 什么是 CI/CD?

  • CI(持续集成):频繁集成代码变更,执行自动化构建和测试
  • CD(持续交付):始终保持可部署到生产环境的状态
  • CD(持续部署):所有变更自动部署到生产环境

6.2 传统 CI/CD vs GitOps

特性 传统 CI/CD GitOps
部署触发 CI 流水线 push Pull Git 变更
真相源 CI 服务器状态 Git 仓库
回滚 需要重新部署 Git revert
审计追踪 CI 日志 Git 历史
安全性 CI 需要集群访问权限 仅在集群内部运行

7. GitOps 介绍

7.1 GitOps 原则

  1. 声明式配置:以声明式方式定义所有基础设施和应用程序状态
  2. 版本控制:使用 Git 作为唯一真相源
  3. 自动同步:批准的变更自动应用到集群
  4. 持续调和:持续检测并修复实际状态与期望状态之间的差异

7.2 ArgoCD

ArgoCD 是使用最广泛的 GitOps 工具。

# 安装 ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# 安装 ArgoCD CLI(macOS)
brew install argocd

# 查看初始 admin 密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

# 端口转发访问
kubectl port-forward svc/argocd-server -n argocd 8080:443

ArgoCD Application 定义

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: my-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/myorg/my-app-config.git
    targetRevision: main
    path: kubernetes/overlays/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true        # 自动清理已删除的资源
      selfHeal: true     # 自动恢复手动更改
    syncOptions:
      - CreateNamespace=true

7.3 Flux CD

# 安装 Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash

# Flux 引导(使用 GitHub)
flux bootstrap github \
  --owner=myorg \
  --repository=fleet-infra \
  --branch=main \
  --path=./clusters/production \
  --personal

Flux GitRepository 和 Kustomization

# flux-source.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 1m
  url: https://github.com/myorg/my-app-config
  ref:
    branch: main
---
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 10m
  targetNamespace: production
  sourceRef:
    kind: GitRepository
    name: my-app
  path: ./kubernetes/overlays/production
  prune: true
  healthChecks:
    - apiVersion: apps/v1
      kind: Deployment
      name: my-app
      namespace: production

8. 使用 GitHub Actions 自动化 K8s 部署

8.1 GitHub Actions 工作流基本结构

# .github/workflows/ci-cd.yaml
name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # 1. 测试和构建
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Run linting
        run: npm run lint

  # 2. Docker 镜像构建和推送
  build:
    needs: test
    runs-on: ubuntu-latest
    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,prefix=
            type=ref,event=branch
            type=semver,pattern={{version}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # 3. Kubernetes 部署
  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Set up kubectl
        uses: azure/setup-kubectl@v3
        with:
          version: 'latest'

      - name: Configure kubeconfig
        run: |
          mkdir -p $HOME/.kube
          echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
          chmod 600 $HOME/.kube/config

      - name: Set up Helm
        uses: azure/setup-helm@v3
        with:
          version: 'latest'

      - name: Deploy with Helm
        run: |
          helm upgrade --install my-app ./charts/my-app \
            --namespace production \
            --create-namespace \
            --set image.tag=${{ github.sha }} \
            --set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
            --wait \
            --timeout 5m

      - name: Verify deployment
        run: |
          kubectl rollout status deployment/my-app -n production
          kubectl get pods -n production -l app.kubernetes.io/name=my-app

8.2 GitOps 方式的 GitHub Actions

# .github/workflows/gitops-ci.yaml
name: GitOps CI Pipeline

on:
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'Dockerfile'

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}
  CONFIG_REPO: myorg/k8s-config

jobs:
  build-and-update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

      # GitOps: 更新配置仓库
      - name: Checkout config repo
        uses: actions/checkout@v4
        with:
          repository: ${{ env.CONFIG_REPO }}
          token: ${{ secrets.CONFIG_REPO_TOKEN }}
          path: config-repo

      - name: Update image tag
        run: |
          cd config-repo
          # 使用 kustomize 时
          cd kubernetes/overlays/production
          kustomize edit set image ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}

      - name: Commit and push
        run: |
          cd config-repo
          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git add .
          git commit -m "Update image to ${{ github.sha }}"
          git push

9. 实战流水线构建示例

9.1 完整项目结构

my-project/
├── .github/
│   └── workflows/
│       ├── ci.yaml           # CI 流水线
│       ├── cd-staging.yaml   # 预发布部署
│       └── cd-production.yaml # 生产部署
├── src/                      # 应用程序源代码
├── tests/                    # 测试代码
├── charts/
│   └── my-app/              # Helm Chart
│       ├── Chart.yaml
│       ├── values.yaml
│       ├── values-staging.yaml
│       ├── values-production.yaml
│       └── templates/
├── Dockerfile
└── package.json

9.2 完整的 CI/CD 流水线

.github/workflows/ci.yaml

name: Continuous Integration

on:
  pull_request:
    branches: [main, develop]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: test
          POSTGRES_DB: testdb
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test
        env:
          DATABASE_URL: postgres://postgres:test@localhost:5432/testdb

  security-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
          severity: 'CRITICAL,HIGH'

  build-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/setup-buildx-action@v3
      - name: Build Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: false
          tags: test-image:${{ github.sha }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

.github/workflows/cd-staging.yaml

name: Deploy to Staging

on:
  push:
    branches: [develop]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: staging
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:staging

      - name: Configure kubectl
        run: |
          mkdir -p $HOME/.kube
          echo "${{ secrets.STAGING_KUBECONFIG }}" | base64 -d > $HOME/.kube/config

      - name: Deploy to Staging
        run: |
          helm upgrade --install my-app-staging ./charts/my-app \
            --namespace staging \
            --create-namespace \
            -f ./charts/my-app/values-staging.yaml \
            --set image.tag=${{ github.sha }} \
            --wait

      - name: Run smoke tests
        run: |
          STAGING_URL=$(kubectl get ingress my-app-staging -n staging -o jsonpath='{.spec.rules[0].host}')
          curl -f https://$STAGING_URL/health || exit 1

      - name: Notify Slack
        if: always()
        uses: 8398a7/action-slack@v3
        with:
          status: ${{ job.status }}
          fields: repo,message,commit,author
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

.github/workflows/cd-production.yaml

name: Deploy to Production

on:
  release:
    types: [published]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract version
        id: version
        run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: |
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.VERSION }}
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

      - name: Configure kubectl
        run: |
          mkdir -p $HOME/.kube
          echo "${{ secrets.PRODUCTION_KUBECONFIG }}" | base64 -d > $HOME/.kube/config

      - name: Deploy to Production
        run: |
          helm upgrade --install my-app ./charts/my-app \
            --namespace production \
            --create-namespace \
            -f ./charts/my-app/values-production.yaml \
            --set image.tag=${{ steps.version.outputs.VERSION }} \
            --wait \
            --timeout 10m

      - name: Verify deployment
        run: |
          kubectl rollout status deployment/my-app -n production
          kubectl get pods -n production

      - name: Run integration tests
        run: |
          PROD_URL=$(kubectl get ingress my-app -n production -o jsonpath='{.spec.rules[0].host}')
          npm run test:integration -- --url=https://$PROD_URL

      - name: Create deployment record
        run: |
          echo "Deployed version ${{ steps.version.outputs.VERSION }} at $(date)" >> DEPLOYMENTS.md
          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git add DEPLOYMENTS.md
          git commit -m "Record deployment ${{ steps.version.outputs.VERSION }}" || true
          git push || true

10. 结论与系列总结

本篇我们了解了简化 Kubernetes 应用程序部署的 Helm 和自动化 CI/CD 流水线:

  • Helm:作为 Kubernetes 包管理器,简化复杂应用程序的部署
  • Chart 结构:利用模板、values、辅助函数创建可重用的包
  • GitOps:以 Git 为真相源的现代部署方式
  • ArgoCD/Flux:代表性的 GitOps 工具
  • GitHub Actions:构建完整的 CI/CD 流水线

Docker & Kubernetes 完全指南系列总结

在这10篇系列中,我们涵盖了 Docker 和 Kubernetes 的核心概念和实战应用:

  1. 第1篇:Docker 基础和容器概念
  2. 第2篇:Docker 镜像和 Dockerfile
  3. 第3篇:使用 Docker Compose 管理多容器
  4. 第4篇:Kubernetes 基础和架构
  5. 第5篇:Pod、Deployment、Service
  6. 第6篇:Volume 和持久化
  7. 第7篇:资源管理和扩缩
  8. 第8篇:网络和 Service Mesh
  9. 第9篇:ConfigMap、Secret、Ingress
  10. 第10篇:Helm 和 CI/CD 流水线

希望通过本系列,您已经掌握了从容器技术基础到生产级 Kubernetes 运维的全面知识。容器和编排技术在不断发展,请通过官方文档和社区持续关注最新动态。

实践和经验是最好的老师。请将所学知识直接应用到您的项目中!