Terraform 和云资源管理

前言 过去一年在前公司(电信)写了很多基础设施的自动化的实现,主要是通过 Ansible 将以往手动部署的中间件代码化,实现中间件的高效部署和持续运维。但像云服务器,域名等云资源,还是通过人工在控制台点点点来完成的。过去新机房的建设,近万台服务器,全是靠人工点出来的。 业界已经有成熟的工具:Terraform,国内的云公司比如:阿里云和腾讯云,也都有完善的支持了。这里记录一下 Arch Linux DevOps 团队的实现和我本地的实践。 本文会包含: 云资源如何代码化 Terraform 代码如何实现本地 AK、SK 等加密信息的加密存储 IaC & Terraform Terraform 介绍 Terraform 是声明式的(类似 K8s),基于自己的描述语言:HCL。比如有 10 台服务器,那么在存放 HCL 的基础设施代码仓库里,就会有 10 台服务器对应的安全组/规格/镜像的声明(当然,为了避免重复代码,会使用模块进行抽象)。 Terraform HCL 只声明必要的项,一些非必要的项,比如实例的 ID,镜像的 ID,会作为状态,存放在一个叫 state backend 的地方,通过本地的 HCL 代码配合 state backend 中的数据一起,将云资源所有信息声明出来。 默认 state backend 是执行者本地的一份 tfstate 结尾的文件。本地文件会导致一个问题,如果其他人想要获得当前所有云设施的最新状态,就需要跟之前的执行者索取他本地最新的 state 文件。因此,团队内一般会使用 remote state backend,这可以是一个数据库或者 S3(AWS 对象存储服务)。比如我本地就是用 PostgreSQL 来作为 remote state backend。所有基础设施代码的贡献者,确保能安全的访问到 PG 和对象存储即可。 即使使用了 remote state backend,本地还是会有 tfstate 文件,但将只包含 remote state backend 的连接信息,不包含云资源的补充信息。本地 tfstate 文件的信息在初始化 Terraform 时写入,比如我本地的 Terraform 首次初始化的命令如下:...

二月 15, 2023

基础设施代码化

前言 Arch Linux 和 Rust 这两个开源组织的基础设施代码是开源的,那么,在实现基础设施代码开源的时候,如何保证私密信息安全呢? 实现在这里: Arch Linux infrastructure rust simpleinfra Arch Linux 使用 ansible-vault 和 gnupg 来管理私密信息,包括 Terraform 的 ak/sk/token。 Rust Team 使用 aws sts 实现权限管理。使用 aws ssm 来管理 Ansible 和 Terraform 中的私密信息。 Terraform 的 state 保存在 S3 上。 Arch Linux 团队的实践 关于 Ansible 的部分 Arch Linux 是通过 ansible.cfg 中的: vault_identity_list 来实现。 vault_identity_list 是一个逗号分隔的数组,可以传入多份包含密码的文件, 也可以传入多份可执行文件(该文件需要具备可执行权限),会是这样的形式: default@misc/vault-keyring-client.sh,super@misc/vault-keyring-client.sh 实际含义是,依次用如下的形式调用可执行文件: vault-keyring-client.sh --vault-id default vault-keyring-client.sh --vault-id super 只要可执行的脚本将密钥打印到标准输出即可。因此,我们就可以: 将密钥通过 gnupg 加密到一份文件内,存储到 gitlab 上,通过 bash 封装 gnupg 进行解密 将密钥存放在 1password,通过 bash 脚本封装 1password 命令行解密 Arch Linux 团队用的就是第一种方案,见:...

二月 7, 2023

自建虚拟化

