资讯动态

90DaysOfDevOps 第 60 天:用 Terraform 管理 Docker 容器、Provisioners 与 Modules 实战指南

发布时间:2026/10/5 2:12:10 来源:尧图企业网站定制
文档/教程【免费下载链接】90DaysOfDevOpsThis repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.项目地址https://gitcode.com/gh_mirrors/90/90DaysOfDevOps点击查看免费下载本篇技术指南承接第 59 天在本地 VirtualBox 中用 Terraform 配置虚拟机的实践进一步演示如何用 Terraform 的社区版 Docker Provider 把容器部署纳入基础设施即代码IaC管理先以 nginx 为例完成镜像拉取 端口映射的最小可运行示例再完整复刻 docker-compose 版的 WordPress MySQL 多容器编排最后讲解声明式模型覆盖不到时使用的 Provisioners 与用来拆分基础设施的 Modules 两大核心机制。读完本文你将掌握用terraform init / apply驱动本地 Docker、用 Terraform 状态管理容器生命周期以及模块化组织.tf代码的基本套路。前置背景从虚拟机到容器在 Day 59 中我们已经通过 Terraform 在本地免费的 VirtualBox 环境中完成了一台虚拟机的配置对应配置存放在仓库的 virtualbox.tf 中它使用社区版terra-farm/virtualboxProvider通过virtualbox_vm资源一次创建两台节点并输出各自 IP 地址。到了第 60 天我们把同样的 IaC 思路迁移到 Docker不再手动执行docker run而是把要运行的镜像、容器名、端口映射、网络、卷、环境变量全部写成声明式的 Terraform 配置交给 Terraform 统一管理。本文所有核心配置文件都来自仓库的 IaC 目录其中Docker/与Docker-Wordpress/两个子目录就是本课的完整可运行示例。Docker Demo用 Terraform 部署 nginx 容器完整的 Terraform 配置先看第一个示例。目标非常简单把一个 Web 应用部署到 Docker并通过端口映射暴露到宿主机网络——我们选用 nginx 镜像将其发布到笔记本的localhost:8000。这里使用的是社区维护的 Docker Provider镜像来源也在配置中显式声明。完整的配置文件位于仓库 docker.tf内容如下terraform { required_providers { docker { source kreuzwerker/docker version 2.16.0 } } } provider docker {} resource docker_image nginx { name nginx:latest keep_locally false } resource docker_container nginx { image docker_image.nginx.latest name tutorial ports { internal 80 external 8000 } }对这份配置逐个拆解terraform块与required_providers声明本配置依赖kreuzwerker/docker社区 Provider并锁定版本2.16.0保证不同机器上行为一致。版本锁定是 IaC 可复现性的第一道保障。provider docker {}实例化 Provider。默认连接本地 Docker daemon即本机docker命令对应的引擎无需额外认证参数。docker_image资源管理镜像本身。name nginx:latest指定镜像与标签keep_locally false表示当资源从状态中移除如执行terraform destroy时同时删除本地镜像避免残留占用磁盘。docker_container资源管理容器。image直接引用上面镜像资源的latest属性形成资源间依赖——Terraform 会先确保镜像存在再创建容器name tutorial是容器名ports块完成端口映射internal 80为容器内部端口external 8000为宿主机暴露端口。值得注意的写法是image docker_image.nginx.latest它把容器依赖镜像这一关系显式编码进配置这正是 Terraform 相比 shell 脚本式部署的核心优势——依赖图由配置自动推导执行顺序由引擎保证。执行步骤init → apply → docker ps配置文件准备好后第一步是执行terraform init。该命令会依据required_providers下载 Docker Provider 到本地机器并初始化工作目录的状态文件与插件缓存初始化完成后执行terraform apply。Terraform 会生成执行计划提示将创建 1 个 docker_image 与 1 个 docker_container确认后开始创建。随后用docker ps查看就能看到名为tutorial的容器已经在运行最后打开浏览器访问http://localhost:8000/即可看到 NGINX 的欢迎页面——容器已成功通过宿主机端口对外提供服务至此这个 nginx 容器及其镜像都已纳入 Terraform 状态管理你可以用terraform destroy一键清理用terraform plan预览变更用terraform show查看资源属性而不再依赖记忆中的一串docker run参数。这个示例展示了 Terraform Docker 组合的最小闭环也说明了容器编排、基础设施即代码与 Kubernetes 之间存在天然的交叉地带——本系列前面的容器章节讲过 docker-compose两者在用代码描述容器这一目标上是相通的。WordPress MySQL把 docker-compose 迁移到 Terraform单一容器示例相对简单为了体现 Terraform 处理更复杂编排的能力我们把此前在容器章节用 docker-compose 创建的 WordPress MySQL 组合改写为 Terraform 配置。完整文件位于仓库 docker-wordpress.tfterraform { required_providers { docker { source kreuzwerker/docker version 2.16.0 } } } provider docker {} variable wordpress_port { default 8080 } resource docker_volume db_data { name db_data } resource docker_network wordpress_net { name wordpress_net } resource docker_container db { name db image mysql:5.7 restart always network_mode wordpress_net env [ MYSQL_ROOT_PASSWORDwordpress, MYSQL_PASSWORDwordpress, MYSQL_USERwordpress, MYSQL_DATABASEwordpress ] mounts { type volume target /var/lib/mysql source db_data } } resource docker_container wordpress { name wordpress image wordpress:latest restart always network_mode wordpress_net env [ WORDPRESS_DB_HOSTdb:3306, WORDPRESS_DB_USERwordpress, WORDPRESS_DB_NAMEwordpress, WORDPRESS_DB_PASSWORDwordpress ] ports { internal 80 external ${var.wordpress_port} } }这份配置相比 nginx 示例引入了四个新的概念variable wordpress_port声明一个变量默认值为8080用于把 WordPress 对外端口参数化。这样同一份配置可以在不同环境通过-var wordpress_portxxxx或terraform.tfvars覆盖无需改动代码。docker_volume资源创建命名卷db_data用于持久化 MySQL 数据。这是容器部署中最容易踩坑的部分——容器删除后数据不能跟着丢。docker_network资源创建自定义网络wordpress_net让db与wordpress两个容器处于同一网络彼此通过容器名直接通信。mounts块在db容器上挂载卷type volume表示挂载类型为 Docker 卷source db_data引用上面创建的卷target /var/lib/mysql是 MySQL 的数据目录。Terraform 会按声明顺序处理好先建卷、再建容器的依赖关系。同时注意两个容器间的衔接MySQL 容器通过环境变量MYSQL_DATABASEwordpress、MYSQL_USERwordpress、MYSQL_PASSWORDwordpress初始化数据库和账号WordPress 容器则通过WORDPRESS_DB_HOSTdb:3306指向 MySQL 容器网络内使用容器名db作为主机名、WORDPRESS_DB_PASSWORDwordpress与之匹配。这套环境变量约定的参数名与官方镜像规范完全一致与 docker-compose 版本一一对应。执行步骤与验证把上述配置放入一个新的目录例如Docker-Wordpress/然后执行terraform init拉取所需 Provider接着执行terraform apply。执行完毕后用docker ps查看可以看到dbMySQL与wordpress两个容器均处于运行状态浏览器访问http://localhost:8080/变量默认值即可进入 WordPress 的安装配置页面。与容器章节用 docker-compose 走通的过程一致完成初始化向导后博客文章数据会持久化保存在 MySQL 数据库中容器方案的边界生产环境为何转向 Kubernetes到这里需要客观看待容器直接部署方案的适用边界。前面几课已经较为详细地介绍了容器与 Kubernetes可以得出结论本地测试、CI 验证这类场景用 Terraform Docker 完全够用但如果真的要运营一个对外提供服务的网站仅靠裸容器会面临高可用、滚动升级、伸缩、自愈等系统性短板此时应把编排交给 Kubernetes。这也正是本系列下一步的方向——Day 61 将开始用 Terraform 对接 Kubernetes。仓库中已给出可参考的 kubernetes.tf 示例它使用官方hashicorp/kubernetesProvider读取~/.kube/config声明式地创建kubernetes_namespace、kubernetes_deployment2 个副本的 nginx Deployment与kubernetes_serviceNodePort 30201 对外暴露。Provisioners把命令式操作注入声明式模型Terraform 是声明式工具但现实中总有声明式模型无法直接表达的环节例如等待服务就绪后执行初始化脚本、按特定顺序触发外部动作。Provisioners 的存在意义就是当某些事无法用声明式描述时为部署流程提供一条命令式处理的通道。需要强调的是Terraform 官方文档也建议只有找不到更优替代方案、且接受由此引入的复杂度时才使用 Provisioners——它是最后的手段而非默认首选。典型写法如下resource docker_container db { # ... provisioner local-exec { command echo The servers IP address is ${self.private_ip} } }local-exec在运行 Terraform 的机器本地上执行命令。上例把容器的private_ip通过${self.private_ip}自引用注入命令字符串在资源创建完成后打印。常用于本地触发脚本、通知外部系统、写入本地缓存等。remote-exec在远程资源上执行脚本适用于资源创建后需要执行系统级初始化如安装软件包、写入配置文件的场景也可以用来包装 Ansible、Chef、Puppet 等配置管理工具的调用。Terraform 内置的 Provisioner 主要包括四类file把本地文件上传到远程资源local-exec在本地执行命令remote-exec在远程资源上执行命令或脚本供应商vendor提供的 Provisioner例如 Ansible、Chef、Puppet 对应的集成。实际使用时还要注意Provisioners 在terraform apply失败时可能导致状态不一致通常需要配合creation-time/destroy-time触发时机when参数与on_failure策略一起规划这些细节都值得在生产实践中仔细推敲。Modules把基础设施拆成可复用的组件Module模块是多个一起使用的资源的容器。在 Terraform 中一个模块就是同一目录下的一组.tf文件的集合。事实上你随手写下的每个包含.tf文件的目录本身就是一个根模块而可被其他配置引用的则是子模块。模块的两个核心价值拆分与组织基础设施假设同一个项目既需要创建虚拟机VM、VPC、安全组Security Group又需要创建 Kubernetes 集群把所有资源写在一个目录里会很快失控。按模块拆分后每个模块聚焦一类资源职责边界清晰也便于独立测试与演进。复用与共享模块可以跨项目复用也可以公开分享给社区避免重复造轮子。无论是自己沉淀的内部模块库还是社区发布的成熟模块都能显著缩短从零搭建基础设施的时间。本仓库的 IaC 目录 本身就是模块化思想的直观体现Docker/nginx 容器、Docker-Wordpress/多容器编排、Kubernetes/集群对象、Virtualbox/虚拟机、Hello-world/最小示例、Terratest/带 Go 测试的示例模块各自独立成目录互不干扰每个目录都可以作为独立项目初始化和 apply——这正是把基础设施分解成组件Modules的实践样板。小结与下一步本课完成了三件事一是用 Terraform Docker Provider 部署了 nginx 容器并暴露到localhost:8000二是把 docker-compose 的 WordPress MySQL 组合完整迁移为 Terraform 配置涵盖卷、网络、环境变量、端口参数化等进阶用法三是理解了 Provisioners命令式补充与 Modules资源组织与复用两大机制。所有配置都可在仓库 IaC 目录 中找到并直接运行验证。关于本主题社区已有大量可深入学习的资料覆盖的典型课题包括基础设施即代码的概念与工具对比、Terraform 从入门到进阶的完整教程、HashiCorp Terraform Associate 认证备考、面向 DevOps 初学者的 Terraform 实战实验含实验室练习、各类 Terraform 小项目创意以及聚合了大量优质 Provider、模块与学习资料的精选清单。建议按概念 → 语法 → 实战 → 认证的顺序系统性推进。Day 61 将进入 Terraform 与 Kubernetes 的结合请继续关注 Day 61。赞分享文档/教程【免费下载链接】90DaysOfDevOpsThis repository started out as a learning in public project for myself and has now become a structured learning map for many in the community. We have 3 years under our belt covering all things DevOps, including Principles, Processes, Tooling and Use Cases surrounding this vast topic.项目地址https://gitcode.com/gh_mirrors/90/90DaysOfDevOps点击查看免费下载相关推荐90DaysOfDevOps 第 60 天用 Terraform 管理 Docker 容器、Provisioners 与 Modules90DaysOfDevOps 第 60 天用 Terraform 管理 Docker 容器、Provisioners 与 Modules 本篇指南以 90Da文档/教程90DaysOfDevOps使用 Terraform 管理 Docker 容器、Provisioners 与 ModulesDay 6090DaysOfDevOps使用 Terraform 管理 Docker 容器、Provisioners 与 ModulesDay 60 本文是 90Da文档/教程90DaysOfDevOps 第 47 天Docker 网络与容器安全实战指南90DaysOfDevOps 第 47 天Docker 网络与容器安全实战指南 本篇文章来自 90DaysOfDevOps 学习项目 2022 年路线图的 D文档/教程上一篇3个技巧彻底解决Blender到Unreal Engine的模型转换难题下一篇3分钟终极指南用BetterNCM-Installer让网易云音乐变身超级播放器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