广告:Codex Token 低价中转站稳定接口 · 快速接入 · 开发者备用通道
Engineering article

ArgoCD GitOps实践 | CTO推荐 服务网格

ArgoCD 是 Kubernetes 上最实用的 GitOps 工具,我见过太多团队在用它做真正的基础设施管理,直接从 Git 仓库同步到集群,保持状态一致。它不是简单的部署工具,而是把整个系统运维流程 Git 化。我见过最惨的场景是团队因为没配置好 sync 模式,导致每次改动都全量重建,浪费了半小时以上的资源。要避免这种问题,必须正

ArgoCD GitOps实践 | CTO推荐 服务网格
配图来源于网络和AI生成,仅供参考。
▌ 技术引导
ArgoCD 是 Kubernetes 上最实用的 GitOps 工具,我见过太多团队在用它做真正的基础设施管理,直接从 Git 仓库同步到集群,保持状态一致。它不是简单的部署工具,而是把整个系统运维流程 Git 化。我见过最惨的场景是团队因为没配置好 sync 模式,导致每次改动都全量重建,浪费了半小时以上的资源。要避免这种问题,必须正确设置 syncStrategy,比如使用 Apply 模式而不是 Sync 模式,同时在 targetRevision 上用 commit hash 控制版本。还有,运维人员要习惯在 Git 中写 manifests,而不是在本地编辑再 push,这是真实踩过的坑之一。CTO 推荐的实践是把 ArgoCD 集成到 CI/CD 流水线,每个 PR 触发自动 sync,同时用服务网格观测部署过程,确保每个应用变更都能被服务网格捕获,这样才叫真正的 GitOps。

▌ 技术参考


GitOps 的核心是让基础设施和应用配置都受 Git 管理。在 Kubernetes 环境中,ArgoCD 是最直接的实现工具。部署 ArgoCD 时,推荐使用 Helm chart,这样可以复用配置和版本控制。创建 namespace 后,用 helm install 命令部署,例如:
```bash
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argo argo/argo-cd --namespace argocd
```
安装后要立即配置 admin 用户,用 argocd admin create 命令,参数建议带上 --username 和 --password,注意密码必须是强密码,否则后期修改会很麻烦。同时要设置 RBAC 规则,确保 ArgoCD 的服务账号有权限访问目标 namespace。


ArgoCD 的核心功能是通过 Git 仓库同步应用配置,这需要正确设置 repo 和 path。通常我们会创建一个单独的 Git 仓库,比如 GitHub 或 GitLab,专门用于存储 Kubernetes manifests。部署时用 kubectl apply 同步,而不是直接写到集群中。创建 Application 时,要指定 repo、path 和 revision。例如:
```bash
argocd app create myapp --repo https://github.com/yourorg/yourrepo --path apps/myapp --revision main
```
这里的 path 必须和 Git 仓库结构严格对应,否则 sync 会失败。常见问题是 path 写错了,或者误把 Dockerfile 放进 manifests 目录,导致 ArgoCD 识别错误。要避免这种情况,必须在 Git 仓库中显式定义 manifests 的目录结构,比如 apps/ 或 config/,并确保所有资源文件都在里面。syncStrategy 要选 apply,这样不会因为资源更新顺序导致问题。


ArgoCD 的 sync 模式有两种:apply 和 sync。在实际使用中,sync 模式会造成大量资源重建,特别是当配置变更较多时,资源状态会丢失,导致需要重新 rollout。所以推荐使用 apply 模式,这样 ArgoCD 会对比实际状态和期望状态,逐个修正。配置方式是通过 Application 的 spec.syncPolicy 指定:
```yaml
spec:
syncPolicy:
automated:
prune: true
selfHeal: true
```
prune 表示清理已删除的资源,selfHeal 表示自动修复不一致的状态。但要注意,selfHeal 会导致某些资源被误删,比如 service account 或 secret,因此在生产环境要严格控制 selfHeal 的使用场景。在某些情况下,例如配置变更影响到依赖关系,最好手动触发 sync 以确保稳定性。


