跳到主要内容

Argo CD

Argo CD 是一个为 Kubernetes 而生的,遵循声明式 GitOps 理念的持续部署工具。Argo CD 可在 Git 存储库更改时自动同步和部署应用程序。

Argo CD 遵循 GitOps 模式,使用 Git 仓库作为定义所需应用程序状态的真实来源,Argo CD 支持多种 Kubernetes 清单:

  • kustomize
  • helm charts
  • ksonnet applications
  • jsonnet files
  • Plain directory of YAML/json manifests
  • Any custom config management tool configured as a config management plugin

Argo CD 可在指定的目标环境中自动部署所需的应用程序状态,应用程序部署可以在 Git 提交时跟踪对分支、标签的更新,或固定到清单的指定版本。

架构

c3a75878d1d8

Argo CD 是通过一个 Kubernetes 控制器来实现的,它持续 watch 正在运行的应用程序并将当前的实时状态与所需的目标状态( Git 存储库中指定的)进行比较。已经部署的应用程序的实际状态与目标状态有差异,则被认为是 OutOfSync 状态,Argo CD 会报告显示这些差异,同时提供工具来自动或手动将状态同步到期望的目标状态。在 Git 仓库中对期望目标状态所做的任何修改都可以自动应用反馈到指定的目标环境中去。

下面简单介绍下 Argo CD 中的几个主要组件:

  1. API Server(API 服务)

API Server 是 Argo CD 的核心组件之一,它提供了用户与 Argo CD 交互的主要入口,支持 gRPC 和 REST API 接口。API Server 是所有操作的中枢,包括通过 Web UI、CLI 和外部系统的请求。

  • 功能:
    • 应用程序管理和状态报告:提供管理应用程序和查询应用状态的接口,允许用户查看应用是否处于同步状态(Synced)或不一致状态(OutOfSync)。
    • 执行操作:用户可以通过 API 执行同步、回滚、暂停、恢复等操作。
    • 管理凭据:API Server 管理 Git 仓库和 Kubernetes 集群的认证凭据,这些凭据通常存储在 Kubernetes 的 Secret 对象中,以确保安全访问。
    • 认证和授权:API Server 支持与外部身份提供者(如 OAuth、OIDC、LDAP 等)集成,进行用户认证,并通过基于角色的访问控制(RBAC)进行授权。
    • Git Webhook 监听:监听来自 Git 仓库的 Webhook 事件(如代码更新),触发 Argo CD 的自动化同步过程。
  • 特点:API Server 是与用户、CLI 和外部系统(如 CI/CD 管道)进行交互的核心点,处理所有管理、查询和操作请求。
  1. Repository Server(仓库服务)

Repository Server 是 Argo CD 的内部服务,负责与 Git 仓库交互,并生成 Kubernetes 清单(Manifests)。它通过本地缓存加速清单的解析和生成。

  • 功能:
    • 存储 Git 仓库缓存:Repository Server 从 Git 仓库拉取应用程序清单,并维护本地缓存,减少对 Git 仓库的请求次数,提升系统性能。
    • 生成 Kubernetes 清单:根据输入(例如仓库 URL、Git 分支、commit、tag 等),Repository Server 生成相应的 Kubernetes 配置清单(YAML 文件),这些清单被用于实际的部署操作。
    • 支持多种配置管理工具:它支持多种应用程序定义格式,包括原生 Kubernetes YAML、Helm Charts、Kustomize、Ksonnet、Jsonnet 等。Repository Server 会根据用户指定的模板配置(如 Helm 的 values.yaml 文件)生成自定义清单。
  • 特点:Repository Server 是 Argo CD 中的模板引擎,它通过缓存加速清单生成,并支持多种声明式应用定义格式。
  1. Application Controller(应用控制器)

Application Controller 是 Argo CD 中的核心控制器,它负责实时监控 Kubernetes 集群中的应用状态,并自动执行同步操作,以确保集群状态与 Git 仓库中的期望状态保持一致。

  • 功能:
    • 监控应用状态:Application Controller 持续监控应用程序的实际运行状态(通过与 Kubernetes API 交互),并将其与 Git 仓库中的期望状态进行比较。
    • 检测 OutOfSync 状态:当应用程序的实际状态偏离 Git 仓库中的定义时,Application Controller 会检测到 OutOfSync 状态,并触发同步操作,将应用状态恢复到期望状态。
    • 同步和回滚:Application Controller 可以执行应用程序的同步、回滚操作,确保集群中的应用与 Git 仓库中的定义保持一致。
    • 生命周期钩子执行:支持用户定义的生命周期事件钩子(如 PreSync、Sync、PostSync),允许在同步操作前后执行自定义脚本或操作。
  • 特点:作为 Kubernetes 控制器,Application Controller 是 Argo CD 实现 GitOps 原则的关键组件,负责自动化同步和修复应用状态。
  1. Redis

Redis 在 Argo CD 中用作缓存系统。虽然 Redis 不是 Argo CD 独有的组件,但它在提升系统性能和加速响应时间方面起到了关键作用。

  • 功能:
    • 缓存应用状态:Redis 缓存应用程序的状态信息,使得 Argo CD 可以快速响应用户的状态查询请求,而不必每次都直接从 Kubernetes API 获取状态。
    • 提高性能:通过缓存机制,Redis 减少了 Argo CD 直接与 Kubernetes 集群交互的频率,特别是在大规模应用场景下,极大地提升了系统的查询性能和响应速度。
  • 特点:Redis 提供高效的缓存功能,支持快速读取和写入操作,确保 Argo CD 在高负载下依然保持较快的响应。
  1. Dex(可选组件)

Dex 是一个开源的身份提供服务(Identity Provider),它通常与 Argo CD 集成,用于实现单点登录(SSO)和身份验证功能。

  • 功能:
    • 支持多种身份提供者:Dex 支持多种身份验证协议,包括 OAuth2、OpenID Connect(OIDC)等。它可以集成第三方身份提供者(如 GitHub、Google、LDAP、AD 等),实现 SSO。
    • 用户认证和授权:通过与 Dex 集成,Argo CD 能够实现基于角色的访问控制(RBAC),管理对不同用户或团队的访问权限。
  • 特点:Dex 提供了可扩展的身份认证解决方案,允许 Argo CD 与企业的现有身份验证基础设施集成,提升安全性和易用性。
  1. Web UI 和 CLI
  • Web UI:Argo CD 提供了一个用户友好的 Web 界面,用户可以通过它管理、监控和操作 Kubernetes 集群中的应用程序。Web UI 显示应用的同步状态、健康状态、同步历史、差异对比等详细信息。
  • CLI(命令行界面):Argo CD 还提供了强大的命令行工具,允许用户通过 CLI 与 Argo CD 交互。这对自动化脚本或 DevOps 工程师非常有用,可以方便地通过命令行进行应用管理、同步、回滚等操作。

