前言
GitOps 的核心不是 Git,而是以声明式系统为基座,以 Git 为单一可信源,通过将应用程序和基础设施代码化(一切皆代码),进行云原生应用程序和基础设施部署管理。更多关于 GitOps 的内容,可以查看另一篇 blog 云原生时代,你还不懂 GitOps?。
极狐GitLab Kubernetes Agent 恰巧就是实现 GitOps workflow 的一个特性功能,在 13.x 版本中陆续引入。本文将通过理论加实践的方式对极狐GitLab GitOps workflow 进行剖析,方便大家对其有个全方位的认知。
关于极狐GitLab Kubernetes Agent
极狐GitLab Kubernetes Agent 是一个位于 Kubernetes 集群侧的组件,能够以安全、云原生的方式来实现极狐GitLab 和 Kubernetes 的集成。主要实现的功能有:
- 将极狐GitLab 与防火墙或 NAT(网络地址转换)后的 Kubernetes 集群进行集成
- “pull”模式的 GitOps 工作流
- 对应用在集群上的资源进行追踪
- 对集群的 API 端点进行实时访问
- 基于容器网络策略的报警生成
- CI/CD 隧道作用,以使用户能够从 GitLab CI/CD 中访问 Kubernetes 集群,即使 GitLab Runner 和集群之间没有网络连接。
更多的功能和特性还在开发过程中,感兴趣的可以查看 Roadmap。
本文将重点分析如何使用极狐GitLab Kubernetes Agent 来实现 GitOps workflow。
极狐GitLab Agent GitOps workflow
极狐GitLab Agent GitOps workflow 的示意图如下
上述列出了完成实践所需的组件
- 极狐GitLab 服务(SaaS 为 https://jihulab.com)
- 一个运行正常且安装了极狐GitLab Kubernetes Agent 的 Kubernetes 集群(Agent 安装过程后续会讲)
- 一个配置仓库,包含
config.yaml
文件,里面定义了 Agent 需要去跟集群侧做同步的 Project 信息。 - 一个清单仓库,包含了往 Kubernetes 集群上部署资源的清单文件。
最终的目的就是:一旦清单仓库中的清单文件发生了变更,则此变更能够自动同步至集群测。
可以将
config.yaml
文件和部署资源清单文件存放在同一个极狐GitLab Project里面,这是 Project 可以是 Public 的,也可以是 Private的,而且这也是官方推荐方式。当然,也可以用不同的 Project 来分别存储config.yaml
文件和部署清单文件,此时,需要注意的是,存放部署清单文件的 Project 必须是 Public 的,而存放config.yaml
文件的 Project 则可以是 Public 或 Private 的,具体原因可以查看issue。
从上述示意图中看到,要完成整个流程,需要两个重要组件的配合:agentk
和 kas
。其中 agentk
代表极狐GitLab Kubernetes Agent,是位于 Kubernetes
集群侧的组件,主要用来和 kas
进行交互。kas
代表极狐GitLab Kubernetes Agent Server,是位于极狐GitLab 侧的组件,主要实现的功能有:
- 接受来自
agentk
侧的请求 - 对
agentk
做权限验证(这一步是通过查询极狐 GitLab RoR 来完成) - 通过查询 Gitaly 来获取 agent 的配置信息
- 将来自极狐GitLab RoR 的请求与正确的
agentk
的现有连接进行匹配,然后将请求转发给agentk
,且将响应转发回来 - 通过和 Gitaly 通信来对存储部署清单的 Project 进行轮询,从而实现 GitOps
整体的架构示意图如下
从架构图中可以看出,要想实现极狐GitLab GitOps workflow,需要对 agentk
和 kas
进行配置。
极狐GitLab Kubernetes Agent Server 的配置
首先,要在极狐GitLab 侧创建一个与存储 config.yaml
文件的配置仓库相关联的 Rails Agent 记录。这个过程分两步走:**创建 Agent 和生成 Agent Token(后面的步骤会用到)
- 创建极狐GitLab Rails Agent
可以使用 GraphQL 来完成创建工作,关于 GraphQL 的更多内容可以查看极狐GitLab GraphQL API使用。当然最快速的方法就是使用GraphQL Explorer来完成创建工作。
在 GraphQL Explorer 的页面中输入创建 Agent 的语法,然后运行即可。如在左侧输入如下 GraphQL 语法
mutation createAgent {
# agent-name should be the same as specified above in the config.yaml
createClusterAgent(input: { projectPath: "your-configuration-project-path", name: "agent-name-you-specified-in-config.yaml" }) {
clusterAgent {
id
name
}
errors
}
}
点击运行按钮之后,在右侧会会出现返回结果,如
{
"data": {
"createClusterAgent": {
"clusterAgent": {
"id": "gid://gitlab/Clusters::Agent/43",
"name": "gitops"
},
"errors": []
}
}
}
整体效果如下:
上述步骤创建了一个名为gitops,且与jihulab/marketing/technical-marketing/devops-demo project相关联的 Agent,Agent 的ID 为gid://gitlab/Clusters::Agent/43。接下来就需要为这个 Agent 创建一个 Agent Token了。
- 创建 Agent Token
和创建 Agent 一样,利用 GraphQL Explorer 页面,在左侧输入 Agent Token 创建的 GraphQL 语法
mutation createToken {
clusterAgentTokenCreate(
input: {
clusterAgentId: "gid://gitlab/Clusters::Agent/43"
description: "GitLab Kubernetes Agent Server Demo"
name: "gitops"
}
) {
secret # This is the value you need to use on the next step
token {
createdAt
id
}
errors
}
}
clusterAgentId为创建 Agent 时候的返回值,如gid://gitlab/Clusters::Agent/43。name为指定的 Agent 名称,本文为 gitops。
点击运行之后,在右侧会返回 Agent Token
{
"data": {
"clusterAgentTokenCreate": {
"secret": "Agent-Token",
"token": {
"createdAt": "2021-08-17T13:22:31+08:00",
"id": "gid://gitlab/Clusters::AgentToken/37"
},
"errors": []
}
}
}
结果中的secret即为 Agent Token。在后续会用到。
紧接着,就需要在 Kubernetes 集群侧安装 Agent 了。
在 Kubernetes 上安装 agent(agentk)
在 Kubernetes 上安装 agent 时,有三个必要参数:
- your-agent-token(上述步骤已经获取)
- Agent 所在的 namespace,这个自定义即可,本文用
gitlab-kubernetes-agent
- Kubernetes Agent Server(KAS)的地址。以极狐GitLab 用户为例,地址为
wss://kas.gitlab.cn
接下来可以用如下命令进行一键式安装
$ docker run --pull=always --rm registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/cli:stable generate --agent-token=your-agent-token --kas-address=wss://kas.gitlab.cn --agent-version stable --namespace gitlab-kubernetes-agent | kubectl apply -f -
将上述的
--agent-token
指定为前面步骤获取的值,同时用--namespace
指定 agent 安装的namespace
,然后执行上述命令
$ docker run --pull=always --rm registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/cli:stable generate --agent-token=your-agent-token --kas-address=wss://kas.gitlab.cn --agent-version stable --namespace gitlab-kubernetes-agent | kubectl apply -f -
stable: Pulling from gitlab-org/cluster-integration/gitlab-agent/cli
Digest: sha256:a34079259440dcb627947e4df26fe5462829a3d6622d031ea0129e5953b70281
Status: Image is up to date for registry.gitlab.com/gitlab-org/cluster-integration/gitlab-agent/cli:stable
namespace/gitlab-kubernetes-agent created
serviceaccount/gitlab-agent created
clusterrole.rbac.authorization.k8s.io/cilium-alert-read created
clusterrole.rbac.authorization.k8s.io/gitlab-agent-gitops-read-all created
clusterrole.rbac.authorization.k8s.io/gitlab-agent-gitops-write-all created
clusterrolebinding.rbac.authorization.k8s.io/cilium-alert-read created
clusterrolebinding.rbac.authorization.k8s.io/gitlab-agent-gitops-read-all created
clusterrolebinding.rbac.authorization.k8s.io/gitlab-agent-gitops-write-all created
secret/gitlab-agent-token-8ccgb67gb2 created
deployment.apps/gitlab-agent created
安装完毕,可在gitlab-kubernetes-agent
namespace 下查看 agent pod
$ kubectl -n gitlab-kubernetes-agent get pods
NAME READY STATUS RESTARTS AGE
gitlab-agent-866cc7fb95-5dgc2 1/1 Running 0 42s
查看 pods 的 log,如果成功的话会看到下面的内容
{"level":"info","time":"2021-08-17T05:31:44.009Z","msg":"Cluster successfully synced","mod_name":"gitops","project_id":"your-configruation-project"}
说明 Agent 在 Kubernetes 集群侧安装成功,且 agent 已和 config project 同步成功。接下来就可以进行 GitOps workflow 实践了。
极狐GitLab GitOps workflow 实践
实践前提条件
- 一个运行良好的极狐GitLab 实例(方便期间,推荐使用极狐GitLab Saas 产品,也即
https://jihulab.com
) - 一个运行良好的
Kubernetes
集群
根据上面的理论介绍,极狐GitLab GitOps workflow 需要有存放 config.yaml
文件和部署清单文件的 Project。两个可以用不同的 Project,也可以用同一个 Project,本次实践是将全部文件存放在同一个极狐GitLab Project 下面。目录结构如下
├── .gitlab
│ └── agents
│ └── gitops
│ └── config.yaml
├── README.md
└── deployment
└── deployment.yaml
其中 .gitlab/agents/gitops/
是 config.yaml
文件存放的路径,gitops
是创建的 agent 名称,config.yaml
文件的内容如下
gitops:
manifest_projects:
- id: "your-jihu-GitLab-project-which-you-want-to-be-listened-by-agent"
paths:
- glob: '/**/*.yaml'
observability:
logging:
level: debug
其中 id
表示存放部署清单文件的 project 路径,glob
表示 agent 要监听的文件,可以监听所有的文件,也可以监听某个目录下的文件。
而 deployment
目录下存放的则是需要部署的清单文件,本文以部署 nginx
来做示范,内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: gitlab-kubernetes-agent
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
上述内容会在 gitlab-kubernetes-agent
namesace 下面部署一个名为 nginx-deployment
的 deployment
,且 pod
副本数为 1
。
$ kubectl -n gitlab-kubernetes-agent get deploy,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/gitlab-agent 1/1 1 1 4h3m
deployment.apps/nginx-deployment 1/1 1 1 4h
NAME READY STATUS RESTARTS AGE
pod/gitlab-agent-866cc7fb95-5dgc2 1/1 Running 0 4h3m
pod/nginx-deployment-66b6c48dd5-mzwdb 1/1 Running 0 4h
接下来我们将 deployment.yaml
文件中的 replicas
修改为 2,来触发极狐GitLab GitOps workflow。观察 agent
的 log
可以看到如下内容
$ kubectl -n gitlab-kubernetes-agent logs -f gitlab-agent-866cc7fb95-5dgc2
{"level":"info","time":"2021-08-17T09:34:58.406Z","msg":"Applying resource Deployment/nginx-deployment in cluster: https://10.96.0.1:443, namespace: gitlab-kubernetes-agent","mod_name":"gitops","project_id":"jihulab/marketing/technical-marketing/devops-demo"}
{"level":"info","time":"2021-08-17T09:34:58.502Z","msg":"Synced","mod_name":"gitops","project_id":"jihulab/marketing/technical-marketing/devops-demo","resource_key":"apps/Deployment/gitlab-kubernetes-agent/nginx-deployment","sync_result":"deployment.apps/nginx-deployment configured"}
同时查看 nginx-deployment
的 pod
数量变化
$ kubectl -n gitlab-kubernetes-agent get pods -w
NAME READY STATUS RESTARTS AGE
gitlab-agent-866cc7fb95-5dgc2 1/1 Running 0 4h5m
nginx-deployment-66b6c48dd5-mzwdb 1/1 Running 0 4h2m
nginx-deployment-66b6c48dd5-hpwqd 0/1 Pending 0 0s
nginx-deployment-66b6c48dd5-hpwqd 0/1 Pending 0 0s
nginx-deployment-66b6c48dd5-hpwqd 0/1 ContainerCreating 0 0s
nginx-deployment-66b6c48dd5-hpwqd 1/1 Running 0 2s
可以看到有新的 pod
被创建,当前 nginx-deployment
下的 pod
副本数是 2
,这和部署清单文件里面描述的是一致的。也再次证明:当部署清单文件发生任何变更的时候,变更会被自动同步至 Kubernetes 集群侧。