在服务网格中,比如 Istio,ArgoCD 的同步过程会受到 Envoy 的影响。当一个应用被 ArgoCD 同步后,它会自动注册到服务网格中,但需要注意 Istio 的配置是否正确。比如,如果应用没有定义 sidecar 注入,即使 ArgoCD 同步了,服务网格也不会自动注入。这时候需要在 Deployment 的 annotations 中添加 istio-injection: enabled。同时,ArgoCD 会自动检测这些注解并进行适配。这种情况下,部署出错的概率会降低,但如果你手动配置了 service mesh 的配置,那要确保和 ArgoCD 的 sync 逻辑一致,避免冲突。


ArgoCD 的 Application 健康检查机制非常关键。在配置 Application 时,要定义 healthCheck 和 diffCheck 的策略。比如,使用 kubectl rollout status 来检查 deployment 是否完成,或者用 HTTP 请求来验证 service 是否正常。可以这样配置:
```yaml
spec:
healthCheck:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
```
diffCheck 用来对比实际配置和期望配置,避免误操作。如果发现 diff 大于 10% 就触发 alert,这个配置可以放在 argocd-notification 配置中。之前在一家公司就因为 diffCheck 设置太松,导致大量资源被误修改,最终引发服务中断,修复成本极高。


ArgoCD 的 rollouts 是一个非常强大的功能,但它的实现方式和传统 CI/CD 不一样。在同步过程中,它会使用 kubectl apply,而 apply 的顺序和策略会影响 rollouts 的成功与否。因此,推荐使用 Helm chart 来管理资源,这样可以确保在 apply 时有明确的依赖关系。例如,先 apply namespace,再 apply service account,然后是 deployment,最后是 service。如果资源之间没有明确的依赖顺序,同步可能会失败,甚至导致资源处于 unknown 状态。在实际部署中,我们设置了 Helm chart 的依赖关系,这样 ArgoCD 会自动按顺序 apply 资源,避免了多次人工干预。


在服务网格中,ArgoCD 的集成需要特别注意 sidecar 的生命周期。例如,当一个应用被 ArgoCD 重新部署时,sidecar 会重新注入,但某些流控策略或安全配置可能会被破坏。为了避免这种情况,需要在 Application 的 spec 中添加 syncStrategy: Requeue,这样 ArgoCD 会等待 sidecar 完全注入后再进行 sync。这个策略在 Istio 中尤其重要,因为 sidecar 注入是异步过程,需要确保应用和 sidecar 的状态都稳定。在一些高并发的场景下,我们还需要设置 syncPeriod,比如 5 分钟,这样 ArgoCD 不会频繁触发 rollouts,减少资源压力。


ArgoCD 的资源同步主要依赖于 Kubernetes 的 API。然而,在某些情况下,比如使用私有 registry 或自签名证书,sync 会失败。这时候需要在 ArgoCD 的配置中添加信任的 CA 或 registry 镜像。可以使用 argocd-registry-secret 来配置 registry 认证信息,例如:
```bash
kubectl create secret generic regsecret --from-file=.dockerconfigjson=/path/to/docker/config.json
```
然后在 Application 的 spec 中引用这个 secret,确保 pull 镜像时不会报错。另外,对于使用自签名证书的集群,需要在 ArgoCD 的 configmap 中添加 kubeconfig 的 CA 证书,否则 sync 时会提示证书无效。这些配置都是真实踩过坑之后才总结出来的经验。


在大型系统中,ArgoCD 的缓存机制会影响同步效率。如果你发现 sync 一直卡在 pending 状态,那可能是缓存没更新。解决方法是手动清空 ArgoCD 的缓存,使用 argocd app sync --force 命令强制重新拉取。另外,如果 Git 仓库的变更频繁,要合理设置 pollInterval 和 syncInterval,避免资源频繁重建。例如,设置 pollInterval 为 10 秒,这样 ArgoCD 会更及时地检测到变更。不过,pollInterval 设置太短也会导致资源频繁同步,增加 CPU 使用率,这在我们的实践中曾导致集群资源瓶颈,后来改用 webhook 方式同步,效率提升很多。


