Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备

Terraform是一种部署技术,任何想要通过基础设施即代码(Infrastructure as Code,IaC)方法来置备和管理基础设施的人,都可以使用这种技术。基础设施指的主要是基于云的基础设施,不过从技术上讲,任何能够通过应用程序编程接口(Application Programming Interface,API)进行控制的东西都可以算作基础设施。基础设施即代码是通过机器可读的定义文件来管理和置备基础设施的过程的。我们使用IaC来自动完成原本要由人手动完成的过程。

因为Terraform的用户在不断增多,所以现在人们比以往任何时候都更需要有一本实用的入门指南,指导他们使用Terraform解决现实世界的问题。《Terraform 实战》就是这样一本专门为您准备的书。

Terraform 实战

[美] 斯科特·温克勒(Scott Winkler) 著,赵利通 译

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第1张图片

实用云部署编程入门指南

DevOps软件开发运维指导书籍

介绍如何使用Terraform自动扩展和管理基础架构

帮你了解并使用Terraform

本书读者对象

本书面向所有想要学习Terraform的人。可能你刚刚接触“基础设施即代码”,或者想要转变角色。也可能你已经有了多年经验,想要进一步提升自己的技能。无论你处于哪种状况,我相信本书都有能帮到你的地方。无论你是一名系统管理员、运营人员、网站可靠性工程师(Site Reliability Engineer,SRE)还是DevOps工程师,只要你想学习Terraform,选择本书就对了。

阅读本书不需要你有使用Terraform的经验。但是,我确实期望你有使用相关技术,特别是云的一些经验。你不必是一名解决方案架构师,但你应该知道云是什么,以及如何使用云。Terraform主要用于置备基于云的基础设施。

Terraform是一种表达能力很强的声明式编程语言。要想扩展Terraform,你需要具备一定的编程能力,最好具备使用Go语言编程的能力。你不必是一名程序员,但你知道的编程知识越多,学习体验就越好。

本书结构

本书分为三部分。第一部分是一个训练营,帮助你尽快了解Terraform并使用Terraform。

  • 第1章介绍Terraform和一个“Hello World!”风格的部署。
  • 第2章展示Terraform资源的生命周期。
  • 第3章介绍编写有效的Terraform程序的基础知识。
  • 第4章演示如何部署较大的Web应用程序。

第二部分探讨各种现实场景下Terraform的使用方式。

  • 第5章展示如何使用Terraform代码部署网站。
  • 第6章讨论如何在团队间复用(reuse)和共享代码。
  • 第7章探讨Terraform如何融入更大的持续集成/持续交付(Continuous Integration/Continuous Delivery, CI/CD)生态系统,以及Terraform的局限性。
  • 第8章展示一个多云场景,用于综合运用前面学到的知识。

第三部分介绍Terraform中的高级场景,如测试、自动化和安全。

  • 第9章介绍如何使用Terraform执行蓝/绿部署,以及如何组合使用Terraform与Ansible。
  • 第10章展示如何测试和重构Terraform配置。
  • 第11章讲述如何通过编写自定义提供程序插件来扩展Terraform。
  • 第12章演示如何成规模运行Terraform,以及如何自动运行Terraform。
  • 第13章讨论如何应对安全威胁,以及如何管理密钥。

你应该按顺序阅读第1章到第7章。之后,你可以按任意顺序阅读。即使你不想继续阅读,我仍然建议你阅读第10章和第13章,因为这些主题对每个人都有用。

关于代码

每章的代码都可在GitHub上获取(请在GitHub上搜索“terraform-in-action manning-code”)。这些代码是针对Terraform 0.15编写的,所以你需要安装Terraform 0.15(更新的版本应该也可以)。

本书包含许多源代码示例。源代码采用了等宽字体,以便与正文区分开。有时代码还会加粗显示,强调代码相比该章之前的步骤发生了变化,如添加了新特性。

在很多地方,原始源代码的格式有调整;我们添加了换行符,并改变了缩进,以便让代码适应本书的版面。极少数情况下,我们还会在代码清单中添加行延续标记(➥)。另外,在正文中描述代码的时候,还常常删除源代码中的注释。许多代码清单有注解,用于说明一些重要的概念。

作者简介

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第2张图片

