企业GitOps流程离线部署
文章目录一、引言二、准备环境2.1 Harbor安装部署2.2 Kubernetes集群和ArgoCD安装部署2.3 Harbor项目准备2.3.1 Docker镜像2.3.2 Helm镜像2.3.3 kubectl镜像2.4 Runner安装部署2.4.1 拉取镜像2.4.2 启动容器2.4.3 注册Runner三、创建流水线3.1 配置CI/CD流水线3.2 创建ArgoCD项目3.3 配置ArgoCD应用3.4 创建Harbor机器人账户可选3.5 添加GitLab变量3.6 初始化Helm Chart四、提交代码4.1 配置Helm Chart4.2 提交仓库4.3 验证状态4.3.1 验证CI/CD流水线4.3.2 验证Harbor项目4.3.3 验证ArgoCD应用部署五、总结一、引言随着云原生和Kubernetes的广泛应用应用交付逐渐从传统的手工部署转向自动化、声明式和可追溯的持续交付模式。传统CI/CD中构建、推送、部署往往由多个脚本和人工步骤组成容易导致环境不一致、配置漂移、回滚困难、权限过大和审计缺失等问题。GitOps正是在这一背景下发展起来的一种持续交付实践其核心思想是以Git作为唯一事实源将应用代码、Kubernetes清单、Helm Chart以及环境配置等全部纳入版本控制通过CI流水线自动构建镜像并推送至镜像仓库再由ArgoCD等GitOps工具持续监听期望状态并自动将 Kubernetes集群同步到该状态。相比传统部署方式GitOps能将“如何部署”沉淀为可审阅、可复现的代码降低人工操作风险提高交付效率、一致性和安全性。本文基于GitLab CI/CD搭建一套从代码提交、镜像与 Chart 构建推送到自动部署与状态验证的规范化GitOps流水线适用于内网或离线环境下的持续交付场景。二、准备环境2.1 Harbor安装部署Harbor安装及部署方法请参考此教程。2.2 Kubernetes集群和ArgoCD安装部署Kubernetes集群及ArgoCD安装部署方法请参考此教程。2.3 Harbor项目准备Harbor安装成功后需要创建Harbor项目用于管理和存储镜像。本GitOps需要创建至少3个Harbor项目gitops项目用于管理GitLab CI流水线依赖harbor_project项目用于管理部署镜像harbor_base项目用于管理构建部署镜像所需的基础镜像。创建项目后需要向gitops项目推送相关依赖镜像包括Docker用于构建镜像、Helm用于打包Helm Chart、kubectl用于管理K3s集群等。2.3.1 Docker镜像本CI/CD流水线需使用Docker CLI基于Dockerfile和基础镜像自动将GitLab仓库代码构建为部署镜像因此需准备Docker CLI用于执行docker命令和DinDDocker-in-Docker用于启动独立的Docker Daemon守护进程镜像并推送至Harbor项目。从Docker Engine官网查看Docker CLI最新稳定版本号在Docker Hub上官方镜像的标签通常只使用主版本号例如docker:29和docker:29-dind。从外网拉取Docker CLI和DinD两个镜像注意拉取镜像的机器需与待部署的离线服务器系统架构相同并保存为tar文件# 拉取最新稳定版 Docker CLI 和 DinD 镜像dockerpull docker:29dockerpull docker:29-dind# 分别保存为tar文件启用 gzip 压缩以减小体积dockersave docker:29|gzipdocker-29.tar.gzdockersave docker:29-dind|gzipdocker-29-dind.tar.gz将docker-29.tar.gz和docker-29-dind.tar.gz传输到离线部署服务器并推送到Harbor# 加载镜像dockerload-idocker-29.tar.gzdockerload-idocker-29-dind.tar.gz# 重新打标签指向HarborexportHARBOR_HOSTharbor_hostexportHARBOR_PROJECTgitopsdockertag docker:29$HARBOR_HOST/$HARBOR_PROJECT/docker:29dockertag docker:29-dind$HARBOR_HOST/$HARBOR_PROJECT/docker:29-dind# 推送到 Harbordockerlogin$HARBOR_HOSTdockerpush$HARBOR_HOST/$HARBOR_PROJECT/docker:29dockerpush$HARBOR_HOST/$HARBOR_PROJECT/docker:29-dind2.3.2 Helm镜像CI/CD流水线使用Helm打包并推送Helm Chart因此需准备Helm镜像。从Helm Releases页面查看Helm最新稳定版本号例如v4.2.4。从外网拉取Helm镜像并保存为tar文件dockerpull helm:v4.2.4dockersave helm:v4.2.4|gziphelm.tar.gz传输到离线部署服务器并推送到Harbordockerload-ihelm.tar.gzdockertag helm:v4.2.4$HARBOR_HOST/$HARBOR_PROJECT/helm:v4.2.4dockerlogin$HARBOR_HOSTdockerpush$HARBOR_HOST/$HARBOR_PROJECT/helm:v4.2.42.3.3 kubectl镜像为了使用ArgoCD自动将镜像部署至Kubernetes集群还需准备一个包含kubectl和envsubst工具的自定义镜像包。首先确定kubectl的版本其应与Kubernetes集群版本匹配。在Kubernetes集群所属服务器上执行kubectl version--short输出中的Server Version就是集群版本例如v1.36.4。接下来手动构建一个包含kubectl和envsubst工具的自定义镜像。创建如下DockerfileFROM alpine/helm:v4.2.4 # 使用国内镜像源加速 RUN sed -i s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g /etc/apk/repositories # 安装gettext提供envsubst RUN apk add --no-cache gettext bash curl # 安装kubectl若为AMD64架构将arm64替换为amd64 ARG KUBECTL_VERSIONv1.36.4 ARG TARGETARCHarm64 RUN curl -LO https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${TARGETARCH}/kubectl \ chmod x kubectl \ mv kubectl /usr/local/bin/ ENTRYPOINT []在外网构建镜像以ARM64架构为例并保存为tar文件dockerbuild--platformlinux/arm64-tkubectl-tools:v1.36.4.dockersave kubectl-tools:v1.36.4|gzipkubectl-tools.tar.gz传输至离线部署服务器并推送到Harbordockerload-ikubectl-tools.tar.gzdockertag kubectl-tools:v1.36.4harbor_host/gitops/kubectl-tools:v1.36.4dockerpushharbor_host/gitops/kubectl-tools:v1.36.42.4 Runner安装部署从外网拉取gitlab-runner主镜像和gitlab-runner-helper辅助镜像。两个镜像都需要安装否则Docker执行器可能无法工作。2.4.1 拉取镜像访问官方CHANGELOG查看镜像版本号并拉取指定版本和系统架构的Docker镜像例如# 拉取镜像dockerpull gitlab/gitlab-runner:v19.3.1dockerpull gitlab/gitlab-runner-helper:x86_64-v19.3.1# 导出镜像包dockersave gitlab/gitlab-runner:v19.3.1-ogitlab-runner.tardockersave gitlab/gitlab-runner-helper:x86_64-v19.3.1-ogitlab-runner-helper.tar在部署服务器上加载镜像dockerload-igitlab-runner.tardockerload-igitlab-runner-helper.tar可选由于已安装Harbor可以将镜像上传至Harbor统一管理。例如将Runner镜像存放至gitops仓库# 将镜像标记为Harbor规范格式harbor_host/harbor_project/image_name:image_tagdockertag gitlab/gitlab-runner:v19.3.1harbor_host/gitops/gitlab-runner:v19.3.1dockertag gitlab/gitlab-runner-helper:x86_64-v19.3.1harbor_host/gitops/gitlab-runner-helper:x86_64-v19.3.1# 推送至Harbor仓库dockerpushharbor_host/gitops/gitlab-runner:v19.3.1dockerpushharbor_host/gitops/gitlab-runner-helper:x86_64-v19.3.12.4.2 启动容器dockerrun-d--namegitlab-runner--restartalways\-v/srv/gitlab-runner/config:/etc/gitlab-runner\-v/var/run/docker.sock:/var/run/docker.sock\harbor_host/gitops/gitlab-runner:v19.3.1关键参数说明-v /srv/gitlab-runner/config:/etc/gitlab-runner将配置目录挂载到宿主机确保容器重启后配置不丢失。-v /var/run/docker.sock:/var/run/docker.sock让Runner能够控制宿主机的Docker守护进程以创建CI任务容器。2.4.3 注册Runner为单一GitLab仓库创建Runner左侧边栏进入“Settings→CI/CD→Runners”点击“New project runner”获取注册令牌Token为GitLab组创建Runner左侧边栏进入“Build→Runners”点击“New project runner”获取注册令牌。进入容器dockerexec-itgitlab-runnerbash在容器内部执行注册命令其中--url填写GitLab地址--token填写上一步获取的令牌--executor根据需求选择如docker、shellsudogitlab-runner register\--urlhttp://gitlab_host\--tokenrunner_token\--executordocker\--docker-imageharbor_host/gitops/helm:v4.2.4\--descriptiongitlab-runner-for-gitops执行命令后系统会自动提示输入注册信息可以直接点击Enter使用默认信息。完成后需要进一步修改配置文件退出容器并修改配置exitvim/srv/gitlab-runner/config/config.toml配置文件内容如下concurrent 1[[runners]][runners.docker]image harbor_host/gitops/helm:v4.2.4 helper_image habor_host/gitops/gitlab-runner-helper:x86_64-v19.3.1 privileged true disable_cache false volumes [/cache]volume_keep false pull_policy [always]关键参数说明concurrent 1并发进程数默认为1。privileged true本GitOps使用Docker-Dind自动构建镜像此功能需使用privileged模式。修改配置文件权限确保Runner容器可以正常访问sudochmod-R755/srv/gitlab-runner三、创建流水线构建规范化的GitOps流程旨在让研发人员几乎只专注于项目本身的开发工作而将打包、推送、同步、部署等步骤全部自动化。完整流程如下研发人员git push提交Git仓库以触发CI/CD ↓ CI流水线打包镜像和Helm Chart并推送到Harbor ↓ ArgoCD自动从Harbor拉取镜像并部署到Kubernetes集群3.1 配置CI/CD流水线GitOps的核心是一套CI/CD流水线支持当研发人员提交代码后自动打包镜像和Helm Chart然后推送到Harbor仓库最后使用ArgoCD将镜像部署到Kubernetes集群。在GitLab仓库根目录创建.gitlab-ci.yml内容如下# # GitLab CI/CD配置# # 说明# 1. 构建镜像并推送到Harbor# 2. 推送Helm Chart到Harbor# 3. 使用ArgoCD部署到K3s集群# stages:-build-package-deploy# # Stage 1: 构建并推送镜像# build-image:stage:buildtags:-runner# 在指定Runner上执行image:name:$HARBOR_HOST/gitops/docker:29entrypoint:[]services:-name:$HARBOR_HOST/gitops/docker:29-dindalias:dockerentrypoint:[/bin/sh,-c]command:-exec dockerd-entrypoint.sh --insecure-registry$HARBOR_HOST_DINDvariables:# 将作业级别的 $HARBOR_HOST 变量的值赋给服务容器内的 $HARBOR_HOST_DIND 变量HARBOR_HOST_DIND:$HARBOR_HOST# 配置 Docker 客户端连接到 DinD 服务DOCKER_HOST:tcp://docker:2375# 使用非 TLS 端口DOCKER_TLS_CERTDIR:# 关闭 TLS因为 Harbor 是 HTTPrules:-if:$CI_COMMIT_TAG# 仅当有 Tag 时运行script:# 使用基础镜像账号构建架构镜像-echo $HARBOR_BASE_PASS|docker login $HARBOR_HOST-u $HARBOR_BASE_USER--password-stdin-export IMAGE_TAG${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}-docker build-t $HARBOR_HOST/$HARBOR_PROJECT/$CI_PROJECT_NAME:$IMAGE_TAG .# 构建部署镜像# 切换到部署镜像项目账号并推送镜像-echo $HARBOR_PROJECT_PASS|docker login $HARBOR_HOST-u $HARBOR_PROJECT_USER--password-stdin-docker push $HARBOR_HOST/$HARBOR_PROJECT/$CI_PROJECT_NAME:$IMAGE_TAG# 推送部署镜像# # Stage 2: 打包并推送Helm Chart# package-helm-chart:stage:packagetags:-runner# 在指定Runner上执行image:name:$HARBOR_HOST/gitops/helm:v4.2.4entrypoint:[]rules:-if:$CI_COMMIT_TAG# 仅当有Tag时运行script:-sed -i s/^version:.*/version: ${CI_COMMIT_TAG}/ Chart.yaml# 将Git Tag写进Chart version以强制要求Chart versionGit tag-sed -i s/^appVersion:.*/appVersion: \${CI_COMMIT_TAG}\/ Chart.yaml# 将Git Tag写进Chart appVersion以强制要求Chart appVersionGit tag-echo $HARBOR_PROJECT_PASS|helm registry login $HARBOR_HOST-u $HARBOR_PROJECT_USER--password-stdin--plain-http-helm package ./# 打包Helm Chart镜像需指定Chart.yaml文件所在目录当前为仓库根目录-helm push*.tgzoci://$HARBOR_HOST/$HARBOR_PROJECT/charts--plain-http# 推送Helm Chart镜像# # Stage 3: 部署到K3s集群# deploy-argocd-app:stage:deploytags:-runner# 在指定Runner上执行image:name:$HARBOR_HOST/gitops/kubectl-tools:v1.36.4entrypoint:[]rules:-if:$CI_COMMIT_TAG# 仅当有 Tag 时运行script:# 配置K3s集群的kubeconfig-mkdir-p ~/.kube-echo $KUBECONFIG_CONTENT~/.kube/config# 约定应用名 Chart name 仓库名Chart version Git tag-export APP_NAME$CI_PROJECT_NAME-export CHART_NAME$CI_PROJECT_NAME-export CHART_VERSION$CI_COMMIT_TAG# 环境变量可从 GitLab CI/CD Variables 获取或直接在这里定义-export TARGET_NAMESPACE$HARBOR_PROJECT# 渲染并应用-envsubst argocd-app.yamlargocd-app-rendered.yaml-kubectl apply-f argocd-app-rendered.yaml3.2 创建ArgoCD项目CI/CD流水线使用ArgoCD基于Helm Chart自动从Harbor拉取镜像并部署至Kubernetes集群。访问ArgoCD Web UI进入“Settings”→“Projects”→“New Project”创建项目。重要配置项如下配置项说明示例GENERAL.NAMEArgoCD项目名可与Harbor项目同名argocd_projectSOURCE REPOSITORIESHelm Chart的Harbor项目地址harbor_host/harbor_project/chartsDESTINATIONS.Server镜像部署地址需与argocd-app.yaml中的spec.destination.server一致https://kubernetes.default.svcDESTINATIONS.Namespace镜像部署命名空间需与argocd-app.yaml中的spec.destination.namespace一致harbor_project3.3 配置ArgoCD应用在.gitlab-ci.yml所在目录下创建argocd-app.yaml文件内容如下apiVersion:argoproj.io/v1alpha1kind:Applicationmetadata:name:${APP_NAME}namespace:argocdspec:project:${ARGOCD_PROJECT}source:repoURL:${HARBOR_HOST}/${HARBOR_PROJECT}/chartschart:${CHART_NAME}targetRevision:${CHART_VERSION}helm:valueFiles:-values.yamldestination:server:https://kubernetes.default.svcnamespace:${TARGET_NAMESPACE}syncPolicy:automated:prune:trueselfHeal:truesyncOptions:-CreateNamespacetrue-ServerSideApplytrue3.4 创建Harbor机器人账户可选CI/CD流水线中涉及对多个Harbor项目的镜像推送和拉取命令这些命令需要该项目的执行权限。最简单的做法是使用Harbor管理员账户admin该账户拥有对所有Harbor项目执行所有命令的权限但这样可能造成权限过大的安全风险。更加推荐的做法是为每个项目分别创建一个机器人账户该账户仅拥有对所属项目中镜像的推送和拉取权限从而满足“最小权限”安全规范。机器人账户的创建流程如下访问Harbor Web UI页面进入一个项目例如gitops在该项目下点击“机器人账户”→“添加机器人账户”输入账户“名称”如ci账户“过期时间”可设置为“永不过期”然后点击“下一步”进入“选择权限”页面勾选“仓库”的“拉取”和“推送”权限最后点击“完成”保存。创建账户完成后系统会弹出该账户的令牌即密码注意该令牌仅会显示一次需妥善保存。本CI/CD流水线需分别为gitops、harbor_base和harbor_project三个项目创建机器人账户。3.5 添加GitLab变量CI/CD流水线.gitlab-ci.yml文件引用了一些变量需在GitLab中创建这些变量。如果仅使用GitOps维护某一个GitLab仓库则仅需在该仓库中添加变量但如果希望维护某个GitLab群组下的多个仓库则建议在该群组中添加变量该群组中的所有仓库会自动继承这些变量。在GitLab仓库或群组页面下进入“Settings→CI/CD→Variables”需“Maintainer”或“Owner”权限添加以下变量不要勾选“Protect variable”变量名说明值示例HARBOR_HOSTHarbor域名不要带http://harbor_hostHARBOR_BASE_USERHarbor基础镜像项目机器人或管理员账户用户名robot$baseciHARBOR_BASE_PASSHarbor基础镜像项目机器人令牌或管理员账户密码勾选“Masked”harbor_base_passwordHARBOR_PROJECT_USERHarbor部署镜像项目机器人或管理员账户用户名robot$projectciHARBOR_PROJECT_PASSHarbor基础镜像项目机器人令牌或管理员账户密码勾选“Masked”harbor_project_passwordHARBOR_PROJECT部署镜像的Harbor项目名harbor_projectARGOCD_PROJECTArgoCD项目名可与Harbor项目同名argocd_projectKUBECONFIG_CONTENTK3s集群的kubeconfigapiVersion: v1...DOCKER_AUTH_CONFIGCI执行权限账户可使用GitOps项目机器人或管理员账户的用户名和密码{auths: {harbor_host: {username: robot$gitopsci, password: harbor_gitops_password}}}其中KUBECONFIG_CONTENT变量的值为K3s服务器上~/.kube/config文件的完整内容应以apiVersion: v1开头包含clusters、contexts、users三个部分并将server地址由https://127.0.0.1:6443改为K3s服务器的实际地址如https://192.168.0.0:6443。3.6 初始化Helm Chart使用helm create命令快速生成一个标准Chart目录结构helm createchart_name其中chart_name为待部署镜像的Chart名称在本CI/CD流水线中约定Chart名称即为GitLab仓库名称。执行后它会在当前目录下创建一个名为chart_name的文件夹chart_name/ ├── Chart.yaml # Chart元数据 ├── values.yaml # 默认配置值 ├── templates/ # Kubernetes资源模板 │ ├── deployment.yaml │ ├── service.yaml │ ├── ingress.yaml │ ├── serviceaccount.yaml │ ├── httproute.yaml │ ├── hpa.yaml │ ├── NOTES.txt # 安装后提示信息 │ ├── _helpers.tpl # 辅助模板 │ └── tests/ │ │ └── test-connection.yaml └── .helmignore # 打包时忽略的文件Chart.yaml文件所在目录需与.gitlab-ci.yml中的helm package命令匹配本CI/CD流水线将其设置为仓库根目录./因此应将chart_name目录下的所有文件移动至GitLab仓库根目录下。四、提交代码CI/CD流水线通过Git提交代码自动触发。提交前应确保代码仓库中已包含以下文件repository_name/ ├── .gitlab-ci.yml # CI/CD流水线 ├── argocd-app.yaml # ArgoCD应用配置 ├── Chart.yaml # Helm Chart元数据 ├── values.yaml # Helm Chart配置 ├── templates/ # Helm Chart模板 ├── Dockerfile # 镜像打包Dockerfile └── source_code/ # 镜像源代码4.1 配置Helm Chart修改values.yaml是Helm Chart配置的核心步骤。需要根据当前仓库的实际需求调整其中的参数值。以下参数为必改项image:repository:harbor_host/harbor_project/image_namepullPolicy:IfNotPresenttag:service:port:80其中image_name为推送至Harbor的部署镜像名称在本CI/CD流水线中约定该镜像名称即为GitLab仓库名称repository_name。其他参数可按需修改。以下为主要参数说明字段说明示例值replicaCountPod 副本数1image.repository镜像地址不含tagharbor_host/harbor_project/image_nameimage.tag镜像版本标签v1.0.0image.pullPolicy拉取策略IfNotPresent/Alwaysservice.typeService类型ClusterIP/NodePort/LoadBalancerservice.portService暴露端口80resourcesCPU/内存请求与限制按需填写4.2 提交仓库配置好Helm Chart后就可以使用Git提交代码仓库并触发CI/CD流水线了。首次使用Git需要配置身份信息gitconfig--globaluser.nameuser_namegitconfig--globaluser.emailuser_email若当前代码仓库为首次提交需要初始化# 初始化Git仓库gitinit# 关联GitLab仓库gitremoteaddorigingitlab_repository# 设置仓库分支gitbranch-Mmain本CI/CD流水线要求仅在具有Tag的Git提交时触发因此需要再提交代码时创建Tag# 添加文件并提交gitadd.gitcommit-mRelease: v1.0.0# 创建Taggittag-av1.0.0-mRelease v1.0.0# 同时推送分支和Taggitpush-uorigin main v1.0.04.3 验证状态完成代码推送后接下来需要验证整个自动化流程是否成功。4.3.1 验证CI/CD流水线首先确认 CI 流水线是否已自动运行。进入所提交的GitLab仓库页面在左侧导航栏选择“Build”→“Pipelines”在流水线列表中找到刚推送触发的流水线如果状态是Passed绿色说明打包和推送成功。若状态为Failed红色点击失败的作业名称查看日志排查错误。成功效果如下图所示4.3.2 验证Harbor项目CI流水线成功后需要确认部署镜像和Helm Chart已正确推送到Harbor项目中。访问Harbor网页进入项目后应该能看到harbor_project/image_name部署镜像和harbor_project/charts/image_nameHelm Chart且Tag为刚推送的Tag版本号。4.3.3 验证ArgoCD应用部署最后还需要验证ArgoCD应用状态确保镜像在Kubernetes集群上部署成功。访问ArgoCD Web UI在Applications界面找到部署镜像对应的应用其状态Status应显示为Healthy和Synced绿色。五、总结本文围绕GitOps理念介绍了一套从环境准备到自动部署的CI/CD流水线通过Harbor管理镜像与Helm Chart使用GitLab Runner执行构建、打包和部署触发借助Helm统一应用模板并由ArgoCD将期望状态持续同步到Kubernetes集群。整个流程以Git Tag为发布入口实现镜像构建、Chart推送、应用部署的自动化、可追溯和可回滚减少了人工操作与环境差异提升了交付效率与运维可靠性。实际落地时还应遵循最小权限原则合理配置机器人账户和CI/CD变量并持续关注流水线、Harbor制品和ArgoCD应用状态。