功能

  • 自动部署应用程序到指定的目标环境
  • 支持多种配置管理/模板工具(Kustomize、Helm、Ksonnet、Jsonnet、plain-YAML)
  • 能够管理和部署到多个集群
  • SSO 集成(OIDC、OAuth2、LDAP、SAML 2.0、GitHub、GitLab、Microsoft、LinkedIn)
  • 用于授权的多租户和 RBAC 策略
  • 回滚/随时回滚到 Git 存储库中提交的任何应用配置
  • 应用资源的健康状况分析
  • 自动配置检测和可视化
  • 自动或手动将应用程序同步到所需状态
  • 提供应用程序活动实时视图的 Web UI
  • 用于自动化和 CI 集成的 CLI
  • Webhook 集成(GitHub、BitBucket、GitLab)
  • 用于自动化的 AccessTokens
  • PreSync、Sync、PostSync Hooks,以支持复杂的应用程序部署(例如蓝/绿和金丝雀发布)
  • 应用程序事件和 API 调用的审计
  • Prometheus 监控指标
  • 用于覆盖 Git 中的 ksonnet/helm 参数

核心概念

  • Application:应用,一组由资源清单定义的 Kubernetes 资源,这是一个 CRD 资源对象
  • Application source type:用来构建应用的工具
  • Target state:目标状态,指应用程序所需的期望状态,由 Git 存储库中的文件表示
  • Live state:实时状态,指应用程序实时的状态,比如部署了哪些 Pods 等真实状态
  • Sync status:同步状态表示实时状态是否与目标状态一致,部署的应用是否与 Git 所描述的一样?
  • Sync:同步指将应用程序迁移到其目标状态的过程,比如通过对 Kubernetes 集群应用变更
  • Sync operation status:同步操作状态指的是同步是否成功
  • Refresh:刷新是指将 Git 中的最新代码与实时状态进行比较,弄清楚有什么不同
  • Health:应用程序的健康状况,它是否正常运行?能否为请求提供服务?
  • Tool:工具指从文件目录创建清单的工具,例如 Kustomize 或 Ksonnet 等
  • Configuration management tool:配置管理工具
  • Configuration management plugin:配置管理插件

安装

当然前提是需要有一个 kubectl 可访问的 Kubernetes 的集群,直接使用下面的命令即可,这里我们安装最新的稳定版 v2.4.9:

通过百度网盘分享的文件:argocd-v2.4.9.yaml

链接:https://pan.baidu.com/s/1x3RPHXeuBNPCCrSZOfNjpQ?pwd=xinn

$ kubectl create namespace argocd
$ kubectl apply -n argocd -f argocd-v2.4.9.yaml

如果你要用在生产环境,则可以使用下面的命令部署一个 HA 高可用的版本:

$ kubectl create namespace argocd
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/v2.4.9/manifests/ha/install.yaml

这将创建一个新的命名空间 argocd,Argo CD 的服务和应用资源都将部署到该命名空间。

$ kubectl get pods -n argocd
NAME READY STATUS RESTARTS AGE
argocd-application-controller-0 1/1 Running 0 2m34s
argocd-applicationset-controller-789fd696bd-72ghf 1/1 Running 0 2m34s
argocd-dex-server-75b7dc4857-44tn2 1/1 Running 0 2m34s
argocd-notifications-controller-fdfcbb856-88v26 1/1 Running 0 2m34s
argocd-redis-5884c8cdf-llwj9 1/1 Running 0 2m34s
argocd-repo-server-64944f996b-x2jp6 1/1 Running 0 2m34s
argocd-server-6f567864dc-rkvtb 1/1 Running 0 2m34s

如果你对 UI、SSO、多集群管理这些特性不感兴趣,只想把应用变更同步到集群中,那么你可以使用 --disable-auth 标志来禁用认证,可以通过命令 kubectl patch deploy argocd-server -n argocd -p '[{"op": "add", "path": "/spec/template/spec/containers/0/command/-", "value": "--disable-auth"}]' --type json 来实现。

CLI 工具

我们可以在本地安装 CLI 工具方便操作 Argo CD,我们可以在 Argo CD Git 仓库发布页面查看最新版本的 Argo CD 或运行以下命令来获取版本:

VERSION=$(curl --silent "https://api.github.com/repos/argoproj/argo-cd/releases/latest" | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/')

VERSION 在下面的命令中替换为你要下载的 Argo CD 版本:

$ curl -sSL -o /usr/local/bin/argocd https://github.com/argoproj/argo-cd/releases/download/$VERSION/argocd-linux-amd64

通过百度网盘分享的文件:argocd-linux-amd64

链接:https://pan.baidu.com/s/1R0HrNiaKgGJOY-unwhsUSw?pwd=xinn 提取码:xinn

为 argocd CLI 赋予可执行权限:

$ cp argocd-linux-amd64 /usr/local/bin/argocd
$ chmod +x /usr/local/bin/argocd

$ argocd version
argocd: v2.4.9+1ba9008
BuildDate: 2022-08-11T15:43:48Z
GitCommit: 1ba9008536b7e61414784811c431cd8da356065e
GitTreeState: clean
GoVersion: go1.18.5
Compiler: gc
Platform: linux/amd64
FATA[0000] Argo CD server address unspecified

现在我们就可以使用 argocd 命令了。如果你是 Mac,则可以直接使用 brew install argocd 进行安装。

暴露服务

Argo CD 会运行一个 gRPC 服务(由 CLI 使用)和 HTTP/HTTPS 服务(由 UI 使用),这两种协议都由 argocd-server 服务在以下端口进行暴露:

  • 443 - gRPC/HTTPS
  • 80 - HTTP(重定向到 HTTPS)

我们可以通过配置 Ingress 的方式来对外暴露服务,其他 Ingress 控制器的配置可以参考 官方文档 进行配置。

Argo CD 在同一端口 (443) 上提供多个协议 (gRPC/HTTPS),所以当我们为 argocd 服务定义单个 nginx ingress 对象和规则的时候有点麻烦,因为 nginx.ingress.kubernetes.io/backend -protocol 这个 annotation 只能接受一个后端协议(例如 HTTP、HTTPS、GRPC、GRPCS)。

为了使用单个 ingress 规则和主机名来暴露 Argo CD APIServer,必须使用 nginx.ingress.kubernetes.io/ssl-passthrough 这个 annotation 来传递 TLS 连接并校验 Argo CD APIServer 上的 TLS。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
nginx.ingress.kubernetes.io/ssl-passthrough: 'true'
spec:
ingressClassName: nginx
rules:
- host: argocd.k8s.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: https

上述规则在 Argo CD APIServer 上校验 TLS,该服务器检测到正在使用的协议,并做出适当的响应。请注意,nginx.ingress.kubernetes.io/ssl-passthrough 注解要求将 --enable-ssl-passthrough 标志添加到 nginx-ingress-controller 的命令行参数中。

由于 ingress-nginx 的每个 Ingress 对象仅支持一个协议,因此另一种方法是定义两个 Ingress 对象。

一个用于 HTTP/HTTPS,另一个用于 gRPC。

如下所示为 HTTP/HTTPS 的 Ingress 对象:

# argocd-ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-http-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/force-ssl-redirect: 'true'
nginx.ingress.kubernetes.io/backend-protocol: 'HTTP'
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: http
host: argocd.k8s.local
tls:
- hosts:
- argocd.k8s.local
secretName: argocd-secret # do not change, this is provided by Argo CD

gRPC 协议对应的 Ingress 对象如下所示:

# argocd-ingress-grpc.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server-grpc-ingress
namespace: argocd
annotations:
nginx.ingress.kubernetes.io/backend-protocol: 'GRPC'
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
name: https
host: grpc.argocd.k8s.local
tls:
- hosts:
- grpc.argocd.k8s.local
secretName: argocd-secret # do not change, this is provided by Argo CD

然后我们需要在禁用 TLS 的情况下运行 APIServer。

编辑 argocd-server 这个 Deployment 以将 --insecure 标志添加到 argocd-server 命令,或者简单地在 argocd-cmd-params-cm ConfigMap 中设置 server.insecure: "true" 即可。

      containers:
- command:
- argocd-server
- --insecure

创建完成后,我们就可以通过 argocd.k8s.local 来访问 Argo CD 服务了,不过需要注意我们这里配置的证书是自签名的,所以在第一次访问的时候会提示不安全,强制跳转即可。

默认情况下 admin 帐号的初始密码是自动生成的,会以明文的形式存储在 Argo CD 安装的命名空间中名为 argocd-initial-admin-secret 的 Secret 对象下的 password 字段下,我们可以用下面的命令来获取:

$ kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d && echo
8nMYyPmiAx-Pe1Gb

使用用户名 admin 和上面输出的密码即可登录 Dashboard。

0668075649d2

同样我们也可以通过 ArgoCD CLI 命令行工具进行登录:

$ argocd login grpc.argocd.k8s.local
WARNING: server certificate had error: x509: certificate is valid for ingress.local, not grpc.argocd.k8s.local. Proceed insecurely (y/n)?
WARNING: server certificate had error: x509: certificate is valid for ingress.local, not grpc.argocd.k8s.local. Proceed insecurely (y/n)? y
Username: admin
Password:
'admin:login' logged in successfully
Context 'grpc.argocd.k8s.local' updated
root@master01:/k8s-Examples/kube-ops/argocd#

需要注意的是这里登录的地址为 gRPC 暴露的服务地址。

CLI 登录成功后,可以使用如下所示命令更改密码:

$ argocd account update-password
*** Enter current password:
*** Enter new password:
*** Confirm new password:
Password updated
Context 'argocd.k8s.local' updated
$ argocd version
argocd: v2.4.9+1ba9008
BuildDate: 2022-08-11T15:43:48Z
GitCommit: 1ba9008536b7e61414784811c431cd8da356065e
GitTreeState: clean
GoVersion: go1.18.5
Compiler: gc
Platform: linux/amd64
argocd-server: v2.4.9+1ba9008
BuildDate: 2022-08-11T15:22:41Z
GitCommit: 1ba9008536b7e61414784811c431cd8da356065e
GitTreeState: clean
GoVersion: go1.18.5
Compiler: gc
Platform: linux/amd64
Kustomize Version: v4.4.1 2021-11-11T23:36:27Z
Helm Version: v3.8.1+g5cb9af4
Kubectl Version: v0.23.1
Jsonnet Version: v0.18.0

配置集群

由于 Argo CD 支持部署应用到多集群,所以如果你要将应用部署到外部集群的时候,需要先将外部集群的认证信息注册到 Argo CD 中,如果是在内部部署(运行 Argo CD 的同一个集群,默认不需要配置),直接使用 https://kubernetes.default.svc 作为应用的 K8S APIServer 地址即可。

首先列出当前 kubeconfig 中的所有集群上下文:

$ kubectl config get-contexts -o name
kubernetes-admin@kubernetes

从列表中选择一个上下文名称并将其提供给 argocd cluster add CONTEXTNAME,比如对于 kind-kind上下文,运行:

root@master01:/k8s-Examples/kube-ops/argocd# argocd cluster add kubernetes-admin@kubernetes
WARNING: This will create a service account `argocd-manager` on the cluster referenced by context `kubernetes-admin@kubernetes` with full cluster level privileges. Do you want to continue [y/N]? y
INFO[0031] ServiceAccount "argocd-manager" created in namespace "kube-system"
INFO[0031] ClusterRole "argocd-manager-role" created
INFO[0031] ClusterRoleBinding "argocd-manager-role-binding" created
Cluster 'https://10.1.0.16:6443' added

$ argocd cluster list
SERVER NAME VERSION STATUS MESSAGE PROJECT
https://10.1.0.16:6443 kubernetes-admin@kubernetes Unknown Cluster has no applications and is not being monitored.
https://kubernetes.default.svc in-cluster Unknown Cluster has no applications and is not being monitored.

创建应用

Git 仓库 https://github.com/argoproj/argocd-example-apps.git 是一个包含留言簿应用程序的示例库,我们可以用该应用来演示 Argo CD 的工作原理。

通过 CLI 创建应用

我们可以通过 argocd app create xxx 命令来创建一个应用:

$ argocd app create --help
Create an application

Usage:
argocd app create APPNAME [flags]

Examples:

# Create a directory app
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --directory-recurse

# Create a Jsonnet app
argocd app create jsonnet-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path jsonnet-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --jsonnet-ext-str replicas=2

# Create a Helm app
argocd app create helm-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path helm-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --helm-set replicaCount=2

# Create a Helm app from a Helm repo
argocd app create nginx-ingress --repo https://charts.helm.sh/stable --helm-chart nginx-ingress --revision 1.24.3 --dest-namespace default --dest-server https://kubernetes.default.svc

# Create a Kustomize app
argocd app create kustomize-guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path kustomize-guestbook --dest-namespace default --dest-server https://kubernetes.default.svc --kustomize-image gcr.io/heptio-images/ks-guestbook-demo:0.1

# Create a app using a custom tool:
argocd app create kasane --repo https://github.com/argoproj/argocd-example-apps.git --path plugins/kasane --dest-namespace default --dest-server https://kubernetes.default.svc --config-management-plugin kasane


Flags:
......

直接执行如下所示命令即可:

$ argocd app create guestbook --repo https://gitee.com/ryanxin/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default
application 'guestbook' created

通过 UI 创建应用

除了可以通过 CLI 工具来创建应用,我们也可以通过 UI 界面来创建,定位到 argocd.k8s.local 页面,登录后,点击 +New App 新建应用按钮,如下图:

e86acff4a42d

将应用命名为 guestbook,使用 default project,并将同步策略设置为 Manual

c6cf771e4003

然后在下面配置 Repository URLhttps://github.com/argoproj/argocd-example-apps.git,由于某些原因我们这里使用的是一个 GitHub 仓库加速地址 https://github.91chi.fun/https://github.com/cnych/argocd-example-apps.git,将 Revision 设置为 HEAD,并将路径设置为 guestbook。然后下面的 Destination 部分,将 cluster 设置为 inCluster 和 namespace 为 default:

686d690828ff

填写完以上信息后,点击页面上方的 Create 安装,即可创建 guestbook 应用,创建完成后可以看到当前应用的处于 OutOfSync 状态:

2d9a842a35a3

Argo CD 默认情况下每 3 分钟会检测 Git 仓库一次,用于判断应用实际状态是否和 Git 中声明的期望状态一致,如果不一致,状态就转换为 OutOfSync。默认情况下并不会触发更新,除非通过 syncPolicy 配置了自动同步。

通过 CRD 创建

除了可以通过 CLI 和 Dashboard 可以创建 Application 之外,其实也可以直接通过声明一个 Application 的资源对象来创建一个应用,如下所示:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: guestbook
spec:
destination:
name: ''
namespace: default
server: 'https://kubernetes.default.svc'
source:
path: guestbook
repoURL: 'https://gitee.com/ryanxin/argocd-example-apps.git'
targetRevision: HEAD
project: default
syncPolicy:
automated: null

部署应用

由于上面我们在创建应用的时候使用的同步策略为 Manual,所以应用创建完成后没有自动部署,需要我们手动去部署应用。同样可以通过 CLI 和 UI 界面两种同步方式。

使用 CLI 同步

应用创建完成后,我们可以通过如下所示命令查看其状态:

$ argocd app get guestbook
Name: guestbook
Project: default
Server: https://kubernetes.default.svc
Namespace: default
URL: https://grpc.argocd.k8s.local/applications/guestbook
Repo: https://gitee.com/ryanxin/argocd-example-apps.git
Target:
Path: guestbook
SyncWindow: Sync Allowed
Sync Policy: <none>
Sync Status: OutOfSync from (d3eb36a)
Health Status: Missing

GROUP KIND NAMESPACE NAME STATUS HEALTH HOOK MESSAGE
Service default guestbook-ui OutOfSync Missing
apps Deployment default guestbook-ui OutOfSync Missing

应用程序状态为初始 OutOfSync 状态,因为应用程序尚未部署,并且尚未创建任何 Kubernetes 资源。要同步(部署)应用程序,可以执行如下所示命令:

$ argocd app sync guestbook

此命令从 Git 仓库中检索资源清单并执行 kubectl apply 部署应用,执行上面命令后 guestbook 应用便会运行在集群中了,现在我们就可以查看其资源组件、日志、事件和评估其健康状态了。

通过 UI 同步

直接添加 UI 界面上应用的 Sync 按钮即可开始同步:

c3bd2604d024

fd0a6bb3ed23

同步完成后可以看到我们的资源状态:

cf05e63bf0a8

甚至还可以直接查看应用的日志信息:

5b16c496fb8e

也可以通过 kubectl 查看到我们部署的资源:

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
guestbook-ui-9f44b6c9c-pl9w5 1/1 Running 0 4m35s
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
guestbook-ui ClusterIP 10.98.250.233 <none> 80/TCP 4m58s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 42d

和我们从 Git 仓库中同步 guestbook 目录下面的资源状态也是同步的,证明同步成功了。

0cf45fb58893

Tekton 结合 Argo CD

前面我们使用 Tekton 完成了应用的 CI/CD 流程,但是 CD 是在 Tekton 的任务中去完成的,现在我们使用 GitOps 的方式来改造我们的流水线,将 CD 部分使用 Argo CD 来完成。

36fe35a8ab92

这里我们要先去回顾下前面的 Tekton 实战部分的内容,整个流水线包括 clone、test、build、docker、deploy、rollback 几个部分的任务,最后的 deploy 和 rollback 属于 CD 部分,我们只需要这部分使用 Argo CD 来构建即可。

准备 CD 文件

首先我们将项目 https://gitee.com/ryanxin/devops-demo.git 仓库中的 Helm Chart 模板单独提取出来放到一个独立的仓库中 https://gitee.com/ryanxin/devops-demo-deploy.git,这样方便和 Argo CD 进行对接,整个项目下面只有用于应用部署的 Helm Chart 模板。

7c1470329e48

创建demo项目

如果有多个团队,每个团队都要维护大量的应用,就需要用到 Argo CD 的另一个概念:项目(Project)。Argo CD 中的项目(Project)可以用来对 Application 进行分组,不同的团队使用不同的项目,这样就实现了多租户环境。项目还支持更细粒度的访问权限控制:

  • 限制部署内容(受信任的 Git 仓库);
  • 限制目标部署环境(目标集群和 namespace);
  • 限制部署的资源类型(例如 RBAC、CRD、DaemonSets、NetworkPolicy 等);
  • 定义项目角色,为 Application 提供 RBAC(例如 OIDC group 或者 JWT 令牌绑定)。

比如我们这里创建一个名为 demo 的项目,将该应用创建到该项目下,只需创建一个如下所示的 AppProject 对象即可:

apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
# 项目名
name: demo
namespace: argocd
spec:
# 目标
destinations:
# 此项目的服务允许部署的 namespace,这里为全部
- namespace: '*'
# 此项目允许部署的集群,这里为默认集群,即为Argo CD部署的当前集群
server: https://kubernetes.default.svc
# 允许的数据源
sourceRepos:
- https://gitee.com/ryanxin/devops-demo-deploy.git

该对象中有几个核心的属性:

  • sourceRepos:项目中的应用程序可以从中获取清单的仓库引用
  • destinations:项目中的应用可以部署到的集群和命名空间
  • roles:项目内资源访问定义的角色

直接创建该对象即可:

$ kubectl get AppProject -n argocd
NAME AGE
default 79m
demo 7s

添加代码仓库

前往 Argo CD 添加仓库:

4bf07e81389b

b32c242700d7

需要注意的是这里的密码需要使用 AccessToken,我们可以前往 GitLab 的页面 http://git.k8s.local/-/profile/personal_access_tokens 创建。

b478-c22f2fd952c3

更多配置信息可以前往 文档 查看,项目创建完成后,在该项目下创建一个 Application,代表环境中部署的应用程序实例。

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: devops-demo
namespace: argocd
spec:
destination:
namespace: default
server: 'https://kubernetes.default.svc'
project: demo
source:
path: helm # 从 Helm 存储库创建应用程序时,chart 必须指定 path
repoURL: 'https://gitee.com/ryanxin/devops-demo-deploy.git'
targetRevision: HEAD
helm:
parameters:
- name: replicaCount
value: '2'
valueFiles:
- my-values.yaml

这里我们定义了一个名为 devops-demo 的应用,应用源来自于 helm 路径,使用的是 my-values.yaml 文件,此外还可以通过 source.helm.parameters 来配置参数,同步策略我们仍然选择使用手动的方式,我们可以在 Tekton 的任务中去手动触发同步。

上面的资源对象创建完成后应用就会处于 OutOfSync 状态,因为集群中还没部署该应用。

a94ebcf535dc

修改Tekton 流水线

现在接下来我们去修改之前的 Tekton 流水线,之前的 Pipeline 流水线如下所示:

# pipeline.yaml
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pipeline
spec:
workspaces: # 声明 workspaces
- name: go-repo-pvc
params:
# 定义代码仓库
- name: git_url
- name: revision
type: string
default: 'main'
# 定义镜像参数
- name: image
- name: registry_url
type: string
default: 'harbor.k8s.local'
- name: registry_mirror
type: string
default: 'https://dockerproxy.com'
# 定义 helm charts 参数
- name: charts_dir
- name: release_name
- name: release_namespace
default: 'default'
- name: overwrite_values
default: ''
- name: values_file
default: 'values.yaml'
tasks: # 添加task到流水线中
- name: clone
taskRef:
name: git-clone
workspaces:
- name: output
workspace: go-repo-pvc
params:
- name: url
value: $(params.git_url)
- name: revision
value: $(params.revision)
- name: test
taskRef:
name: test
runAfter:
- clone
- name: build # 编译二进制程序
taskRef:
name: build
runAfter: # 测试任务执行之后才执行 build task
- test
- clone
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
- name: docker # 构建并推送 Docker 镜像
taskRef:
name: docker
runAfter:
- build
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc
params: # 传递参数
- name: image
value: $(params.image)
- name: registry_url
value: $(params.registry_url)
- name: registry_mirror
value: $(params.registry_mirror)
- name: deploy # 部署应用
taskRef:
name: deploy
runAfter:
- docker
workspaces:
- name: source
workspace: go-repo-pvc
params:
- name: charts_dir
value: $(params.charts_dir)
- name: release_name
value: $(params.release_name)
- name: release_namespace
value: $(params.release_namespace)
- name: overwrite_values
value: $(params.overwrite_values)
- name: values_file
value: $(params.values_file)
- name: rollback # 回滚
taskRef:
name: rollback
when:
- input: '$(tasks.deploy.results.helm-status)'
operator: in
values: ['failed']
params:
- name: release_name
value: $(params.release_name)
- name: release_namespace
value: $(params.release_namespace)

Task- 触发 ArgoCD 同步

现在我们需要去掉最后的 deploy 和 rollback 两个任务,当 Docker 镜像构建推送完成后,我们只需要去修改部署代码仓库中的 values 文件,然后再去手动触发 ArgoCD 同步状态即可(如果开启了自动同步这一步都可以省略了),而回滚操作也是通过操作 Git 仓库来实现的,不需要定义一个单独的 Task 任务。

定义一个如下所的 Taks 任务:

该任务会检测当前服务是否存在,如果存在且跟 git 仓库版本有差异就同步该服务,如果服务不存在及创建服务。

apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: argocd-sync
spec:
workspaces:
- name: ssh-directory
volumes:
- name: argocd-secret
secret:
secretName: $(inputs.params.argocd_secret)

params:
- name: argocd_url
description: 'The URL of the ArgoCD server'
- name: argocd_secret
description: 'The secret containing the username and password for the Tekton task to connect to Argo CD'
- name: app_name
description: 'The name of the Argo CD app to update'
- name: app_revision
default: 'main'
description: 'The revision of the Argo CD app to update'
- name: repo_url
default: 'git@gitee.com:ryanxin/devops-demo-deploy.git'
description: 'The URL of the Git repository containing the Helm chart'
- name: chart_path
default: 'helm'
description: 'The path to the Helm chart in the repository'
- name: deploy_namespace
default: 'default'
description: 'The namespace to deploy the application into'
- name: userHome
description: |
Absolute path to the user's home directory.
type: string
default: "/home/argocd"


steps:
- name: argocd-deploy
env:
- name: PARAM_USER_HOME
value: $(params.userHome)
- name: WORKSPACE_SSH_DIRECTORY_BOUND
value: $(workspaces.ssh-directory.bound)
- name: WORKSPACE_SSH_DIRECTORY_PATH
value: $(workspaces.ssh-directory.path)
image: registry.cn-beijing.aliyuncs.com/xxk8s/argoproj-argocd:v2.4.9
volumeMounts:
- name: argocd-secret
mountPath: /var/secret
readOnly: true
script: |
#!/bin/bash
# 从 Secret 中读取 Argo CD 用户名和密码
ARGOCD_USERNAME=$(cat /var/secret/username)
ARGOCD_PASSWORD=$(cat /var/secret/password)
if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
mkdir -p "${PARAM_USER_HOME}/.ssh"
cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}/." "${PARAM_USER_HOME}/.ssh/"
ls -l "${PARAM_USER_HOME}"/.ssh/
chmod 700 "${PARAM_USER_HOME}"/.ssh
chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
ls -l "${PARAM_USER_HOME}"/.ssh/
fi
# 使用参数
ARGOCD_SERVER=$(inputs.params.argocd_url)
APP_NAME=$(inputs.params.app_name)
REPO_URL=$(inputs.params.repo_url)
CHART_PATH=$(inputs.params.chart_path)
APP_REVISION=$(inputs.params.app_revision)
NAMESPACE=$(inputs.params.deploy_namespace)