Scott Winkler是一位DevOps工程师,还是著名的Terraform专家。他在HashiConf和HashiTalks上展示过自己的成果,并且是HashiCorp的核心贡献者。Scott在社区中很活跃,开发了许多模块和提供程序。在空闲时间,Scott喜欢骑马。Scott还负责提供Terraform的独立咨询服务。

样章试读:第1章 Terraform入门

本章要点:

  • 理解HCL的语法;
  • 了解Terraform的基本元素和构造模块;
  • 设置Terraform工作空间;
  • 配置Ubuntu虚拟机,并将其部署到AWS上。

Terraform是一种部署技术,任何想要通过基础设施即代码(Infrastructure as Code,IaC)方法来置备和管理基础设施的人,都可以使用这种技术。基础设施指的主要是基于云的基础设施,不过从技术上讲,任何能够通过应用程序编程接口(Application Programming Interface,API)进行控制的东西都可以算作基础设施。基础设施即代码是通过机器可读的定义文件来管理和置备基础设施的过程的。我们使用IaC来自动完成原本要由人手动完成的过程。

所谓置备,指的是基础设施部署,而不是配置管理,后者主要处理应用程序交付,特别是在虚拟机(Virtual Machine,VM)上交付。Ansible、Puppet、SaltStack和Chef等配置管理(Configuration Management,CM)工具已经存在多年,非常流行。Terraform并没有取代这些工具,至少不会完全取代,因为基础设施置备和配置管理在本质上是不同的问题。即使如此,Terraform也会提供原本只有CM工具会提供的一些功能,许多公司在采用了Terraform之后,发现自己并不需要CM工具。

Terraform的基本原则是,它允许编写人类可读的配置代码来定义IaC。借助配置代码,你可以把可重复的、短暂的、一致的环境部署到公有云、私有云和混合云上的供应商(参见图1.1)。

本章会先介绍Terraform相对于其他IaC技术的优缺点,以及它如何从这些技术中脱颖而出,然后通过把一个服务器部署到AWS,并使用Terraform的一些动态特性来改进它,演示Terraform的“Hello World!”示例。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第3张图片

图1.1 Terraform可以把基础设施部署到任何云或者混合云中

1.1 Terraform的优点

近来有大量关于Terraform的宣传,但这种宣传有理有据吗?Terraform并不是唯一的IaC技术,还有其他许多工具也能完成同样的工作。软件部署是利润颇丰的市场领域,Terraform为什么能够在这个领域与Amazon、Microsoft和Google等公司的技术竞争呢?有6个关键特征让Terraform与众不同,给它带来了竞争优势。

  • 置备工具:部署基础设施,而不只是应用程序。
  • 易于使用:适合我们这些不是天才的人使用。
  • 免费且开源:谁不喜欢免费的东西呢?
  • 声明式:说出你想要的结果,而不是说出如何实现这个结果。
  • 云无关:使用相同的工具部署到任意云。
  • 表达能力强且可扩展:不受语言的限制。

表1.1将Terraform与其他IaC工具进行了对比。

表1.1 Terraform与其他IaC工具的对比

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第4张图片

技术对比

从技术上讲,Pulumi最接近Terraform,唯一的区别在于它不是声明式的。Pulumi团队认为这是Pulumi相较于Terraform的优势,但Terraform也有一个云开发工具包(Cloud Development Kit,CDK),允许实现相同的功能。

Terraform的设计受到了AWS CloudFormation的启发,并且与GCP Deployment Manager和Azure Resource Manager有很相近的地方。那些技术虽然也不错,但都不是与具体云无关的技术,也都不是开源的。它们只能用于特定的云供应商,并且一般不如Terraform简洁和灵活。

Ansible、Chef、Puppet和SaltStack都是配置管理工具,而不是基础设施置备工具。它们解决的问题类别与Terraform有些区别,不过也存在重叠的地方。

1.1.1 置备工具

Terraform是一种基础设施置备工具,而不是配置管理工具。置备工具部署和管理基础设施,而配置管理工具(如Ansible、Puppet、SaltStack和Chef)将软件部署到现有服务器上。一些配置管理工具也能够执行一定程度的基础设施置备,但不如Terraform,因为它们并不是为这类任务设计的。

配置管理工具和置备工具之间的区别主要在于理念。配置管理工具常用于管理可变基础设施,而Terraform和其他置备工具常用于管理不可变基础设施。

