以代码方式管理基础设施
立即解锁
发布时间: 2025-08-25 01:27:55 阅读量: 1 订阅数: 2 

### 以代码方式管理基础设施
#### 代码下载
可按特定步骤下载代码包,代码包也托管在 GitHub 上,链接如下:
- 主要代码包:[https://github.com/PacktPublishing/Implementing-DevOps-on-AWS](https://github.com/PacktPublishing/Implementing-DevOps-on-AWS)
- 其他代码包:[https://github.com/PacktPublishing/](https://github.com/PacktPublishing/)
#### 模板设计
在开始编码前,有以下规则:
- 可将 TF 模板写成单个大文件或多个小文件的组合。
- 模板可用纯 JSON 或 TF 自身格式编写。
- TF 会在指定文件夹中查找扩展名为 `.tf` 或 `.tf.json` 的文件,并按字母顺序加载。
- TF 模板是声明式的,资源出现的顺序不影响执行流程。
TF 模板通常由三部分组成:资源、变量和输出。为提高可读性,建议使用 TF 格式并将每个部分写在单独的文件中,文件名可自定义,但文件扩展名很重要。
#### 资源
资源文件是模板的核心,资源代表最终要配置的实际组件。例如,使用 VPC、RDS、ELB 等资源进行配置。TF 通过检查资源引用确定执行流程,也可使用 `depends_on` 等显式流控制属性。
以下是 `resources.tf` 文件的部分内容:
```hcl
# Set a Provider
provider "aws" {
region = "${var.aws-region}"
}
# Create a VPC
resource "aws_vpc" "terraform-vpc" {
cidr_block = "${var.vpc-cidr}"
tags {
Name = "${var.vpc-name}"
}
}
# Create an Internet Gateway
resource "aws_internet_gateway" "terraform-igw" {
vpc_id = "${aws_vpc.terraform-vpc.id}"
}
# Create NAT
resource "aws_eip" "nat-eip" {
vpc = true
}
```
下面逐行分析 `aws_subnet` 资源块:
```hcl
resource "aws_subnet" "public-1" {
vpc_id = "${aws_vpc.terraform-vpc.id}"
cidr_block = "${cidrsubnet(var.vpc-cidr, 8, 1)}"
}
```
- 第一个参数是资源类型,后面是任意名称。
- `vpc_id` 属性引用了 `aws_vpc` 资源的 `id` 属性,隐式定义了执行流程,即 VPC 需先创建。
- `cidr_block` 使用 `cidrsubnet` 函数和 `vpc-cidr` 变量返回一个 CIDR 块。
接着添加 RDS、ELB、EC2 自动扩展组等资源:
```hcl
# Add RDS
resource "aws_db_instance" "terraform" {
identifier = "${var.rds-identifier}"
allocated_storage = "${var.rds-storage-size}"
storage_type = "${var.rds-storage-type}"
engine = "${var.rds-engine}"
engine_version = "${var.rds-engine-version}"
instance_class = "${var.rds-instance-class}"
username = "${var.rds-username}"
password = "${var.rds-password}"
port = "${var.rds-port}"
vpc_security_group_ids = ["${aws_security_group.terraform-rds.id}"]
db_subnet_group_name = "${aws_db_subnet_group.rds.id}"
}
# Add ELB
resource "aws_elb" "terraform-elb" {
name = "terraform-elb"
security_groups = ["${aws_security_group.terraform-elb.id}"]
subnets = ["${aws_subnet.public-1.id}", "${aws_subnet.public-2.id}"]
listener {
instance_port = 80
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
tags {
Name = "terraform-elb"
}
}
# Define Launch Configuration
resource "aws_launch_configuration" "terraform-lcfg" {
image_id = "${var.autoscaling-group-image-id}"
instance_type = "${var.autoscaling-group-instance-type}"
key_name = "${var.autoscaling-group-key-name}"
security_groups = ["${aws_security_group.terraform-ec2.id}"]
user_data = "#!/bin/bash \n set -euf -o pipefail \n exec 1> >(logger -s -t $(basename $0)) 2>&1 \n yum -y install nginx; chkconfig nginx on; service nginx start"
lifecycle {
create_before_destroy = true
}
}
# Define Auto Scaling Group
resource "aws_autoscaling_group" "terraform-asg" {
name = "terraform"
launch_configuration = "${aws_launch_configuration.terraform-lcfg.id}"
vpc_zone_identifier = ["${aws_subnet.private-1.id}", "${aws_subnet.private-2.id}"]
min_size = "${var.autoscaling-group-minsize}"
max_size = "${var.autoscaling-group-maxsize}"
load_balancers = ["${aws_elb.terraform-elb.name}"]
depends_on = ["aws_db_instance.terraform"]
tag {
key = "Name"
value = "terraform"
propagate_at_launch = true
}
}
```
#### 变量
变量使模板更具可重用性。以下是 `variables.tf` 文件的部分内容:
```hcl
variable "aws-region" {
type = "string"
description = "AWS region"
}
variable "aws-availability-zones" {
type = "string"
description = "AWS zones"
}
variable "vpc-cidr" {
type = "string"
description = "VPC CIDR"
}
variable "vpc-name" {
type = "string"
description = "VPC name"
}
```
变量赋值方式有多种:
- 直接在 `variables.tf` 中赋值:
```hcl
variable "aws-region" {
type = "string"
description = "AWS region"
default = 'us-east-1'
}
```
- 不赋值,运行时 TF 会提示输入。
- 使用 `-var 'key=value'` 参数传递:`-var 'aws-region=us-east-1'`
- 将键值对存储在文件中。
- 使用以 `TF_VAR_` 为前缀的环境变量。
示例 `terraform.tfvars` 文件内容:
```hcl
autoscaling-group-image-id = "ami-08111162"
autoscaling-group-instance-type = "t2.nano"
autoscaling-group-key-name = "terraform"
autoscaling-group-maxsize = "1"
autoscaling-group-minsize = "1"
aws-availability-zones = "us-east-1b,us-east-1c"
aws-region = "us-east-1"
rds-engine = "postgres"
rds-engine-version = "9.5.2"
rds-identifier = "terraform-rds"
rds-instance-class = "db.t2.micro"
rds-port = "5432"
rds-storage-size = "5"
rds-storage-type = "gp2"
rds-username = "dbroot"
rds-password = "donotusethispassword"
vpc-cidr = "10.0.0.0/16"
vpc-name = "Terraform"
```
#### 输出
输出部分主要用于在测试、部署或部署后向用户返回选定的值。以下是 `outputs.tf` 文件内容:
```hcl
output "VPC ID" {
value = "${aws_vpc.terraform-vpc.id}"
}
output "NAT EIP" {
value = "${aws_nat_gateway.terraform-nat.public_ip}"
}
output "ELB URI" {
value = "${aws_elb.terraform-elb.dns_name}"
}
output "RDS Endpoint" {
value = "${aws_db_instance.terraform.endpoint}"
}
```
#### 操作流程
主要的 TF 操作有五个:
1. 验证模板
2. 测试(预演)
3. 初始部署
4. 更新部署
5. 删除部署
以下是操作步骤的 mermaid 流程图:
```mermaid
graph LR
A[验证模板] --> B[测试(预演)]
B --> C[初始部署]
C --> D[更新部署]
D --> E[删除部署]
```
#### TF 操作详细说明
| 操作 | 命令 | 说明 |
| --- | --- | --- |
| 验证模板 | `terraform validate` | 进行基本语法检查 |
| 测试(预演) | `terraform plan` | 显示实际部署时会发生的情况 |
| 初始部署 | `terraform apply` | 部署模板 |
| 更新部署 | 修改模板后执行 `terraform plan` 和 `terraform apply` | 更新部署 |
| 删除部署 | `terraform destroy` | 删除部署的资源 |
### 以代码方式管理基础设施
#### 验证操作
在进行任何进一步的操作之前,需要使用 `terraform validate` 命令对模板进行基本的语法检查。例如,当在 `resources.tf` 中重命名一个变量后,运行验证命令会返回未知变量错误:
```bash
$ terraform validate
Error validating: 1 error(s) occurred:
* provider config 'aws': unknown variable referenced: 'aws-region-1'.
define it with 'variable' blocks
```
当变量名被修正后,再次运行验证命令没有输出,这意味着验证通过。
#### 预演操作
接下来,使用 `terraform plan` 命令进行测试或预演执行,该命令会显示实际部署时会发生的情况。命令返回一个按字母顺序排列的资源及其属性的彩色列表,具体如下:
```bash
$ terraform plan
Resources are shown in alphabetical order for quick scanning. Green
resources will be created (or destroyed and then created if an existing
resource exists), yellow resources are being changed in-place, and red
resources will be destroyed.
```
若想直观了解待部署的基础设施的样子,可以使用 `terraform graph` 命令:
```bash
$ terraform graph > my_graph.dot
```
DOT 文件可以使用 Graphviz 开源软件(请参考 [Graphviz 官网](http://www.graphviz.org))或许多在线阅读器/转换器进行处理。
#### 部署操作
如果对预演和图形结果满意,就可以使用 `terraform apply` 命令部署模板:
```bash
$ terraform apply
aws_eip.nat-eip: Creating...
allocation_id: "" => "<computed>"
association_id: "" => "<computed>"
domain: "" => "<computed>"
instance: "" => "<computed>"
network_interface: "" => "<computed>"
private_ip: "" => "<computed>"
public_ip: "" => "<computed>"
vpc: "" => "1"
aws_vpc.terraform-vpc: Creating...
cidr_block: "" => "10.0.0.0/16"
default_network_acl_id: "" => "<computed>"
default_security_group_id: "" => "<computed>"
dhcp_options_id: "" => "<computed>"
enable_classiclink: "" => "<computed>"
enable_dns_hostnames: "" => "<computed>"
Apply complete! Resources: 22 added, 0 changed, 0 destroyed.
```
部署成功后,会显示输出信息和状态文件的路径。TF 会存储管理的基础设施的状态,默认存储在本地的 `terraform.tfstate` 文件中,也可以远程存储,这在团队环境中更适用。在团队环境中,如果遇到太多合并冲突,可以将状态文件存储在替代位置,如 S3(请参考 [TF 状态远程存储文档](https://www.terraform.io/docs/state/remote/index.html))。
#### 更新操作
根据墨菲定律,部署模板后往往需要进行更改。例如,需要向 ELB 安全组添加新规则,操作步骤如下:
1. **更新资源块**:在 `resources.tf` 中更新 `aws_security_group` "terraform-elb" 资源块:
```hcl
resource "aws_security_group" "terraform-elb" {
name = "terraform-elb"
description = "ELB security group"
vpc_id = "${aws_vpc.terraform-vpc.id}"
ingress {
from_port = "80"
to_port = "80"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = "443"
to_port = "443"
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
```
2. **验证更改**:运行 `terraform plan` 命令验证即将发生的更改:
```bash
$ terraform plan
...
~ aws_security_group.terraform-elb
ingress.#: "1" => "2"
ingress.2214680975.cidr_blocks.#: "1" => "1"
ingress.2214680975.cidr_blocks.0: "0.0.0.0/0" => "0.0.0.0/0"
ingress.2214680975.from_port: "80" => "80"
ingress.2214680975.protocol: "tcp" => "tcp"
ingress.2214680975.security_groups.#: "0" => "0"
ingress.2214680975.self: "0" => "0"
ingress.2214680975.to_port: "80" => "80"
ingress.2617001939.cidr_blocks.#: "0" => "1"
ingress.2617001939.cidr_blocks.0: "" => "0.0.0.0/0"
ingress.2617001939.from_port: "" => "443"
ingress.2617001939.protocol: "" => "tcp"
ingress.2617001939.security_groups.#: "0" => "0"
ingress.2617001939.self: "" => "0"
ingress.2617001939.to_port: "" => "443"
Plan: 0 to add, 1 to change, 0 to destroy.
```
3. **部署更改**:运行 `terraform apply` 命令部署更改:
```bash
$ terraform apply
...
aws_security_group.terraform-elb: Modifying...
ingress.#: "1" => "2"
ingress.2214680975.cidr_blocks.#: "1" => "1"
ingress.2214680975.cidr_blocks.0: "0.0.0.0/0" => "0.0.0.0/0"
ingress.2214680975.from_port: "80" => "80"
ingress.2214680975.protocol: "tcp" => "tcp"
ingress.2214680975.security_groups.#: "0" => "0"
ingress.2214680975.self: "0" => "0"
ingress.2214680975.to_port: "80" => "80"
ingress.2617001939.cidr_blocks.#: "0" => "1"
ingress.2617001939.cidr_blocks.0: "" => "0.0.0.0/0"
ingress.2617001939.from_port: "" => "443"
ingress.2617001939.protocol: "" => "tcp"
ingress.2617001939.security_groups.#: "0" => "0"
```
#### 删除操作
若要删除部署的资源,可以使用 `terraform destroy` 命令。该命令会删除之前通过 `terraform apply` 部署的所有资源。
#### 总结
通过以上步骤,可以使用 Terraform 以代码方式管理基础设施,包括模板设计、变量定义、输出设置以及各种操作(验证、预演、部署、更新和删除)。使用代码管理基础设施可以提高效率、减少人为错误,并方便团队协作。
以下是整个操作流程的详细 mermaid 流程图:
```mermaid
graph LR
classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;
A([开始]):::startend --> B(验证模板):::process
B --> C{验证是否通过?}:::decision
C -->|是| D(预演操作):::process
C -->|否| B
D --> E{预演是否满意?}:::decision
E -->|是| F(初始部署):::process
E -->|否| D
F --> G(更新操作):::process
G --> H(删除操作):::process
H --> I([结束]):::startend
```
通过这个流程图,可以清晰地看到整个以代码方式管理基础设施的操作流程,从开始的验证到最终的删除操作,每个步骤都紧密相连。同时,表格和代码示例也帮助我们更详细地了解每个操作的具体内容和实现方式。
0
0
复制全文
相关推荐