# 登录到 Argo CD
argocd login $ARGOCD_SERVER --username $ARGOCD_USERNAME --password $ARGOCD_PASSWORD --insecure
argocd repo add $REPO_URL \
--ssh-private-key-path "${PARAM_USER_HOME}/.ssh/id_rsa" \
--insecure-skip-server-verification \

# 检查应用是否存在
if argocd app get $APP_NAME > /dev/null 2>&1; then
echo "应用 '$APP_NAME' 已存在,更新到新版本..."

# 更新应用的 revision
argocd app set $APP_NAME --repo $REPO_URL --path $CHART_PATH --revision $APP_REVISION

# 同步应用
echo "同步应用 '$APP_NAME' 到新版本..."
argocd app sync $APP_NAME --force
argocd app wait $APP_NAME --health

else
echo "应用 '$APP_NAME' 不存在,正在创建..."
# 使用 Helm Chart 创建应用
argocd app create $APP_NAME \
--repo $REPO_URL \
--path $CHART_PATH \
--revision $APP_REVISION \
--dest-server https://kubernetes.default.svc \
--dest-namespace $NAMESPACE \
--sync-policy automated
--self-heal \
--project default \


# 同步新创建的应用
echo "同步新创建的应用..."
argocd app sync $APP_NAME
fi

