Kubernetes部署 #

一、Kubernetes集成概述 #

text
┌─────────────────────────────────────────────────────────────┐
│                    GitLab + Kubernetes                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│  GitLab CI/CD                Kubernetes                     │
│  ┌─────────────────┐        ┌─────────────────┐            │
│  │ • 构建镜像      │        │ • Deployment    │            │
│  │ • 推送镜像      │   →    │ • Service       │            │
│  │ • 部署命令      │        │ • Ingress       │            │
│  │ • 滚动更新      │        │ • ConfigMap     │            │
│  └─────────────────┘        └─────────────────┘            │
│                                                              │
└─────────────────────────────────────────────────────────────┘

二、配置Kubernetes集群 #

1. 添加Kubernetes集群 #

  1. 进入项目Operations → Kubernetes
  2. 点击"Add Kubernetes cluster"
  3. 选择"Add existing cluster"
  4. 填写集群信息

2. 集群信息 #

字段 说明
Name 集群名称
API URL Kubernetes API地址
CA Certificate CA证书
Service Token 服务令牌
Namespace 命名空间

3. 获取集群信息 #

bash
# 获取API URL
kubectl cluster-info

# 获取CA证书
kubectl get secret -n default <secret-name> -o jsonpath="{.data['ca\.crt']}"

# 创建服务账号
kubectl create serviceaccount gitlab-runner -n default

# 创建令牌
kubectl create token gitlab-runner -n default

三、基本部署 #

1. 使用kubectl #

yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - kubectl apply -f k8s/deployment.yaml

2. 使用环境变量 #

yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - kubectl rollout status deployment/myapp

3. 使用GitLab Agent #

yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  variables:
    KUBE_CONTEXT: my-group/my-project:my-agent
  script:
    - kubectl config use-context $KUBE_CONTEXT
    - kubectl apply -f k8s/

四、Kubernetes配置文件 #

Deployment #

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  labels:
    app: myapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: registry.example.com/group/project:latest
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: production
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          initialDelaySeconds: 5
          periodSeconds: 5

Service #

yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
  - port: 80
    targetPort: 3000
  type: ClusterIP

Ingress #

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - example.com
    secretName: myapp-tls
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myapp
            port:
              number: 80

ConfigMap #

yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  DATABASE_HOST: "postgres.default.svc.cluster.local"
  REDIS_HOST: "redis.default.svc.cluster.local"

Secret #

yaml
apiVersion: v1
kind: Secret
metadata:
  name: myapp-secret
type: Opaque
stringData:
  DATABASE_PASSWORD: "your-password"
  API_KEY: "your-api-key"

五、滚动更新 #

基本滚动更新 #

yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - kubectl rollout status deployment/myapp --timeout=300s

自定义更新策略 #

yaml
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0

金丝雀发布 #

yaml
deploy_canary:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - |
      cat <<EOF | kubectl apply -f -
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: myapp-canary
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: myapp
            track: canary
        template:
          metadata:
            labels:
              app: myapp
              track: canary
          spec:
            containers:
            - name: myapp
              image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
      EOF
  only:
    - main

蓝绿部署 #

yaml
deploy_blue:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl apply -f k8s/deployment-blue.yaml
    - kubectl patch service myapp -p '{"spec":{"selector":{"version":"blue"}}}'
  only:
    - main

deploy_green:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl apply -f k8s/deployment-green.yaml
    - kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'
  only:
    - main
  when: manual

六、回滚策略 #

手动回滚 #

yaml
rollback:
  stage: rollback
  image: bitnami/kubectl:latest
  script:
    - kubectl rollout undo deployment/myapp
    - kubectl rollout status deployment/myapp
  when: manual

回滚到指定版本 #

yaml
rollback:
  stage: rollback
  image: bitnami/kubectl:latest
  script:
    - kubectl rollout undo deployment/myapp --to-revision=2
  when: manual

自动回滚 #

yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - |
      if ! kubectl rollout status deployment/myapp --timeout=300s; then
        kubectl rollout undo deployment/myapp
        exit 1
      fi

七、多环境部署 #

环境配置 #

yaml
deploy_staging:
  stage: deploy
  image: bitnami/kubectl:latest
  environment:
    name: staging
    url: https://staging.example.com
  variables:
    KUBE_NAMESPACE: staging
  script:
    - kubectl apply -f k8s/staging/ -n $KUBE_NAMESPACE
  only:
    - develop

deploy_production:
  stage: deploy
  image: bitnami/kubectl:latest
  environment:
    name: production
    url: https://example.com
  variables:
    KUBE_NAMESPACE: production
  script:
    - kubectl apply -f k8s/production/ -n $KUBE_NAMESPACE
  only:
    - main
  when: manual