ArgoCD 与服务网格的联动需要特别关注镜像拉取和依赖项的版本一致性。例如,在 Istio 中,如果你使用了 Istio 的特定版本,所有应用的镜像必须兼容该版本。否则,sidecar 注入会失败,导致某些应用无法正常运行。我们曾遇到一个案例,某个应用的镜像版本过旧,导致 Envoy 无法正确解析流量策略,最终引发整个网格的异常。为了避免这种情况,要在 Application 的 spec 中明确指定所需的镜像版本,并确保 Git 仓库中的镜像标签和实际部署的标签一致。同时,可以使用 GitLab 或 GitHub 的镜像依赖项管理功能,自动识别镜像版本是否匹配。

十一
ArgoCD 的 Application 可以通过环境变量来控制不同环境的部署策略。例如,在 staging 环境,可以配置 diffCheck 为 true,确保每次 sync 都有检测。而在 production 环境,可以关闭 diffCheck,减少不必要的 diff 检查。这个功能可以通过在 Application 的 spec 中定义 env 变量,例如:
```yaml
spec:
env:
- name: DIFF_CHECK
value: "true"
```
再结合 argocd 的配置,将 env 变量映射到不同的 syncPolicy。但在实际操作中,我们发现这种方式不够灵活,后来改用 Application 的多个副本,分别配置不同环境的策略,这样更可控。这种方式也避免了环境变量泄露的风险。

十二
ArgoCD 支持多种 Git 仓库,如 GitHub、GitLab、Bitbucket 等。在实际部署中,我们常见的问题是权限配置错误,导致 ArgoCD 无法访问 Git 仓库。解决方法是创建一个专用的 Git 用户,只赋予 read 权限,而不是 admin 权限,这样可以减少安全风险。同时,在 ArgoCD 的 configmap 中配置 ssh 或 https 的方式,例如:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-cm
namespace: argocd
data:
ssh-private-key: |
-----BEGIN OPENSSH PRIVATE KEY-----
...
-----END OPENSSH PRIVATE KEY-----
```
这里的数据要确保没有换行符,否则会报错。另外,如果使用 https 方式,需要在 ArgoCD 的配置中添加 git user 和 password,而且要使用 token 而不是明文密码,防止泄露。这些配置细节在实际部署中必须确认,否则 sync 会失败。

十三
ArgoCD 的 Application 定义文件中,可以使用变量来控制不同环境的配置。例如,通过使用 --arg 和 --argfile 参数,可以动态注入环境相关的配置参数。例如:
```bash
argocd app create myapp --repo https://github.com/yourorg/yourrepo --path apps/myapp --revision main --arg env=prod
```
这个方式可以避免在 Application 定义中硬编码参数,提高复用性。但实际使用中,我们发现变量注入有时会出错,比如参数格式不对,或者遗漏了某些字段。因此,建议使用 --argfile 来导入 YAML 文件,这样更清晰,也更容易调试。例如,创建一个 env.yaml 文件,包含 env: prod 或 env: dev,然后在 Application 定义中引用这个文件,减少错误率。

十四
在服务网格中,ArgoCD 的 Application 可以通过 Kubernetes 的 label 来分类管理。比如,所有属于 istio 的 Application 都打上 istio-app: true 的标签,这样可以方便筛选和监控。同时,可以在 ArgoCD 的 dashboard 中配置自动分组和过滤,这样在部署时能更清晰地看到哪些应用是网格的一部分。这种方法不仅提高了管理效率,还减少了误操作的可能。但要注意,label 必须和 Kubernetes 的标签策略一致,否则会导致分组失败。

十五
ArgoCD 的 Application 可以通过 helm chart 来管理版本。例如,使用 Helm 的 version 字段来控制应用的版本,这样每次 sync 会自动拉取最新的 chart。但需要注意,如果 chart 的版本管理不规范,可能导致资源更新失败。我们曾遇到一个 case,chart 中的 release 名称没有唯一性,导致多个 release 同时存在,最终无法正确 sync。因此,在定义 helm chart 时,必须确保 release 名称是唯一的,同时在 Application 中指定 chart 的版本,例如:
```yaml
spec:
source:
repoURL: https://your-chart-repo
chart: mychart
version: 1.2.3
```
这样可以避免版本冲突,同时确保每次 sync 都是基于正确的 chart 版本。这种方法在管理多个微服务时特别有用,可以减少版本混乱的可能。