Task-修改镜像仓库values

由于我们这里只需要修改 Helm Chart 的 Values 文件中的 image.tag 参数,最好的方式当然还是在一个 Task 中去修改 values.yaml 文件并 commit 到 Repo 仓库中去,当然也可以为了简单直接在 ArgoCD 的应用侧配置参数即可,比如可以使用 argocd app set 命令来为应用配置参数,然后下面再用 argocd app sync 命令手动触发同步操作,这里其实就可以有很多操作了,比如我们可以根据某些条件来判断是否需要部署,满足条件后再执行 sync 操作,最后使用 wait 命令等待应用部署完成。

当然除了通过手动 argocd app set 的方式来配置参数之外,可能更好的方式还是直接去修改 Repo 仓库中的 values 值,这样在源代码仓库中有一个版本记录,我们可以新建如下所示的一个任务用来修改 values 值:

主要目的是通过自动化的方式修改 Git 仓库中的 Helm values.yaml 文件的 image.tag 并将更改提交回仓库。在 CI/CD 管道中更新 Kubernetes 部署使用的 Docker 镜像的标签(tag),确保使用最新的镜像进行部署。

思路:

  • 从 Git 仓库中拉取 Helm chart 或 Kubernetes manifests 文件,修改 values.yaml 文件中的 image.tag 值,确保它更新为最新的 Docker 镜像标签。
  • 检测文件是否有改动,如果有改动,则提交并推送回 Git 仓库。
  • 通过 SSH 进行 Git 操作,使用 id_rsa 私钥和 known_hosts 文件来安全地进行拉取和推送操作。
