在中文中,重新表达如下内容:学习在AWS上实践Terraform①〜创建AWS资源(初级篇)

首先

大家有没有在使用IaC?
说到IaC工具,人们常常会想到Terraform和Ansible这两个巨头,经常听到大家讨论该用哪个。我个人认为,在AWS/Azure/GCP等公共云的资源管理方面,Terraform比较强大;而在本地网络设置和虚拟服务器内部配置方面,Ansible更具优势。
然而,最近我还是觉得公共云的使用和相应的基础架构即代码化变得更加活跃,所以我想着现在是时候制作一个以教程形式学习Terraform的内容了。

教程部分 bù

教程1:创建AWS资源(初级)
教程2:利用本地值和资源引用
教程3:使用计数一次性创建多个资源
教程4:使用Terraform创建AWS资源(中级)
教程5:使用for_each实现更灵活的循环处理
教程6:使用模块共享资源
教程7:使用Terraform创建AWS资源(高级)
额外1:加密秘密信息并上传到Git
额外2:使用外部存储的tfstate文件
额外3:引用其他由Terraform管理的资源

在教程中追求的目标

    • Terraformの基本的な利用方法を理解する

 

    • tfファイルの記述方法やディレクトリ構成を理解する

 

    現場である程度のレベルでTerraform導入を実施することができる

请留意事项。

这个教程的目标是让初次接触Terraform的人们按照顺序完成各个章节,以获得实践知识。因此,在教程中我们故意使用一些不推荐的写法,但请原谅,这是为了加深对Terraform的理解过程。

假设条件

教程的整个过程基于以下前提进行。

    • ある程度AWSのサービスとその関連性を理解している(AWS-SAAレベル)

 

    • terraformを実行できる環境がある

Terraformのインストール方法はこちらなどを参照ください。
今回は Terraform v1.4.4 を利用します。

AWSアカウントを持っており、AdministratorAccess権限を持つIAMユーザーを利用できる

本編

我们从这里开始教程。
在本部分中,通过AWS的简单配置部署,我们将理解Terraform的基本写法。

这个部分的目标

能够使用Terraform在以下方式上进行部署

AWS.png

事前准备

我会创建一个任务文件夹。
由于terraform是通过文件夹管理源代码的,所以我会先在本地创建一个任务文件夹。

mkdir -p ~/terraform-tutorial/tutorial-1
cd ~/terraform-tutorial/tutorial-1

创建.tf文件来进行环境设置 → 执行初始化

关于tf文件。

在Terraform中,我们会使用.tf文件来存储部署资源信息和认证信息等。
在执行Terraform命令时,会读取当前目录下所有的.tf文件。
因此,虽然把所有的信息都写在一个.tf文件中也没有问题,但是为了管理方便,我们会将.tf文件分成几个部分。

用于环境设置的.tf文件

为了执行terraform,您需要创建一些类似于环境设置的文件。
本次将创建以下两个文件。

    • provider.tf

 

    versions.tf

提供者.tf

在Terraform中,可以通过称为Provider的组件来定义部署哪个提供程序(例如AWS、Azure、GCP、K8s)的资源。
AWS Provider需要访问密钥、秘密密钥和默认区域设置。(与在aws-cli中输入aws configure时需要的值相同)
在这里,请输入具有AdministratorAccess权限的IAM用户的信息。

provider aws {
  access_key = "XXXXXXXXXXXXXXXXXXXXXXXXX"
  secret_key = "YYYYYYYYYYYYYYYYYYYYYYYYY"
  region     = "ap-northeast-1"
}

tf版本

如果关注 Provider 和 Terraform 自身版本的一致性,将能防止在未来出现版本更新时出现错误的情况。在这里,我们指定了 AWS 的 Provider 和 Terraform 的版本。如果尝试使用其他版本的时候,会在执行之前报错。最新的 AWS Provider 版本可以在这里查看。

terraform {
  required_version = "= 1.4.4"
  required_providers {
    aws         = "= 4.61.0"
  }
}

