本教程面向中国开发者,系统讲解如何将 Kubernetes 与 GitHub Actions 深度集成,实现从代码提交到生产部署的全自动化流水线。
- Kubernetes 基础概念回顾
- GitHub Actions 部署到 K8s 的方案
- kubectl 配置与 GitHub Secrets
- Helm Chart + GitHub Actions 部署
- Kustomize + GitHub Actions 部署
- ArgoCD + GitOps 工作流
- Flux CD + GitHub 集成
- K8s 多环境管理(dev/staging/prod)
- K8s 自动扩缩容配置
- 监控与告警(Prometheus + Grafana)
- K8s 安全最佳实践
- 云厂商 K8s 服务
- K8s 成本优化
- 国内 K8s 部署注意事项
Kubernetes(简称 K8s)是由 Google 开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它已经成为云原生领域的事实标准,被国内外各大企业广泛采用。
Kubernetes 采用主从架构,主要包含以下组件:
控制平面(Control Plane):
kube-apiserver:API 服务器,所有操作的入口etcd:分布式键值存储,保存集群状态kube-scheduler:调度器,决定 Pod 运行在哪个节点kube-controller-manager:控制器管理器,维护期望状态
工作节点(Worker Node):
kubelet:节点代理,管理 Pod 生命周期kube-proxy:网络代理,实现 Service 负载均衡Container Runtime:容器运行时(Docker、containerd、CRI-O)
# Pod - 最小部署单元
apiVersion: v1
kind: Pod
metadata:
name: my-app
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-registry.com/my-app:v1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
---
# Deployment - 无状态应用部署
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 3
selector:
matchLabels:
app: my-app
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-registry.com/my-app:v1.0.0
ports:
- containerPort: 8080
---
# Service - 服务发现与负载均衡
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
selector:
app: my-app
ports:
- port: 80
targetPort: 8080
type: ClusterIP
---
# Ingress - HTTP 路由
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app-service
port:
number: 80GitHub Actions 作为 CI/CD 平台的优势:
- 原生集成:与 GitHub 仓库无缝集成,代码推送即触发
- 丰富的生态:Marketplace 提供数千个现成的 Action
- 矩阵构建:支持多平台、多版本并行测试
- 自托管 Runner:可在内网 K8s 集群中运行 Runner
- 安全机制:Secrets、OIDC、环境审批等完善的安全体系
| 方案 | 复杂度 | 安全性 | 适用场景 |
|---|---|---|---|
| kubectl 直接部署 | 低 | 中 | 小型项目、快速验证 |
| Helm Chart 部署 | 中 | 中 | 中大型项目、多环境 |
| Kustomize 部署 | 中 | 中 | 多环境变体管理 |
| ArgoCD (GitOps) | 高 | 高 | 企业级生产环境 |
| Flux CD (GitOps) | 高 | 高 | 企业级生产环境 |
代码提交 → GitHub Actions CI → 构建镜像 → 推送镜像仓库 → 部署到 K8s
↓ ↓ ↓ ↓ ↓
触发器 测试/扫描 Docker Build 阿里云ACR/ kubectl/Helm
腾讯云CCR/
华为云SWR
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
tags: ['v*']
pull_request:
branches: [main]
env:
REGISTRY: registry.cn-hangzhou.aliyuncs.com
NAMESPACE: my-namespace
IMAGE_NAME: my-app
jobs:
# 阶段1:代码测试
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Run tests
run: go test -v -race -coverprofile=coverage.out ./...
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
file: ./coverage.out
# 阶段2:构建与推送镜像
build:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'push'
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Alibaba Cloud ACR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.ACR_USERNAME }}
password: ${{ secrets.ACR_PASSWORD }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ 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 }}
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' || startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
with:
version: 'v1.29.0'
- name: Configure kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
chmod 600 $HOME/.kube/config
- name: Deploy to K8s
run: |
IMAGE_TAG=${GITHUB_SHA::8}
kubectl set image deployment/my-app \
my-app=${{ env.REGISTRY }}/${{ env.NAMESPACE }}/${{ env.IMAGE_NAME }}:${IMAGE_TAG} \
-n production
kubectl rollout status deployment/my-app -n production --timeout=300s
- name: Notify on success
if: success()
run: |
# 发送钉钉/飞书/企业微信通知
curl -X POST "${{ secrets.DINGTALK_WEBHOOK }}" \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"部署成功: '${{ github.repository }}' @ '${GITHUB_SHA::8}'"}}'方式一:从云厂商控制台获取
以阿里云 ACK 为例:
# 安装 aliyun CLI
curl -O https://aliyuncli.alicdn.com/aliyun-cli-linux-latest-amd64.tgz
tar xzvf aliyun-cli-linux-latest-amd64.tgz
sudo mv aliyun /usr/local/bin/
# 配置阿里云账号
aliyun configure
# 获取集群 kubeconfig
aliyun cs GET /k8s/{cluster_id}/user_config | jq -r '.config' > kubeconfig.yaml方式二:使用 kubectl 直接配置
# 阿里云 ACK
aliyun cs GET /k8s/{cluster_id}/user_config | jq -r '.config' > ~/.kube/config
# 腾讯云 TKE
# 从控制台下载 kubeconfig 或使用 tke 命令行工具
# 华为云 CCE
# 从控制台下载 kubeconfig 文件方式三:使用 OIDC Token(更安全)
# 使用 aws-iam-authenticator(EKS)
# 使用 gcp-auth-plugin(GKE)
# 使用 OIDC Token在 GitHub 仓库中设置 Secrets:
- 进入仓库 → Settings → Secrets and variables → Actions
- 点击 "New repository secret"
- 添加以下 Secrets:
| Secret 名称 | 说明 | 获取方式 |
|---|---|---|
KUBECONFIG |
Base64 编码的 kubeconfig | cat ~/.kube/config | base64 -w 0 |
ACR_USERNAME |
镜像仓库用户名 | 阿里云控制台 |
ACR_PASSWORD |
镜像仓库密码 | 阿里云控制台 |
SLACK_WEBHOOK |
通知 Webhook | Slack/钉钉/飞书设置 |
# Linux
cat ~/.kube/config | base64 -w 0
# macOS
cat ~/.kube/config | base64
# Windows PowerShell
[Convert]::ToBase64String([IO.File]::ReadAllBytes("$env:USERPROFILE\.kube\config"))# 创建环境:Settings → Environments → New environment
# - development
# - staging
# - production(添加审批规则)
jobs:
deploy-prod:
runs-on: ubuntu-latest
environment: production # 需要审批
steps:
- name: Deploy
run: kubectl apply -f k8s/prod/GitHub Actions 支持 OIDC(OpenID Connect)与云厂商联合认证,避免存储长期凭证:
# 阿里云 OIDC 配置
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Configure Alibaba Cloud credentials
uses: aliyun/oss-upload-action@v1
with:
access-key-id: ${{ secrets.ALIYUN_ACCESS_KEY_ID }}
access-key-secret: ${{ secrets.ALIYUN_ACCESS_KEY_SECRET }}
# 或使用 OIDC(更安全)
- name: Assume Role via OIDC
run: |
# 获取 OIDC Token
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=sts.aliyuncs.com" | jq -r '.value')
# 使用 STS Assume Role
aliyun sts AssumeRoleWithOIDC \
--RoleArn "acs:ram::123456789:role/github-actions-role" \
--OIDCProviderArn "acs:ram::123456789:oidc-provider/github" \
--OIDCToken "$OIDC_TOKEN" \
--RoleSessionName "github-actions"AWS EKS OIDC 配置示例:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: cn-northwest-1
- name: Update kubeconfig
run: aws eks update-kubeconfig --name my-cluster --region cn-northwest-1Helm 是 Kubernetes 的包管理器,将相关资源打包为 Chart:
my-chart/
├── Chart.yaml # Chart 元数据
├── values.yaml # 默认配置值
├── templates/ # 模板文件
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ ├── hpa.yaml
│ └── _helpers.tpl
├── charts/ # 依赖的子 Chart
└── README.md
# 创建新的 Chart
helm create my-app
# Chart.yaml
cat > my-app/Chart.yaml << 'EOF'
apiVersion: v2
name: my-app
description: A Helm chart for my application
type: application
version: 0.1.0
appVersion: "1.0.0"
dependencies:
- name: postgresql
version: "12.x.x"
repository: "https://charts.bitnami.com/bitnami"
condition: postgresql.enabled
EOF# values.yaml - 默认值
replicaCount: 1
image:
repository: registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app
pullPolicy: IfNotPresent
tag: "latest"
service:
type: ClusterIP
port: 80
ingress:
enabled: false
className: nginx
annotations: {}
hosts:
- host: my-app.local
paths:
- path: /
pathType: Prefix
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 10
targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}# values-production.yaml - 生产环境覆盖值
replicaCount: 3
image:
tag: "" # 由 CI/CD 动态设置
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rate-limit: "100"
hosts:
- host: my-app.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: my-app-tls
hosts:
- my-app.example.com
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "2"
memory: 2Gi
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 20
targetCPUUtilizationPercentage: 70
postgresql:
enabled: true
auth:
existingSecret: postgres-credentialsname: Helm Deploy
on:
push:
branches: [main]
env:
RELEASE_NAME: my-app
NAMESPACE: production
CHART_PATH: ./helm/my-app
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Helm
uses: azure/setup-helm@v3
with:
version: 'v3.14.0'
- name: Configure kubectl
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
- name: Add Helm repos
run: |
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
- name: Update Chart dependencies
run: |
helm dependency update ${{ env.CHART_PATH }}
- name: Helm Lint
run: |
helm lint ${{ env.CHART_PATH }} -f ${{ env.CHART_PATH }}/values-production.yaml
- name: Helm Diff (dry-run)
run: |
helm diff upgrade ${{ env.RELEASE_NAME }} ${{ env.CHART_PATH }} \
-f ${{ env.CHART_PATH }}/values-production.yaml \
--namespace ${{ env.NAMESPACE }} \
--allow-unreleased || true
- name: Deploy with Helm
run: |
IMAGE_TAG=${GITHUB_SHA::8}
helm upgrade --install ${{ env.RELEASE_NAME }} ${{ env.CHART_PATH }} \
-f ${{ env.CHART_PATH }}/values-production.yaml \
--namespace ${{ env.NAMESPACE }} \
--create-namespace \
--set image.tag=${IMAGE_TAG} \
--wait \
--timeout 5m
- name: Verify deployment
run: |
kubectl rollout status deployment/${{ env.RELEASE_NAME }} \
-n ${{ env.NAMESPACE }} --timeout=300s
kubectl get pods -n ${{ env.NAMESPACE }} -l app.kubernetes.io/name=my-app# 在 GitHub Actions 中运行 Helm 测试
- name: Run Helm tests
run: |
helm test ${{ env.RELEASE_NAME }} -n ${{ env.NAMESPACE }} --timeout 5m# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "my-app.fullname" . }}-test-connection"
labels:
{{- include "my-app.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "my-app.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: NeverKustomize 是 Kubernetes 原生的配置管理工具,通过 overlay 机制实现多环境配置管理,无需模板引擎。
k8s/
├── base/
│ ├── kustomization.yaml
│ ├── deployment.yaml
│ ├── service.yaml
│ └── ingress.yaml
└── overlays/
├── dev/
│ ├── kustomization.yaml
│ └── namespace.yaml
├── staging/
│ ├── kustomization.yaml
│ ├── replica-count.yaml
│ └── resource-limits.yaml
└── prod/
├── kustomization.yaml
├── replica-count.yaml
├── resource-limits.yaml
└── hpa.yaml
# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonLabels:
app: my-app
managed-by: kustomize
resources:
- deployment.yaml
- service.yaml
- ingress.yaml
configMapGenerator:
- name: app-config
literals:
- APP_ENV=production
- LOG_LEVEL=info
secretGenerator:
- name: app-secrets
type: Opaque
literals:
- DB_PASSWORD=changeme
images:
- name: my-app
newName: registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app
newTag: latest# base/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app
ports:
- containerPort: 8080
envFrom:
- configMapRef:
name: app-config
- secretRef:
name: app-secrets
resources:
requests:
cpu: 100m
memory: 128Mi# overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: production
resources:
- ../../base
- hpa.yaml
patches:
- path: replica-count.yaml
- path: resource-limits.yaml
configMapGenerator:
- name: app-config
behavior: merge
literals:
- APP_ENV=production
- LOG_LEVEL=warn
images:
- name: my-app
newTag: "" # 由 CI/CD 动态设置# overlays/prod/replica-count.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 5# overlays/prod/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 3
maxReplicas: 20
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70name: Kustomize Deploy
on:
push:
branches: [main]
env:
IMAGE: registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up kubectl
uses: azure/setup-kubectl@v3
- name: Configure kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
- name: Set image tag
id: tag
run: echo "tag=${GITHUB_SHA::8}" >> $GITHUB_OUTPUT
- name: Kustomize build and apply
run: |
cd k8s/overlays/prod
# 使用 kustomize edit 设置镜像标签
kustomize edit set image my-app=${{ env.IMAGE }}:${{ steps.tag.outputs.tag }}
# 构建并应用
kustomize build . | kubectl apply -f -
# 等待部署完成
kubectl rollout status deployment/my-app -n production --timeout=300s# 直接使用 kubectl apply -k
- name: Deploy with kubectl kustomize
run: |
cd k8s/overlays/prod
kustomize edit set image my-app=${{ env.IMAGE }}:${{ steps.tag.outputs.tag }}
kubectl apply -k .GitOps 是一种以 Git 仓库为唯一事实来源的运维模式:
- 声明式:所有配置以声明式方式存储在 Git 中
- 版本化:所有变更通过 Git 追踪
- 自动化:变更自动应用到集群
- 自愈:集群状态与 Git 声明不一致时自动修复
Git Repository (期望状态)
↓
ArgoCD Server
↓
Application Controller → Kubernetes Cluster (实际状态)
↓
Notification Controller → 钉钉/飞书/Slack
# 创建命名空间
kubectl create namespace argocd
# 安装 ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 获取初始密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# 访问 UI(端口转发)
kubectl port-forward svc/argocd-server -n argocd 8080:443
# 安装 CLI
curl -sSL -o argocd-linux-amd64 https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
sudo install -m 555 argocd-linux-amd64 /usr/local/bin/argocd# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/my-org/my-app-config.git
targetRevision: HEAD
path: overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # 删除 Git 中不存在的资源
selfHeal: true # 自动修复手动更改
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m方式一:ArgoCD 自动检测 Git 变更(Pull 模式)
ArgoCD 默认每 3 分钟检查 Git 仓库变更,无需额外配置。
方式二:GitHub Actions 触发 ArgoCD 同步(Push 模式)
name: Build and Notify ArgoCD
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and push image
run: |
IMAGE_TAG=${GITHUB_SHA::8}
docker build -t registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app:${IMAGE_TAG} .
docker push registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app:${IMAGE_TAG}
- name: Update image tag in config repo
run: |
# 克隆配置仓库
git clone https://x-access-token:${{ secrets.CONFIG_REPO_TOKEN }}@github.com/my-org/my-app-config.git
cd my-app-config
# 更新镜像标签
cd overlays/prod
kustomize edit set image my-app=registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app:${GITHUB_SHA::8}
# 提交并推送
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add .
git commit -m "Update image to ${GITHUB_SHA::8}"
git push
- name: Trigger ArgoCD sync
run: |
# 方式一:使用 ArgoCD CLI
argocd app sync my-app --server argocd.example.com \
--auth-token ${{ secrets.ARGOCD_TOKEN }} \
--insecure
# 方式二:使用 ArgoCD API
curl -X POST "https://argocd.example.com/api/v1/applications/my-app/sync" \
-H "Authorization: Bearer ${{ secrets.ARGOCD_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{}' --insecure# 配置 ArgoCD 通知
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.webhook.dingtalk: |
url: https://oapi.dingtalk.com/robot/send?access_token=xxx
headers:
- name: Content-Type
value: application/json
template.app-sync-succeeded: |
webhook:
dingtalk:
method: POST
body: |
{
"msgtype": "markdown",
"markdown": {
"title": "ArgoCD 部署通知",
"text": "## ArgoCD 部署成功\n\n- **应用**: {{.app.metadata.name}}\n- **状态**: {{.app.status.sync.status}}\n- **提交**: {{.app.status.sync.revision}}"
}
}
trigger.on-sync-succeeded: |
- when: app.status.operationState.phase in ['Succeeded']
send: [app-sync-succeeded]Flux CD 是 CNCF 毕业项目,原生支持 GitOps,与 Kubernetes API 深度集成。
# 安装 Flux CLI
curl -s https://fluxcd.io/install.sh | sudo bash
# 检查集群是否满足要求
flux check --pre
# Bootstrap Flux(以 GitHub 为例)
flux bootstrap github \
--owner=my-org \
--repository=my-cluster-config \
--branch=main \
--path=clusters/production \
--personal# git-repository.yaml
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
url: https://github.com/my-org/my-app-config.git
ref:
branch: main
secretRef:
name: github-credentials# kustomization.yaml
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./overlays/prod
prune: true
sourceRef:
kind: GitRepository
name: my-app
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: production
timeout: 3mname: Update Flux Image
on:
push:
branches: [main]
jobs:
update-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Flux CLI
uses: fluxcd/flux2/action@main
- name: Update image in config repo
run: |
IMAGE_TAG=${GITHUB_SHA::8}
flux create image policy my-app \
--image=my-app \
--select-semver=">=1.0.0" \
--interval=5m \
--export > policy.yaml
# 或直接使用 flux 命令更新
flux update kustomization my-app \
--source=GitRepository/my-app# image-repository.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app
interval: 5m
---
# image-policy.yaml
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: my-app
namespace: flux-system
spec:
imageRepositoryRef:
name: my-app
policy:
semver:
range: ">=1.0.0"| 策略 | 说明 | 适用场景 |
|---|---|---|
| 单集群多命名空间 | 一个集群用 Namespace 隔离 | 成本敏感、小团队 |
| 多集群 | 每个环境独立集群 | 安全要求高、大团队 |
| 混合模式 | dev/staging 同集群,prod 独立 | 平衡成本与安全 |
name: Multi-Environment Deploy
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
# 开发环境 - develop 分支自动部署
deploy-dev:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/develop'
environment: development
steps:
- uses: actions/checkout@v4
- name: Deploy to Dev
run: |
kubectl config use-context dev-cluster
kustomize build k8s/overlays/dev | kubectl apply -f -
kubectl rollout status deployment/my-app -n development
# 预发布环境 - main 分支自动部署
deploy-staging:
runs-on: ubuntu-latest
needs: [test, build]
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- uses: actions/checkout@v4
- name: Deploy to Staging
run: |
kubectl config use-context staging-cluster
kustomize build k8s/overlays/staging | kubectl apply -f -
kubectl rollout status deployment/my-app -n staging
- name: Run integration tests
run: |
# 运行集成测试
npm run test:integration -- --base-url=https://staging.example.com
# 生产环境 - Tag 触发,需要审批
deploy-prod:
runs-on: ubuntu-latest
needs: [deploy-staging]
if: startsWith(github.ref, 'refs/tags/v')
environment: production # 需要人工审批
steps:
- uses: actions/checkout@v4
- name: Deploy to Production
run: |
kubectl config use-context prod-cluster
kustomize build k8s/overlays/prod | kubectl apply -f -
kubectl rollout status deployment/my-app -n production
- name: Notify success
run: |
curl -X POST "${{ secrets.DINGTALK_WEBHOOK }}" \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text","text":{"content":"生产部署成功: ${{ github.ref_name }}"}}'jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
environment: [dev, staging]
include:
- environment: dev
namespace: development
replicas: 1
- environment: staging
namespace: staging
replicas: 2
environment: ${{ matrix.environment }}
steps:
- uses: actions/checkout@v4
- name: Deploy to ${{ matrix.environment }}
run: |
kustomize build k8s/overlays/${{ matrix.environment }} | kubectl apply -f -
kubectl scale deployment/my-app --replicas=${{ matrix.replicas }} -n ${{ matrix.namespace }}# 使用 GitHub Environments 配置环境变量
# Settings → Environments → 选择环境 → Environment variables
# 在工作流中使用
- name: Use environment config
run: |
echo "Deploying to ${{ vars.CLUSTER_NAME }}"
echo "Namespace: ${{ vars.NAMESPACE }}"
echo "Replicas: ${{ vars.REPLICAS }}"# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: my-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
minReplicas: 2
maxReplicas: 50
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Pods
value: 4
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 10
periodSeconds: 60# vpa.yaml
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-app
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: my-app
minAllowed:
cpu: 100m
memory: 128Mi
maxAllowed:
cpu: 4
memory: 8Gi
controlledResources: ["cpu", "memory"]# 阿里云 ACK 集群自动伸缩配置
# 在 ACK 控制台配置节点池的自动伸缩策略
# AWS EKS Cluster Autoscaler
apiVersion: apps/v1
kind: Deployment
metadata:
name: cluster-autoscaler
namespace: kube-system
spec:
replicas: 1
selector:
matchLabels:
app: cluster-autoscaler
template:
metadata:
labels:
app: cluster-autoscaler
spec:
containers:
- image: registry.aliyuncs.com/acs/autoscaler:v1.26.3-eks
name: cluster-autoscaler
command:
- ./cluster-autoscaler
- --v=4
- --cloud-provider=aws
- --skip-nodes-with-local-storage=false
- --expander=least-waste
- --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/my-cluster# 安装 KEDA
helm repo add kedacore https://kedacore.github.io/charts
helm install keda kedacore/keda --namespace keda --create-namespace
# ScaledObject 配置
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: my-app
spec:
scaleTargetRef:
name: my-app
minReplicaCount: 1
maxReplicaCount: 100
triggers:
- type: kafka
metadata:
bootstrapServers: kafka:9092
consumerGroup: my-group
topic: my-topic
lagThreshold: "100"
- type: redis
metadata:
address: redis:6379
listName: my-queue
listLength: "10"# 使用 Helm 安装 kube-prometheus-stack
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.adminPassword=your-password \
--set prometheus.prometheusSpec.retention=30d# service-monitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
labels:
release: prometheus
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics
interval: 15s
path: /metrics# alert-rules.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: my-app-alerts
labels:
release: prometheus
spec:
groups:
- name: my-app
rules:
- alert: HighErrorRate
expr: |
rate(http_requests_total{service="my-app", status=~"5.."}[5m])
/ rate(http_requests_total{service="my-app"}[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "高错误率告警"
description: "my-app 的 5xx 错误率超过 5%,当前值: {{ $value }}"
- alert: HighLatency
expr: |
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket{service="my-app"}[5m])) > 1
for: 5m
labels:
severity: warning
annotations:
summary: "高延迟告警"
description: "my-app 的 P95 延迟超过 1 秒,当前值: {{ $value }}"
- alert: PodCrashLooping
expr: |
rate(kube_pod_container_status_restarts_total{namespace="production"}[15m]) > 0
for: 5m
labels:
severity: critical
annotations:
summary: "Pod 重启告警"
description: "Pod {{ $labels.pod }} 正在频繁重启"# grafana-dashboard.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-dashboard
labels:
grafana_dashboard: "1"
data:
my-app.json: |
{
"dashboard": {
"title": "My App Dashboard",
"panels": [
{
"title": "请求速率",
"type": "graph",
"targets": [
{
"expr": "rate(http_requests_total{service=\"my-app\"}[5m])",
"legendFormat": "{{method}} {{status}}"
}
]
},
{
"title": "延迟分布",
"type": "heatmap",
"targets": [
{
"expr": "rate(http_request_duration_seconds_bucket{service=\"my-app\"}[5m])",
"legendFormat": "{{le}}"
}
]
}
]
}
}name: Deploy Monitoring Stack
on:
push:
branches: [main]
paths:
- 'monitoring/**'
jobs:
deploy-monitoring:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure kubectl
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
- name: Deploy Prometheus
run: |
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
-f monitoring/values.yaml \
--wait
- name: Apply custom rules
run: |
kubectl apply -f monitoring/alert-rules.yaml
kubectl apply -f monitoring/service-monitors.yaml
kubectl apply -f monitoring/dashboards/# rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app-sa
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: my-app-role
namespace: production
rules:
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: my-app-rolebinding
namespace: production
subjects:
- kind: ServiceAccount
name: my-app-sa
namespace: production
roleRef:
kind: Role
name: my-app-role
apiGroup: rbac.authorization.k8s.ioGitHub Actions 使用最小权限:
# 为 GitHub Actions 创建专用 ServiceAccount
apiVersion: v1
kind: ServiceAccount
metadata:
name: github-actions-deployer
namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: github-actions-deployer-role
namespace: production
rules:
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "update", "patch"]
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["configmaps", "secrets"]
verbs: ["get", "list", "create", "update"]# network-policy.yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: my-app-netpol
namespace: production
spec:
podSelector:
matchLabels:
app: my-app
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
name: ingress-nginx
ports:
- protocol: TCP
port: 8080
egress:
- to:
- namespaceSelector:
matchLabels:
name: database
ports:
- protocol: TCP
port: 5432
- to: # 允许 DNS 查询
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53# pod-security.yaml
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: my-app
image: my-app:latest
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}# 在 GitHub Actions 中集成 Trivy 扫描
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
exit-code: '1' # 发现高危漏洞时失败
- name: Upload Trivy scan results
uses: github/codeql-action/upload-sarif@v3
if: always()
with:
sarif_file: 'trivy-results.sarif'# 安装 Sealed Secrets
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
# 安装 kubeseal CLI
wget https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/kubeseal-0.24.0-linux-amd64.tar.gz
tar xvfz kubeseal-0.24.0-linux-amd64.tar.gz
sudo mv kubeseal /usr/local/bin/
# 创建 Sealed Secret
echo -n mypassword | kubectl create secret generic my-secret \
--dry-run=client --from-file=password=/dev/stdin -o yaml | \
kubeseal -o yaml > sealed-secret.yaml创建集群:
# 使用 aliyun CLI 创建 ACK 集群
aliyun cs POST /clusters --header "Content-Type=application/json" --body '{
"name": "my-cluster",
"cluster_type": "ManagedKubernetes",
"region_id": "cn-hangzhou",
"kubernetes_version": "1.28.9-aliyun.1",
"worker_instance_types": ["ecs.g6.large"],
"num_of_nodes": 3,
"pod_cidr": "172.20.0.0/16",
"service_cidr": "172.21.0.0/20"
}'配置 GitHub Actions:
- name: Setup kubeconfig for ACK
run: |
# 使用阿里云 OIDC 或 AccessKey
aliyun cs GET /k8s/${{ secrets.ACK_CLUSTER_ID }}/user_config | jq -r '.config' > kubeconfig.yaml
export KUBECONFIG=kubeconfig.yaml
kubectl get nodes# 使用腾讯云 CLI 配置
- name: Configure TKE
run: |
# 安装 tke 命令行工具
pip install tencentcloud-sdk-python
# 配置 kubeconfig
# 从控制台下载或使用 API 获取
echo "${{ secrets.TKE_KUBECONFIG }}" | base64 -d > $HOME/.kube/config# 使用华为云 CLI 配置
- name: Configure CCE
run: |
# 安装 cce 命令行工具
pip install huaweicloudsdkcce
# 配置 kubeconfig
echo "${{ secrets.CCE_KUBECONFIG }}" | base64 -d > $HOME/.kube/config# 使用 GitHub Actions Matrix 多云部署
jobs:
deploy-multi-cloud:
runs-on: ubuntu-latest
strategy:
matrix:
cloud: [alibaba, tencent, huawei]
include:
- cloud: alibaba
cluster: ack-cluster
registry: registry.cn-hangzhou.aliyuncs.com
- cloud: tencent
cluster: tke-cluster
registry: ccr.ccs.tencentyun.com
- cloud: huawei
cluster: cce-cluster
registry: swr.cn-north-4.myhuaweicloud.com
steps:
- uses: actions/checkout@v4
- name: Deploy to ${{ matrix.cloud }}
run: |
# 配置对应的云厂商凭证
echo "${{ secrets[format('{0}_KUBECONFIG', matrix.cloud)] }}" | base64 -d > $HOME/.kube/config
# 部署
kubectl apply -f k8s/# resource-quota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: production-quota
namespace: production
spec:
hard:
requests.cpu: "20"
requests.memory: 40Gi
limits.cpu: "40"
limits.memory: 80Gi
pods: "50"
services: "20"
persistentvolumeclaims: "10"# limit-range.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: production-limits
namespace: production
spec:
limits:
- default:
cpu: "500m"
memory: "512Mi"
defaultRequest:
cpu: "100m"
memory: "128Mi"
max:
cpu: "4"
memory: "8Gi"
min:
cpu: "50m"
memory: "64Mi"
type: Container# 使用 kubecost 进行成本监控
helm install kubecost cost-analyzer \
--repo https://kubecost.github.io/cost-analyzer/ \
--namespace kubecost \
--create-namespace \
--set kubecostToken="your-token"# 使用 Spot/抢占式实例
# 阿里云抢占式实例配置
apiVersion: v1
kind: Node
metadata:
labels:
node-type: spot
spec:
taints:
- key: spot
value: "true"
effect: NoSchedule
# Pod 配置容忍
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
tolerations:
- key: spot
operator: Equal
value: "true"
effect: NoSchedule
nodeSelector:
node-type: spot# 使用缓存减少构建时间
- name: Cache Docker layers
uses: actions/cache@v4
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
# 使用自托管 Runner 降低成本
jobs:
build:
runs-on: self-hosted # 使用自托管 Runner
steps:
- uses: actions/checkout@v4# 配置 Docker 镜像加速器
# /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://registry.cn-hangzhou.aliyuncs.com",
"https://hub-mirror.c.163.com"
]
}# 阿里云容器镜像服务
image: registry.cn-hangzhou.aliyuncs.com/my-namespace/my-app:v1.0.0
# 腾讯云容器镜像服务
image: ccr.ccs.tencentyun.com/my-namespace/my-app:v1.0.0
# 华为云容器镜像服务
image: swr.cn-north-4.myhuaweicloud.com/my-namespace/my-app:v1.0.0# 阿里云 Helm 仓库
helm repo add aliyun https://kubernetes.oss-cn-hangzhou.aliyuncs.com/charts
# 微软中国镜像
helm repo add azurecn-mirror https://kubernetesartifacts.azureedge.net/stable
# 腾讯云 Helm 仓库
helm repo add tencentcloud https://mirror.ccs.tencentyun.com# 使用国内 Git 仓库镜像
# Gitee 镜像同步 GitHub 仓库
# 或使用代理
- name: Git proxy
run: |
git config --global http.proxy http://proxy.example.com:8080
git config --global https.proxy http://proxy.example.com:8080
# 使用 ghproxy 加速下载
- name: Download binary
run: |
wget https://ghproxy.com/https://github.com/owner/repo/releases/download/v1.0.0/binary-linux-amd64# 数据驻留要求
# - 确保 K8s 集群部署在国内区域
# - 镜像仓库使用国内节点
# - 日志和监控数据存储在国内
# 阿里云区域选择
region: cn-hangzhou # 杭州
region: cn-shanghai # 上海
region: cn-beijing # 北京
region: cn-shenzhen # 深圳
region: cn-guangzhou # 广州
region: cn-chengdu # 成都
# 腾讯云区域选择
region: ap-guangzhou # 广州
region: ap-shanghai # 上海
region: ap-beijing # 北京
region: ap-nanjing # 南京my-k8s-app/
├── .github/
│ └── workflows/
│ ├── ci.yml # 持续集成
│ ├── cd-dev.yml # 开发环境部署
│ ├── cd-prod.yml # 生产环境部署
│ └── monitoring.yml # 监控栈部署
├── src/
│ └── ... # 应用源代码
├── Dockerfile
├── helm/
│ └── my-app/
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── values-dev.yaml
│ ├── values-staging.yaml
│ ├── values-prod.yaml
│ └── templates/
├── k8s/
│ ├── base/
│ └── overlays/
├── monitoring/
│ ├── alert-rules.yaml
│ ├── service-monitors.yaml
│ └── dashboards/
├── terraform/
│ └── ... # 基础设施代码
└── README.md
本教程详细介绍了 Kubernetes 与 GitHub Actions 集成的完整方案,从基础概念到高级实践,涵盖了:
- CI/CD 流水线:从代码提交到生产部署的自动化流程
- 部署策略:kubectl、Helm、Kustomize、ArgoCD、Flux CD 等多种方案
- 多环境管理:dev/staging/prod 环境隔离与配置管理
- 自动扩缩容:HPA、VPA、KEDA 等弹性伸缩方案
- 监控告警:Prometheus + Grafana 可观测性体系
- 安全实践:RBAC、NetworkPolicy、镜像扫描等安全措施
- 云厂商集成:阿里云 ACK、腾讯云 TKE、华为云 CCE
- 成本优化:资源配额、Spot 实例、缓存策略
- 国内实践:镜像加速、网络优化、合规要求
通过这些实践,中国开发者可以构建高效、安全、可靠的云原生 CI/CD 流水线。