Kustomize #

目录结构:

text
k8s/
├── base/
│   ├── deployment.yaml
│   ├── service.yaml
│   └── kustomization.yaml
└── overlays/
    ├── staging/
    │   ├── kustomization.yaml
    │   └── patch.yaml
    └── production/
        ├── kustomization.yaml
        └── patch.yaml
yaml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl apply -k k8s/overlays/$ENVIRONMENT

八、Helm部署 #

基本Helm部署 #

yaml
deploy:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm upgrade --install myapp ./chart \
        --set image.repository=$CI_REGISTRY_IMAGE \
        --set image.tag=$CI_COMMIT_SHA \
        --namespace $KUBE_NAMESPACE

使用values文件 #

yaml
deploy_staging:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm upgrade --install myapp ./chart \
        -f ./chart/values-staging.yaml \
        --set image.tag=$CI_COMMIT_SHA
  only:
    - develop

deploy_production:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm upgrade --install myapp ./chart \
        -f ./chart/values-production.yaml \
        --set image.tag=$CI_COMMIT_SHA
  only:
    - main
  when: manual

Helm回滚 #

yaml
rollback:
  stage: rollback
  image: alpine/helm:latest
  script:
    - helm rollback myapp
  when: manual

九、完整示例 #

yaml
stages:
  - build
  - test
  - deploy
  - rollback

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

docker_build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

test:
  stage: test
  image: $DOCKER_IMAGE
  script:
    - npm test

deploy_staging:
  stage: deploy
  image: bitnami/kubectl:latest
  environment:
    name: staging
    url: https://staging.example.com
  variables:
    KUBE_NAMESPACE: staging
  script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - |
      cat <<EOF | kubectl apply -n $KUBE_NAMESPACE -f -
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: myapp
      spec:
        replicas: 2
        selector:
          matchLabels:
            app: myapp
        template:
          metadata:
            labels:
              app: myapp
          spec:
            containers:
            - name: myapp
              image: $DOCKER_IMAGE
              ports:
              - containerPort: 3000
              resources:
                requests:
                  cpu: 100m
                  memory: 128Mi
                limits:
                  cpu: 500m
                  memory: 512Mi
      EOF
    - kubectl rollout status deployment/myapp -n $KUBE_NAMESPACE
  only:
    - develop

deploy_production:
  stage: deploy
  image: bitnami/kubectl:latest
  environment:
    name: production
    url: https://example.com
  variables:
    KUBE_NAMESPACE: production
  script:
    - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
    - kubectl config set-credentials admin --token="$KUBE_TOKEN"
    - kubectl config set-context default --cluster=k8s --user=admin
    - kubectl config use-context default
    - kubectl set image deployment/myapp myapp=$DOCKER_IMAGE -n $KUBE_NAMESPACE
    - |
      if ! kubectl rollout status deployment/myapp -n $KUBE_NAMESPACE --timeout=300s; then
        kubectl rollout undo deployment/myapp -n $KUBE_NAMESPACE
        exit 1
      fi
  only:
    - main
  when: manual

rollback_staging:
  stage: rollback
  image: bitnami/kubectl:latest
  variables:
    KUBE_NAMESPACE: staging
  script:
    - kubectl rollout undo deployment/myapp -n $KUBE_NAMESPACE
  when: manual
  only:
    - develop

rollback_production:
  stage: rollback
  image: bitnami/kubectl:latest
  variables:
    KUBE_NAMESPACE: production
  script:
    - kubectl rollout undo deployment/myapp -n $KUBE_NAMESPACE
  when: manual
  only:
    - main

十、最佳实践 #

1. 使用命名空间隔离环境 #

yaml
variables:
  KUBE_NAMESPACE: $ENVIRONMENT

2. 设置资源限制 #

yaml
resources:
  requests:
    cpu: 100m
    memory: 128Mi
  limits:
    cpu: 500m
    memory: 512Mi

3. 配置健康检查 #

yaml
livenessProbe:
  httpGet:
    path: /health
    port: 3000
readinessProbe:
  httpGet:
    path: /ready
    port: 3000

4. 使用GitLab Agent #

yaml
variables:
  KUBE_CONTEXT: my-group/my-project:my-agent

5. 自动回滚 #

yaml
script:
  - |
    if ! kubectl rollout status deployment/myapp --timeout=300s; then
      kubectl rollout undo deployment/myapp
      exit 1
    fi

恭喜你完成了GitLab CI/CD完全指南的学习!现在你已经掌握了从基础到高级的所有GitLab CI/CD知识。

最后更新:2026-03-28