我的基础设施环境主要靠我家局域网内一台 7x24 小时运行的工作站支撑,我平时使用的基础设施,比如:gitlab、gitlab-runner、jira 甚至是现在你正在访问的博客站点,都是运行在这台工作站上的。这台工作站基于 Arch Linux,部署了 libvirt 虚拟化,不同的基础设施运行在彼此独立的虚拟机内。 下面简单介绍一下我平时是如何使用这个虚拟化的。 关于网络 我的虚拟化使用的是 bridge 网络模式,所以任何一台虚拟机都可以直接拿到局域网 IP,如何配置可参考:archwiki systemd-networkd#bridge-interface 关于系统和镜像 我的所有虚拟机也是 Arch Linux 系统。在虚拟化的宿主机上准备了一个 Arch Linux 虚拟机作为模板(模板镜像的准备使用了 virt-sysprep 这个工具),其他的虚拟机的镜像都是从模板镜像克隆出来的。虚拟机的镜像文件来自 Arch 官方,下载地址如下:Arch-Linux-x86_64-basic.qcow2 如何基于模板机创建实例 列出所有的虚拟机 virsh list --all 模板机关机备用 virsh shutdown template 基于模板机(我这里的模板机名字是:template)克隆出所需的主机 virt-clone --auto-clone --original template --name demo1 virt-clone --auto-clone --original template --name demo2 virt-clone --auto-clone --original template --name demo3 镜像准备,避免 machine-id、ssh-host-key 等冲突问题(这步是必须的) virt-sysprep -d demo1 virt-sysprep -d demo2 virt-sysprep -d demo3 [可选] 为了后面能够通过 SSH 免密登录,所以在准备镜像的时候,我会顺便注入我的公钥,命令如下:...

一月 27, 2023

可持续运维:质量、安全、效率

前言 过去手动部署 1 个高可用 apollo 集群并验证往往需要 1 ~ 2 个工作日,现在1 个工作日(7小时)可以部署 24 套,部署一套只需 18 分钟,并且所有集群都是生产就绪的,如何实现的? TL;DR 基于 vscode 的统一开发环境 基于 libvirtd 的配套测试环境 基于 wireguard 的私网 gitlab 和生产服务器集群加密通信虚拟局域网 基于 gitlab 的多分支开发模式 基于 gitlab ci 的运维代码自动同步 统一的开发环境 & 可重复的测试环境 在我司办公区机房有一台 Linux 物理服务器,我使用这台服务器作为统一开发环境,平时所有的 ansible 代码编写工作都是通过 vscode remote development 登录这台物理服务器完成。下面是常见的 2 种访问方式: 每一个开发者会有自己的一个 Linux 普通用户,开发者只需在自己的电脑上安装好 vscode,通过 vscode remote development 插件和自己在服务器的普通账号 ssh 连接物理服务器即可, vscode 会在各自的开发者用户下运行 vscode server 进程,因为 vscode 实际上都跑在同一台物理服务器上,所以其他开发者就有了跟我一模一样的 ansible 开发环境。 这篇博客也是通过 vscode remote development 方式,编写出来的,如下图:...

十二月 3, 2022

可持续运维:运维代码化中的数据与操作

这是上一篇的展开说说。 可持续运维解决的几个问题: 一,运维代码化后,运维操作相关的代码可复用。比如:同一套运维操作代码,在不同的服务器上都可以使用。只需拷贝一份运维操作相关的代码,执行一遍,就可以得到完全相同的 2 套服务; 二,运维代码化后,运维操作相关的代码可叠加使用。比如:安装 kafka 集群为例。部署 kafka 需要先安装 zookeeper,部署 codis 集群也需要安装 zookeeper。zookeeper 的运维操作代码化后,我们就可以在 kafka 和 codis 的运维操作代码中直接调用 zookeeper 的运维操作代码,类似拼积木一般,无需重复实现 zookeeper 的运维操作代码; 三、运维代码化后,运维数据可按需传入。比如:在不同的机房部署的 codis 集群,无论是密码还是集群名字都是不同的。代码化运维,运维数据会通过 jinja2 等模板语言抽象成变量;部署时,按需传入不同的变量值,就实现了不同 codis 集群的部署,从而实现了运维代码的自定义,提高了运维代码化的兼容性; 四、运维代码化后,运维数据的加密存储。比如:上一步提到了 codis 集群的数据,其中数据分为普通数据和私密数据,比如前面,codis 集群的名字就是普通数据,codis 集群的密码就是私密数据。运维代码化无论是普通数据还是加密数据,都会直接存放在 Git 等版本控制系统中,这样可以全面、简单的记录所有运维的操作,但私密数据是经过加密的,如下图: 普通数据 私密数据(未解密) 私密数据(已解密) 可以看到,私密数据,在没有解密的时候,是一串密文。无论是普通数据还是私密数据(解密后的),其实都是变量。运维数据加密存储可以实现人员权限的管理。比如,我们可以控制哪些人的公钥(一个人或多个人)可以解开私密数据。有权限的人(内部人员)才能成功的执行运维代码(实际情况中还会通过 SSH 公私钥实现更精细的服务器权限管理,管理谁可以操作哪些服务器,而运维数据的加密存储则是对内部数据的保护)。 运维数据加密存储也为运维协作带来可能,因为运维仓库内,实际上就只有运维操作和安全的运维数据。另外,可以把开源看作是大规模协作的一种形式,这种形式,不是走的最快,但会走得最远。 五、运维代码化后,运维操作的持续迭代。我喜欢使用开源软件,但维护几个、几十个开源软件的运行环境是痛苦的。举个例子:我本地的 Nginx 都是 HTTPS 加密的,这里就离不开 lego 和 dns-01 实现的自动证书申请和续期。我的内网 nginx、外网 nginx、gitlab、jira 都有一份证书,都需要创建和配置自动证书刷新,这是很消耗精力的。几个原因,一个是开源软件的持续迭代往往是 github、gitlab,国内网络不友好,下载更新体验差;其次,几个,几十个开源软件的运行环境持续更新,运维操作没有代码化的时候,手动运维时间和精力成本太大了,并且还有不少重复操作可能导致犯错。因此,将运维操作代码化,在可控人力成本(我一个人)条件下,实现稳定、高效、持续的更新非常重要,而这离不开 Git 和 CI 的支持。 我现在只需要在安装 nginx、gitlab、jira 的 playbook 内,调用这块的运维操作代码,如下图: 即可自动完成证书的申请(泛域名证书),并配置自动刷新所需的所有定时任务(如果你也尝试使用 dns-01 实现证书自动刷新,记得在自动刷新的时间点上加上一点随机性哦,避免刷新时间点冲突)。 另外,如果我需要更新 lego 这个开源组件,我只需更新 lego 版本对应的变量,提交改动到 Git,我的 CI 会自动下载最新的 lego,并更新所有服务器上的 lego 版本,如下图: 这一篇文章,主要还是解释一下,运维代码化中,操作和数据分离的必要性。代码化运维可以实现持续的优化、安全的权限控制和广泛的协同、高效的自动化。这也是可持续运维所需要的。