进行terraform初始化

为了初始化 Terraform 的工作区并下载插件,需要运行 “terraform init” 命令。
这将获取在 provider.tf 文件中指定的提供程序插件。

terraform init
Initializing the backend...

Initializing provider plugins...
- Finding hashicorp/aws versions matching "4.61.0"...
- Installing hashicorp/aws v4.61.0...
- Installed hashicorp/aws v4.61.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 目录中。

tree -a
.
├── .terraform
│   └── providers
│       └── registry.terraform.io
│           └── hashicorp
│               └── aws
│                   └── 4.61.0
│                       └── darwin_arm64
│                           └── terraform-provider-aws_v4.61.0_x5
├── .terraform.lock.hcl
├── provider.tf
└── versions.tf

7 directories, 4 files

创建用于部署的tf文件并执行。

在使用Terraform部署源代码时,使用一个名为”Resource”的组件。
将包含Resource的.tf文件存储在文件夹中,当输入部署执行命令时,将自动执行部署。
关于各种Resource的描述方法,只需在Google上搜索所需创建的资源,并将搜索结果的模板基本复制粘贴即可,几乎没有任何问题。
例如,如果要将RDS转换为Terraform代码,只需搜索”terraform AWS RDS resource”,Terraform官方网站将出现在首位。

创建VPC

首先我们将创建VPC。

制作.tf文件。

创建用于部署VPC的.tf文件的资源。
此资源的官方文档在这里。

enable_dns_hostnames をtrueにしておくことで、VPC内からでもエンドポイントのドメイン名を解決できます。

resource "aws_vpc" "vpc" {
  cidr_block           = "192.168.0.0/16"
  enable_dns_hostnames = true

  tags = {
    Name = "tutorial-vpc"
  }
}

当前的文件夹结构如下

.
├── .terraform
├── .terraform.lock.hcl
├── provider.tf
├── versions.tf
└── vpc.tf

执行部署

让我们实际执行命令并进行部署。
当执行terraform plan时,它会读取当前目录中的.tf文件,并确认将部署哪些AWS资源。
如果存在语法错误,它会在执行此计划时拒绝部署,所以在实际执行之前,请务必执行计划。

terraform plan
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc.vpc will be created
  + resource "aws_vpc" "tutorial_vpc" {
      + arn                                  = (known after apply)
      + cidr_block                           = "192.168.0.0/16"
      + default_network_acl_id               = (known after apply)
      + default_route_table_id               = (known after apply)
      + default_security_group_id            = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_classiclink                   = (known after apply)
      + enable_classiclink_dns_support       = (known after apply)
      + enable_dns_hostnames                 = true
      + enable_dns_support                   = true
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = "default"
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + ipv6_cidr_block_network_border_group = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + tags                                 = {
          + "Name" = "tutorial-vpc"
        }
      + tags_all                             = {
          + "Name" = "tutorial-vpc"
        }
    }

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

───────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to
take exactly these actions if you run "terraform apply" now.

执行terraform apply命令来部署。
与计划阶段输出相同的内容,如果没有问题,请在“输入一个值:”处输入yes来执行部署。
然后开始执行部署,过一段时间后会输出完成的消息。

terraform apply
---omit(planと同様)---
  Enter a value: yes  ←yesを入力

aws_vpc.vpc: Creating...
aws_vpc.vpc: Still creating... [10s elapsed]
aws_vpc.vpc: Creation complete after 12s [id=vpc-04fb5154d22486542]

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

关于tfstate文件的问题。

完成申请后,将在当前目录下生成一个名为 terraform.tfstate 的文件。该文件以 JSON 格式保存了实际部署的资源信息。
将来执行 terraform apply 进行差分执行时,会根据 terraform.tfstate 文件、实例和 tf 文件的三个信息进行差分检测并执行。
有些人可能会认为只要看看实例和 tf 文件之间的差异就可以了,不需要看 tfstate。但实际上,还需要一些实例上不存在的资源依赖关系等信息,因此该文件也是必不可少的状态管理工具。更详细的解释请参阅官方网页。

