我将这本《Infrastructure as Code入门(AWS)》奉献给曾因对Terraform感到害怕而颤抖的过去的自己

首先

你好。我是管理营养师 @Sadalsuud,负责基础设施、后端和前端工作。我喜欢的饮料是红牛。

突然說,基礎設施即程式碼這個概念你不覺得有點可怕嗎?

代码可以管理基础设施。哦,原来如此…这太棒了。
太棒了,但是太棒了…它太可怕了…!

    • 既存インフラ・本番環境を吹き飛ばしちゃったらどうしよう…!

 

    • 大量のリソースが意図せず爆誕してしまったら…!?

 

    飲酒したノリで、高価なインフラを大量に生成してしまったら…..!?!?!?

脑海中闪过无数个不安的念头。与后端代码不同,它可以通过执行产生费用,并且令人颤抖的是,仅仅一个命令就能把生产环境变成一片废墟。

虽然仍然感到害怕,但在使用中,开始看到了必须抑制的要点和需要确认的地方,终于能够以平常心来使用了。这次我打算将这些要点整理成文章。

terraform的工作原理。

使用Terraform,您可以编写类似main.tf这样的tf文件,并通过执行Terraform的各种命令来在云上等地构建基础设施资源。它支持指定AWS、Azure、GCP等提供商进行使用,因此您可以构建各种云环境。

当运行terraform apply命令时,它会读取该目录下所有的*.tf文件,并在指定的云环境中创建基础设施。

tf.gif

不仅可以创建,而且可以进行设置更改,当然还可以进行删除。

使用terraform创建的基础设施信息会被记录在terraform.tfstate文件中。由于资源标识符等分配是在资源创建之后才可知的,因此会在执行后被整理到terraform.tfstate中。

image.png

当terraform执行下一步操作时,它将比较当前terraform.tfstate文件的状态与执行后的状态,并显示出差异。

这个terraform.tfstate文件中包含了已创建的基础设施信息,所以最好不要将其包含在公开的代码仓库中。
如果是个人项目以外的情况,通常会选择将它存储在S3等地方,我在工作中也是使用这种方法,但这次不详细讨论。
参考:使用Terraform在S3中管理tfstate文件。

讓我們開始使用Terraform:試著創建一個EC2實例吧。

我們計劃涵蓋四個步驟。

    • IAMユーザーの作成/適用

 

    • terraformの導入

 

    • tfファイルを作成する

 

    実行する

创建/应用IAM用户

执行terraform需要对所处理的资源具有IAM权限。可以使用aws configure等命令设置认证信息,如aws_access_key_id和aws_secret_access_key。

配置文件和认证信息文件

我知道有些人已经拥有管理员身份验证信息,但是我担心安全问题,所以只增加了必要权限。

$ aws配置

使用terraform

如果你使用的是MAC,可以通过下面的方式一次性安装。
(由于我使用的是WSL(Ubuntu),所以我参照了在WSL(Ubuntu 18.04)上使用命令行安装Terraform的方法来进行安装。)

$ brew install terraform

创建tf文件

无论如何,我想要创建一个可运行EC2的实例。
(在实际工作中,我们会利用terraform执行时读取目录内所有的*.tf文件的特性,将常量指定到一个文件中,并将创建资源的操作写在另一个文件中以进行分离,但是目前我想仅使用最少的描述来进行执行。)

provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

resource "aws_instance" "tf_test_instance1" {
  ami           = "ami-0ebe863c3d16bca9d" # AmazonLinax2 → https://aws.amazon.com/jp/amazon-linux-2/release-notes/
  instance_type = "t2.micro"

  tags = {
    Name = "tf_test(20191201)"
  }
}

我只设置了最基本的项目,但还可以设置各种可以在EC2的Web控制台上设置的项目。关于这些项目,您可以在文档中查到相关信息。

如果上述文件创建成功,执行以下操作以初始化terraform。这只需执行一次即可。
在本例中,AWS插件将在此时引入到terraform中。
顺便说一下,根据文档,init命令可以多次执行而不会有问题。

$ terraform init

如果在WSL环境下初始化失败,可以尝试以下方法解决 Terraform init 时出现 “Registry service unreachable.” 错误:

进行

大家期待已久的是terrafarom的执行。
但在执行之前,可以先运行一个命令来检查当前的配置是否正确,以及执行该命令会发生什么。