十一月 25, 2022

可持续运维

最近在看 archlinux infrastructure 仓库中的代码,这个仓库是 archlinux 运维开发团队的运维仓库, 他们以代码化的方式实现了可持续的运维。 可持续的运维意味着什么: 随着时间的流逝和运维人员更换,运维操作不会丢失,服务器不会成为黑盒; 无论服务器是 1 台还是 1 万台,都能保证长期的可操作、可维护、强一致性。这里的例子有 k8s 集群持续升级到安全版本,无论是一个还是多个集群,中间件的升级方式基本一致(服务的持续更新); 新人可通过阅读运维代码,实现对现有服务、架构的了解,具备运维代码技能基础后(面试通过后),即具备持续运维的能力(人力资源的持续更新); 这里的代码化,主要是通过 ansible,以 yaml 的方式,将服务器的状态(跑什么服务,需要什么配置等)保存到 git 版本控制系统内, 并通过 gitlab 进行协作和持续迭代。 代码化运维的优势: 第一、版本化优势。因为所有的运维操作都通过 ansible 记录到了 gitlab 仓库,任何公司内部员工都可以知道服务器上发生的所有改动。比如: 可通过 git 查到某台服务器上的某个服务是怎么部署的、何时部署的、谁做的部署或者改动 可直接在仓库内确认服务器是否需要更新配置而无须登陆任何生产服务器(手动登录服务器是危险的) 可直接在一个仓库内查到所有架构信息。避免架构黑盒对梳理、优化运维架构会有非常大的作用 第二、服务器状态版本化。以 nginx 集群配置为例,nginx 集群状态以相应的 git commit 保存在 gitlab 内,如果 nginx 的改动导致了故障,可以通过 git checkout <commit_id> 快速的回退 nginx 的运维代码,重新执行 ansible 即可恢复服务。有的人会问,我在改动 nginx 配置的时候: cp nginx.conf nginx.conf.bak 故障时: cp -f nginx.conf.bak nginx.conf && nginx -s reload 就好了。为何还需要代码化?一方面,试设想如果你的集群有 30 台,每台服务器上都要执行上述操作的时候,会出现大量的人为操作,出错的可能性变大了。其次,在持续运维的过程中,会涉及到多次改动,如果 30 台服务器,都要改 30 次,就会在服务器上存在 30 个不同的 nginx....

十月 24, 2022

Hello World

你好,世界 :)

十月 24, 2022