顺便说一句,创建VPC时的tfstate文件的形式如下。

{
  "version": 4,
  "terraform_version": "1.4.4",
  "serial": 1,
  "lineage": "a2216e14-10e4-bfb0-99e2-d69cfa87452d",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "aws_vpc",
      "name": "vpc",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "arn": "arn:aws:ec2:ap-northeast-1:XXXXXXXXXXXX:vpc/vpc-04fb5154d22486542",
            "assign_generated_ipv6_cidr_block": false,
            "cidr_block": "192.168.0.0/16",
            "default_network_acl_id": "acl-07759005723d928fc",
            "default_route_table_id": "rtb-0ab93bd6a0c2cf95e",
            "default_security_group_id": "sg-0f7cc93c60b68fbb6",
            "dhcp_options_id": "dopt-01152b10208f13dd5",
            "enable_classiclink": false,
            "enable_classiclink_dns_support": false,
            "enable_dns_hostnames": true,
            "enable_dns_support": true,
            "enable_network_address_usage_metrics": false,
            "id": "vpc-04fb5154d22486542",
            "instance_tenancy": "default",
            "ipv4_ipam_pool_id": null,
            "ipv4_netmask_length": null,
            "ipv6_association_id": "",
            "ipv6_cidr_block": "",
            "ipv6_cidr_block_network_border_group": "",
            "ipv6_ipam_pool_id": "",
            "ipv6_netmask_length": 0,
            "main_route_table_id": "rtb-0ab93bd6a0c2cf95e",
            "owner_id": "878728386472",
            "tags": {
              "Name": "tutorial-vpc"
            },
            "tags_all": {
              "Name": "tutorial-vpc"
            }
          },
          "sensitive_attributes": [],
          "private": "eyJzY2hlbWFfdmVyc2lvbiI6IjEifQ=="
        }
      ]
    }
  ],
  "check_results": null
}

创建Internet Gateway

接下来,我们将创建一个互联网网关。

创建.tf文件

创建用于部署Internet Gateway的.tf文件的资源。
这个资源的官方文档在这里。

vpc_id には、先ほど作成したVPCのIDを入力しておきます。これによってこのInternet Gatewayは tutorial-vpc 内に作成されます。

resource "aws_internet_gateway" "igw" {
  vpc_id = "vpc-04fb5154d22486542"

  tags = {
    Name = "tutorial-igw"
  }
}

执行部署

使用Terraform apply 创建互联网网关。

terraform plan
terraform apply
AWS.png

创建子网

接下来,我们将创建一个用于部署EC2实例的子网。

创建.tf文件

创建.tf文件以部署子网资源。
此资源的官方文档在此处。

vpc_id は tutorial_vpc のIDを入力します。

cidr_block のCIDRはVPC CIDRの範囲内に指定します。

resource aws_subnet subnet {
  vpc_id            = "vpc-04fb5154d22486542"
  cidr_block        = "192.168.1.0/24"
  availability_zone = "ap-northeast-1a"

  tags = {
    Name = "tutorial-public-subnet"
  }
}

执行部署

使用Terraform apply命令创建子网。

terraform plan
terraform apply
AWS.png

创建路由表

如果不将创建的子网和互联网网关与路由表关联起来,VPC内的EC2无法与互联网通信。因此,需要创建用于通向互联网网关的路由表。

创建.tf文件

创建一个用于部署路由表的.tf文件资源。
此资源的官方文档在这里。

vpc_id は tutorial-vpc のIDを入力します。

gateway_id は tutorial-igw のIDを入力します。

resource aws_route_table route_table {
  vpc_id = "vpc-04fb5154d22486542"
  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = "igw-0e204fdaad34cae29"
  }
  tags = {
    Name = "tutorial-route-table"
  }
}

执行部署

用terraform apply命令创建路由表。

terraform plan
terraform apply
AWS.png

路由表和子网的关联连接

将创建的路由表与子网相关联。