# task-change-values-manifests.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: change-values-manifests
spec:
workspaces:
- name: ssh-directory
params:
- name: git_url
description: Git repository containing manifest files to update
- name: git_email
default: pipeline@k8s.local
- name: git_name
default: Tekton Pipeline
- name: git_manifest_dir
description: Manifests files dir
- name: tool_image
default: registry.cn-beijing.aliyuncs.com/xxk8s/git-yq:24918
- name: image_tag
description: Deploy docker image tag
- name: userHome
description: |
Absolute path to the user's home directory.
type: string
default: "/home/root"
steps:
- name: git-push
image: $(params.tool_image)
env:
- name: PARAM_USER_HOME
value: $(params.userHome)
- name: WORKSPACE_SSH_DIRECTORY_BOUND
value: $(workspaces.ssh-directory.bound)
- name: WORKSPACE_SSH_DIRECTORY_PATH
value: $(workspaces.ssh-directory.path)
command: ['/bin/bash']
args:
- -c
- |
set -eu
if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then
mkdir -p "${PARAM_USER_HOME}/.ssh"

ls -la /home/root/
pwd
cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}/." "${PARAM_USER_HOME}/.ssh/"
ls -l "${PARAM_USER_HOME}"/.ssh/
echo "home root ssh目录"

chmod 700 "${PARAM_USER_HOME}"/.ssh
chmod -R 400 "${PARAM_USER_HOME}"/.ssh/*
ls -l "${PARAM_USER_HOME}"/.ssh/
pwd

fi


export GIT_SSH_COMMAND="ssh -i /home/root/.ssh/id_rsa -o UserKnownHostsFile=/home/root/.ssh/known_hosts"
git clone --branch main --depth 1 $(params.git_url) repo
git config --global user.email "$(params.git_email)"
git config --global user.name "$(params.git_name)"
#git clone --branch main --depth 1 http://${GIT_USERNAME}:${GIT_PASSWORD}@$(params.git_url) repo
cd "repo/$(params.git_manifest_dir)"
ls -l


# 读取当前的 image.tag 值
old_value=$(yq r values.yaml 'image.tag')

# 新的 tag 值
new_value=$(params.image_tag)

echo "Old value: $old_value"
echo "Replacing with new value: $new_value"

# 如果新值和旧值相同,直接退出
if [ "$old_value" == "$new_value" ]; then
echo "New value is the same as the old value. No changes made."
exit 0
fi

# 更新 YAML 文件中的 image.tag
yq w -i values.yaml 'image.tag' "$new_value"

echo "Verifying new value:"
yq r values.yaml 'image.tag'

# 检查文件是否真的发生了变化
if ! git diff-index --quiet HEAD --; then
echo "Changes detected, updating git repository..."
git status
git add values.yaml
git commit -m "Helm values updated by Tekton pipeline in change-manifests task"
git push
else
echo "No changes, git repository is up to date."
fi

Task-generate-build-id

把我们之前项目的 generate id task 也加进来,用于在 docker task 构建项目时增加时间戳为后缀之一,有利于展示业务集成的流程和记录更清晰。

主要目的

  • 生成一个带有当前时间戳的构建 ID,常用于在 CI/CD 工作流中唯一标识构建版本。
  • 基于给定的基础版本号(base_version)和当前的时间戳来生成该构建 ID。

主要功能

  • 基础版本号(base_version)由用户通过参数传递。
  • 时间戳用当前的日期和时间来生成,格式为 YYYYMMDDHHMMSS
  • 生成的构建 ID 格式为:<base_version>-<timestamp>,例如:1.0-20240920083045

关键部分解析:

  1. 参数 base_version
    • 参数 base_version 是任务的基础版本号,默认为 1.0。用户可以传递不同的版本号。
  2. 结果 timestamp
    • 任务的第一个结果是当前的时间戳(timestamp),格式为 YYYYMMDDHHMMSS,用于生成唯一的构建 ID。
  3. 结果 build-id
    • 任务的第二个结果是生成的构建 ID,它由 base_versiontimestamp 组成。
# generate-build-id.yaml
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
name: generate-build-id-911
spec:
description: >-
Given a base version, this task generates a unique build id by appending
the base-version to the current timestamp.
params:
- name: base_version
description: Base product version
type: string
default: '1.0'
results:
- name: timestamp
description: Current timestamp
- name: build-id
description: ID of the current build
steps:
- name: get-timestamp
image: registry.cn-beijing.aliyuncs.com/xxk8s/bash:5.0.18
script: |
#!/usr/bin/env bash
ts=`date "+%Y%m%d%H%M%S"`
echo "Current Timestamp: ${ts}"
echo ${ts} | tr -d "\n" | tee $(results.timestamp.path)
- name: get-buildid
image: registry.cn-beijing.aliyuncs.com/xxk8s/bash:5.0.18
script: |
#!/usr/bin/env bash
ts=`cat $(results.timestamp.path)`
buildId=$(inputs.params.base_version)-${ts}
echo ${buildId} | tr -d "\n" | tee $(results.build-id.path)

pipeline-argocd

现在我们的流水线就变成这样,这个 Pipeline 定义了 7 个任务,用于从代码克隆、构建、推送 Docker 镜像、更新 Helm values.yaml 文件,再到同步 Argo CD 应用的完整 CI/CD 流程。下面是每个任务的作用及其运行顺序:

Pipeline 概览

  1. clone:克隆 Git 仓库。
  2. test:运行测试。
  3. build:编译二进制程序。
  4. generate-build-id:生成唯一的构建 ID。
  5. docker:构建并推送 Docker 镜像。
  6. manifests:更新 Kubernetes Helm values.yaml 文件中的镜像标签。
  7. sync:使用 Argo CD 同步最新的应用配置。
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: pipeline-argocd
spec:
workspaces: # 声明 workspaces
- name: go-repo-pvc
- name: secret-gitee-auth
params:
# 定义代码仓库
- name: git_url
- name: git_infra_url
- name: revision
type: string
default: 'main'
# 定义镜像参数
- name: image
- name: image_tag
- name: registry_url
type: string
default: 'harbor.k8s.local'
- name: registry_mirror
type: string
default: 'https://ot2k4d59.mirror.aliyuncs.com/'
- name: git_manifest_dir
default: 'helm'
- name: base_version
# 定义 argocd 参数
- name: argocd_url
- name: argocd_secret
- name: app_name
- name: app_revision
type: string
default: 'HEAD'
tasks: # 添加task到流水线中
- name: clone
taskRef:
name: git-clone-911
workspaces:
- name: output
workspace: go-repo-pvc
- name: ssh-directory
workspace: secret-gitee-auth
params:
- name: url
value: $(params.git_url)
- name: revision
value: $(params.revision)
- name: test
taskRef:
name: test-911
runAfter:
- clone

- name: build # 编译二进制程序
taskRef:
name: build-911
runAfter:
- test
- clone
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc

- name: generate-build-id
taskRef:
name: generate-build-id-911
runAfter:
- build
params:
- name: base_version
value: $(params.base_version)

- name: docker # 构建并推送 Docker 镜像
taskRef:
name: docker-911
runAfter:
- generate-build-id
workspaces: # 传递 workspaces
- name: go-repo
workspace: go-repo-pvc

params: # 传递参数
- name: image
value: '$(params.registry_url)/$(params.image):$(tasks.clone.results.gitCommitHash)-$(tasks.generate-build-id.results.build-id)'
- name: registry_url
value: $(params.registry_url)
- name: registry_mirror
value: $(params.registry_mirror)

- name: manifests
taskRef:
name: change-values-manifests
runAfter:
- docker
workspaces: # 传递 workspaces
- name: ssh-directory
workspace: secret-gitee-auth
params:
- name: git_url
value: $(params.git_infra_url)
- name: git_manifest_dir
value: $(params.git_manifest_dir)
- name: image_tag
value: '$(tasks.clone.results.gitCommitHash)-$(tasks.generate-build-id.results.build-id)'
- name: sync
taskRef:
name: argocd-sync
runAfter:
- manifests
workspaces: # 传递 workspaces
- name: ssh-directory
workspace: secret-gitee-auth
params:
- name: argocd_url
value: $(params.argocd_url)
- name: argocd_secret
value: $(params.argocd_secret)
- name: app_name
value: $(params.app_name)
- name: app_revision
value: $(params.app_revision)

38de73a08491

4d6c52183613

2ffe3afaa6e0

修改触发器

修改 Tekton Triggers 中的 Template,如下所示:

# gitlab-template.yaml
apiVersion: triggers.tekton.dev/v1alpha1
kind: TriggerTemplate
metadata:
name: gitlab-template
spec:
params: # 定义参数,和 TriggerBinding 中的保持一致
- name: gitrevision
- name: gitrepositoryurl
resourcetemplates: # 定义资源模板
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun # 定义 pipeline 模板
metadata:
generateName: gitlab-run- # TaskRun 名称前缀
spec:
serviceAccountName: tekton-build-sa
pipelineRef:
name: pipeline
workspaces:
- name: go-repo-pvc
persistentVolumeClaim:
claimName: go-repo-pvc
params:
- name: git_url
value: $(tt.params.gitrepositoryurl)
- name: git_infra_url
value: git.k8s.local/course/devops-demo-deploy.git
- name: image
value: 'harbor.k8s.local/course/devops-demo'
- name: image_tag
value: '$(tt.params.gitrevision)'
- name: argocd_url
value: argocd.k8s.local
- name: argocd_secret
value: argocd-auth
- name: app_name
value: devops-demo

现在我们的整个流水线就更加精简了。现在我们去应用仓库中修改下源代码并提交就可以触发我们的流水线了。

38de73a08491

同样可以访问下应用来验证结果是否正确:

$ curl devops-demo.k8s.local
{"msg":"Hello Tekton On GitLab With ArgoCD"}

现在查看 Argo CD 中的应用可以发现都是已同步状态了。

bc165008ffd8

如果需要回滚,则可以直接在 Argo CD 页面上点击 HISTORY AND ROLLBACK 安装查看部署的历史记录选择回滚的版本即可:

177dfd4f5e03

可以查看整个 Tekton 流水线的状态:

$ tkn pr describe gitlab-run-4npk7

Name: gitlab-run-4npk7
Namespace: default
Pipeline Ref: pipeline
Service Account: tekton-build-sa
Timeout: 1h0m0s
Labels:
tekton.dev/pipeline=pipeline
triggers.tekton.dev/eventlistener=gitlab-listener
triggers.tekton.dev/trigger=gitlab-push-events-trigger
triggers.tekton.dev/triggers-eventid=6e21e686-79dc-421c-951a-e1591dcfd2f8

🌡️ Status

STARTED DURATION STATUS
10 minutes ago 4m11s Succeeded

⚓ Params

NAME VALUE
∙ git_url http://git.k8s.local/course/devops-demo.git
∙ git_infra_url git.k8s.local/course/devops-demo-deploy.git
∙ image harbor.k8s.local/course/devops-demo
∙ image_tag 1a49370f2708a01e8eef14c25688c5e0acf3a07c
∙ argocd_url grpc.argocd.k8s.local
∙ argocd_secret argocd-auth
∙ app_name devops-demo

📂 Workspaces

NAME SUB PATH WORKSPACE BINDING
∙ go-repo-pvc --- PersistentVolumeClaim (claimName=go-repo-pvc)

🗂 Taskruns

NAME TASK NAME STARTED DURATION STATUS
∙ gitlab-run-4npk7-sync sync 6 minutes ago 26s Succeeded
∙ gitlab-run-4npk7-manifests manifests 7 minutes ago 19s Succeeded
∙ gitlab-run-4npk7-docker docker 10 minutes ago 3m6s Succeeded
∙ gitlab-run-4npk7-build build 10 minutes ago 10s Succeeded
∙ gitlab-run-4npk7-test test 10 minutes ago 3s Succeeded
∙ gitlab-run-4npk7-clone clone 10 minutes ago 7s Succeeded

最后用一张图来总结下我们使用 Tekton 结合 Argo CD 来实现 GitOps 的工作流:

6190d03ee38d

webhook 配置

我们知道 Argo CD 会自动检查到配置的应用变化,这是因为 Argo CD 会每个三分钟去轮询一次 Git 存储库来检测清单的变化,为了消除这种轮询延迟,我们也可以将 API 服务端配置为接收 webhook 事件的方式,这样就能实时获取到 Git 存储库中的变化了。Argo CD 支持来着 GitHub、GitLab、Bitbucket、Bitbucket Server 和 Gogs 的 Git webhook 事件,这里我们仍然以上面的 GitLab 为例来说明如果配置 Webhook。

进入到 GitLab 项目仓库 http://git.k8s.local/course/devops-demo-deploy 中配置 Webhooks:

8f1794908d31

Webhook 的地址填写 Argo CD 的 API 接口地址 http://argocd.k8s.local/api/webhook,下面的 Secret token 是可选的,建议添加上,任意定义即可。另外需要注意这里我们使用的是自签名的 https 证书,所以需要在下方去掉启用SSL验证

然后需要将上面配置的 Secret token 添加到 Argo CD 的 Secret 配置中:

$ kubectl edit secret argocd-secret -n argocd
apiVersion: v1
kind: Secret
metadata:
name: argocd-secret
namespace: argocd
type: Opaque
data:
...
stringData:
# gitlab webhook secret
webhook.gitlab.secret: youdianzhishi

保存后,更改会自动生效,我们可以在 GitLab 这边测试配置的 Webhook,查看 Argo CD 的 API 服务 Pod 日志,正常就可以收到 Push 事件了:

➜  ~ kubectl logs -f argocd-server-76b578f79f-5zfsg -n argocd
time="2022-08-16T09:27:12Z" level=info msg="Received push event repo: http://git.k8s.local/course/devops-demo-deploy, revision: main, touchedHead: true"
time="2022-08-16T09:27:12Z" level=info msg="Requested app 'devops-demo' refresh"

Metrics 指标

Argo CD 作为我们持续部署的关键组件,对于本身的监控也是非常有必要的,Argo CD 本身暴露了两组 Prometheus 指标,所以我们可以很方便对接监控报警。

默认情况下 Metrics 指标通过端点 argocd-metrics:8082/metrics 获取指标,包括:

  • 应用健康状态指标
  • 应用同步状态指标
  • 应用同步历史记录

关于 Argo CD 的 API 服务的 API 请求和响应相关的指标(请求数、响应码值等等...)通过端点 argocd-server-metrics:8083/metrics 获取。

然后可以根据我们自己的需求来配置指标抓取任务,比如我们是手动维护 Prometheus 的方式,并且开启了 endpoints 这种类型的服务自动发现,那么我们可以在几个指标的 Service 上添加 prometheus.io/scrape: "true" 这样的 annotation:

$ kubectl edit svc argocd-metrics -n argocd
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/component: metrics
app.kubernetes.io/name: argocd-metrics
app.kubernetes.io/part-of: argocd
......
$ kubectl edit svc argocd-server-metrics -n argocd
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8083" # 指定8083端口为指标端口
creationTimestamp: "2021-07-03T06:16:47Z"
labels:
app.kubernetes.io/component: server
app.kubernetes.io/name: argocd-server-metrics
app.kubernetes.io/part-of: argocd
......
$ kubectl edit svc argocd-repo-server -n argocd
apiVersion: v1
kind: Service
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8084" # 指定8084端口为指标端口
creationTimestamp: "2021-07-03T06:16:47Z"
labels:
app.kubernetes.io/component: repo-server
app.kubernetes.io/name: argocd-repo-server
app.kubernetes.io/part-of: argocd
......

配置完成后正常就可以自动发现上面的几个指标任务了:

6fed68f12bc2

如果你使用的是 Prometheus Operator 方式,则可以手动创建 ServiceMonitor 对象来创建指标对象。

然后我们可以在 Grafana 中导入 Argo CD 的 Dashboard,地址:https://github.com/argoproj/argo-cd/blob/master/examples/dashboard.json

b5d89e610c64