[技术版] 基础设施配置的编码。 尝试使用 terraform 部署 AWS 实例。
目录
我叫寺冈,是一名基础设施工程师。
这次是继上一次知识版之后的技术版。
基础设施即代码让我们亲自体验一下吧。
上次只是长请参阅下面的知识博客。
【知识版】基础设施配置的编码。 了解“基础架构即代码”的概念,让配置管理变得更加智能。
在本文中,terraform的工具
在 AWS 上构建 EC2 实例。
■一点前言,什么是terraform?
HashiCorp 生产的配置管理工具,
可使用代码自动化基础架构构建和设置。
这家公司本身Vagrant(我一直很感谢他们)。
开发本身非常活跃,更新也很频繁,所以它是我个人非常关注的一个工具。
……好吧,我们现在就开始吧。
■准备terraform执行环境
首先,准备执行环境。除非你这样做,否则它不会启动(
分发了一个zip文件,所以只需使用wget即可获取它。简单方便。
解压它并将其放在路径中。
$ wget https://releases.hashicorp.com/terraform/0.9.0/terraform_0.9.0_linux_amd64.zip $ 解压 terraform_0.9.0_linux_amd64.zip $ mv terraform /usr/bin/ $ terraform -v Terraform v0.9.0
……完成了!
这就是准备执行环境所需的全部内容(
■创建模板文件
给你一个粗略的解释......
一个程序手册,其中写着“使用此配置创建基础设施”,
用代码编写,以便 Terraform 可以解释它。
Terraform 将基于此文件构建基础设施。
首先,准备一个工作目录并在其中创建一个模板文件。
$ mkdir /var/tmp/terraform $ cd /var/tmp/terraform $ touch main.tf
模板文件的扩展名应为“*.tf”。
Terraform 将具有此扩展名的文件识别为模板。
现在,这是我创建的用于构建一个 EC2 实例的模板文件 ↓
(我提前创建了它。这是一种作弊,也用于烹饪节目)
变量“aws_access_key”{}变量“aws_secret_key”{}变量“region”{default =“ap-northeast-1”}变量“images”{default = {us-east-1 =“ami-1ecae776”us-west- 2 =“ami-e7527ed7”us-west-1 =“ami-d114f295”eu-west-1 =“ami-a10897d6”eu-central-1 =“ami-a8221fb5”ap-southeast-1 =“ami-68d8e93a” " ap-southeast-2 = "ami-fd9cecc7" ap-northeast-1 = "ami-cbf90ecb" sa-east-1 = "ami-b52890a8" } } 提供商 "aws" { access_key = "${var.aws_access_key} “secret_key =”${var.aws_secret_key}”区域=“${var.region}”}资源“aws_vpc”“默认”{cidr_block =“172.30.0.0/16”instance_tenancy =“默认”enable_dns_support =“true”enable_dns_hostnames = "false" 标签 { Name = "default" } } 资源 "aws_internet_gateway" "gw" { vpc_id = "${aws_vpc.default.id}" } 资源 "aws_subnet" "public_subnet_a" { vpc_id = "${aws_vpc.default" .id}" available_zone = "ap-northeast-1a" cidr_block = "${cidrsubnet(aws_vpc.default.cidr_block, 4, 1)}" } 资源 "aws_route_table" "public_route" { vpc_id = "${aws_vpc.default. id}" 路由 { cidr_block = "0.0.0.0/0" gateway_id = "${aws_internet_gateway.gw.id}" } } 资源 "aws_route_table_association" "public_route_a" {subnet_id = "${aws_subnet.public_subnet_a.id}" route_table_id = "${aws_route_table.public_route.id}" } 资源 "aws_security_group" "ec2_terraform_test" { name = "ec2_terraform_test" vpc_id = "${aws_vpc.default.id}" 入口 { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } 出口 { from_port = 0 to_port = 0 协议 = "-1" cidr_blocks = ["0.0.0.0/0"] } } 资源 "aws_instance" "terraform-test" { ami = "${var.images["ap-northeast-1"]}" instance_type = "t2.micro" key_name = "XXXXXXXX" vpc_security_group_ids = [ "${aws_security_group.ec2_terraform_test.id}" ]subnet_id = "${aws_subnet. public_subnet_a.id}" Associate_public_ip_address = "true" root_block_device { volume_type = "gp2" volume_size = "8" } 标签 { Name = "terraform-test" } } 输出 "public ip" { value = "${aws_instance.terraform-test .public_ip}" }
……原来如此(
下面我将把每一部分的代码一一写出来。)
提供商定义
提供商“aws”{ access_key =“${var.aws_access_key}”secret_key =“${var.aws_secret_key}”区域=“${var.region}”}
我们先从这部分开始吧。在 Terraform 中,您首先需要配置提供程序。
事实上,它还支持 Terraform、Azure 和 Google Cloud 等云服务,因此您
需要首先告诉我们您要编写哪个提供商的配置。
这次我想在AWS上构建EC2实例,所以我指定了AWS。
定义变量
变量“aws_access_key”{}变量“aws_secret_key”{}变量“region”{default =“ap-northeast-1”}
可以使用变量块定义变量。
存储在该变量中的值可以从其他块中调用和使用。
变量中的值在定义提供者的部分中被调用。
它是类似于“var.aws_access_key”的部分。
顺便说一句,如果您查看代码,您可能想知道“变量中存储的值在哪里?”但是,
在 terraform 中,通过将要存储在变量中的值写入单独的文件中,
该文件被引用并且该值将自动存储在变量中。
该文件还指定了扩展名,并且必须是“*.tfvars”。
aws_access_key = "AKIAXXXXXXXXXXXXXXX" aws_secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
内部看起来是这样的。 “变量名=“值””。
资源定义
资源“aws_vpc”“默认”{ cidr_block =“172.30.0.0/16”instance_tenancy =“默认”enable_dns_support =“true”enable_dns_hostnames =“false”标签{名称=“默认”}}
这部分。我们将描述通常从管理控制台创建的资源的配置。
在 terraform 中,“VPC”和“EC2”都被视为资源。
定义VPC时,指定“cidr_block”。
定义安全组时,指定“ingress”、“egress”等,
对于EC2实例,指定“ami”、“instance_type”等。
顺便说一句,每个描述项都不是编写代码的人可以自由决定的。
terraform有一定的礼仪,写错了就会被骂语法错误(
具体请看下面官方文档(全英文))
输出
输出“公共IP”{值=“${aws_instance.terraform-test.public_ip}”}
如果您部署代码但没有返回结果,您将不知道发生了什么。
通过编写输出块,您可以接收部署的结果。
上面的代码接收创建的EC2实例的公共IP。
■尝试部署它。但在那之前
当然,一旦部署,结果就会立即体现出来。
即使您编写的代码有错误... (这对你的心理健康不利)
所以,Terraform有一个试运行功能,所以我们就使用它吧。
这是一个方便的功能,可以让您通过提前验证代码是否有错误来检查执行计划。
如果您在此处犯了语法错误,您将收到错误通知,因此请务必注意它(
尝试输入“terraform plan”。
$ terraform plan 正在计划之前刷新内存中的 Terraform 状态... 刷新的状态将用于计算此计划,但不会持久保存到本地或远程状态存储 Terraform 执行计划已生成,如下所示。资源按字母顺序显示,以便快速扫描。绿色资源将被创建(或销毁,然后创建,如果现有资源存在),黄色资源将被就地更改,而红色资源将被销毁。注意:您没有指定“-out”参数来保存此计划,因此当调用“apply”时,Terraform 无法保证这就是执行的内容。 -cbf90ecb" Associate_public_ip_address: "true" available_zone: "<computed> “ ebs_block_device.#:”<computed> “ ephemeral_block_device.#:”<computed> “实例状态:”<computed> ”实例类型:“t2.micro”ipv6_addresses.#:“<computed> " key_name: "XXXXXXXXXX" network_interface_id: "<computed> “放置组:”<computed> “私人域名:”<computed> “私人IP:”<computed> “公共域名:”<computed> “公共IP:”<computed> " root_block_device.#: "1" root_block_device.0.delete_on_termination: "true" root_block_device.0.iops: "<computed> " root_block_device.0.volume_size: "8" root_block_device.0.volume_type: "gp2" security_groups.#: "<computed> “ source_dest_check:“true”subnet_id:“$ {aws_subnet.public_subnet_a.id}”标签。%:“1”标签。名称:“terraform-test”租户:“<computed> “ vpc_security_group_ids.#:”<computed> " + aws_internet_gateway.gw vpc_id: "${aws_vpc.default.id}" + aws_route_table.public_route 路由.#: "1" 路由.~2599208424.cidr_block: "0.0.0.0/0" 路由.~2599208424.egress_only_gateway_id: " “路由。~ 2599208424.gateway_id:”{aws_internet_gateway.id}”路由。~ 2599208424.nat_gateway_id:“”路由。~ 2599208424。network_interface_id:“”路由。~2599208424.vpc_peering_connection _id: "" vpc_id: “${aws_vpc.default.id}” + aws_route_table_association.public_route_a route_table_id:“${aws_route_table.public_route.id}”subnet_id:“${aws_subnet.public_subnet_a.id}”+ aws_security_group.ec2_terraform_test 描述:“由 Terraform 管理”出口.#: "1" egress.482069346.cidr_blocks.#: "1" egress.482069346.cidr_blocks.0: "0.0.0.0/0" egress.482069346 .from_port: "0" egress.482069346.ipv6_cidr_blocks.#: " 0" egress.482069346.prefix_list_ids.#: "0" egress.482069346.protocol: "-1" egress.482069346.security_groups.#: "0" egress.482069346.self: "false" egress.482069346.to_port: " 0" ingress.#: "1" ingress.2541437006.cidr_blocks.#: "1" ingress.2541437006.cidr_blocks.0: "0.0.0.0/0" ingress.2541437006.from_port: "22" ingress.2541437006.ipv6_cidr_blocks。 #:“0”ingress.2541437006.protocol:“tcp”ingress.2541437006.security_groups.#:“0”ingress.2541437006.self:“false”ingress.2541437006.to_port:“22”名称:“ec2_terraform_test”owner_id: ”<computed> “ vpc_id:“$ {aws_vpc.default.id}”+ aws_subnet.public_subnet_a allocate_ipv6_address_on_creation:“false”availability_zone:“ap-northeast-1a”cidr_block:“172.30.16.0/20”ipv6_cidr_block_association_id:“<computed> “map_public_ip_on_launch:“假”vpc_id:“$ {aws_vpc.default.id}”+ aws_vpc.default allocate_ generated_ipv6_cidr_block:“假”cidr_block:“172.30.0.0/16”default_network_acl_id:“<computed> “默认路由表ID:”<computed> “default_security_group_id:”<computed> “ dhcp_options_id:”<computed> “启用经典链接:”<computed> “enable_dns_hostnames:“假”enable_dns_support:“真”instance_tenancy:“默认”ipv6_association_id:“<computed> “ ipv6_cidr_块:”<computed> “ main_route_table_id:”<computed> " 标签。%: "1" 标签.名称: "默认" 计划: 7 个添加,0 个更改,0 个销毁。
如果运行成功且没有任何错误,
结果将显示实际执行部署时将添加哪些资源。
这次是“计划:添加7个”,所以总共会添加7个资源。
如果您得到如下所示的结果,那将是不幸的。让我们修复代码中的错误(
发生 2 个错误:* aws_security_group.ec2_terraform_test:egress.0:无效或未知密钥:cidr_block * aws_security_group.ec2_terraform_test:ingress.0:无效或未知密钥:cidr_block
■尝试部署它
现在我们已经确认在试运行期间没有发生错误,让我们实际部署它。
您还可以通过键入“terraform apply”使用单个命令进行部署。
$ terraform apply aws_vpc.default:正在创建...<computed> “default_route_table_id:”“=>”<computed> “default_security_group_id:”“=>”<computed> " dhcp_options_id: "" => "<computed> “启用经典链接:”“=>”<computed> “enable_dns_hostnames:“”=>“假”enable_dns_support:“”=>“真”instance_tenancy:“”=>“默认”ipv6_association_id:“”=>“<computed> " ipv6_cidr_block: "" => "<computed> “ main_route_table_id:”“=>”<computed> " tag.%: "" => "1" tags.Name: "" => "default" aws_vpc.default: 创建完成 (ID: vpc-XXXXXXXX) aws_internet_gateway.gw: 正在创建... vpc_id: "" => “vpc-XXXXXXXX” aws_security_group.ec2_terraform_test:正在创建... 描述:“” => “由 Terraform 管理” egress.#:“” => “1” egress.482069346.cidr_blocks.#:“” => “1” egress.482069346.cidr_blocks.0: "" => "0.0.0.0/0" egress.482069346.from_port: "" => "0" egress.482069346.ipv6_cidr_blocks.#: "" => "0" egress.482069346 .prefix_list_ids.#: "" => "0" egress.482069346.protocol: "" => "-1" egress.482069346.security_groups.#: "" => "0" egress.482069346.self: "" = > "false" egress.482069346.to_port: "" => "0" ingress.#: "" => "1" ingress.2541437006.cidr_blocks.#: "" => "1" ingress.2541437006.cidr_blocks.0 : "" => "0.0.0.0/0" ingress.2541437006.from_port: "" => "22" ingress.2541437006.ipv6_cidr_blocks.#: "" => "0" ingress.2541437006.protocol: "" => "tcp" ingress.2541437006.security_groups.#: "" => "0" ingress.2541437006.self: "" => "false" ingress.2541437006.to_port: "" => "22" 名称: "" => “ec2_terraform_test”owner_id:“”=>“<computed> “ vpc_id:“”=>“vpc-XXXXXXXX”aws_subnet.public_subnet_a:正在创建... .16.0/20" ipv6_cidr_block_association_id: "" => "<computed> " map_public_ip_on_launch: "" => "false" vpc_id: "" => "vpc-XXXXXXXX" aws_internet_gateway.gw: 创建完成 (ID: igw-XXXXXXXX) aws_route_table.public_route: 正在创建...路由。#: "" => "1" 路由.3460203481.cidr_block: "" => "0.0.0.0/0" 路由.3460203481.egress_only_gateway_id: "" => "" 路由.3460203481.gateway_id: "" => "igw-XXXXXXX" 路由.3460203481 .instance_id:“”=>“”route.3460203481.ipv6_cidr_block:“”=>“”route.3460203481.nat_gateway_id:“”=>“”route.3460203481.network_interface_id:“”=>“”route.3460203481.vpc_peering_connection_id : "" => "" vpc_id: "" => "vpc-XXXXXXXX" aws_subnet.public_subnet_a:创建完成(ID:subnet-XXXXXXXX) aws_route_table.public_route:创建完成(ID:rtb-XXXXXXXX) aws_route_table_association.public_route_a:创建中。 ..route_table_id:“”=>“rtb-XXXXXXXX”subnet_id:“”=>“subnet-XXXXXXXX”aws_route_table_association.public_route_a:创建完成(ID:rtbassoc-XXXXXXXX)aws_security_group.ec2_terraform_test:创建完成(ID:sg-XXXXXXXX) aws_instance.terraform-test:正在创建... ami:“”=>“ami-cbf90ecb”associate_public_ip_address:“”=>“true”availability_zone:“”=>“<computed> " ebs_block_device.#: "" => "<computed> " ephemeral_block_device.#: "" => "<computed> “实例状态:”“=>”<computed> “instance_type:”“=>“t2.micro”ipv6_addresses.#:“”=>“<computed> " key_name: "" => "XXXXXXXX" network_interface_id: "" => "<computed> “ 安置组:“”=>“<computed> “私有_dns:”“=>”<computed> “私有IP:”“=>”<computed> “ public_dns:”“ =>”<computed> “ 公共IP:”“ =>”<computed> " root_block_device.#: "" => "1" root_block_device.0.delete_on_termination: "" => "true" root_block_device.0.iops: "" => "<computed> " root_block_device.0.volume_size: "" => "8" root_block_device.0.volume_type: "" => "gp2" security_groups.#: "" => "<computed> “ source_dest_check:“”=>“true”subnet_id:“”=>“subnet-XXXXXXXX”标签。%:“”=>“1”个标签。名称:“”=>“terraform-test”租户:“”= > ”<computed> " vpc_security_group_ids.#: "" => "1" vpc_security_group_ids.766820655: "" => "sg-XXXXXXXX" aws_instance.terraform-test: 仍在创建...(已过 10 秒)aws_instance.terraform-test: 仍在创建.. (已过 20 秒) aws_instance.terraform-test:创建完成(ID:i-XXXXXXXXXXXXXXXXX) 应用完成!资源:7 个已添加,0 个已更改,0 个已销毁 您的基础设施的状态已保存到以下路径。修改和破坏您的基础设施,因此要确保其安全,请使用“terraform show”命令: 输出:public ip = XX.XX.XXX.XX。
是的,返回了Outputs项中创建的实例的公网IP。
让我们从管理控制台检查实例是否确实已创建。
...完成了(太棒了)
与此同时,一个名为“terraform.tfstate”的文件也悄然创建。
这是一个以 json 格式存储“当前基础设施状态”的文件。在
Terraform 中,通过将这个文件与定义文件(.tf 文件)和实际资源状态进行比较,可以在
创建目标资源时确定进行哪个操作。执行,例如修改或删除。
也就是说,如果这个文件存在不一致的情况,就无法正常部署,所以
处理的时候要小心(
■概要
我尝试使用 terraform 来“编码基础设施配置”
我的印象是它很容易使用,因为编写的代码具有很高的可读性,并且基本命令很简单。
这种工具经常与“devops”这个词一起谈论。
如果开发人员和运营人员一起工作,就要防止它变成黑匣子。
我绝对想有效地利用这些工具!
文章变得比知识版还要长,这已经不是什么秘密了。
就是这样,感谢您的阅读!