《Terraform 101 从入门到实践》这本小册在南瓜慢说官方网站和GitHub两个地方同步更新,书中的示例代码也是放在GitHub上,方便大家参考查看。


初闻不知Terraform,再闻已是云中人。

什么叫基础设施即代码?

在以前,当我们需要把应用部署在服务器时,需要购买多台服务器和机房、组装交换机和网络、不间断电源UPS等。随着云时代的到来,我们可以在IaaS(Infrastructure as a Service)平台直接购买所有的基础设施,包括服务器、专用网络、DNS、负载均衡等,而你只需要专注于应用层面即可。

IaaS(Infrastructure as a Service)的意思是基础设施即服务,它是云服务的基础。著名的IaaS厂商有亚马逊、微软、谷歌和阿里云等。

云厂商为我们解决了许多运维问题:我们不再需要自己管理物理机器,而且能够根据需要随时创建和销毁云机器,还能根据业务和性能要求指定创建服务器的配置和数量。这种便利对于创业型的小公司和个人开发者尤其重要。

随时公司业务的良好发展,所需要的硬件资源越来越多,架构越来越复杂。通过界面操作手工创建服务器、数据库等资源的方式带来越来越多的问题。首先,只要是人工操作,都会有失误的可能,没有人能保证自己不会犯错;而人工操作在软件行业发生事故的案例屡见不鲜。其次,为保证正确率,人工操作一般只能串行,资源多的时候时间会很长。最后,如果我需要根据开发环境的配置再创建一个测试环境和生产环境,人工操作可能会造成差异和错误。

因此,对于这种复杂需要,最佳的方式是通过代码来创建所有硬件资源。这种思想就是基础设施即代码(Infrastructure as Code,很简称IaC),通过代码与定义、部署、更新和销毁基础设施。把硬件映射为软件,而开发和运维人员通过管理代码来管理硬件。

IaC的好处有:

  • 自动化:与软件代替人工,实现自动化,减少风险和安全问题;
  • 效率高:软件可以并行创建资源,大大提高效率;
  • 记录与追踪:通过代码与执行情况,记录硬件变更,出问题也可以追溯;
  • 重用与复制:抽取公共模块实现重用,如创建一个Kubernetes集群的资源可以封装成一个模块。

最终,实现快速安全地应用部署交付(Devivery)。

IaC工具

在IaC这方面的优秀工具还是非常多的,而且不同的工具完成不同的职责,下面列出一些比较常见的工具:

图标工具名GitHub STAR数
Ansible50.9k
Terraform30.2k
Vagrant23k
Chef6.8k
Puppet6.4k
AWS CloudFormation
Azure Resource Manager
Google Cloud Deployment Manager

其中,Ansible在配置自动化应该是领头羊的地位。而Terraform则在服务开通上的事实标准。这里并不想给各个工具做具体介绍,感兴趣的可以去官网或GitHub了解。

注:有些文章或书籍会把Docker和Kubernetes也列为IaC工具,它们的主要职责是在容器与服务编排方面。

Terraform隆重登场Terraform是什么

我们的主角Terraform终于登场了。它是由HashiCorp公司研发的开源的IaC工具,它是由GO语言编写的,可以在各个平台上运行,支持Linux、Mac、Windows等。它简单易用,即使没有太多代码经验的人,也能读懂Terraform的配置代码HCL。

HCL,即HashiCorp Configuration Language,是HashiCorp公司开发的配置语言。后续我们会介绍一些常用语法。

Terraform是一个安全高效的用于对基础设施进行创建和变更且进行版本控制的工具。它支持私有云和公有云,如AWS、Azure、GCP和阿里云等。它的官方网站为https://www.terraform.io。

特性

主要特性有:

  • 基础设施即代码:通过配置语言HCL来描述基础设施,也让代码更好地共享和重用。
  • 变更计划:在实际变更前可以根据代码和状态生成即将要发生变更的计划,它能告诉你将要生成、改变和销毁哪些资源。这可以在执行变更前再做最好的检查,为基础设施提供多一层保护。
  • 资源视图:可以根据依赖关系创建出资源视图,可以直观地查看整个基础设施的关系。
  • 自动化:无须人工干预就可以完成变更。

