ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

腾讯云CVM管理:Terraform基础设施即代码实践指南

腾讯云CVM管理:Terraform基础设施即代码实践指南 1. 从手工点控制台到代码化交付为什么我最终选了 Terraform 管 CVM第一次接触腾讯云 CVM 的时候我跟大多数人一样打开控制台点“新建实例”选镜像、选机型、配安全组、挂云硬盘一套流程走下来十几分钟感觉挺顺手。可当项目从一台机器变成三套环境开发、测试、生产每套环境又要保持配置一致时手工点击的代价就暴露出来了改一个安全组规则三套环境要重复点三遍某台机器的标签漏打了事后排查半天更麻烦的是谁在什么时候改了什么控制台上根本说不清楚。这就是我转向 Terraform 的直接原因。Terraform 是 HashiCorp 出的一套基础设施即代码Infrastructure as CodeIaC工具它把云上的资源——CVM 实例、VPC、子网、安全组、云硬盘、弹性 IP——全部用声明式的配置文件描述出来然后通过terraform apply一次性把想要的状态落地。你写的是“我要什么”而不是“我一步步怎么点”。腾讯云官方维护了tencentcloudproviderCVM 的创建、变更、销毁都能覆盖。这篇文章适合三类人看一是刚接触腾讯云、想把手上的 CVM 管理规范起来的新手二是已经在用控制台但被多环境一致性折磨的运维或后端同学三是想了解 IaC 到底能解决什么问题、值不值得投入时间学习的开发者。我会从整体设计思路讲起把 provider 配置、terraform init、资源定义、变量管理、状态文件这些核心环节拆开揉碎再给出一套可以直接抄的 CVM 创建方案最后把我踩过的坑和排查经验整理成速查表。全程按我实际操作的顺序来不绕弯子。2. 整体设计思路为什么是 Terraform而不是脚本或控制台2.1 三种管理方式的取舍逻辑在决定用 Terraform 之前我认真对比过三种方案这里把当时的思考过程摊开讲方便你做同样的判断。管理方式上手成本多环境一致性变更可追溯学习曲线适合场景控制台手工点击极低差靠人记几乎没有无一次性、临时性资源Shell/CLI 脚本中中靠脚本维护弱日志分散中简单、固定的批量操作Terraform中高强代码即真相强配合版本控制中高长期维护、多环境、团队协作控制台的问题前面说过了核心是“状态不可控”。脚本方案我试过用腾讯云 CLI 写 bash一开始挺爽但很快就遇到麻烦脚本是命令式的执行到一半失败前面创建的资源就悬在那里重跑又会因为资源已存在而报错得手动写一堆判断逻辑。而且脚本里没有“期望状态”的概念你只能描述过程没法描述结果。Terraform 的核心优势在于声明式 状态管理。你在.tf文件里写清楚“我要一台 2 核 4G 的 CVM用某个镜像挂在某个子网下”Terraform 会自己算出当前状态和目标状态的差异然后只做必要的操作。它维护一个terraform.tfstate文件记录资源的真实 ID 和属性下次执行时拿这个文件跟配置对比该建的建、该改的改、该删的删。这个“差异计算”能力是脚本给不了的。2.2 声明式模型背后的执行逻辑很多人第一次用 Terraform 会困惑我明明只是改了配置文件里的一个参数为什么它知道要更新而不是重建这背后是 Terraform 的资源依赖图Dependency Graph和CRUD 生命周期在起作用。Terraform 解析所有.tf文件后会构建一张有向图节点是资源边是依赖关系。比如 CVM 依赖安全组安全组依赖 VPC那创建顺序就是 VPC → 安全组 → CVM。销毁时反过来。这个图让 Terraform 能并行处理没有依赖关系的资源同时保证有依赖的按序执行。每个资源在 provider 里都定义了它的 schema包括哪些字段是ForceNew改了就必须重建、哪些是Optional Computed不填则由云端生成。当你修改配置Terraform 对比 state 里的旧值和配置里的新值如果改的是ForceNew字段它会先销毁旧资源再建新的如果是普通字段就调用 Update 接口原地改。理解这一点能帮你预判terraform plan的输出避免误删生产机器。2.3 目录结构怎么规划才不给自己挖坑我见过太多人把所有.tf文件堆在一个目录里几十个资源混在一起改起来眼花。我的建议是按“环境 模块”来分。一个经过实践检验的结构大概是这样terraform-tencentcloud/ ├── modules/ │ └── cvm/ │ ├── main.tf │ ├── variables.tf │ └── outputs.tf ├── environments/ │ ├── dev/ │ │ ├── main.tf │ │ ├── terraform.tfvars │ │ └── backend.tf │ └── prod/ │ ├── main.tf │ ├── terraform.tfvars │ └── backend.tf └── README.mdmodules/cvm把创建一台 CVM 的通用逻辑封装起来接收变量机型、镜像、子网 ID 等输出实例 ID 和内网 IP。environments/dev和environments/prod各自引用这个模块只传不同的变量值。这样开发和生产用的是同一套逻辑差异只在参数上一致性天然得到保证。提示模块化不是一开始就要做的。如果你只有一台机器单文件完全够用。等资源超过十个、或者需要多环境时再抽模块避免过度设计。3. 核心细节解析provider、init 与状态文件这三件事3.1 tencentcloud provider 的配置与认证Terraform 本身不认识腾讯云它通过provider 插件来对接。腾讯云的 provider 叫tencentcloud由官方维护。配置它需要两样东西secret_id和secret_key也就是腾讯云账号的 API 密钥。最直接的方式是写死在 provider 块里但强烈不建议这么做因为密钥会进版本库。我推荐用环境变量export TENCENTCLOUD_SECRET_ID你的SecretId export TENCENTCLOUD_SECRET_KEY你的SecretKey export TENCENTCLOUD_REGIONap-guangzhouprovider 块里只需要声明来源和版本terraform { required_providers { tencentcloud { source tencentcloudstack/tencentcloud version ~ 1.81 } } required_version 1.3.0 } provider tencentcloud { region var.region }这里source的写法要注意是tencentcloudstack/tencentcloud不是hashicorp/tencentcloud。写错了terraform init会找不到插件。version用~锁定大版本允许小版本升级既拿到 bug 修复又避免大版本破坏性变更。关于密钥权限我踩过一个坑直接用主账号密钥权限太大一旦泄露后果严重。正确做法是在访问管理里创建一个子用户只授予 CVM、VPC、安全组相关的策略用子用户的密钥。这样即使密钥泄露影响范围也可控。3.2 terraform init 到底做了什么terraform init是每个 Terraform 项目的第一步很多人只知道“要跑一下”但不知道它具体干了什么。它主要做四件事初始化后端Backend确定 state 文件存在哪里本地还是远程。下载 provider 插件根据required_providers里的 source 和 version从插件仓库下载对应的二进制文件到.terraform目录。下载模块如果配置里引用了外部模块一并拉取。写入依赖锁文件生成.terraform.lock.hcl记录 provider 的精确版本和校验和保证团队每个人用的插件版本一致。我第一次跑init时卡在下载插件上因为网络原因超时。解决办法是配置插件镜像或者手动把插件放到~/.terraform.d/plugins目录。另外如果你改了 provider 的 source 或 version必须重新跑init否则用的还是旧插件。注意.terraform目录和.terraform.lock.hcl的处理方式不同。.terraform是缓存应该加进.gitignore而.terraform.lock.hcl应该提交到版本库它保证团队环境一致。3.3 状态文件Terraform 的“记忆”terraform.tfstate是 Terraform 最核心也最容易被忽视的东西。它记录了每个资源在云上的真实 ID 和所有属性。Terraform 每次操作前都会读它操作后都会更新它。如果这个文件丢了Terraform 就“失忆”了会认为云上什么都没有下次 apply 会重复创建资源。本地 state 只适合个人练手。团队协作必须用远程后端。腾讯云提供了 COS对象存储作为 backend配置如下terraform { backend cos { region ap-guangzhou bucket my-terraform-state-125xxxxxxx prefix terraform/state } }这样 state 存在 COS 里多人操作时通过锁机制避免并发冲突。我强烈建议开启版本控制万一 state 被误改还能回滚到上一个版本。还有一个高频操作是terraform import当资源是手工创建的想纳入 Terraform 管理时用import把它的 ID 写进 state。比如terraform import tencentcloud_instance.web ins-xxxxxxxx导入后要立刻跑terraform plan检查配置和真实资源是否有差异把差异补进配置文件直到 plan 显示无变更才算真正接管成功。4. 实操过程从零创建一台可用的 CVM4.1 前置准备与变量定义先把变量抽出来放在variables.tf里这样不同环境只改tfvars文件variable region { description 腾讯云地域 type string default ap-guangzhou } variable instance_type { description CVM 机型 type string default S5.MEDIUM4 } variable image_id { description 镜像 ID type string default img-xxxxxxxx } variable subnet_id { description 子网 ID type string } variable instance_count { description 创建数量 type number default 1 }机型S5.MEDIUM4是标准型 S52 核 4G。选机型时要注意可用区不同可用区支持的机型不一样选错了 apply 会报错。镜像 ID 可以在控制台镜像列表里查到也可以用data源动态获取后面会讲。4.2 定义 CVM 资源与关键参数核心的main.tf长这样resource tencentcloud_instance web { count var.instance_count instance_name web-${count.index 1} availability_zone ${var.region}-1 image_id var.image_id instance_type var.instance_type system_disk_type CLOUD_PREMIUM system_disk_size 50 allocate_public_ip true internet_max_bandwidth_out 5 subnet_id var.subnet_id security_groups [tencentcloud_security_group.web.id] tags { Environment dev ManagedBy terraform } }几个参数值得展开说。system_disk_type选CLOUD_PREMIUM是高性能云硬盘IO 比普通云硬盘好价格也适中生产环境我一般用它。system_disk_size给 50G是因为默认的 20G 装完系统再放点日志就紧张了扩容虽然可以但不如一开始给够。internet_max_bandwidth_out是公网出带宽5Mbps 对一般 Web 服务够用按流量计费的话这个值影响不大按带宽计费就要算成本了。count是 Terraform 的循环机制count.index从 0 开始所以名字用count.index 1让它从 1 开始看起来更自然。如果你需要每个实例有不同配置用for_each配合 map 更合适。4.3 安全组与依赖关系安全组单独定义CVM 通过security_groups引用它Terraform 会自动识别依赖先建安全组再建 CVMresource tencentcloud_security_group web { name web-sg description Web 服务安全组 } resource tencentcloud_security_group_rule ssh { security_group_id tencentcloud_security_group.web.id type ingress cidr_ip 0.0.0.0/0 ip_protocol tcp port_range 22 policy accept } resource tencentcloud_security_group_rule http { security_group_id tencentcloud_security_group.web.id type ingress cidr_ip 0.0.0.0/0 ip_protocol tcp port_range 80,443 policy accept }注意cidr_ip写0.0.0.0/0意味着对全网开放。SSH 端口这样开风险很高生产环境一定要限制成公司出口 IP 或跳板机 IP。我见过因为 22 端口全开被暴力破解的案例教训很深刻。4.4 用 data 源动态获取镜像和可用区硬编码镜像 ID 的问题是镜像会更新ID 会变。用data源可以动态查询data tencentcloud_images ubuntu { image_type [PUBLIC_IMAGE] os_name ubuntu } data tencentcloud_availability_zones all { name var.region }然后在资源里引用data.tencentcloud_images.ubuntu.images[0].image_id。这样每次 apply 都会查最新的镜像避免手动维护 ID。不过要注意镜像更新后如果image_id变了而它是ForceNew字段会导致实例重建。所以生产环境我建议还是锁定具体镜像 ID只在需要升级时手动改。4.5 执行流程与输出完整流程是terraform init # 初始化下载 provider terraform fmt # 格式化代码 terraform validate # 语法校验 terraform plan # 预览变更 terraform apply # 执行plan这一步千万别跳过。它会列出所有将要创建、修改、销毁的资源用、~、-标记。我每次 apply 前都会仔细看 plan 输出尤其是看到-/销毁重建时一定要确认是不是预期内的。apply 完成后用output把关键信息暴露出来output instance_ids { value tencentcloud_instance.web[*].id } output public_ips { value tencentcloud_instance.web[*].public_ip }这样创建完直接能看到实例 ID 和公网 IP不用再去控制台翻。5. 常见问题与排查技巧实录5.1 高频报错速查表报错信息原因解决方法Error: Failed to query available provider packagesprovider source 写错或网络问题检查 source 是否为tencentcloudstack/tencentcloud配置镜像Error: Invalid credential密钥错误或未设置环境变量检查TENCENTCLOUD_SECRET_ID/KEY是否正确导出Error: ResourceInsufficient所选可用区机型库存不足换可用区或换机型Error: InvalidImageId.NotFound镜像 ID 不存在或不在该地域确认镜像 ID 和地域匹配Error: SecurityGroupLimitExceeded安全组规则数量超限合并规则减少条目Error acquiring the state lock上次操作异常中断锁未释放确认无其他操作后terraform force-unlock lock-id5.2 状态文件损坏与恢复有一次我在 apply 过程中网络断了state 文件写了一半导致后续 plan 报错。恢复步骤是先从 COS 的版本历史里找到上一个正常的 state 下载下来覆盖本地然后跑terraform refresh让 state 和真实资源同步。refresh会读取云上资源的真实属性更新 state但不会改配置。如果 refresh 后还有差异再手动调整配置。提示开启 COS 版本控制是救命稻草。我现在的习惯是每次重要变更前先手动备份一份 state多一层保险。5.3 几个只有踩过才知道的坑坑一allocate_public_ip和带宽计费方式。默认按流量计费如果实例跑大流量业务账单会吓人。生产环境建议改成按带宽计费在internet_charge_type里指定BANDWIDTH_PREPAID或TRAFFIC_POSTPAID_BY_HOUR根据业务特性选。坑二标签tags的键值限制。腾讯云标签的 key 和 value 都有长度和字符限制中文、特殊符号可能报错。我一般只用英文和数字用-连接。坑三terraform destroy的杀伤力。它会删掉 state 里记录的所有资源包括数据库、云硬盘。执行前一定用terraform plan -destroy预览确认没有误纳入管理的资源。我现在的做法是给关键资源加lifecycle { prevent_destroy true }防止手滑。坑四provider 版本升级。升级 provider 后某些字段的默认值或行为可能变化导致 plan 出现意外差异。升级前先在测试环境验证确认无影响再推到生产。5.4 实操心得让 Terraform 用起来更顺手的几个习惯第一永远先 plan 再 apply把plan的输出当成代码评审的一部分。第二配置和 state 都进版本库state 用远程后端这样任何变更都有记录出问题能追溯。第三变量给默认值要谨慎尤其是instance_type这种影响成本的宁可强制填写也不要给一个可能被误用的默认值。第四定期跑terraform plan检查漂移有人手工在控制台改了配置plan 会显示出来及时发现及时收敛。这套流程我用了大半年从最初的三台机器扩展到现在的几十台多环境一致性再也没出过问题。Terraform 的学习曲线确实存在但一旦跨过去基础设施管理的效率和可靠性是手工操作完全比不了的。如果你还在犹豫要不要上手我的建议是先用一台测试机跑通整个流程感受一下plan和apply的节奏剩下的就是水到渠成的事。
返回列表