可变基础设施意味着在现有服务器上执行软件更新。不可变基础设施则不关心现有服务器,它把基础设施视为用后即可丢弃的商品。这两种范式之间的区别可归结为复用思想与用后丢弃思想的区别。

1.1.2 易于使用

即使是非程序员,也可以快速、轻松地学会Terraform的基础知识。到第4章结束时,你将具备中级Terraform用户必备的技能。细想一下,这简直让人难以置信。当然,要精通Terraform就是另外一回事了,不过对于大部分技能都是如此。

Terraform之所以如此易用,主要原因在于其代码是用一种称作HashiCorp Configuration Language(HCL)的领域特定的配置语言编写的。HashiCorp开发了这种语言,用来替代更加冗长的JSON和XML等配置语言。HCL试图在人类可读性和机器可读性之间达到一种平衡,并受到了这个领域中一些早期尝试(如libucl和Nginx配置)的影响。HCL与JSON完全兼容,这意味着HCL能够完全转换为JSON,反之亦然。这就使得与Terraform之外的系统进行互操作或者动态生成配置代码变得十分简单。

1.1.3 免费且开源的软件

Terraform的引擎称作Terraform core,这是一款免费且开源的软件,通过Mozilla Public License v2.0提供。该许可规定,任何人都可以出于个人目的和商业目的使用、分发或修改软件。免费这一点很好,因为这意味着你在使用Terraform时不必担心会承担额外的费用。另外,它使得产品及其工作方式对用户来说变得透明。

Terraform没有提供高级版本,但提供了商业解决方案和企业解决方案(Terraform Cloud和Terraform Enterprise),可成规模运行Terraform。第6章将介绍这些解决方案,在第12章中,我们将自己实现一个Terraform Enterprise。

1.1.4 声明式编程

声明式编程指的是表达计算逻辑(做什么),但不描述控制流(怎么做)。你不必编写一步步执行的指令,只要描述自己想要的结果即可。数据库查询语言(SQL)、函数式编程语言(Haskell、Clojure)、配置语言(XML、JSON)和大部分IaC工具(Ansible、Chef、Puppet)都是声明式编程语言的示例。

声明式编程语言是与命令式(或过程式)编程相对的。命令式语言使用条件分支、循环和表达式来控制系统流程、保存状态和执行命令。几乎所有传统编程语言(如Python、Java、C等)都是命令式编程语言。

注意 声明式编程关注的是结果,而不是过程。命令式编程关注的是过程,而不是结果。

1.1.5 云无关

云无关指的是能够使用一组相同的工具和工作流,无缝运行在任意云平台上。Terraform是云无关的,使用Terraform把基础设施部署到AWS与部署到GCP、Azure甚至私有数据中心一样简单(参见图1.2)。云无关很重要,因为这意味着你不会被局限于特定的云供应商,也不需要在每次改变云供应商时学习一种全新的技术。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第5张图片

图1.2 使用Terraform同时部署到多个云

Terraform通过提供程序(provider)与不同的云集成。提供程序是Terraform插件,用于与外部API进行交互。每个云供应商都会维护自己的Terraform提供程序,使Terraform能够管理该云中的资源。提供程序是使用Go语言编写的,并作为二进制文件分发到Terraform注册表上。它们负责进行身份验证、发出API请求以及处理超时和错误。在这个注册表中,有数百个已经发布的提供程序,它们协同起来,使你能够管理数千种不同的资源。第11章将会对此进行介绍,你甚至可以编写自己的Terraform提供程序。

1.1.6 表达能力强且高度可扩展

与其他声明式IaC工具相比,Terraform的表达能力强,且高度可扩展。通过使用条件语句、for表达式、指令、模板文件、动态块、变量和许多内置函数,我们可以轻松地编写代码来实现自己的目的。表1.2从技术的角度对比了Terraform和AWS CloudFormation(催生Terraform的技术)。

表1.2 Terraform和AWS CloudFormation的技术对比

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第6张图片

1.2 “Hello Terraform!”

本节介绍Terraform的一种经典用例——在AWS上部署一个虚拟机(EC2实例)。我们将使用Terraform的AWS提供程序来代表我们发出API调用和部署EC2实例。完成部署后,我们将让Terraform销毁该实例,避免服务器一直运行,造成越来越多的费用。图1.3显示了该操作的部署流程。