$ terraform plan
image.png

当执行完毕后,输出会显示出执行结果。
如果查看这些结果,会发现资源已经被添加,并且同时创建了一个实例以及相关的EBS等内容。

现在是正式执行的时候了。执行以下命令来将此内容应用到AWS。

$ terraform apply

执行命令后,将返回一次计划的结果。这是最后的最后检查。如果一切顺利,请在此输入“是”并按下回车键。

image.png

让我们从Web控制台上确认一下。
由于本次执行只使用了最基本的必需项,所以没有指定VPC或子网。在这种情况下,将被分配和创建到默认VPC的某个子网中。

image.png

EC2实例已创建成功!!

删除/预防删除资源

因为这是为了考试而创建的实例,所以我想删除它以避免不必要的计费。

在执行terraform destroy命令之前,先执行plan命令,以确认将会删除哪些内容。

$ terraform plan -destroy
image.png

既经验证了之前创建的实例可以通过运行”terraform destroy”来删除,所以我想要执行…但在此之前!

我想实验删除预防措施。

指定生命周期以阻止删除。

如前所述,尽管删除很容易,但有些资源可能不希望轻易消失。这些资源可能包括生产环境的实例和RDS等。

通过指定下列内容,可以防止意外删除这些事物。

  lifecycle {
    prevent_destroy = true
  }

让我们把上述描述应用到之前创建的 main.tf 文件中。

provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

resource "aws_instance" "tf_test_instance1" {
  ami           = "ami-0ebe863c3d16bca9d" 
  instance_type = "t2.micro"

  tags = {
    Name = "tf_test(20191201)"
  }

  # 追加
  lifecycle {
    prevent_destroy = true
  }
}

让我们在这种情况下试试删除资源,看会发生什么。

$ terraform plan -destroy
image.png

出现错误,无法执行并显示删除资源。

即使没有明确指定destroy,资源的破坏也可能发生。
例如,在更改子网等操作时,Terraform会先销毁现有的实例,然后再创建新的实例。

假设我们修改了子网。

provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

resource "aws_instance" "tf_test_instance1" {
  ami           = "ami-0ebe863c3d16bca9d" 
  instance_type = "t2.micro"
  subnet_id = "subnet-xxxxxxxx" # 別のサブネットidを指定する

  tags = {
    Name = "tf_test(20191201)"
  }

  lifecycle {
    prevent_destroy = true
  }
}

如果没有”prevent_destroy = true”的设置,则当前实例将被删除,并且一个新实例将在指定的子网中生成。但由于此次已经添加了防止删除设置,因此将会发生错误。

$ terraform plan -destroy
image.png

刚才发生错误导致程序结束,与之前一样。

好的,我们稍微绕了点路,现在让我们终于删掉这个实例。
删除网络描述和prevent_destroy = true的描述后,它将变成这样。这是一开始应用的状态。

provider "aws" {
  version = "~> 2.0"
  region  = "ap-northeast-1"
}

resource "aws_instance" "tf_test_instance1" {
  ami           = "ami-0ebe863c3d16bca9d" # AmazonLinax2 → https://aws.amazon.com/jp/amazon-linux-2/release-notes/
  instance_type = "t2.micro"

  tags = {
    Name = "tf_test(20191201)"
  }
}

这样就可以了

$ terraform plan -destroy
image.png

似乎要全部消失了。那么,我们就晴天行动吧。

$ terraform destroy
image.png

当执行terraform show命令时,您会发现terraform没有管理任何资源,其已全部被清空。

安全点

我想总结一下到目前为止的回顾,并提供一些额外的方法,让我们在进行terraform时感到更加安心。

不要将认证信息写入*.tf文件中。

实际上,您也可以直接将身份验证信息写入 tf 文件中。这样一来,就不需要进行 AWS $ aws configure 的设置,非常方便……但是,如果这个 tf 文件泄露了,例如提交并公开在代码库中,那么很容易被滥用。由于身份验证信息的泄漏非常危险,即使是个人项目,也最好不要在 .tf 文件中记录它们,这可能更为稳妥。

参考:因为AWS遭受了未经授权的访问,所以记录下当时的应对措施(已获得退款)。

image.png

只授权给创建资源的IAM角色

image.png

指定执行 terraform 的 IAM 角色。

