这篇文章写给 DevOps 和想要了解的各位朋友。
前言#
在开始之前,还是先讲一下传统的 GitOps 流程。 使用 git 仓库配置 cicd 的流水线,
git push 之后根据当前 git sha 构建出一个镜像,然后 apply 到 kubernetes 中。
Deployment 就会自动更新。
这很简单,并且也很有用,kubernetes 会自动的滚动更新你的镜像,但我们会有更多的问题和需求。
-
如何只更变资源
假设我只是做了编排改动,例如增加了副本数量或者增加了资源,它会创建一个新的 git commit。
从流程上这和提交新的代码是一样的,仍然要走一遍[ci]->build->deploy
的流程。 当然可以配置 pipeline 来做到当 deploy 文件更改的时候不会触发 build 流程。只有在 src/ 或者 app/ 这样的目录下文件更变才需要构建一次镜像。
那么这又会带来新的问题,刚才说到,我们是根据 git commit sha 作为镜像 tag 来应用到部署的。假设我提交了一次a1b2c3
的 commit,但是 skip 了 build,在 deploy 的阶段就会出错,因为找不到 tag 为a1b2c3
的镜像。 -
如何存放敏感信息
通常应用会伴随着一些DATABASE_URL
或者ACCESS_TOKEN
之类的敏感信息,这些不应该放到 git 仓库中,即使是私有或者私域仓库。
这些通常会以 kubernetes secret 的形式存在,而 secret 只是简单的 base64 加密,约等于明文存储。当然我们可以把 secret 单独存放,或者直接手动应用到集群中。
但是这么做会导致,一方面,整个应用的发布和 secret 割裂,另一方面无法有效的管理。
ArgoCD#
Argocd 是一个 CD 工具,官方的介绍如下
What Is Argo CD?
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes.
ArgoCD 采用 Application (后续简称 app) 级别的单位来管理,一般来说,一个 app 对应单个集群中的单个应用。
ArgoCD 使用监听 git 仓库资源的形式管理 app,它支持 Helm/Kustomize/Directory 等多种管理 kubernetes 资源的方式。简单来说,只要把需要 deploy 的文件放在 git 仓库里,并且正确的配置 app,argocd 就会监听 deploy 的更变。
例如
OK, 到现在为止,我们解决了一个问题 —— 《如何在不重新构建镜像下更变资源》
Secret management#
https://argo-cd.readthedocs.io/en/stable/operator-manual/secret-management/
ArgoCD 没有强制管理 secret 的方案,上述的链接中提到推荐和支持一部分的 secret 管理方式,本文会使用 Hashicorp Vault 和 argocd-vault-plugin 作为工具来管理。
Vault#
Vault 是一个 Hashicorp 出品的支持 KV 键值对的 secret-based engine。 大概可以理解为 server 版本的 1password。由于篇幅有限,这里不会多赘述 vault 的安装和配置方式。
假设现在我们把 secret 存在 vault 的 kv/<namepsace>/<app>
路径下,例如 DATABASE_URL 等。
vault 自带的 pod inject 由于不满足使用需求,这里也不多赘述。
我们希望有一个可以同步 vault secret 到 kubernetes secret 的方案。
argocd-vault-plugin#
argocd-vault-plugin 是一个 argocd 用于访问 vault 的插件,以下简称 avp。
avp 的主要作用就是可以把相应 template 转化成 vault secret
例如我有一个 yaml
kind: Secret
apiVersion: v1
metadata:
name: example-secret
annotations:
avp.kubernetes.io/path: "path/to/secret"
type: Opaque
data:
password: <password-vault-key>
使用 avp 处理过之后再应用到集群中,就是真实的数据,而不是 template。
具体可以看:https://argocd-vault-plugin.readthedocs.io/en/stable/howitworks/
然而, 上面虽然讲到了 argocd 支持多种资源编排工具,但是它们是不会默认启用 avp。
想要使用 avp ,需要自定义插件,也就是使用 plugin 的方式来使用。
plugin 本身只是一个预处理脚本,在 AVP Install 中的 一段 github yaml 文件示例
discover:
find:
command:
- find
- "."
- -name
- kustomization.yaml
generate:
command:
- sh
- "-c"
- "kustomize build . | argocd-vault-plugin generate -"
这里可以看到, 有一个 discover 来发现 一个 kustomization.yaml,并且在 build 之后使用 avp 插件生成。
特别说明 由于 helm 和 kustomize 使用的插件不一样,按照官方的插件示例在使用的时候需要指定 plugin 的名称
例如 plugin = avp-helm 和 plugin = avp-kustomize 否则会报错。
由于 kustomize 在 4.x 的版本中在 kustomization 中支持 helm-charts 的语法,不过需要手动使用 --enable-helm flags,所以我们自定义了插件,部分代码如下所示。
avp-kustomize:
allowConcurrency: true
discover:
find:
command:
- sh
- "-c"
- "find . -name kustomization.yaml"
generate:
command:
- sh
- "-c"
- "kustomize edit set annotation \"github.com/url:${ARGOCD_ENV_APP_REPO}\"; kustomize edit set image ${ARGOCD_ENV_IMAGE_NAME}:${ARGOCD_ENV_IMAGE_TAG}; kustomize build --enable-helm . | argocd-vault-plugin -s ${ARGOCD_ENV_AVP_SECRET} generate -"
lockRepo: false
https://argo-cd.readthedocs.io/en/latest/operator-manual/upgrading/2.3-2.4/#update-plugins-to-use-newly-prefixed-environment-variables
根据文章所示,我们需要在传入 plugin 的 env 中加上 ARGO_ENV 的 prefix
在这里我们加入了四个环境变量,分别是
- IMAGE_NAME 镜像名称
- IMAGE_TAG 镜像 tag
- AVP_SECRET 配置 vault 的凭据
- APP_REPO git 仓库地址
git 仓库地址会被用于一个 global annotations 用来在集群中查看 某个资源会属于哪个仓库。
到这里,我们已经完成了大部分了。
Git CI#
不管用的是 github action/gitlab ci/drone 等任意流水线,都能做到相应的配置方式。
我们在 CI 中应该配置两个阶段,build 和 deploy
build 阶段用于 build docker 镜像 和 push 到镜像仓库。
deploy 阶段是一个更新 / 创建 argocd app 的过程。
主要重点介绍 deploy 阶段, 它会使用 argocd 的 cli 来更新或者创建镜像的 tag。
example:
argocd app create {your_app} \
--repo https://github.com/{git_url} \
--path {your_repo_pass} \
--project {your_project} \
--dest-name {deploy_cluster} \
--dest-namespace {cluster_ns} \
--config-management-plugin=avp-kustomize \
--revision {revision} \
--plugin-env AVP_SECRET={secret_name} \
--plugin-env APP_REPO={git_url} \
--plugin-env IMAGE_NAME={image.name} \
--plugin-env IMAGE_TAG={image.tag} \
--sync-policy automated \
--sync-option ApplyOutOfSyncOnly=true,ServerSideApply=true \
--upsert
这将会创建一个 argocd app。如此一来,argocd 将会自己监听 git repo,当你更变 deploy 文件后,由于应用到 app 的 image name 和 tag 没有变化,可以以之前的镜像生成新的部署。
因此现在可以在 git pipeline 中配置一些 触发条件,排除 deploy 文件或者只包含代码文件。
总结#
这篇文章主要讲了如何把 argocd,vault,argocd-vault-plugin,ci 串联起来使用,构建一个相对比较完善的 gitops 生态,可能比不上成熟的商业方案,但是开源的组件自由搭配,能够找到一个最佳的实践形式。
例如 CI 和 Git 仓库没有任何的限定, 使用 vault 和 avp 也只是我的方案,在 argocd 中提到的任何管理 secret 的方式,以 plugin 的形式使用都是可以的。