Terraform是目前最流行的基础设施即代码(Infrastructure as CodeIaC)工具由HashiCorp开发能用代码来定义和,管理云基础设施实现基础设施的自动化创建修改和销毁支持AWSAzureGCP阿里云腾讯云等几乎所有主流云服务商也支持私有云和本地基础设施。

基础设施即代码是DevOps的重要实践能让基础设施像代码一样版本控制代码审查自动化测试和,部署大大提高基础设施管理的效率和可靠性减少人为错误实现基础设施的可重复和可追溯。

最近我们团队做了一次基础设施迁移把原来手动管理的旧基础设施(在云控制台手动创建和管理没有代码没有版本控制变更全靠人工记录经常出问题)迁移到Terraform管理的新基础设施整个过程持续了大概一个月踩了不少坑也积累了一些实战经验。

今天想记录一下这次Terraform基础设施迁移的实战过程包括迁移前的准备迁移方案设计具体迁移步骤遇到的问题和解决方案以及,迁移后的维护和最佳实践希望能帮大家少走弯路。

一、为什么要迁移到Terraform

先说说我们为什么要迁移到Terraform也就是原来手动管理基础设施有什么痛点。

痛点1:变更不可追溯

原来基础设施的变更都是在云控制台手动操作没有记录谁在什么时候改了什么为什么改都不知道出了问题排查起来非常困难不知道是谁改了什么导致的也无法回滚到之前,的状态。

有一次我们的数据库配置被人改了导致数据库性能下降影响了业务我们排查了很久才发现是有人改了数据库的参数,但是不知道是谁改的为什么改也不知道改之前,是什么样非常被动。

痛点2:环境不一致

我们有开发测试预发布生产四个环境原来都是手动创建的每个环境的配置都有差异开发环境能跑测试环境可能就跑不起来预发布环境没问题生产环境可能就出问题,因为环境不一致导致很多"在我机器上能跑"的问题。

而且新建一个环境非常麻烦要手动创建一堆资源云服务器数据库缓存负载均衡网络安全组等等要花好几天还容易出错漏配一些配置。

痛点3:无法自动化测试和部署

手动管理的基础设施无法和CI/CD流水线集成无法自动化测试和部署基础设施的变更需要手动操作效率低容易出错也无法做自动化验证和回滚。

我们的应用代码已经用了CI/CD自动化部署,但是基础设施还是手动管理成为了效率的瓶颈也是风险点。

痛点4:资源浪费和成本不可控

手动管理的基础设施经常有资源浪费,比如测试环境的云服务器下班和周末没有关机一直跑着浪费钱,还有一些废弃的资源没有及时清理一直计费成本不可控也不知道哪些资源是有用的哪些是废弃的。

因为这些痛点我们决定迁移到Terraform用基础设施即代码的方式来管理基础设施解决这些问题。

二、迁移前的准备

迁移之前,我们做了充分的准备工作这是迁移成功的基础。

1. 梳理现有基础设施

首先,我们对现有基础设施做了全面的梳理和盘点把所有的资源都列出来包括:

  • 计算资源:云服务器容器集群函数计算等等
  • 存储资源:对象存储块存储文件存储等等
  • 数据库:关系型数据库NoSQL数据库缓存等等
  • 网络资源:VPC子网路由表安全组负载均衡NAT网关等等
  • 其他资源:域名SSL证书CDN消息队列等等

每个资源都记录了资源ID名称配置所属环境用途创建时间等等信息做成了一个详细的清单确保没有遗漏。

2. 学习Terraform

然后我们组织团队学习Terraform的基本概念和用法包括:

  • Terraform的核心概念:ProviderResourceData SourceVariableOutputModuleState等等
  • Terraform的基本命令:initplanapplydestroy等等
  • Terraform的最佳实践:代码结构命名规范状态管理模块复用等等
  • 我们用的云服务商的Terraform Provider文档和示例

我们还做了一些小的实验用Terraform创建一些测试资源熟悉Terraform的用法和,工作流确保团队都掌握了基本技能。

3. 制定迁移方案

在梳理和学习的基础上我们制定了详细的迁移方案包括:

  • 迁移范围:哪些资源要迁移哪些暂时不迁移
  • 迁移顺序:先迁移什么后迁移什么优先级排序
  • 迁移策略:是原地导入(import)还是新建资源迁移数据
  • 回滚方案:如果迁移出问题怎么回滚
  • 时间计划:每个阶段的时间安排负责人
  • 风险评估:可能遇到的风险和应对措施