这个场景有一个先决条件——你必须安装了Terraform 0.15.X,并具有AWS的访问凭据。部署项目的步骤如下所示。

(1)编写Terraform配置文件。

(2)配置AWS提供程序。

(3)使用terraform init初始化Terraform。

(4)使用terraform apply部署EC2实例。

(5)使用terraform destroy进行清理。

图1.4演示了“Hello Terraform!”部署的工作流程。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第7张图片

图1.3 使用Terraform在AWS上部署一个EC2实例的架构

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第8张图片

图1.4 “Hello Terraform!”的部署流程

1.2.1 编写Terraform配置

Terraform通过读取配置文件来部署基础设施。要告诉Terraform部署一个EC2实例,需要使用代码来声明该EC2实例。为此,先要创建一个新文件,将其命名为main.tf,并添加代码清单1.1中的内容。.tf扩展名表示这是一个Terraform配置文件。Terraform在运行时,将读取工作目录中所有具有.tf扩展名的文件,并把它们连接起来。

注意 本书中的所有代码均可在GitHub上通过搜索“terraform-in-action/manning-code”获取。

代码清单1.1 main.tf的内容

resource "aws_instance" "helloworld" {    ⇽---  声明一个名为“HelloWorld”的aws_instance资源
  ami           = "ami-09dd2e08d601bff67"  ⇽--- EC2实例的特性 
  instance_type = "t2.micro"
  tags = {
    Name = "HelloWorld"
  }
}

注意 此Amazon机器映像(Amazon Machine Image,AMI)仅对us-west-2地区有效。

代码清单1.1中的代码声明,我们希望Terraform置备一个t2.micro AWS EC2实例,使其具有Ubuntu AMI和一个名称标签。对比下面给出的等效的CloudFormation代码,可以看到Terraform代码要清晰得多,也简洁得多。

{
    "Resources": {
        "Example": {
            "Type": "AWS::EC2::Instance",
            "Properties": {
                "ImageId": "ami-09dd2e08d601bff67",
                "InstanceType": "t2.micro",
                "Tags": [
                    {
                        "Key": "Name",
                        "Value": "HelloWorld"
                    }
                ]
            }
        }
    }
}

这个EC2代码块是Terraform资源的一个示例。在Terraform中,资源是最重要的元素,因为它们置备虚拟机、负载均衡器、NAT网关等基础设施。资源被声明为HCL对象,具有resource类型和两个标签。第一个标签指定了要创建的资源的类型,第二个标签是资源的名称。名称并没有特别的意义,只用来在给定模块作用域内引用该资源。类型与名称合起来构成资源标识符,每个资源的标识符都是唯一的。图1.5显示了Terraform资源块的语法。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第9张图片

图1.5 资源块的语法

每个资源都有输入和输出。输入称作实参,输出称作特性。实参通过资源进行传递,也可作为资源特性使用。另外,资源还有计算特性,但只有在创建了资源后才能使用它们。计算特性包含计算得到的关于管理资源的信息。图1.6显示了aws_instance资源的实参、特性和计算特性的示例。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第10张图片

图1.6 aws_instance资源的实参、特性和计算特性的示例

1.2.2 配置AWS提供程序

接下来,我们需要配置AWS提供程序。AWS提供程序负责理解API交互、发出经过身份验证的请求,以及为Terraform提供资源。下面通过添加一个provider块来配置AWS提供程序。按照代码清单1.2更新main.tf中的代码。

代码清单1.2 main.tf

provider "aws" {    ⇽---  声明AWS提供程序
![箭头08{5%}](/api/storage/getbykey/original?key=22031b3595d646878b29)  region = "us-west-2"    ⇽---  配置部署地区
}

resource "aws_instance" "helloworld" {
  ami           = "ami-09dd2e08d601bff67"
  instance_type = "t2.micro"
  tags = {
    Name = "HelloWorld"
  }
}

注意 在置备基础设施之前,需要先获得AWS凭据。凭据可以存储到凭据文件中或者环境变量中。

与资源不同,提供程序只有一个标签Name。这是该提供程序在Terraform注册表中发布时使用的正式名称(如“aws”代表AWS,“google”代表GCP,“azurerm”代表Azure)。提供程序块的语法如图1.7所示。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第11张图片

