当前位置: 首页 > news >正文

基于 Helm + Argo CD 的 Kubernetes GitOps 多环境( dev/test/prod)自动化部署实践

1、整体架构

image

当前总体流水线

  • 提交dockerfile至gitlab -- CI 构建镜像 -- 推送至 Harbor -- CI 更新helm chart中使用harbor镜像的版本 -- ArgoCD 自动同步gitlab -- kustomize 管理多环境下的values.yaml -- K8s 自动完成部署

优化方向

  • 提交helm chart代码至gitlab -- CI 构建镜像 -- 推送至 Harbor -- ArgoCD 自动同步harbor -- image updater更新镜像标签
  • CI中使用buildkit构建镜像

2、Dockerfile仓库配置

image

Dockerfile

FROM  192.168.40.15:5005/mygroup/dockerproject/nginx:alpine
RUN echo "Hello Docker Build in GitLab CI 10" > /usr/share/nginx/html/index.html

.gitlab-ci.yaml

  • 在脚本里先 export IMAGE_FULL 拼接上 tagKaniko 使用 --destination 引用镜像名称
  • 不要在 Kaniko 命令里直接写 ${…},它不会被解析
  • 在之前的实践中使用docker:dind来构建镜像,但是 docker:dind需要 特权容器(--privileged)才能启动自己的 Docker daemon。使用kaniko,可以在没有特权的情况下部署镜像
stages:- build- deploy_prodvariables:DOCKER_CONFIG: /kaniko/.docker/# 构建
build:stage: buildtags: [k8s]image: ${REGISTRY}/library/kaniko-executor:debugscript:- mkdir -p /kaniko/.docker- echo "{\"auths\":{\"${REGISTRY}\":{\"username\":\"${HARBOR_USERNAME}\",\"password\":\"${HARBOR_PASSWORD}\"}}}" > /kaniko/.docker/config.json- export IMAGE_FULL="${REGISTRY}/${PROJECT}/${IMAGE_NAME}:${CI_COMMIT_SHORT_SHA}"- echo "Building image $IMAGE_FULL"- |/kaniko/executor \--context $CI_PROJECT_DIR \--dockerfile $CI_PROJECT_DIR/Dockerfile \--destination $IMAGE_FULL \--oci-layout-path $CI_PROJECT_DIR/output \--skip-tls-verifyartifacts:paths:- $CI_PROJECT_DIR/outputexpire_in: 1h# 部署 PROD
deploy_prod:stage: deploy_prodtags: [k8s]image: core.harbor.domain/library/alpine-git:2.36.2script:- |git clone -b  v1 http://${GITLAB_USER}:${GITLAB_TOKEN}@${GITLAB_ADDR}/k8s/k8s-deploy.gitcd k8s-deploy/nginx/envs/prod# 更新 Helm valuessed -i "s|tag: .*|tag: ${CI_COMMIT_SHORT_SHA}|g" values-prod.yamlgit config --global user.email "ci@gitlab.com"git config --global user.name "gitlab-ci"git add .if git diff --cached --quiet; thenecho "No changes"elsegit commit -m "ci(prod): update image to ${CI_COMMIT_SHORT_SHA}"git push origin HEAD:v1fionly:- v1

变量

# 全局变量
REGISTRY: core.harbor.domain
PROJECT: myproject
IMAGE_NAME: nginx
IMAGE_TAG: ${CI_COMMIT_SHORT_SHA}
IMAGE_FULL: ${REGISTRY}/${PROJECT}/${IMAGE_NAME}:${IMAGE_TAG}
GITLAB_ADDR: 192.168.40.15# 项目变量
HARBOR_USERNAME: admin
HARBOR_PASSWORD: Harbor12345
GITLAB_USER: root
GITLAB_TOKEN: glpat-bjQGqa59FHemVnSTc3NY

runner配置

  • 注册runner时使用的executor为k8s
[runners.kubernetes]host = "https://192.168.40.11:6443"bearer_token = "<TOKEN>"      # token和service_account二选一namespace = "gitlab-runner"service_account = "gitlab-runner"image = "core.harbor.domain/library/alpine-git:2.36.2"ca_file = "/etc/gitlab-runner/config/ca.crt"

快速获取runner配置内容

  • 获取token
kubectl create token gitlab-runner -n gitlab-runner --duration=315360000s
  • 获取 API Server。即runner配置中的host字段
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}'
  • 创建 ServiceAccount + rbac权限
kubectl create namespace gitlab-runner
kubectl create serviceaccount gitlab-runner -n gitlab-runnerapiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:name: gitlab-runner-rolenamespace: gitlab-runner
rules:- apiGroups: [""]resources: ["pods", "pods/exec", "pods/attach", "pods/log", "secrets", "configmaps", "services", "persistentvolumeclaims"]verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]- apiGroups: ["apps"]resources: ["deployments", "statefulsets", "replicasets"]verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]- apiGroups: ["batch"]resources: ["jobs", "cronjobs"]verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]kubectl create rolebinding gitlab-runner-binding \--role=gitlab-runner-role \--serviceaccount=gitlab-runner:gitlab-runner \-n gitlab-runner
  • 获取k8s集群ca