我们决定采用"新建+迁移"的策略也就是用Terraform新建一套新的基础设施,然后把数据和业务从旧基础设施迁移到新基础设施最后下线旧基础设施而不是用import把旧资源导入Terraform管理。

为什么不用import因为我们的旧基础设施有很多历史遗留问题配置不规范资源混乱,如果直接import会把这些问题也带进来,而且import的过程也比较复杂容易出问题,所以我们决定借迁移的机会重新设计和规范基础设施用Terraform新建一套干净的规范的新基础设施,然后迁移数据和业务这样,虽然工作量大一些,但是迁移后的基础设施更干净更规范更好维护长期来看更好。

4. 设计新的基础设施架构

借迁移的机会我们重新设计了基础设施架构解决旧架构的一些问题,比如:

  • 网络架构重新规划VPC子网安全组更合理更安全
  • 环境隔离更彻底开发测试预发布生产完全隔离用不同的云账号,或者不同的VPC
  • 高可用架构优化关键组件都做高可用避免单点故障
  • 安全加固安全组权限最小化加密访问控制等等
  • 成本优化资源规格合理配置自动伸缩避免浪费

新的架构设计好后我们做了评审确保没有问题才开始写Terraform代码。

三、Terraform代码编写

准备工作做好后我们开始写Terraform代码这是迁移的核心工作。

1. 代码结构设计

我们参考了Terraform的最佳实践设计了代码结构:

terraform/
├── environments/          # 环境配置
│   ├── dev/               # 开发环境
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   └── outputs.tf
│   ├── test/              # 测试环境
│   ├── staging/           # 预发布环境
│   └── prod/              # 生产环境
├── modules/               # 可复用模块
│   ├── vpc/               # VPC模块
│   ├── ec2/               # 云服务器模块
│   ├── rds/               # 数据库模块
│   ├── redis/             # 缓存模块
│   ├── alb/               # 负载均衡模块
│   └── ...
└── globals/               # 全局变量和公共配置

每个环境有自己的目录和配置引用公共的模块这样环境之间,隔离配置复用代码简洁好维护。

2. 模块编写

我们把常用的资源封装成模块(Module)比如VPC云服务器数据库缓存负载均衡等等每个模块封装了一类资源的创建和,配置对外暴露变量和输出这样代码复用配置统一减少重复代码。

比如VPC模块封装了VPC子网路由表安全组NAT网关等资源的创建对外只需要传入VPC名称网段可用区等少数变量就能创建一套完整的VPC环境非常方便。

模块编写的时候,我们注意了以下几点:

  • 单一职责:每个模块只做一件事不要太复杂
  • 合理的变量:只暴露必要的变量有默认值方便使用
  • 清晰的输出:输出有用的属性,比如资源ID地址等等方便其他模块引用
  • 文档和示例:每个模块都有README说明用法和示例
  • 版本控制:模块有版本号变更需要升级版本避免影响现有使用

3. 状态管理

Terraform的状态(State)管理非常重要状态文件记录了Terraform管理的资源的实际状态是Terraform工作的基础,如果状态文件丢失,或者损坏Terraform就无法正确管理资源,所以状态管理一定要做好。

我们没有把状态文件放在本地而是用远程状态存储(Remote State)我们用的是云服务商的对象存储(比如AWS S3阿里云OSS)来存储状态文件,并且开启了版本控制和加密确保状态文件安全可靠不会丢失。

同时我们开启了状态锁定(State Locking)用云服务商的数据库(比如AWS DynamoDB阿里云表格存储)来做锁确保同一时间,只有一个人能修改状态避免并发修改导致状态冲突和损坏。

每个环境的状态文件分开存储用不同的路径,或者不同的存储桶确保环境之间,隔离不会互相影响。

4. 变量和敏感信息处理

Terraform的变量(Variable)用来参数化配置不同环境用不同的变量值我们把变量定义在,variables.tf文件里每个变量有描述类型默认值等等信息方便使用。

敏感信息(比如数据库密码API密钥等等)不能明文写在代码里也不能提交到代码仓库我们用环境变量,或者专门的密钥管理工具(比如HashiCorp Vault云服务商的密钥管理服务)来管理敏感信息Terraform运行时从环境变量,或者密钥管理工具读取敏感信息不明文存储。

我们还用了.gitignore文件忽略状态文件变量文件(包含敏感信息的)临时文件等等确保敏感信息不会被提交到代码仓库。

