文章总结: 本文介绍GitOps实践,通过ArgoCD实现K8s应用全自动交付流水线。核心是将Git作为期望状态来源,ArgoCD持续同步确保环境一致性。关键发现包括权限分离、仓库结构规范、清单编写需包含探针和安全上下文。可操作建议有使用Helm、设置保护分支、进行dry-run检查。注意机密数据管理,避免人工与ArgoCD管理同一对象。 综合评分: 88 文章分类: 安全建设,解决方案,技术标准,安全运营,应用安全
GitOps实践:ArgoCD实现K8s应用全自动交付流水线
点击关注👉 点击关注👉
马哥Linux运维
2026年7月27日 18:25 广东
在小说阅读器读本章
去阅读
GitOps实践:ArgoCD实现K8s应用全自动交付流水线
传统 Kubernetes 发布常由 CI 或人工终端直接执行 kubectl apply。服务和环境增多后,线上版本、人工热修、配置来源和回滚依据很难对应。GitOps 将 Git 定义为期望状态来源;Argo CD 持续获取指定 revision,渲染清单、比较实际状态并在受控权限范围内同步。
本文使用 Kubernetes、Helm 和 Argo CD。<集群上下文> 是 kubeconfig context,<命名空间> 是业务 namespace,<仓库地址> 是 Git 地址,<不可变镜像标签> 是 Git SHA 或构建号。不要把密码、Token、私钥写进 Git;机密数据应使用企业密钥系统、External Secrets 或 Sealed Secrets。
1. 确定交付边界和权限
CI 负责测试、构建、扫描、推送镜像;环境仓库声明镜像 tag 和 Kubernetes 配置;Argo CD 从环境仓库部署。不要让 CI 同时持有生产集群管理员权限,也不要允许人工和 Argo CD 同时管理同一对象,否则 OutOfSync 会掩盖真实漂移。
以下检查主要是只读操作,但 use-context 会改变本机默认 context。执行前确认没有误连接生产。
bash
kubectl config get-contexts
kubectl config use-context <集群上下文>
kubectl version --client
kubectl cluster-info
无法访问 API Server 时先检查 kubeconfig、网络、VPN 和身份认证。记录服务端版本、节点和当前权限,这些是排查兼容性、调度或 RBAC 的依据。
bash
kubectl version -o yaml
kubectl get nodes -o wide
kubectl auth can-i create deployments -n <命名空间>
kubectl auth can-i get pods -n <命名空间>
生产建议仅授予 Argo CD 控制器目标 namespace 的写权限,开发与 CI 仅通过受保护分支或合并请求触发发布,并保留必要的只读排障权限。
2. 让仓库表达全部环境差异
应用模板与环境配置可在同一仓库,也可因权限分拆。无论哪种方式,生产运行的镜像、资源、入口和策略都必须在一个明确 commit 中重现,不能依赖个人电脑的临时参数。
text
platform-gitops/
├── apps/orders-api/
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── templates/
│ └── values/
│ ├── test.yaml
│ ├── staging.yaml
│ └── production.yaml
└── argocd/
├── projects/
└── applications/
初始化时应设置保护分支、审批和测试门禁。生产目录只允许审查过的变更进入 main,CI 禁止强推绕过审计。
bash
git init platform-gitops
cd platform-gitops
git checkout -b main
git config user.name "<提交者名称>"
git config user.email "<提交者邮箱>"
mkdir -p apps/orders-api/{templates,values} argocd/{projects,applications}
Chart 版本不等于镜像版本;镜像 tag 必须在 values 中显式管理。生产禁止 latest,否则镜像仓库覆盖或节点缓存都会破坏可复现性。
yaml
# apps/orders-api/Chart.yaml
apiVersion: v2
name: orders-api
description: GitOps managed API
type: application
version: 0.1.0
appVersion: "1.0.0"
yaml
# apps/orders-api/values.yaml
replicaCount: 2
image:
repository: <镜像仓库>/orders-api
tag: "1.0.0"
pullPolicy: IfNotPresent
service:
port: 8080
resources:
requests: {cpu: 100m, memory: 128Mi}
limits: {cpu: 500m, memory: 512Mi}
生产 values 只包含真实环境差异。requests 是调度依据,limits 是隔离上限,数值应通过容量评估与监控确定。
yaml
# apps/orders-api/values/production.yaml
replicaCount: 4
image:
tag: "<不可变镜像标签>"
resources:
requests: {cpu: 500m, memory: 512Mi}
limits: {cpu: "1", memory: 1Gi}
3. 编写可被正确判定的应用清单
Argo CD 的 Synced 不等于业务可用。Deployment 应包含一致的标签、资源请求、readiness/liveness 探针与基础安全上下文。readiness 不通过时 Pod 不会进入 Service Endpoints,是业务不可达的关键证据。
yaml
# templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "orders-api.fullname" . }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels: {app.kubernetes.io/name: {{ include "orders-api.name" . }}}
template:
metadata:
labels: {app.kubernetes.io/name: {{ include "orders-api.name" . }}}
spec:
securityContext: {runAsNonRoot: true, seccompProfile: {type: RuntimeDefault}}
containers:
- name: orders-api
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
ports: [{name: http, containerPort: 8080}]
resources: {{- toYaml .Values.resources | nindent 12 }}
readinessProbe: {httpGet: {path: /readyz, port: http}, initialDelaySeconds: 5}
livenessProbe: {httpGet: {path: /healthz, port: http}, initialDelaySeconds: 15}
securityContext: {allowPrivilegeEscalation: false, readOnlyRootFilesystem: true}
统一 helper 可避免 Service selector 与 Pod label 不一致。若服务没有 Endpoint,应先对比这两处,而不是先删除或重启 Pod。
gotemplate
{{/* templates/_helpers.tpl */}}
{{- define "orders-api.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "orders-api.fullname" -}}
{{- printf "%s-%s" .Release.Name (include "orders-api.name" .) | trunc 63 | trimSuffix "-" }}
{{- end }}
yaml
# templates/service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ include "orders-api.fullname" . }}
spec:
selector: {app.kubernetes.io/name: {{ include "orders-api.name" . }}}
ports:
- {name: http, port: {{ .Values.service.port }}, targetPort: http}
ConfigMap 改动若依赖进程重启,必须触发 Pod template 变更。仅改 ConfigMap 不会重启使用环境变量的容器。
yaml
# templates/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "orders-api.fullname" . }}-config
data:
LOG_LEVEL: "info"
FEATURE_MODE: "stable"
yaml
# 添加到 deployment 的 spec.template.metadata
annotations:
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
提交前做 lint、渲染和客户端 dry-run。客户端检查不访问 API Server;服务器端检查才会经过 admission webhook,但也不会持久化资源。
bash
cd apps/orders-api
helm lint .
helm template orders-api . --namespace <命名空间> \
-f values.yaml -f values/production.yaml > /tmp/orders.yaml
kubectl apply --dry-run=client -f /tmp/orders.yaml
bash
kubectl apply --dry-run=server -n <命名空间> -f /tmp/orders.yaml
kubectl diff -n <命名空间> -f /tmp/orders.yaml
被 webhook 拒绝时应保存资源、字段和 webhook 名称作为证据,再修复 Git 配置;不要临时放宽生产策略绕过检查。
4. 安装并验证 Argo CD
安装会创建 CRD、RBAC、控制器和服务,属于控制面变更。生产必须固定经审查的 release tag,先在隔离环境验证,执行前检查内部镜像仓库、网络策略、资源规格和变更窗口。
bash
kubectl create namespace argocd --dry-run=client -o yaml | kubectl apply -f -
kubectl apply -n argocd \
-f https://raw.githubusercontent.com/argoproj/argo-cd/<版本号>/manifests/install.yaml
kubectl rollout status deployment/argocd-server -n argocd --timeout=10m
UI 能打开不代表控制器正常;repo-server、application-controller、Redis 中任一异常都可能阻塞交付。
bash
kubectl get pods -n argocd -o wide
kubectl get deployments,statefulsets -n argocd
kubectl get events -n argocd --sort-by=.lastTimestamp
kubectl logs deployment/argocd-application-controller -n argocd --tail=100
初始密码只用于首次登录。解码 Secret 有泄露风险,禁止复制输出到工单、日志或聊天记录;使用后立即改密或接入 SSO。
bash
kubectl get secret argocd-initial-admin-secret -n argocd \
-o jsonpath='{.data.password}' | base64 -d; echo
kubectl port-forward svc/argocd-server -n argocd 8080:443
bash
argocd version --client
argocd login localhost:8080 --username admin --insecure
argocd account update-password
argocd account list
5. 用 AppProject 缩小爆炸半径
默认 project 过宽。生产 Application 应限制源仓库、目标集群、业务 namespace 与允许资源类型。即使 Application 被误改,项目边界仍能拒绝越权目标。
yaml
# argocd/projects/orders-production.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: orders-production
namespace: argocd
spec:
sourceRepos: ["<仓库地址>"]
destinations:
- namespace: <命名空间>
server: https://kubernetes.default.svc
clusterResourceWhitelist: []
namespaceResourceWhitelist:
- {group: "", kind: Service}
- {group: "", kind: ConfigMap}
- {group: apps, kind: Deployment}
AppProject 位于 argocd namespace,不在业务 namespace。需要 HPA、Ingress 或 ServiceAccount 时,经评审后显式增加,不能使用通配白名单。
bash
kubectl apply --dry-run=client -f argocd/projects/orders-production.yaml
kubectl apply -n argocd -f argocd/projects/orders-production.yaml
kubectl get appprojects -n argocd
kubectl describe appproject orders-production -n argocd
私有 Git 仓库使用最小权限的只读 deploy key 或机器人 Token,避免复用人员个人 PAT。
bash
argocd repo add <仓库地址> \
--username <机器人账户> \
--password
argocd repo list
6. Application 定义完整交付契约
Application 绑定仓库、revision、路径、Helm values、项目和目标集群。受保护 main 适合常规发布;严格冻结可固定 tag 或 commit SHA。首次上线建议关闭 prune,先观察资源树和删除影响。
yaml
# argocd/applications/orders-production.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: orders-api-production
namespace: argocd
spec:
project: orders-production
source:
repoURL: <仓库地址>
targetRevision: main
path: apps/orders-api
helm:
valueFiles: [values.yaml, values/production.yaml]
destination:
server: https://kubernetes.default.svc
namespace: <命名空间>
syncPolicy:
automated: {prune: false, selfHeal: true}
syncOptions: [CreateNamespace=true]
selfHeal 会纠正人工修改。紧急变更应回写 Git,或按流程暂停自动同步;否则下一轮 reconcile 将恢复 Git 版本。
bash
git status --short
git add apps/orders-api argocd
git commit -m "feat(gitops): add orders-api production application"
git push origin main
kubectl apply --dry-run=client -f argocd/applications/orders-production.yaml
首次同步前查看差异。app diff 发现差异可返回非零状态,重点应是阅读差异内容,确认没有未知资源删除、selector 变化或权限配置变化。
bash
kubectl apply -n argocd -f argocd/applications/orders-production.yaml
argocd app get orders-api-production
argocd app diff orders-api-production
argocd app resources orders-api-production
bash
argocd app sync orders-api-production
argocd app wait orders-api-production --sync --health --timeout 600
argocd app history orders-api-production
7. Kubernetes 层验证与故障定位
所有 kubectl 命令带 namespace,防止默认 namespace 误判。Synced/Healthy 后仍检查 rollout、Pod、Endpoint、事件和业务接口。
bash
kubectl rollout status deployment/orders-api-orders-api -n <命名空间> --timeout=5m
kubectl get pods -n <命名空间> -l app.kubernetes.io/name=orders-api
kubectl get svc,endpoints -n <命名空间>
kubectl get events -n <命名空间> --sort-by=.lastTimestamp
网络和镜像策略允许时,可创建临时 curl Pod 验证集群内链路。它会创建和删除 Pod;生产前确认镜像来自允许的内部仓库,不携带生产凭据。
bash
kubectl run curl-check -n <命名空间> --rm -i --restart=Never \
--image=curlimages/curl:<镜像版本> \
-- curl -fsS http://orders-api-orders-api:<端口>/readyz
Endpoint 为空时,对比 selector、labels 与 readiness。这比重启更能说明根因。
bash
kubectl get service orders-api-orders-api -n <命名空间> -o yaml
kubectl get pods -n <命名空间> -l app.kubernetes.io/name=orders-api --show-labels
kubectl get endpoints orders-api-orders-api -n <命名空间> -o yaml
资源长期 Progressing 时,Deployment condition、Pod event 和上一轮容器日志是根因证据。ImagePullBackOff、FailedScheduling、CrashLoopBackOff 不能用同一种手段处理。
bash
kubectl describe deployment orders-api-orders-api -n <命名空间>
kubectl get pods -n <命名空间> -l app.kubernetes.io/name=orders-api
kubectl describe pod <Pod名称> -n <命名空间>
kubectl logs <Pod名称> -n <命名空间> -c orders-api --previous --tail=200
8. CI 只更新 Git,不直接更新集群
CI 构建不可变 tag 后应在环境仓库创建变更或合并请求;审批合并后 Argo CD 拉取 revision。以下脚本先同步 main、备份 values、渲染 Helm 并展示 diff。实际环境应固定执行器上的工具版本。
bash
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="<GitOps仓库本地目录>"
IMAGE_TAG="<不可变镜像标签>"
VALUES_FILE="$REPO_DIR/apps/orders-api/values/production.yaml"
cd "$REPO_DIR"
git fetch origin main
git checkout main
git pull --ff-only origin main
sed -i.bak -E "s|^( tag: ).*|\\1\\"$IMAGE_TAG\\"|" "$VALUES_FILE"
helm lint apps/orders-api
helm template orders-api apps/orders-api -f "$VALUES_FILE" >/tmp/orders-api.yaml
git diff -- "$VALUES_FILE"
sed 的原地编辑参数与操作系统有关,应先在执行器确认。无论使用 sed 还是 YAML 工具,都要限制改动字段、做渲染校验,禁止使用强推绕过保护分支。
bash
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="<GitOps仓库本地目录>"
IMAGE_TAG="<不可变镜像标签>"
cd "$REPO_DIR"
git add apps/orders-api/values/production.yaml
git commit -m "chore(release): orders-api $IMAGE_TAG"
git push origin HEAD:refs/heads/<发布分支>
若 push 被拒绝,通常是远端已有提交或保护规则生效。应基于最新 main 重新生成变更,或提交合并请求,不能强推覆盖共享历史。
9. 对 OutOfSync 进行证据化排查
先确认 Argo CD 实际使用的 revision、资源树和事件。revision 与预期 Git SHA 不同,优先检查仓库认证、分支、缓存和 repo-server;revision 一致而对象异常,再进入 Kubernetes 排查。
bash
argocd app get orders-api-production --refresh
kubectl get application orders-api-production -n argocd -o yaml
kubectl describe application orders-api-production -n argocd
argocd app resources orders-api-production
控制器日志需要时间范围与应用名。看到权限错误时,同时验证 AppProject、目标集群 RBAC 和控制器身份;看到 Git 超时时,检查 DNS、NetworkPolicy、代理和证书。
bash
kubectl logs deployment/argocd-repo-server -n argocd --since=30m | \
grep -F "orders-api-production"
kubectl logs statefulset/argocd-application-controller -n argocd --since=30m | \
grep -F "orders-api-production"
人工修改、HPA 改副本数和 admission 注入字段都会导致 OutOfSync。先定位字段,再决定修 Git、撤销人工改动或设置最窄的忽略规则。不要以宽泛 ignoreDifferences 隐藏未知漂移。
yaml
# 仅在 HPA 负责副本数且差异来源已确认时使用
spec:
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers: [/spec/replicas]
bash
kubectl get hpa -n <命名空间>
kubectl describe hpa <HPA名称> -n <命名空间>
kubectl get deployment orders-api-orders-api -n <命名空间> \
-o jsonpath='{.spec.replicas}{" desired, "}{.status.availableReplicas}{" available\n"}'
本地复现必须 checkout 到 Argo CD 显示的同一 SHA,并使用相同 values。未提交工作区不能作为线上对比证据。
bash
git fetch origin main
git checkout <ArgoCD显示的提交SHA>
helm dependency build apps/orders-api
helm template orders-api apps/orders-api --namespace <命名空间> \
-f apps/orders-api/values.yaml \
-f apps/orders-api/values/production.yaml > /tmp/revision-rendered.yaml
10. 自动同步、删除和回滚
暂停自动同步时修改 Git 中的 Application,随后同步该变更。只在 UI 临时操作会造成集群状态先于 Git 漂移,恢复自动同步时可能出现意外覆盖。
yaml
# 移除 automated 后的示例
spec:
syncPolicy:
syncOptions: [CreateNamespace=true]
bash
argocd app get orders-api-production -o json | \
jq '.spec.syncPolicy, .status.sync, .status.health'
kubectl get application orders-api-production -n argocd \
-o jsonpath='{.spec.syncPolicy}{"\n"}'
启用 prune 前,只读评估删除范围。若差异涉及 PVC、共享 Service、Ingress、Secret 或 ConfigMap,必须确认归属、备份或快照、灰度方案和回滚路径。
bash
argocd app diff orders-api-production
argocd app resources orders-api-production
kubectl get all -n <命名空间> -l app.kubernetes.io/name=orders-api
kubectl get pvc -n <命名空间>
正常回滚优先回滚 Git。先审阅目标 commit,确认其中没有混入其他服务、数据库迁移或基础设施变更。
bash
git log --oneline -- apps/orders-api/values/production.yaml
git show --stat <待回滚提交SHA>
git show <待回滚提交SHA> -- apps/orders-api/values/production.yaml
bash
#!/usr/bin/env bash
set -euo pipefail
REPO_DIR="<GitOps仓库本地目录>"
COMMIT_TO_REVERT="<待回滚提交SHA>"
cd "$REPO_DIR"
git checkout main
git pull --ff-only origin main
git revert --no-edit "$COMMIT_TO_REVERT"
helm lint apps/orders-api
helm template orders-api apps/orders-api \
-f apps/orders-api/values/production.yaml >/tmp/orders-rollback.yaml
git push origin main
Git 服务不可用且需紧急止损时才使用 Argo CD history 回滚。这会先改变集群 Application,必须立刻补等价 Git 回滚,否则下一次 refresh 可能再次部署新版本。
bash
argocd app history orders-api-production
argocd app rollback orders-api-production <历史ID>
argocd app wait orders-api-production --sync --health --timeout 600
bash
kubectl rollout status deployment/orders-api-orders-api -n <命名空间> --timeout=5m
kubectl get pods -n <命名空间> -l app.kubernetes.io/name=orders-api \
-o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[0].image}{"\n"}{end}'
kubectl get endpoints orders-api-orders-api -n <命名空间>
argocd app get orders-api-production
11. 巡检和交接
应用状态应接入监控。Prometheus 指标名称与标签以实际 exporter 暴露的指标为准;不同 Argo CD 版本和 ServiceMonitor 会有差异,先检查 metrics 端点再固化规则。
promql
# 以实际 exporter 暴露的指标为准
argocd_app_info{sync_status!="Synced"}
or
argocd_app_info{health_status!="Healthy"}
控制器重启和 Warning Event 是辅助证据,仍需结合 OOMKilled、日志、节点压力和 Git 连通性判断根因。
bash
kubectl get pods -n argocd \
-o custom-columns=NAME:.metadata.name,READY:.status.containerStatuses[*].ready,RESTARTS:.status.containerStatuses[*].restartCount
kubectl get events -n argocd --field-selector type=Warning --sort-by=.lastTimestamp
下面脚本只读检查一个 Application,可接入定时任务。账户只需要 Argo CD 读取权限;非零退出码交给上层告警,不替代 Kubernetes 与业务健康检查。
bash
#!/usr/bin/env bash
set -euo pipefail
APP_NAME="orders-api-production"
APP_JSON="$(argocd app get "$APP_NAME" -o json)"
SYNC_STATUS="$(jq -r '.status.sync.status // "Unknown"' <<<"$APP_JSON")"
HEALTH_STATUS="$(jq -r '.status.health.status // "Unknown"' <<<"$APP_JSON")"
printf 'application=%s sync=%s health=%s\n' \
"$APP_NAME" "$SYNC_STATUS" "$HEALTH_STATUS"
if [[ "$SYNC_STATUS" != "Synced" || "$HEALTH_STATUS" != "Healthy" ]]; then
exit 2
fi
交接时保存 revision、Argo CD history、Kubernetes rollout history、审批记录和关键监控链接。以下命令只读收集证据。
bash
argocd app get orders-api-production
argocd app history orders-api-production
kubectl get deployment,service,pods -n <命名空间> \
-l app.kubernetes.io/name=orders-api
kubectl rollout history deployment/orders-api-orders-api -n <命名空间>
Git 说明应该部署什么;Argo CD revision 与同步记录说明控制器尝试交付什么;Kubernetes 状态、日志、指标和业务探针说明实际是否可用。三类证据一致时,自动交付才是可控的;出现不一致时先保存差异与日志、缩小影响范围,再以 Git 修正为主完成恢复。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:马哥Linux运维 点击关注👉 点击关注👉《GitOps实践:ArgoCD实现K8s应用全自动交付流水线》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论