版本号

截至2021年12月02日,Terraform的最新版本为1.0.11,而它在2021年6月8日才正式发布1.0.0版本。可见Terraform是如此年轻且有活力。而在Terraform还不是1.0.0版本的时候,已经有大量公司在生产环境上使用了。

架构与原理

Terraform是一个由Go语言编写的程序,它会读取HCL语言编写的配置文件,然后将变更信息通过RPC与插件通信,由插件调用云厂商的API完成变更操作。这就是Terraform的工作原理,架构图如下:

基本概念

Terraform core:Terraform的核心组件,类似于指挥官,负责解析配置、管理状态、模块等核心功能。

插件Plugin:完成具体变更的组件,因为Terraform支持多种平台,它并没有把对所有平台的支持都放到核心组件中实现,而是通过插件的方式来提供这些功能。需要对接什么平台,就加入什么平台的插件,非常方面。

模块module:可以将完成特定功能的HCL封装成一个模块,以实现代码复用。类似于其它编程语言中的函数或方法。有入参和出参,一切都可自定义。

状态state:状态存在专门的状态文件里,它是作用是记录实际基础设施的状态。当再次执行变更请求时,Terraform会读取状态文件,判断是否真的需要变更实际的基础设施。如果状态文件记录的状态与HCL描述的一致,就不用再执行变更操作了。

初体验下载安装

Terraform就是一个二进制的程序,只要下载并添加到PATH中去就可以了。各个系统的安装方式没有太大差异。这里以Mac系统为例,做个简单介绍。

下载程序:

可以直接到官网界面(https://www.terraform.io/downloads.html)去下载,请根据自己的系统选择对应的文件:

下载后进行解压,并将该程序添加到环境变量中。

比如我的Terraform放在路径/Users/larry/Software/terraform中,则添加到环境变量的命令如下:

export PATH=$PATH:/Users/larry/Software/terraform

为了让它一直生效,我把上面命令放在home目录下的.bash_profile文件中。

检查是否安装成功如下:

$ terraform versionTerraform v1.0.11on darwin_amd64

如果在纯终端的环境下,也可以通过命令进行下载和解压,命令如下:

# 下载安装包$ wget https://releases.hashicorp.com/terraform/1.0.11/terraform_1.0.11_darwin_amd64.zip# 解压$ unzip terraform_1.0.11_darwin_amd64.zip

最简单的任务:创建一个文件

Terraform的主要应用场景是云服务的基础设施管理,但为了让大家能快速的接触与体验Terraform,我会先选择最简单的一个插件来入门,以免需要太多的环境设置。我们的任务是创建一个文本文件,内容由我们来指定。可以通过插件hashicorp/local来完成。

在当前目录创建一个main.tf文件,完整的代码如下:

terraform {  required_version = "= v1.0.11"  required_providers {    local = {      source  = "hashicorp/local"      version = "= 2.1.0"    }  }}resource "local_file" "terraform-introduction" {  content  = "Hi guys, this the tutorial of Terraform from pkslow.com"  filename = "${path.module}/terraform-introduction-by-pkslow.txt"}

然后执行下面命令:

$ terraform initInitializing the backend...Initializing provider plugins...- Finding hashicorp/local versions matching "2.1.0"...- Installing hashicorp/local v2.1.0...- Installed hashicorp/local v2.1.0 (signed by HashiCorp)Terraform has created a lock file .terraform.lock.hcl to record the providerselections it made above. Include this file in your version control repositoryso that Terraform can guarantee to make the same selections by default whenyou run "terraform init" in the future.Terraform has been successfully initialized!You may now begin working with Terraform. Try running "terraform plan" to seeany changes that are required for your infrastructure. All Terraform commandsshould now work.If you ever set or change modules or backend configuration for Terraform,rerun this command to reinitialize your working directory. If you forget, othercommands will detect it and remind you to do so if necessary.

看命令的输出结果可以知道,Terraform会自动帮我们去下载对应版本的插件hashicorp/local,并做一些初始化的操作。

接着我们通过命令terraform plan来查看将要执行的变更计划:

$ terraform planTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:  + createTerraform will perform the following actions:  # local_file.terraform-introduction will be created  + resource "local_file" "terraform-introduction" {      + content              = "Hi guys, this the tutorial of Terraform from pkslow.com"      + directory_permission = "0777"      + file_permission      = "0777"      + filename             = "./terraform-introduction-by-pkslow.txt"      + id                   = (known after apply)    }Plan: 1 to add, 0 to change, 0 to destroy.

输出日志中会提示需要创建、改变和销毁多少资源。

Plan: 1 to add, 0 to change, 0 to destroy

这里表示会创建一个资源。

废话少说,我们直接执行变更:

$ terraform applyTerraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:  + createTerraform will perform the following actions:  # local_file.terraform-introduction will be created  + resource "local_file" "terraform-introduction" {      + content              = "Hi guys, this the tutorial of Terraform from pkslow.com"      + directory_permission = "0777"      + file_permission      = "0777"      + filename             = "./terraform-introduction-by-pkslow.txt"      + id                   = (known after apply)    }Plan: 1 to add, 0 to change, 0 to destroy.Do you want to perform these actions?  Terraform will perform the actions described above.  Only 'yes' will be accepted to approve.  Enter a value: 

会让你确认是否执行变更,如果是,则输入yes。我们直接输入yes并按回车。

  Enter a value: yeslocal_file.terraform-introduction: Creating...local_file.terraform-introduction: Creation complete after 0s [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

成功执行,创建了文件。

$ ls -ltotal 24-rw-r--r--  1 larry  staff  344 Dec  3 00:01 main.tf-rwxr-xr-x  1 larry  staff   55 Dec  3 00:13 terraform-introduction-by-pkslow.txt-rw-r--r--  1 larry  staff  921 Dec  3 00:13 terraform.tfstate

上面还有一个tfstate文件,是用来记录状态的,以后会详细讲这块内容。

查看一下文件内容:

$ cat terraform-introduction-by-pkslow.txt Hi guys, this the tutorial of Terraform from pkslow.com

与我们预期的内容一致。

如果再次执行apply会不会再次创建一个文件呢?还是创建失败,因为文件已存在?

带着这样的问题,我们再执行一次:

$ terraform applylocal_file.terraform-introduction: Refreshing state... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]No changes. Your infrastructure matches the configuration.Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

发现提示不需要变更,不会执行任何操作。

大家可以思考一下为什么,答案会在后面章节揭晓。

现在我不需要这个文件呢,通过destroy命令可以删除:

$ terraform destroylocal_file.terraform-introduction: Refreshing state... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:  - destroyTerraform will perform the following actions:  # local_file.terraform-introduction will be destroyed  - resource "local_file" "terraform-introduction" {      - content              = "Hi guys, this the tutorial of Terraform from pkslow.com" -> null      - directory_permission = "0777" -> null      - file_permission      = "0777" -> null      - filename             = "./terraform-introduction-by-pkslow.txt" -> null      - id                   = "f63c7933c953ea2d03820d1ec35a80c718bd4777" -> null    }Plan: 0 to add, 0 to change, 1 to destroy.Do you really want to destroy all resources?  Terraform will destroy all your managed infrastructure, as shown above.  There is no undo. Only 'yes' will be accepted to confirm.  Enter a value: yeslocal_file.terraform-introduction: Destroying... [id=f63c7933c953ea2d03820d1ec35a80c718bd4777]local_file.terraform-introduction: Destruction complete after 0sDestroy complete! Resources: 1 destroyed.

一样需要你确认是否真的需要删除,输入yes回车即可。

到这里,就已经真正地带大家体验了一下Terraform是如何工作的,介绍了它的整个流程,也就是Terraform官网所说的Write, Plan, Apply。希望大家能真正动手实践,包括后续的实验,这跟学编程语言是一样的。

最后,对于本次实验我想提几点:

  • 其中的plan命令不是必须的,它是展示即将发生的变更,你可以直接apply也是可以的;
  • 可以通过plan命令输出计划文件,然后apply的时候指定计划文件;
  • 命令apply和destroy可以不必交互式输入yes,通过添加参数-auto-approve即可。