kubectl config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}' | base64 -d > ca.crt

3、helm仓库配置

image

创建 Helm Chart

helm create nginx-app
  • 目录结构
helm-repo/
├── apps/
│   └── nginx/
│       ├── Chart.yaml
|       ├── values.yaml
│       └── templates/
│           ├── rollout.yaml
│           └── service.yaml
│       └── envs/
│           ├── dev/
│           │   └── values-dev.yaml
│           ├── test/
│           │   └── values-test.yaml
│           └── prod/
│               └── values-prod.yaml

image

Chart.yaml

apiVersion: v2
name: nginx
version: 0.1.0
description: Nginx chart

/helm-repo/apps/nginx/values.yaml

replicaCount: 2image:repository: core.harbor.domain/myproject/nginxtag: "latest"pullPolicy: IfNotPresentservice:type: ClusterIPport: 80targetPort: 80resources:requests:cpu: "50m"memory: "64Mi"limits:cpu: "100m"memory: "128Mi"probes:readiness:path: /initialDelaySeconds: 5periodSeconds: 10liveness:path: /initialDelaySeconds: 10periodSeconds: 10strategy:maxSurge: 25%maxUnavailable: 25%labels:app: demo-nginx

/helm-repo/apps/nginx/envs/prod/values-prod.yaml

  • 金丝雀配置
replicaCount: 3image:tag: stablerollout:strategy:canary:steps:- setWeight: 10- pause: { duration: 60s }- setWeight: 30- pause: { duration: 60s }- setWeight: 60- pause: { duration: 60s }

/helm-repo/apps/nginx/templates/rollout.yaml

  • 用 Rollout.yaml 替换 Deployment.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:name: {{ .Release.Name }}labels:app: {{ .Values.labels.app }}
spec:replicas: {{ .Values.replicaCount }}strategy:canary:steps:
{{ toYaml .Values.rollout.strategy.canary.steps | indent 8 }}selector:matchLabels:app: {{ .Values.labels.app }}template:metadata:labels:app: {{ .Values.labels.app }}spec:containers:- name: {{ .Chart.Name }}image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"imagePullPolicy: {{ .Values.image.pullPolicy }}ports:- containerPort: {{ .Values.service.targetPort }}resources:requests:cpu: {{ .Values.resources.requests.cpu }}memory: {{ .Values.resources.requests.memory }}limits:cpu: {{ .Values.resources.limits.cpu }}memory: {{ .Values.resources.limits.memory }}readinessProbe:httpGet:path: {{ .Values.probes.readiness.path }}port: {{ .Values.service.targetPort }}initialDelaySeconds: {{ .Values.probes.readiness.initialDelaySeconds }}periodSeconds: {{ .Values.probes.readiness.periodSeconds }}livenessProbe:httpGet:path: {{ .Values.probes.liveness.path }}port: {{ .Values.service.targetPort }}initialDelaySeconds: {{ .Values.probes.liveness.initialDelaySeconds }}periodSeconds: {{ .Values.probes.liveness.periodSeconds }}

/helm-repo/apps/nginx/templates/service.yaml

apiVersion: v1
kind: Service
metadata:name: {{ .Release.Name }}labels:app: {{ .Values.labels.app }}
spec:type: {{ .Values.service.type }}selector:app: {{ .Values.labels.app }}ports:- name: httpport: {{ .Values.service.port }}targetPort: {{ .Values.service.targetPort }}protocol: TCP

4、ArgoCD配置

  • 通过注解使用 Argo CD Image Updater 自动更新镜像
  • 添加仓库连接,使argocd可以直接访问helm repo

安装Rollouts

  • 参考文档:https://github.com/argoproj/argo-rollouts

安装argo-rollouts

kubectl create namespace argo-rollouts
kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml
kubectl get all -n argo-rollouts
  • 查看安装情况

image

安装Kubectl 插件

wget https://github.com/argoproj/argo-rollouts/releases/download/v1.8.3/kubectl-argo-rollouts-linux-amd64
mv kubectl-argo-rollouts-linux-amd64 /usr/local/bin/kubectl-argo-rollouts
chmod u+x /usr/local/bin/kubectl-argo-rollouts
kubectl argo rollouts version

image

安装dashboard插件

wget https://github.com/argoproj/argo-rollouts/releases/download/v1.8.3/dashboard-install.yaml
kubectl apply -f dashboard-install.yaml -n argo-rollouts

创建ingress

cat <<EOF> argocd-dashboard-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:name: argo-rolloutsnamespace: argo-rollouts
spec:ingressClassName: nginxtls:- hosts:- argo-rollouts.clx.cnsecretName: ingress-tlsrules:- host: argo-rollouts.clx.cnhttp:paths:- path: /pathType: Prefixbackend:service:name: argo-rollouts-dashboardport:number: 3100kubectl apply -f argocd-dashboard-ingress.yaml
  • 查看ingress