四、具体迁移步骤

Terraform代码写好后我们开始具体的迁移工作我们按环境逐个迁移先开发环境再测试环境再预发布环境最后生产环境每个环境迁移成功验证没问题再迁移下一个环境降低风险。

步骤1:创建新基础设施

首先,用Terraform创建新的基础设施在新的VPC里创建所有需要的资源云服务器数据库缓存负载均衡等等和旧基础设施完全独立互不影响。

创建之前,先运行terraform plan查看将要创建的资源和配置确认无误再运行terraform apply创建资源创建完成后检查所有资源是否正确创建配置是否正确。

新的基础设施创建好后先不接入业务只是空的资源等后续迁移数据和业务。

步骤2:迁移数据

新的基础设施创建好后开始迁移数据主要是数据库的数据迁移我们用的是数据库的主从复制,或者数据导入导出工具来迁移数据。

对于关系型数据库我们先在新的数据库实例上创建和旧数据库一样的库和表结构,然后用数据同步工具把旧数据库的数据同步到新数据库先全量同步再增量同步等数据同步追上后就可以准备切换。

对于缓存数据不需要迁移,因为缓存的数据是临时的切换后重新预热就可以。

对于对象存储的文件用数据迁移工具,或者脚本把旧存储桶的文件复制到新存储桶确保文件完整。

数据迁移过程中我们做了数据校验确保新旧数据一致没有丢失,或者错误。

步骤3:部署应用到新基础设施

数据迁移好后把应用部署到新的基础设施上用CI/CD流水线把应用部署到新的云服务器,或者容器集群上配置好数据库缓存等连接确保应用能正常连接新的基础设施。

部署完成后做内部测试验证应用功能是否正常性能是否达标确保新的基础设施能正常承载业务。

步骤4:流量切换

应用测试没问题后开始流量切换把用户流量从旧基础设施切换到新基础设施。

我们用的是灰度切换的方式先切一小部分流量(比如10%)到新的基础设施观察一段时间看有没有问题,如果没问题再逐步扩大流量比例20%50%100%直到全部流量都切到新的基础设施。

切换过程中密切监控应用的性能错误率用户反馈等等一旦发现问题立即把流量切回旧的基础设施排查问题确保业务不受影响。

步骤5:验证和观察

全部流量切到新的基础设施后继续观察一段时间(比如一周)确保新的基础设施稳定运行没有问题应用性能和,用户体验正常甚至比旧的更好。

观察期间旧的基础设施先不下线保留作为备份万一新的基础设施出问题还能快速切回旧的确保业务安全。

步骤6:下线旧基础设施

观察一段时间确认新的基础设施稳定没问题后就可以下线旧的基础设施了先做最后的确认确保所有业务都已经切到新的基础设施没有流量再走旧的基础设施,然后备份旧的数据和配置最后销毁旧的资源节省成本。

旧的基础设施下线后迁移工作就完成了整个过程,虽然繁琐,但是按部就班做好每个步骤的验证和回滚准备还是比较顺利的。

五、遇到的问题和解决方案

迁移过程中我们遇到了一些问题这里记录一下和解决方案希望能帮大家避坑。

问题1:Terraform版本不一致导致问题

团队成员用的Terraform版本不一致有的用0.11有的用0.12导致代码兼容性问题状态文件格式不一致运行报错。

解决方案:统一Terraform版本团队都用同一个版本我们用了.terraform-version文件指定版本用tfenv工具管理Terraform版本确保每个人用的版本一致避免兼容性问题。

问题2:状态文件冲突

有一次两个人,同时运行terraform apply修改同一个环境的资源导致状态文件冲突损坏差点出大事。

解决方案:开启状态锁定(State Locking)确保同一时间,只有一个人能修改状态其他人运行apply的时候,会等待锁释放,或者报错避免并发修改导致状态冲突。同时制定规范同一个环境同一时间只允许一个人操作避免并发修改。

问题3:资源依赖关系处理不当

有些资源之间,有依赖关系,比如云服务器要在子网创建后才能创建数据库要在VPC创建后才能创建,如果依赖关系处理不当会导致创建失败,或者顺序错误。

解决方案:用Terraform的隐式依赖(引用其他资源的属性)或者显式依赖(depends_on)来声明资源之间,的依赖关系让Terraform正确处理创建顺序避免依赖问题。同时模块化的时候,注意模块之间,的依赖关系合理设计。

问题4:数据库迁移 downtime