图1.7 提供程序块的语法

注意 Terraform注册表是一个全球商店,用来分享版本化提供程序的二进制文件。当Terraform初始化时,会从该注册表自动查找和下载任何必要的提供程序。

提供程序没有输出,只有输入。通过传递输入(或配置实参)给provider块,可以配置提供程序。配置实参包括服务端点URL、地区、提供程序版本、通过API身份验证所需的任何凭据等。图1.8演示了其注入过程。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第12张图片

图1.8 当发出API调用时,配置的提供程序如何把凭据注入aws_instance中

通常,你不会想要把凭据信息作为纯文本传递给提供程序,特别是以后要把这些代码签入版本控制系统的时候更是如此。因此,许多提供程序允许从环境变量或者共享凭据文件中读取凭据。如果对凭据管理感兴趣,建议阅读第13章,详细了解这个主题。

1.2.3 初始化Terraform

在让Terraform部署EC2实例之前,我们首先必须初始化工作空间。尽管我们已经声明了AWS提供程序,但是Terraform仍然需要从Terraform注册表下载和安装二进制文件。至少需要为所有工作空间执行一次初始化。

运行terraform init命令可以初始化Terraform。运行该命令将看到如下输出。

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.28.0...    ⇽---  Terraform获取AWS提供程序的最新版本
- Installed hashicorp/aws v3.28.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the
provider selections it made above. Include this file in your version
control repository so that Terraform can guarantee to make the same
selections by default when you run "terraform init" in the future.

_Terraform has been successfully initialized!    ⇽---  我们真正关心的只有这条信息
__
You may now begin working with Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure. All Terraform
commands should 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,
other commands will detect it and remind you to do so if necessary. 

注意 如果还没有安装Terraform,需要先进行安装,然后才能运行此命令。

1.2.4 部署EC2实例

现在,我们就准备好使用Terraform部署EC2实例了。这需要执行下面的terraform apply命令。

