基础设施即代码 IaC
在理解 GitOps 之前,需要先理解什么是基础设施即代码。
基础设施即代码(Infrastructure as Code,简称IaC)是一种软件工程实践,它将基础设施的管理和配置过程像管理代码一样进行版本控制、自动化和可追溯。这意味着基础设施的创建、配置和管理不再依赖手动操作,而是通过编码的方式进行定义和管理,以实现更高效、可靠、可复用和可扩展的基础设施管理。
在传统的基础设施管理中,管理员通常需要手动完成服务器、网络、存储等基础设施的配置和管理工作。这样做可能会导致配置的不一致性、人为错误和时间消耗较多。
通过 IaC,管理员可以使用编程语言(如 Ansible)来定义基础设施的状态和配置,然后使用工具或平台将这些定义转换为实际的基础设施。这些定义文件可以保存在版本控制系统如 Git 中,确保配置的可追溯性和可重现性。当需要进行更新或扩展时,只需修改代码并重新执行即可,从而实现基础设施的快速部署和变更管理。
IaC 的优势包括:
- 可重复性和一致性:基础设施代码能够确保在不同环境中的一致性,消除了手动配置带来的不稳定和错误。
- 自动化:自动化配置和管理基础设施,减少了人工操作和减轻了管理员的负担。
- 版本控制:基础设施代码可以像软件代码一样进行版本管理,方便回滚、跟踪和团队协作。
- 快速部署和扩展:由于基础设施的定义已经以代码的形式存在,因此可以快速部署新的基础设施实例或扩展现有基础设施。
- 文档化:基础设施代码本身就是对基础设施架构和配置的文档化,降低了维护和管理的复杂性。
广义上的 IaC 不仅仅只关于基础设施,还包含了网络、安全、配置等等,所以广义上的 IaC 又叫 X as Code。比如你想在某公有云中创建一台服务器,配置网络,部署 Kubernetes 集群以及各种工作负载,你只需要定义好 Ansible 的声明式配置,以及 Kubernetes 的配置清单即可,免去繁杂的手动操作。
什么是 GitOps
GitOps = IaC + Git + CI/CD
翻译过来就是, Git 版本控制管理 IaC 的 CI/CD,核心是使用 Git 仓库来管理基础设施和应用的配置,以 Git 仓库作为基础设施和应用的单一事实来源,从其他地方修改配置(比如手动改线上配置)一概不予通过。
借助 IaC,目标环境当前所需基础设施的期望状态以声明式配置的方式作为代码保存在 Git 仓库中,借助于 GitOps,如果集群的实际状态与 Git 仓库中定义的期望状态不匹配,会根据期望状态来调整当前的状态,最终使实际状态符合期望状态。
GitOps vs DevOps
从广义上来看,GitOps 与 DevOps 并不冲突,GitOps 是一种技术手段,而 DevOps 是一种文化。GitOps 是一种实现持续交付(Continuous Delivery)、持续部署(Continuous Deployment)和基础设施即代码(IaC)的工具和框架,它是符合和满足 DevOps 文化的。
从狭义上来看,GitOps 与 DevOps 有以下几个区别:
- GitOps 是以目标为导向的。它使用 Git 来维护期望状态,并不断调整实际状态,最终与期望状态相匹配。而 DevOps 更多关注的是最佳实践,这些实践可以是利用其他任何工具实现。
- GitOps 采取声明式的操作方法,而 DevOps 同时接受声明式和命令式的方法,所以 DevOps 除了适用于容器环境之外,还适用于虚拟机和裸机环境。
- 针对 CD 流水线,GitOps 采用 Pull 模式,GitOps 系统的各个组件(如 Kuberntes 集群)从 Git 仓库拉取(拉取动作由代理 agent 完成)状态和配置信息,使集群状态调整为和 Git 中描述的一致。而传统 Devops 中使用 Push 模式,配置更改和代码部署是由开发团队主动推送到目标服务器或平台上的。
Push vs Pull
在上面 GitOps 和 Devops 的对比中,简单提到了 GitOps 采用 Pull 模式,而传统 Devops 采用 push 模式,下面展开介绍一下这两种模式的区别。
Push 模式
目前大多数 CI/CD 工具都使用基于 Push 的部署模式,例如最常见的 Jenkins。这种模式一般都会在 CI 流水线运行完成后执行一个命令(比如 kubectl apply)将应用部署到目标环境中。因此这种 CD 模式的相比 pull 模式有如下缺点:
- 需要安装配置额外工具(比如 kubectl);
- 需要 Kubernetes 对其进行授权;
- 无法自动感知部署状态,也就无法感知期望状态与实际状态的偏差,需要再通过查询集群信息的方式来感知。
Pull 模式
Pull 模式会在目标环境中安装一个 Agent,例如在 Kubernetes 集群中就靠自定义的 Operator 来充当这个 Agent。Operator 会周期性地监控目标环境的实际状态,并与 Git 仓库中的期望状态进行比较,如果实际状态不符合期望状态,Operator 就会更新基础设施的实际状态以匹配期望状态。
目前基于 Pull 模式的 CD 工具有 Argo CD, Flux CD 以及 ks-devops
GitOps 设计原则
声明式
必须通过声明式来描述系统的期望状态。例如 Kubernetes,众多现代云原生工具都是声明式的,Kubernetes 只是其中的一种。
版本控制/不可变
因为所有的状态声明都存储在 Git 仓库中,并且把 Git 仓库作为单一事实来源,那么所有的操作都是从 Git 仓库里驱动的,而且保留了完整的版本历史,方便回滚。有了 Git 优秀的安全保障,对代码的作者和出处实施强有力的安全保障。
自动应用变更
Git 仓库中声明的期望状态发生了任何变更,都可以立即应用到系统中,而且不需要安装配置额外工具(比如 kubectl),也不需要配置 Kubernetes 的认证授权。
持续的协调
协调 Reconciliation 其实最早是 Kubernetes 里的一个概念,表示的是确保系统的实际状态与期望状态一致的过程。具体的实现方式是在目标环境中安装一个 agent,一旦实际状态与期望状态不匹配,agent 就会进行自动修复。这里的修复比 Kubernetes 的故障自愈更高级,即使是手动修改了集群的编排清单,集群也会被恢复到 Git 仓库中的清单所描述的状态。
GitOps 的工作流
鉴于以上这些设计原则,GitOps 的工作流如下:
- 首先,团队中的任何一个成员都可以 clone 仓库对配置进行更改,然后提交 Pull Request。
- 接下来会运行 CI 流水线,一般会做这么几件事情:验证配置文件、执行自动化测试、检测代码的复杂性、构建镜像、将镜像推送到镜像仓库等等。
- CI 流水线运行完成后,团队中拥有合并代码权限的人将会将这个 Pull Request 合并到主分支中 。一般拥有这个权限的都是研发人员、安全专家或者高级运维工程师。
- 最后会运行 CD 流水线,将变更应用到目标系统中(比如自建 Kubernetes 集群或者其他云服务商) 。
GitOps 是对现有 DevOps 文化的补充,相比传统模式,GitOps 的整个过程自动化且透明,部署过程清晰可见,可以查看和跟踪对系统进行的任何变更,提高了生产力、安全性和合规性。而传统的模式只能由工程师在自己的电脑上手动操作这一切,其他人不知道发生了什么,也无法对其操作进行 Review。而且在 GitOps 中,整个系统都是通过声明式来描述的,天然适合云原生环境,因为 Kubernetes 也是这么设计的。