GitLab教程(10): GitLab与Kubernetes集成

GitLab可以与Kubernetes深度集成,实现自动化部署和环境管理。本文将介绍GitLab与Kubernetes的集成方法和部署策略。

连接Kubernetes集群

使用GitLab Agent

# 1. 在项目中创建Agent配置
# 文件: .gitlab/agents/my-agent/config.yaml

ci_access:
  projects:
    - id: mygroup/myproject

# 2. 注册Agent
# Project > Infrastructure > Kubernetes clusters > Connect a cluster
# 选择Agent,点击 "Register"
# 获取Agent Token

# 3. 在Kubernetes中安装Agent
helm repo add gitlab https://charts.gitlab.io
helm repo update

helm install gitlab-agent gitlab/gitlab-agent \
  --namespace gitlab-agent-my-agent \
  --create-namespace \
  --set config.token= \
  --set config.kasAddress=wss://kas.gitlab.com

# 输出
NAME: gitlab-agent
NAMESPACE: gitlab-agent-my-agent
STATUS: deployed
REVISION: 1

# 验证安装
kubectl get pods -n gitlab-agent-my-agent

# 输出
NAME                           READY   STATUS    RESTARTS   AGE
gitlab-agent-abc123-xyz        1/1     Running   0          2m

在CI/CD中访问Kubernetes

# 使用Agent访问集群

deploy:
  stage: deploy
  image:
    name: bitnami/kubectl:latest
    entrypoint: [""]
  script:
    - kubectl config get-contexts
    - kubectl get nodes
    - kubectl apply -f k8s/
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

# CI_JOB_TOKEN自动用于Agent认证
# 无需手动配置kubeconfig

# 执行输出
$ kubectl config get-contexts
CURRENT   NAME                               CLUSTER   AUTHINFO
*         gitlab-agent:my-agent              ...       ...

$ kubectl get nodes
NAME                    STATUS   ROLES    AGE   VERSION
node-1                  Ready       30d   v1.28.0
node-2                  Ready       30d   v1.28.0

$ kubectl apply -f k8s/
deployment.apps/myapp created
service/myapp created

Kubernetes Manifest部署

# k8s/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.gitlab.com/mygroup/myproject:CI_COMMIT_SHA
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: production
          resources:
            limits:
              memory: "256Mi"
              cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 3000
  type: ClusterIP

# .gitlab-ci.yml
deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    # 替换镜像标签
    - sed -i "s/CI_COMMIT_SHA/$CI_COMMIT_SHA/g" k8s/deployment.yaml
    # 应用配置
    - kubectl apply -f k8s/
    # 等待部署完成
    - kubectl rollout status deployment/myapp --timeout=300s
  environment:
    name: production
    url: https://myapp.example.com

使用Helm部署

# Helm Chart结构
myapp-chart/
├── Chart.yaml
├── values.yaml
├── values-staging.yaml
├── values-production.yaml
└── templates/
    ├── deployment.yaml
    ├── service.yaml
    ├── ingress.yaml
    └── _helpers.tpl

# Chart.yaml
apiVersion: v2
name: myapp
version: 1.0.0
appVersion: "1.0"

# values.yaml
replicaCount: 2

image:
  repository: registry.gitlab.com/mygroup/myproject
  tag: latest
  pullPolicy: IfNotPresent

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: true
  host: myapp.example.com

# .gitlab-ci.yml
deploy-staging:
  stage: deploy
  image:
    name: alpine/helm:latest
    entrypoint: [""]
  script:
    - helm upgrade --install myapp ./myapp-chart \
        --namespace staging \
        --create-namespace \
        --set image.tag=$CI_COMMIT_SHA \
        -f ./myapp-chart/values-staging.yaml
  environment:
    name: staging
    url: https://staging.myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

deploy-production:
  stage: deploy
  image:
    name: alpine/helm:latest
    entrypoint: [""]
  script:
    - helm upgrade --install myapp ./myapp-chart \
        --namespace production \
        --create-namespace \
        --set image.tag=$CI_COMMIT_SHA \
        -f ./myapp-chart/values-production.yaml \
        --wait \
        --timeout 10m
  environment:
    name: production
    url: https://myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

# 执行输出
$ helm upgrade --install myapp ./myapp-chart ...
Release "myapp" has been upgraded. Happy Helming!
NAME: myapp
LAST DEPLOYED: Sat Feb  8 12:00:00 2026
NAMESPACE: production
STATUS: deployed
REVISION: 5

Auto DevOps

# GitLab Auto DevOps自动提供完整的CI/CD流程
# 无需手动编写.gitlab-ci.yml

# 启用Auto DevOps
# Project > Settings > CI/CD > Auto DevOps
# 勾选 "Default to Auto DevOps pipeline"

# Auto DevOps包含:
# - 自动构建 (使用Cloud Native Buildpacks)
# - 自动测试
# - 自动代码质量检查
# - 自动安全扫描
# - 自动部署到Kubernetes
# - Review Apps
# - 自动扩缩容

# 环境变量配置
# Settings > CI/CD > Variables

# 必需变量
KUBECONFIG: (base64编码的kubeconfig)
KUBE_INGRESS_BASE_DOMAIN: example.com

# 可选变量
POSTGRES_ENABLED: "true"
AUTO_DEVOPS_CHART: stable/auto-deploy-app
REPLICAS: 3

环境管理

