Contents

GitOps与ArgoCD入门

何为GitOps

在云原生时代,云原生应用的部署与配置很大程度上已经是声明式的了——工程师编写deployment、service与configmap等YAML文件来声明应用在k8s上的部署状态,然后交给各种controller来计算需要执行的变更动作,并应用到集群上,使得集群的状态最终与声明的文件保持一致。我想使用过传统虚拟机部署的读者不难明白这种声明式运维模型的优势:

  • 应用的部署以文本形式描述出来,作为一个单一事实来源(single source of truth)明确定义了应用运行的模样,所见即所得
  • 应用变更时,只需要修改部署文件,描述出新的期望状态,controller们便会自动作出正确的修改,避免了人为操作的繁琐与风险

基于这些声明式的部署模型,GitOps这一方法论更进一步,把这些部署文件存放在一个版本git仓库进行版本管理,并使用自动化程序去监听仓库中的部署文件,以及对应集群的真实状态,当二者发生差异时,自动对集群进行变更,使其往仓库中描述的状态靠拢,最终实现一致。

实现GitOps运维的团队在进行应用变更的时候,比如说需要升级应用版本,只需要更新git仓库中deployment、statefulset的pod的image,便可舒舒服服地等待自动化工具检测到git上的变化,自动对集群中的yaml进行更新,最后只需要验证集群中的pod是否更新即可。

ArgoCD

ArgoCD是十分流行的GitOps自动化工具之一,它负责自动监控git仓库与集群状态,令二者时刻保持一致。在这篇文章中,我们将介绍ArgoCD在集群上的部署,并实现一个application作为GitOps模式的入门示例。

下面是ArgoCD的整体工作架构:

argoCD由很多个组件组成,它们负责不同的自动化工作,但整个应用本质上是一个controller,它会不断监听声明的git仓库,同时调用集群api,获取部署文件声明内容在集群内的真实情况,当仓库中的文件发生变化时,调用集群api来修改集群内的配置,使二者最终保持一致。

安装

https://argo-cd.readthedocs.io/en/stable/operator-manual/installation/

由于argoCD是k8s集群上的程序,所以安装起来也是应用一些部署文件就可以了,根据赋予它的权限范围不同,有两种模式:

  • 默认模式下,argoCD将拥有本地集群内的cluster admin权限,用于管理本地集群上的应用
  • namespace模式,只赋予argoCD namespace级别的权限,主要场景是用argoCD来管理外部集群,而不管本地集群

我们这里选择默认安装,虽然后文示例是用argoCD来管理我digitalOcean上的集群,但不排除后面也会部署到本地,所以直接默认就好了,homelab就不用关心隔离性之类的问题。

1
2
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

安装完后,我们可以看一眼大概有哪些程序:

接下来我们就可以访问它的webUI了,通过改argocd-server service为nodePort,或者直接使用kubectl port-forward来暴露服务即可,暴露后便能打开浏览器进行访问,初次访问时,需要查看初始化密码,使用admin登录:

1
 kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

Demo application

接下来我们来创建一个application来演示argoCD的gitOps能力。application是argoCD的CRD,它承载一个使用gitOps的项目的基本配置:

  • 事实来源的git仓库

  • 要同步的集群与命名空间

  • 以及同步与资源回收的一些选项

添加git仓库

首先,需要先给argoCD添加git仓库的连接信息与密钥,这次就用本人一个业余golang微服务项目来做实验吧,我把部署到k8s上所需的yaml文件全都放到这个github仓库下:

然后在自己账号的settings->Developer settings->Personal access token中创建一个专属的密钥。生成后,在argoCD的Settings->Repositories中进行添加,输入git地址,自己github的账号名和access token作为密码,如无意外就能创建并连接成功:

添加集群

接下来,由于需要这个go应用拥有公网入口,所以我打算把它部署在公有云上,用的是digitalOcean的k8s,单节点4G2C就要24刀/月。。。跟他家vm配置一个价,也就是送control plane与集群管理服务,还是有点小贵🤣😢

添加远程集群的步骤就不能在UI上执行了,原因后续解释。首先,我们需要使用argoCD的命令行工具,用于作为客户端向argoCD server发送指令,下载安装后,在准备使用该客户端的linux主机上,添加远程集群的kubeconfig:

1
2
3
4
export KUBECONFIG=~/.kube/config:~/kube_demo/argocd/remote-cluster.yaml #添加配置文件路径
kubectl config get-contexts #查看新增的context名字
kubectl config use-context do-sgp1-k8s-1-29-1-do-0-xxxx #切换到该context
kubectl cluster-info #验证是否已经切换到远程集群

接下来,我们便可以调用argoCD cli工具进行集群添加了:

1
2
argocd login localhost:30443 #登录到本地的argocd服务端
argocd cluster add <远端集群的context name>

预期返回下面内容,就是添加成功了:

纳管原理

看到上面的输出,你可能会好奇添加集群背后都做了什么:

  1. argocd客户端程序根据声明的kubectl context在本机获取远端集群api密钥
  2. 使用这个api密钥去访问远端集群:
    1. 在kube-system ns创建一个service account
    2. 创建一个有cluster admin权限的clusterrole
    3. 将service account与这个clusterrole进行绑定
    4. 创建service account的access token,并将其写入argocd
    5. 后续对远端集群的访问,使用这个有cluster admin的access token

这就是为什么在webUI上没法添加集群,因为它一开始需要借用kubeconfig中的cluster admin信息来进行bootstrap

编写application

最后,我们编写一份application的CR,来命令argoCD监控github与远端集群:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: autoquiz
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/midknight24/autoquiz-yaml.git
    targetRevision: HEAD
    path: '.'
  destination:
    server: https://xxxx.k8s.ondigitalocean.com
    namespace: autoquiz

kubectl apply -f yaml后,便能在argoCD上看到对应的application:

点击去,可以发现argoCD自动发现了所有与仓库中部署文件相关的所有资源,并以树状结构自动生成出拓扑图。现在显示整个应用的状态的Healthy,也就是运行正常,但是是OutOfSync,说明集群与仓库存在差异。点击Diff,便能看到二者差异所在,再点击SYNC,就会令argoCD去修改集群的部署文件,使它们与仓库内保持一致。当然,可以设置成autoSync,这样就不需要手工同步了,但生产环境不建议这么做。

总结

argoCD作为业界主流的gitOps开源工具,已经发展得十分成熟,相比于其他竞品,他们的UI具有独特的优势,而且生产落地所需的权限隔离,扩容,备份恢复等能力都十分完备,完全推荐它作为gitOps落地的中间件。然而,工具终究只是帮手,云原生、gitOps在IT企业中能否落地,交付价值,最终还是依赖于开发团队、运维团队的实现能力。在应用运维团队工作了大半年,笔者发现云原生时代对运维的知识储备、学习能力与抽象思维的要求完全是不亚于以前在开发团队的工作。一个来自以前的意外馈赠是,以前自学golang的经历让我很多时候能够直接去看这些云原生应用的源代码(因为很多都是go写的嘛),来解决一些文档不全,或者理解不清,导致应用行为不符预期的场景。

所以还是需要紧跟时代不断地提升自己啊,说不准挑战与机会什么时候就拍过来呢。