数据库切换的时候,有短暂的downtime影响业务,虽然时间不长,但是对用户还是有影响。

解决方案:用灰度切换和主从复制的方式尽量减少downtime先把数据同步到新数据库等数据追上后在,业务低峰期(比如凌晨)做切换把应用的数据库连接切到新数据库切换时间控制在几秒内尽量减少影响。对于要求更高的业务可以用双写的方式实现零downtime切换,但是复杂度更高。

问题5:安全组配置错误导致网络不通

新的基础设施创建好后发现应用访问不通排查发现是安全组配置错误该开的端口没开导致网络不通。

解决方案:安全组配置要仔细检查按照最小权限原则只开需要的端口和来源创建后做网络连通性测试确保各个组件之间,网络通我们还把安全组的配置封装在模块里统一管理避免配置错误。

问题6:Terraform代码复用和维护

一开始代码写得比较乱重复代码多不好维护后来重构了代码结构和模块才好一些。

解决方案:参考Terraform最佳实践合理设计代码结构和模块把通用的资源封装成模块复用代码减少重复每个模块单一职责清晰的变量和输出文档完善方便维护和使用。同时代码提交前做代码审查(Code Review)确保代码质量。

六、迁移后的维护和最佳实践

迁移完成后不是结束而是新的开始需要做好日常维护和管理发挥Terraform的价值这里总结一些最佳实践。

1. 代码审查和版本控制

所有Terraform代码变更都要提交到代码仓库(Git)做版本控制,并且经过代码审查(Code Review)才能合并和应用确保代码质量避免错误的变更影响基础设施。

变更要有明确的说明为什么改改了什么影响范围等等方便追溯和回滚。

2. 自动化测试和CI/CD

把Terraform代码纳入CI/CD流水线自动化测试和部署,比如:

  • 代码提交后自动运行terraform fmt检查格式
  • 运行terraform validate检查语法和配置
  • 运行terraform plan查看变更内容自动评论到Merge Request
  • 合并后自动运行terraform apply应用变更(生产环境需要人工审批)

这样基础设施的变更也能像应用代码一样自动化测试和部署提高效率和可靠性。

3. 状态文件管理和备份

状态文件是Terraform的核心一定要做好管理和备份:

  • 用远程状态存储不要放本地
  • 开启版本控制和加密
  • 开启状态锁定避免并发修改
  • 定期备份状态文件防止丢失和损坏
  • 不要手动修改状态文件除非知道自己在做什么

4. 模块化和代码复用

持续优化模块设计提高代码复用率减少重复代码让基础设施的创建和管理更简单更高效。

通用的模块可以抽出来做成独立的模块仓库版本化管理多个项目可以复用提高效率。

5. 成本管理和优化

用Terraform管理基础设施后成本管理也更方便,比如:

  • 测试环境的资源下班和周末自动关机节省成本
  • 定期审查资源清理废弃的资源避免浪费
  • 用Terraform统一管理资源规格和配置避免不合理的资源配置
  • 结合云服务商的成本管理工具监控和优化成本

6. 文档和知识共享

基础设施的架构配置模块用法等等都要有文档方便团队成员理解和使用也方便新人上手。

定期做知识分享和培训让团队都掌握Terraform的用法和,最佳实践提高团队整体能力。

七、写在最后

以上就是我们这次Terraform基础设施迁移的实战过程和经验总结包括为什么迁移迁移前的准备Terraform代码编写具体迁移步骤遇到的问题和解决方案以及迁移后的维护和最佳实践。

基础设施即代码(IaC)是DevOps的重要实践能大大提高基础设施管理的效率和可靠性Terraform作为最流行的IaC工具功能强大生态完善值得学习和使用。

迁移的过程,虽然繁琐也遇到了一些问题,但是整体还是比较顺利迁移完成后基础设施的管理效率和可靠性都有很大的提升变更可追溯环境一致自动化程度高成本也更可控这些好处都是手动管理无法比拟的。

如果你的团队还在手动管理基础设施经常遇到变更不可追溯环境不一致效率低等问题推荐考虑迁移到Terraform用基础设施即代码的方式来管理基础设施,虽然迁移需要花一些时间和精力,但是长期来看收益很大。

希望我们的实战经验能帮大家在迁移的过程中少走弯路顺利完成迁移。

最后用一句话结束这篇文章:"基础设施即代码不是目的而是手段目的是让基础设施的管理更高效更可靠更安全。"

愿大家都能用好Terraform管理好自己的基础设施享受基础设施即代码带来的便利。