创建.tf文件

创建用于关联路由表和子网的.tf文件的资源。
此资源的官方文档在此。

subnet_id は先ほど作成したSubnetのIDを指定します。

route_table_id は先ほど作成したRoute TableのIDを指定します。

resource aws_route_table_association rta {
  subnet_id      = "subnet-0bf5661c57db0d425"
  route_table_id = "rtb-072ca46273b6a88e6"
}

执行部署

使用terraform apply命令来关联路由表和子网。

terraform plan
terraform apply
AWS.png

生成私钥和公钥

在创建EC2实例时,如果使用GUI进行操作,AWS会帮助我们生成SSH密钥并进行公钥设置。但是,如果使用aws-cli或Terraform执行操作,则只能导入事先创建的SSH密钥。因此,我们需要提前创建SSH密钥对。

ssh-keygen -t rsa -b 4096

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/XXX/.ssh/id_rsa): /Users/XXX/.ssh/aws-ec2
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/XXX/.ssh/aws-ec2.
Your public key has been saved in /Users/XXX/.ssh/aws-ec2.pub
The key fingerprint is:
-------omit-------------
ll ~/.ssh/

-rw-------  1 XXX        XXX        3326 11月 26 01:10 aws-ec2
-rw-r--r--  1 XXX        XXX         781 11月 26 01:10 aws-ec2.pub

上传密钥对

将创建的SSH公钥上传到AWS上。

创建.tf文件。

创建一个用于上传密钥的.tf文件资源。
该资源的官方文档在这里。

    public_keyには公開鍵(aws-ec2.pub)の中身を記載します。
resource "aws_key_pair" "tutorial_key" {
  key_name   = "tutorial-key"
  public_key = "ssh-rsa AAAAB3NzaC1yc2---omit---XXX"
}

执行部署

使用 Terraform apply 命令上传公钥。

terraform plan
terraform apply
AWS.png

创建安全组

在创建EC2实例时,需要指定安全组(Security Group),但如果使用默认的安全组,可能会在0.0.0.0/0上开放22端口。虽然可以通过密钥对进行访问控制,但为了确保安全起见,建议预先创建一个只允许特定访问源的安全组。

创建.tf文件

我将为Security Group创建一个用于Resource的.tf文件。
这个资源的官方文档在这里。

    • インバウンドルール(ingress)に自分の作業端末のIPからのSSHアクセスを許可します。

 

    アウトバウンドルール(egress)は全ての通信を許可します。