为了限制之前提到的IAM权限,我们可以限制terraform的权限。

虽然可以通过”aws configure”设置多个配置文件,但如果不进行特殊配置,它应该会在默认配置文件中执行。

如果默认配置文件是具有Admin权限的话,那么terraform将拥有创建任何资源的权限。

当然,我知道在进行plan确认和apply前都会仔细核对,但我个人认为一直期望人类的判断能力是危险的,所以我希望能够对其进行控制。

通过这种方式,您也可以指定配置文件,以防止意外创建资源。这样,即使在喝醉的状态下,只要您能够编辑tf文件并更换IAM角色的人,情况就会有所不同了…

provider "aws" {
  region                  = "ap-northeast-1"
  profile                 = "my-profile" # credentialsのプロファイル名を指定する
}

利用生命周期进行有意义的使用,以防止意外删除等行为。

前面所说的prevent_destroy = true将防止意外删除资源。
但是,如果滥用此选项,可能会妨碍所期望的资源删除,因此应注意。
有关详细信息,请参阅文档。
生命周期:生命周期定制化。

不要直接编辑tfstate文件/不要保存在本地。

由于terraform.tfstate保存了Terraform当前基础设施的状态,直接对其进行编辑可能会导致意外情况的发生。
此外,如果将其保存在本地,可能会意外永久删除或者无意中进行编辑。在实际工作中,使用Terraform的后端机制将状态文件保存到S3可能更为安全可靠。

确保对 terraform 进行正确的计划。

我明白没有确认任何事情都可能会出错,但是只是改变实例大小,所以觉得没关系!结果实例被删除了…因为我曾经有过类似的差点意外,所以即使改变很明显,我也会尽量冷静地进行计划。

请给我做个评论。

由于是以代码形式存在,基础架构即代码具有一些优点,其中之一是在团队开发中,可以对其进行审查。
在我的团队中,有两个人,一个是Android工程师,另一个是机器学习工程师,他们记住了语法并尽可能地进行了审查,这对我们非常有帮助。

申请破坏需要多人参与。

即使多么小心,手指和思维可能会一下子乱了,可能会不小心执行 terraform destroy。
但是,如果多个人逐个确认和执行命令,就可以避免这种无法挽回的疏忽。

使用CI

听说,从控制台目视确认terraform计划的输出结果似乎已经达到了极限。听说有些情况下通过CI来解决这个问题。太厉害了。

由Mercari的微服务团队介绍Terraform的操作,以及他们在其中开发的开源软件。

用Terraform构建的资源不需要通过Web控制台进行更改。

Terraform会将当前资源状态保存在tfstate中。在这种情况下,如果您尝试在Terraform构建的资源上进行更改,会导致tfstate与实际情况之间产生差异。

在某些情况下,标签名称等可以在tf文件中后续进行协调,但也可能需要在某些情况下先破坏后重新创建。

在我的情况下,我偷偷从Web控制台上调整了实例的大小,然后试图在tf文件中进行一些修改以匹配差异。但是,由于tfstate记录的instance_id不匹配,无论我怎么努力,plan总是要先销毁旧的实例再重新创建新的实例。

在我的情况下,我悄悄地在Web控制台上提高了实例的大小,然后尝试通过对tf文件进行一些修改来同步差异。然而,由于tfstate中记录的instance_id不匹配,所以无论我如何努力,计划始终会先销毁原有实例,然后重新创建新实例。

最终,通过执行 “terraform state rm [资源名称]” 命令,我们从tfstate中移除了资源的信息。接下来,通过执行 “terraform import [资源类型.资源名称] [资源ID]” 命令,我们成功地将AWS当前状态导入到state中,并成功消除了差异。

总之,如果没有紧急的情况,管理通过terraform实施的事物最好也由terraform来处理。

结束

最近我使用起来变得很有乐趣,从控制台观察大量资源一次性启动也感到很开心。我与之前提到的团队成员也像是一个事件一样,能够一起执行 “terraform apply”,整个团队感觉非常好。

此外,我认为Terraform本身就是基础架构操作日志,可以保证操作的完整性和准确性,这非常棒。

明天是 @tom-ock 先生的 “使用Vim编写React” 的讲座!期待你的参与!

我非常感激受到了这篇文章的照顾。

用10分钟简单了解Terraform
Terraform – 简要解释其机制和入门部分。

bannerAds