# 多环境部署配置

stages:
  - build
  - deploy

build:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

.deploy-template:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - envsubst < k8s/deployment.yaml | kubectl apply -f -
    - kubectl rollout status deployment/myapp -n $KUBE_NAMESPACE

deploy-dev:
  extends: .deploy-template
  variables:
    KUBE_NAMESPACE: dev
  environment:
    name: development
    url: https://dev.myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

deploy-staging:
  extends: .deploy-template
  variables:
    KUBE_NAMESPACE: staging
  environment:
    name: staging
    url: https://staging.myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy-production:
  extends: .deploy-template
  variables:
    KUBE_NAMESPACE: production
  environment:
    name: production
    url: https://myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

# 查看环境
# Project > Deployments > Environments

# 环境列表
┌─────────────┬───────────────┬──────────────────┬──────────┐
│ Environment │ URL           │ Last Deployment  │ Status   │
├─────────────┼───────────────┼──────────────────┼──────────┤
│ production  │ myapp.example │ 2 hours ago      │ Running  │
│ staging     │ staging.myapp │ 1 hour ago       │ Running  │
│ development │ dev.myapp     │ 30 minutes ago   │ Running  │
└─────────────┴───────────────┴──────────────────┴──────────┘

Review Apps

# 为每个MR创建临时环境

deploy-review:
  stage: deploy
  image: bitnami/kubectl:latest
  variables:
    KUBE_NAMESPACE: review-$CI_COMMIT_REF_SLUG
  script:
    - kubectl create namespace $KUBE_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
    - helm upgrade --install review-$CI_COMMIT_REF_SLUG ./chart \
        --namespace $KUBE_NAMESPACE \
        --set image.tag=$CI_COMMIT_SHA \
        --set ingress.host=$CI_COMMIT_REF_SLUG.review.example.com
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    url: https://$CI_COMMIT_REF_SLUG.review.example.com
    on_stop: stop-review
    auto_stop_in: 1 week
  rules:
    - if: $CI_MERGE_REQUEST_IID

stop-review:
  stage: deploy
  image: bitnami/kubectl:latest
  variables:
    KUBE_NAMESPACE: review-$CI_COMMIT_REF_SLUG
    GIT_STRATEGY: none
  script:
    - helm uninstall review-$CI_COMMIT_REF_SLUG --namespace $KUBE_NAMESPACE || true
    - kubectl delete namespace $KUBE_NAMESPACE || true
  environment:
    name: review/$CI_COMMIT_REF_SLUG
    action: stop
  rules:
    - if: $CI_MERGE_REQUEST_IID
      when: manual

# MR页面会显示Review App链接
# View app: https://feature-login.review.example.com

部署回滚

# 方式1: 通过GitLab界面回滚
# Project > Deployments > Environments > production
# 选择之前的部署 > Re-deploy

# 方式2: 通过Kubernetes回滚
rollback:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl rollout undo deployment/myapp -n production
    - kubectl rollout status deployment/myapp -n production
  environment:
    name: production
  when: manual

# 方式3: Helm回滚
rollback-helm:
  stage: deploy
  image: alpine/helm:latest
  script:
    - helm history myapp -n production
    - helm rollback myapp -n production
  when: manual

# Helm历史
$ helm history myapp -n production
REVISION  STATUS      DESCRIPTION
1         superseded  Install complete
2         superseded  Upgrade complete
3         superseded  Upgrade complete
4         deployed    Upgrade complete

Secrets管理

# 使用GitLab CI/CD变量作为Secrets

deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    # 创建或更新Secret
    - |
      kubectl create secret generic myapp-secrets \
        --from-literal=database-url="$DATABASE_URL" \
        --from-literal=api-key="$API_KEY" \
        --namespace production \
        --dry-run=client -o yaml | kubectl apply -f -
    
    # 部署应用
    - kubectl apply -f k8s/

# 在Deployment中使用Secret
# k8s/deployment.yaml
spec:
  containers:
    - name: myapp
      envFrom:
        - secretRef:
            name: myapp-secrets

# 使用External Secrets Operator
# externalsecret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: myapp-secrets
spec:
  secretStoreRef:
    name: gitlab-secrets
    kind: ClusterSecretStore
  target:
    name: myapp-secrets
  data:
    - secretKey: database-url
      remoteRef:
        key: DATABASE_URL

完整示例

# 完整的Kubernetes部署Pipeline

stages:
  - build
  - test
  - deploy

variables:
  DOCKER_TLS_CERTDIR: "/certs"

build:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

test:
  stage: test
  image: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  script:
    - npm run test

.kubectl-deploy:
  image: bitnami/kubectl:latest
  before_script:
    - kubectl config get-contexts

deploy-staging:
  extends: .kubectl-deploy
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n staging
    - kubectl rollout status deployment/myapp -n staging --timeout=300s
  environment:
    name: staging
    url: https://staging.myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

deploy-production:
  extends: .kubectl-deploy
  stage: deploy
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA -n production
    - kubectl rollout status deployment/myapp -n production --timeout=300s
  environment:
    name: production
    url: https://myapp.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

总结

本文介绍了GitLab与Kubernetes的集成方法,包括Agent配置、部署策略、环境管理和Review Apps。GitLab提供了完整的Kubernetes部署解决方案。

下一篇我们将学习GitLab的安全扫描功能。

发表回复

后才能评论