resource "aws_security_group" "sg" {
  name        = "tutorial-security-group"
  description = "Allow SSH inbound traffic from XXX"
  vpc_id      = "vpc-04fb5154d22486542"

  ingress {
    description = "SSH from XXX"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["XXX.XXX.XXX.XXX/32"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "tutorial-security-group"
  }
}

执行部署

使用 terraform apply 命令创建安全组。

terraform plan
terraform apply
AWS.png

创建EC2实例

因为创建实例时所需的Key和安全组已经创建完成,所以我们将开始部署实际的实例。

创建.tf文件

创建用于EC2实例的.tf文件资源。
该资源的官方文档在这里。

ami は ap-northeast-1 のAmazon Linuxのイメージを指定します。

subnet_id は作成したSubnetのIDを指定します。

key_name は作成したキーの名前を指定します。

vpc_security_group_ids は作成したSecurity GroupのIDを指定します。

resource aws_instance instance {
  ami                         = "ami-02a2700d37baeef8b"
  instance_type               = "t2.micro"
  subnet_id                   = "subnet-0bf5661c57db0d425"
  associate_public_ip_address = true
  key_name                    = "tutorial-key"
  vpc_security_group_ids      = ["sg-09e5b29077cb81637"]

  tags = {
    Name = "tutorial-instance"
  }
}

执行部署

使用terraform apply命令来部署EC2实例。

terraform plan
terraform apply
AWS.png

连接到EC2的SSH

由于完成了所需的配置,我们现在可以尝试访问EC2。

ssh -i ./aws-ec2 ec2-user@43.207.107.19
The authenticity of host '43.207.107.19 (43.207.107.19)' can't be established.
ED25519 key fingerprint is SHA256:D+N8jZVoLknkReqOBEr8zJS1HHfkyLt1Ks+DCuxUmhs.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '43.207.107.19' (ED25519) to the list of known hosts.
Enter passphrase for key './aws-ec2':
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
[ec2-user@ip-192-168-1-197 ~]$

因此,我成功地能够访问EC2实例的SSH。

删除已部署的资源

有三种方法可以删除在这个教程中创建的环境。

    1. 执行 terraform apply 前删除或注释 .tf 文件中的 resource 部分的描述

 

    1. 将文件扩展名更改为新的(例如:aaa.tf → aaa.tf_old),然后执行 terraform apply

执行 terraform destroy

在.tf文件中删除或注释掉resource的描述。

我們試著將”route_table_association.tf”文件中與路由表和子網關聯的部分注釋掉。

#resource aws_route_table_association rta {
#  subnet_id      = "subnet-0bf5661c57db0d425"
#  route_table_id = "rtb-072ca46273b6a88e6"
#}

当您执行此计划和观察,可以看到输出了与删除资源关联的内容。

terraform plan
---omit---

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_route_table_association.rta will be destroyed
  # (because aws_route_table_association.rta is not in configuration)
  - resource "aws_route_table_association" "rta" {
      - id             = "rtbassoc-089a58f9f877fe6d8" -> null
      - route_table_id = "rtb-072ca46273b6a88e6" -> null
      - subnet_id      = "subnet-0bf5661c57db0d425" -> null
    }

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

───────────────────────────────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to
take exactly these actions if you run "terraform apply" now.

如果没有问题,我们将执行”terraform apply”。

terraform apply
---omit(Planと同様)---

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

aws_route_table_association.rta: Destroying... [id=rtbassoc-089a58f9f877fe6d8]
aws_route_table_association.rta: Destruction complete after 0s

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

在这种状态下,我们可以看到无法访问SSH。

ssh -i ./aws-ec2 ec2-user@43.207.107.19 -vvv
---omit---
debug3: ssh_connect_direct: entering
debug1: Connecting to 43.207.107.19 [43.207.107.19] port 22.
debug3: set_sock_tos: set socket 3 IP_TOS 0x48


<以降、返答なし>

2. 更改文件的扩展名(例如:将aaa.tf改为aaa.tf_old)。

将扩展名为.tf的文件更改为与要删除的资源相关联的文件。

mv route_table_association.tf route_table_association.tf_old

后续行为与注释时相同。

3. 强制摧毁地形

在Terraform中,存在一个用于删除特定资源或所有资源的命令terraform destroy。
如果要删除所有资源,请执行以下命令。

terraform plan -destroy
terraform destroy

要删除特定的资源时,请使用-target选项指定资源。

terraform plan -destroy -target aws_route_table_association.rta
terraform destroy -target aws_route_table_association.rta

在指定目标时,可以使用<resource种类>.<resource名称>的方式。例如,如果要删除由aws_route_table_association资源创建的rta组件,则需要指定aws_route_table_association.rta。

环境的清洁

在这个部分最后,将删除在此创建的一系列资源。

terraform plan -destroy
terraform destroy

最后

在本节中,我们学习了Terraform的计划/应用/销毁等基本操作,以及如何编写tf文件来部署AWS的简单配置。在下一节“AWS实践学习Terraform2〜本地值和资源引用的应用”中,我们将学习更有效的tf文件写作方法。

请提供一个上下文或者更多的信息。

这次使用的代码已经上传到以下的仓库中:
https://github.com/skitamura7446/terraform-tutorial/tree/master/tutorial-1
请注意,由于各种tf文件中包含了个人使用的ID、AWS账户信息和EC2的公钥等,请勿直接使用该仓库进行apply操作,谢谢。

广告
将在 10 秒后关闭
bannerAds