警告 完成此操作后会启用EC2和CloudWatch Logs,这可能会导致对你的AWS账户收费。

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.helloworld will be created
  + resource "aws_instance" "helloworld" { 
      + ami                                = "ami-09dd2e08d601bff67"    ⇽---  ami特性
      + arn                                = (known after apply) 
      + associate_public_ip_address        = (known after apply)
      + availability_zone                 = (known after apply) 
      + cpu_core_count                    = (known after apply)
      + cpu_threads_per_core               = (known after apply) 
      + get_password_data                  = false
      + host_id                           = (known after apply) 
*      + id                                 = (known after apply)
      + instance_state                    = (known after apply) 
*      + instance_type                      = "t2.micro"    ⇽---  instance_type特性
      + ipv6_address_count                 = (known after apply) 
      + ipv6_addresses                    = (known after apply)
      + key_name                           = (known after apply) 
      + network_interface_id               = (known after apply)
      + outpost_arn                        = (known after apply) 
      + password_data                      = (known after apply)
      + placement_group                    = (known after apply) 
      + primary_network_interface_id     = (known after apply)
      + private_dns                      = (known after apply) 
      + private_ip                       = (known after apply)
      + public_dns                       = (known after apply) 
      + public_ip                        = (known after apply)
      + security_groups                  = (known after apply) 
      + source_dest_check                 = true
      + subnet_id                        = (known after apply) 
      + tags                             = {    ⇽---  Tags特性
          +  "Name"                      = "HelloWorld"
        }
      + tenancy                          = (known after apply) 
      + volume_tags                      = (known after apply)
      + vpc_security_group_ids           = (known after apply) 

      + ebs_block_device {
          + delete_on_termination        = (known after apply) 
          + device_name                  = (known after apply)
          + encrypted                    = (known after apply) 
          + iops                         = (known after apply)
          + kms_key_id                   = (known after apply) 
          + snapshot_id                  = (known after apply)
          + volume_id                    = (known after apply) 
          + volume_size                  = (known after apply)
          + volume_type                  = (known after apply)
        }

      + ephemeral_block_device { 
          + device_name                  = (known after apply)
          + no_device                    = (known after apply) 
          + virtual_name                 = (known after apply)
        }

      + metadata_options { 
          + http_endpoint                  = (known after apply)
          + http_put_response_hop_limit    = (known after apply) 
          + http_tokens                   = (known after apply)
        }

      + network_interface { 
          + delete_on_termination        = (known after apply)
          + device_index                  = (known after apply) 
          + network_interface_id          = (known after apply)
        }

      + root_block_device { 
          + delete_on_termination          = (known after apply)
          + device_name                    = (known after apply) 
          + encrypted                     = (known after apply)
          + iops                          = (known after apply) 
          + kms_key_id                    = (known after apply)
          + volume_id                     = (known after apply) 
          + volume_size                   = (known after apply)
          + volume_type                   = (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:     ⇽---  手动批准步骤

提示 如果收到错误“No Valid Credentials Sources Found”,说明Terraform无法通过AWS的身份验证。

CLI输出称为执行计划,描述了Terraform计划执行哪些操作来得到人们期望的状态。在继续操作前,作为一种健全性检查,检查执行计划是一个好主意。除非在拼写时出错,否则这里不应有什么奇怪的地方。检查完执行计划后,通过在命令行输入yes批准执行。

一两分钟后(置备EC2实例大概需要这么长时间),apply即成功完成。下面是一些示例输出。

aws_instance.helloworld: Creating...
aws_instance.helloworld: Still creating... [10s elapsed]
aws_instance.helloworld: Still creating... [20s elapsed]
aws_instance.helloworld: Creation complete after 25s [id=i-070098fcf77d93c54]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed. 

要验证资源已被创建,你可以在AWS的EC2控制台找到它,如图1.9所示。注意,此实例位于us-west-2地区,因为我们在提供程序中就是这么设置的。

Terraform实战 | 实用云部署编程入门指南,DevOps软件开发运维必备_第13张图片

图1.9 AWS控制台中的EC2实例

资源的状态信息存储在一个名为terraform.tfstate的文件中。不要被扩展名.tfstate误导,它其实就是一个JSON文件。使用terraform show命令可以从状态文件输出人类可读的输出,这使得列举Terraform管理的资源的信息非常方便。下面是一条terraform show命令的执行结果。

$ terraform show
# aws_instance.helloworld:
resource "aws_instance" "helloworld" {
    ami                                = "ami-09dd2e08d601bff67"
    arn                                =
    ➥"arn:aws:ec2:us-west-2:215974853022:instance/i-070098fcf77d93c54"
    associate_public_ip_address        = true
    availability_zone                  = "us-west-2a"
    cpu_core_count                     = 1
    cpu_threads_per_core               = 1
    disable_api_termination            = false
    ebs_optimized                      = false
    get_password_data                  = false
    hibernation                        = false
   id                                 = "i-070098fcf77d93c54"    ⇽---  id是一个重要的计算特性
    instance_state                     = "running"
    instance_type                      = "t2.micro"
    ipv6_address_count                 = 0
    ipv6_addresses                     = []
    monitoring                         = false
    primary_network_interface_id     = "eni-031d47704eb23eaf0"
    private_dns                      =
    ➥"ip-172-31-25-172.us-west-2.compute.internal"
    private_ip                       = "172.31.25.172"
    public_dns                       =
    ➥"ec2-52-24-28-182.us-west-2.compute.amazonaws.com"
    public_ip                        = "52.24.28.182"
    secondary_private_ips            = []
    security_groups                  = [
        "default",
    ]
    source_dest_check                = true
    subnet_id                        = "subnet-0d78ac285558cff78"
    tags                             = {
        "Name"                       = "HelloWorld"
    }
    tenancy                          = "default"
    vpc_security_group_ids           = [
        "sg-0d8222ef7623a02a5",
    ]

    credit_specification {
        cpu_credits = "standard"
    }

    enclave_options {
        enabled = false
    }

    metadata_options {
        http_endpoint                  = "enabled"
        http_put_response_hop_limit    = 1
        http_tokens                    = "optional"
    }

    root_block_device {
        delete_on_termination        = true
        device_name                  = "/dev/sda1"
        encrypted                    = false
        iops                         = 100
        tags                         = {}
        throughput                   = 0
        volume_id                    = "vol-06b149cdd5722d6bc"
        volume_size                  = 8
        volume_type                  = "gp2"
    }
}

这里的特性远多于我们一开始在资源块中设置的特性,这是因为aws_instance中的特性大部分是可选特性或计算特性。通过设置可选实参,你可以自定义aws_instance。如果你想知道有哪些可选实参,可以参阅AWS的提供程序文档。

1.2.5 销毁EC2实例

现在是时候跟EC2实例说再见了。当不再使用基础设施时,应该销毁它们,因为在云中运行基础设施是要收费的。Terraform提供了一个特殊命令——terraform destroy,用于销毁全部资源。当运行此命令时,Terraform将会给出提示,要求你手动确认销毁操作。

$ terraform destroy
aws_instance.helloworld: Refreshing state... [id=i-070098fcf77d93c54]

Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.helloworld will be destroyed
  - resource "aws_instance" "helloworld" {
      - ami                              = "ami-09dd2e08d601bff67" -> null
      - arn                              = "arn:aws:ec2:us-west-2:215974853022:
        ➥instance/i-070098fcf77d93c54" -> null
      - associate_public_ip_address      = true -> null
      - availability_zone                = "us-west-2a" -> null
      - cpu_core_count                   = 1 -> null
      - cpu_threads_per_core             = 1 -> null
      - disable_api_termination          = false -> null
      - ebs_optimized                    = false -> null
      - get_password_data                = false -> null
      - hibernation                      = false -> null
      - id                               = "i-070098fcf77d93c54" -> null
      - instance_state                   = "running" -> null
      - instance_type                    = "t2.micro" -> null
      - ipv6_address_count               = 0 -> null
      - ipv6_addresses                   = [] -> null
      - monitoring                       = false -> null
      - primary_network_interface_id     = "eni-031d47704eb23eaf0" -> null
      - private_dns                      =
        ➥"ip-172-31-25-172.us-west-2.compute.internal" -> null
      - private_ip                       = "172.31.25.172" -> null
      - public_dns                       =
        ➥"ec2-52-24-28-182.us-west-2.compute.amazonaws.com" -> null
      - public_ip                        = "52.24.28.182" -> null
      - secondary_private_ips            = [] -> null
      - security_groups                  = [
          - "default",
        ] -> null
      - source_dest_check                = true -> null
      - subnet_id                        = "subnet-0d78ac285558cff78" -> null
      - tags = {
          - "Name"                       = "HelloWorld"
        } -> null
      - tenancy                          = "default" -> null
      - vpc_security_group_ids           = [
          - "sg-0d8222ef7623a02a5",
        ] -> null

      - credit_specification {
          - cpu_credits = "standard" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - metadata_options {
          - http_endpoint                  = "enabled" -> null
          - http_put_response_hop_limit     = 1 -> null
          - http_tokens                    = "optional" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/sda1" -> null
          - encrypted             = false -> null
          - iops                  = 100 -> null
          - tags                  = {} -> null
          - throughput            = 0 -> null
          - volume_id             = "vol-06b149cdd5722d6bc" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> null
        }
   }

*Plan: 0 to add, 0 to change, 1 to destroy.    ⇽---  Terraform计划采取的操作的摘要

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: 

警告 不要手动编辑或删除terraform.tfstate文件,这一点很重要,否则Terraform将无法跟踪其管理的资源。

销毁计划与前面的执行计划类似,只不过它用于删除操作。

注意 terraform destroy执行的操作相当于你删除了所有配置代码,然后运行terraform apply。

通过在命令行输入yes,确认自己希望应用销毁计划。等待几分钟,让Terraform进行处理,然后你将收到Terraform已经销毁了所有资源的通知。输出将如下所示。

aws_instance.helloworld: Destroying… [id=i-070098fcf77d93c54]
aws_instance.helloworld: Still destroying...
➥[id=i-070098fcf77d93c54, 10s elapsed]  
aws_instance.helloworld: Still destroying...
➥[id=i-070098fcf77d93c54, 20s elapsed]  
aws_instance.helloworld: Still destroying...
➥[id=i-070098fcf77d93c54, 30s elapsed]  
aws_instance.helloworld: Destruction complete after 31s

Destroy complete! Resources: 1 destroyed. 

通过刷新AWS控制台,或者运行terraform show命令并确认它没有返回任何东西,验证资源确实被销毁了。

你可能感兴趣的:(Terraform,编程语言,云部署编程,DevOps)