kubectl get ingress -A

image

配置hosts后访问验证

image

5、kustomize管理多套application

  • 用 Kustomize 管理 ArgoCD Application,实现三环境差异化配置复用
  • 目录结构
argocd-repo/
├── argocd-apps/
│   ├── base/
│   │   ├── application.yaml
│   │   └── kustomization.yaml
│   └── overlays/
│       ├── dev/
│       │   ├── kustomization.yaml
│       │   └── patch.yaml
│       ├── test/
│       │   ├── kustomization.yaml
│       │   └── patch.yaml
│       └── prod/
│           ├── kustomization.yaml
│           └── patch.yaml

image

base/application.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:name: nginxnamespace: argocdannotations:argocd-image-updater.argoproj.io/image-list: nginx=core.harbor.domain/myproject/nginxargocd-image-updater.argoproj.io/nginx.update-strategy: latestargocd-image-updater.argoproj.io/write-back-method: git
spec:project: defaultsource:repoURL: http://192.168.40.15/k8s/k8s-deploy.gittargetRevision: v1path: nginxdestination:server: https://kubernetes.default.svcnamespace: defaultsyncPolicy:automated:prune: trueselfHeal: true

base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomizationresources:- application.yaml

overlays/prod/patch.yaml

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:name: nginxnamespace: argocdannotations:argocd-image-updater.argoproj.io/nginx.allow-tags: regexp:^v.*
spec:destination:namespace: prodsource:helm:valueFiles:- envs/prod/values-prod.yamlvalues: |replicaCount: 3image:tag: 5b258db4    # CI会把tag替换为构建过程中使用的tagrollout:strategy:canary:steps:- setWeight: 10- pause: { duration: 60s }- setWeight: 30- pause: { duration: 60s }- setWeight: 60- pause: { duration: 60s }

overlays/prod/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomizationresources:- ../../basepatchesStrategicMerge:- patch.yaml

应用方式

  • 分别部署三套
kubectl apply -k overlays/dev
kubectl apply -k overlays/test
kubectl apply -k overlays/prod

image

http://www.jsqmd.com/news/618792/

相关文章:

  • 聊一聊 C# 中的闭包陷阱:foreach 循环的坑你还记得吗?夯
  • 告别粗放营销,用绿色积分搭建门店长效经营体系
  • 把用户主数据放到该放的位置,聊透 SAP NetWeaver AS ABAP 里的 User Data Synchronization
  • 二次元游戏模组管理革命:为什么你需要一个统一的启动器平台?
  • 2026年光辉海棠树木厂家推荐:美国红枫/紫叶稠李/青仟云杉树木厂家——开原市小松苗圃 - 品牌推荐官
  • 国产知识库软件哪个好?8 款类 Confluence 工具横向对比
  • 5分钟让Windows 11焕然一新:极速系统加速与性能优化终极指南
  • GitHub汉化插件终极指南:3步让GitHub界面全面中文化
  • 软考 系统架构设计师历年真题集萃(237)
  • AidLux远程SSH连接实战 | 密钥与密码双模式详解
  • 理想汽车又孵化一家具身公司......
  • 2026年4月SEM原位纳米压痕仪的技术架构与供应商核心技术边界——从超高真空兼容到亚微牛级力反馈的工程实现 - 品牌推荐大师1
  • HarmonyOS音频播放核心规范:从“能响”到“专业”
  • Switch第三方控制器终极指南:用sys-con解锁全平台手柄支持 [特殊字符]
  • ROS2 Jazzy/Rollin连接PX4仿真与实机切换指南:一个Launch文件搞定两种模式
  • Piggy_Packages V2026.1 帮助文档(一)开箱即用
  • ABAP 平台里的用户认证与单点登录,从密码登录到 SAML 2.0 的落地路径
  • 千帆竞发:126颗卫星升空背后的全球卫星互联网竞速
  • 2026雅思听力素材App推荐:精选高效备考神器助你提分 - 品牌2025
  • 如何快速解决Windows热键冲突:Hotkey Detective终极使用指南
  • 无人机多模态火灾图像识别 多光谱野火识别 智慧林业火灾识别 火灾识别图像数据集 多模态数据集 可见光+红外图像对其数据集第10652期
  • 终极键盘防抖指南:如何彻底解决机械键盘连击问题
  • Windows系统部署工具终极指南:3大优势实现自动化安装方案
  • 2026年云南有实力的钢管、钢板、无缝管、钢结构、钢材厂家选型推荐手册 - 深度智识库
  • LeetCode 删除无效的括号:python 题解诜
  • 告别虚拟机!在WSL2的Ubuntu里5分钟跑通LVGL v9.2图形界面(附SDL2配置避坑)
  • C++11新特性 智能指针
  • 从零搭建LaTeX:一站式环境配置与编辑器选择指南
  • 【Zabbix】Zabbix告警优化实战:从MySQL到Redis的性能调优指南
  • 国产信创库fio破坏主备库以及备份故障处理--惜分飞傧