Terraform 实战 | 万字长文

本文详述了Terraform的使用,从初体验到编程,再到多云部署和零宕机策略。通过实例展示了如何在不同环境下安装Terraform,创建阿里云ECS实例,并利用workspace管理多环境部署。文章还探讨了编写自定义Provider的过程,强调了基础设施即代码的原则及其优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

fb2691f887b6efccf5f6d0c918a24129.gif

新钛云服已为您服务1456

b78cc00e47523ae55b190d5bbaf98e95.gif

(万字长文,建议 PC 端观看效果更佳)

Terraform 是什么

ff31aa37704a612711ab02b386e60bf7.png

Terraform(https://www.terraform.io/)是 HashiCorp 旗下的一款开源(Go 语言开发)的 DevOps 基础架构资源管理运维工具,可以看下对应的 DevOps 工具链:

c0dfe03e2d1b70a5b508051223b44cc7.png

Terraform 可以安全高效的构建、更改和合并多个云厂商的各种服务资源,当前支持有阿里云、AWS、微软 Azure、Vmware、Google Cloud Platform 等多个云厂商云产品的资源创建。

2d3fd3bc6a05f5f5bdf64721cf2d80bf.png

Write, Plan, and Create Infrastructure as Code

Terraform 通过模板配置文件定义所有资源类型(有如主机,OS,存储类型,中间件,网络 VPC,SLB,DB,Cache 等)和资源的数量、规格类型、资源创建依赖关系,基于资源厂商的 OpenAPI 快速创建一键创建定义的资源列表,同时也支持资源的一键销毁。

顺便介绍一下 HashiCorp 这家公司的其他产品:

  1. Vagrant Vagrant by HashiCorp

  2. Consul HashiCorp Consul - Connect and Secure Any Service

  3. Vault HashiCorp Vault - Manage Secrets & Protect Sensitive Data

  4. Nomad HashiCorp Nomad Enterprise

  5. Packer Packer by HashiCorp



Terraform 初体验

接下来,我们就安装并体验一下 Terraform。

安装

CentOS 7 安装

接下来在 CentOS 7 上面进行安装,如下:

sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum -y install terraform

验证版本信息:

[root@mybox02 ~]# terraform version
Terraform v1.0.2
on linux_amd64

MacOS 安装

如果是在 MacOS 上面安装,则执行如下命令:

$ brew install terraform

验证版本信息:

$ terraform version
Terraform v1.0.3
on darwin_amd64

获取命令行帮助

如何获取命令行帮助呢?

# 获取帮助信息,查看 Terraform 支持哪些子命令及参数
terraform -help

# 查看具体某个子命令的帮助信息
terraform -help plan

# 开启命令行补全
terraform -install-autocomplete

创建一台阿里云 ECS 实例

准备子账号

创建 RAM 子账户,子账户只能通过 OpenAPI 的形式访问云上的资源,而且不能赋予所有的权限,只赋予指定的权限,如 ECS、RDS、SLB 等具体的权限。

推荐使用环境变量的方式存放身份认证信息:

export ALICLOUD_ACCESS_KEY="********"
export ALICLOUD_SECRET_KEY="*************"
export ALICLOUD_REGION="cn-shanghai"

一段代码

下面是一段测试的代码 main.tf,其主要功能是在阿里云上创建 VPC、vSwitch、安全组、ECS 实例,最后输出 ECS 的外网 IP。代码如下:

resource "alicloud_vpc" "vpc" {
  name       = "tf_test_foo"
  cidr_block = "172.16.0.0/12"
}

resource "alicloud_vswitch" "vsw" {
  vpc_id            = alicloud_vpc.vpc.id
  cidr_block        = "172.16.0.0/21"
  availability_zone = "cn-shanghai-b"
}

resource "alicloud_security_group" "default" {
  name = "default"
  vpc_id = alicloud_vpc.vpc.id
}

resource "alicloud_security_group_rule" "allow_all_tcp" {
  type              = "ingress"
  ip_protocol       = "tcp"
  nic_type          = "intranet"
  policy            = "accept"
  port_range        = "1/65535"
  priority          = 1
  security_group_id = alicloud_security_group.default.id
  cidr_ip           = "0.0.0.0/0"
}

resource "alicloud_instance" "instance" {
  availability_zone = "cn-shanghai-b"
  security_groups = alicloud_security_group.default.*.id
  instance_type        = "ecs.n2.small"
  system_disk_category = "cloud_efficiency"
  image_id             = "ubuntu_18_04_64_20G_alibase_20190624.vhd"
  instance_name        = "test_foo"
  vswitch_id = alicloud_vswitch.vsw.id
  internet_max_bandwidth_out = 1
  password = "yourPassword"
}

output "public_ip" {
  value = alicloud_instance.instance.public_ip
}

我们通过一个 main.tf 文件(只需要是 .tf 文件)定义了 ECS(镜像、实例类型)、VPC(CIDR、VPC Name)、安全组等,通过 Terraform 对资源配置参数做解析,调用阿里云 OpenAPI 进行资源校验于创建,同时把整个资源创建状态化到一个 .tf.state 文件中,基于该文件则可以得知资源创建的所有信息,包括资源数量调整,规格调整,实例变更都依赖这种非常重要的文件。

查看结果
$ terraform show

有何感想

我们通过代码完成了基础设施的创建,而且创建出来的资源就是按照我们声明文件中那样描述的那样。这其实就是基础设施即代码的一种技术实现。

基础设施即代码是一种使用新的技术来构建和管理动态基础设施的方式。它把基础设施、工具和服务以及对基础设施的管理本身作为一个软件系统,采纳软件工程实践以结构化的安全的方式来管理对系统的变更。

基础设施即代码有四项关键原则:

  • 再生性:环境中的任何元素可以轻松复制。

  • 一致性:无论何时,创建的环境各个元素的配置是完全相同的。

  • 快速反馈:能够频繁、容易地进行变更,并快速知道变更是否正确。

  • 可见性:所有对环境的变更应该容易理解、可审计、受版本控制。

接下来的章节就具体看看 Terraform 是如何编程、及扩展 Terraform。



Terraform 编程

如果在编写代码时,遇到什么问题,可以在官方网站寻找答案。官方网站是最好的学习资源,没有之一。

文档链接为:https://www.terraform.io/language。接下来就看一个示例。


一个示例

变量定义:

# 列表的例子
variable "list_example" {
    description = "An example of a list in Terraform"
    type = "list"
    default = [1, 2, 3]
}

# 字典的例子
variable "map_example" {
    description = "An example of a map in Terraform"
    type = "map"
    default = {
        key1 = "value1"
        key2 = "value2"
        key3 = "value3"
    }
}

# 如果不指定类型,默认是字符串
variable "server_port" {
    description = "The port the server will use for HTTP requests"
}

一个例子:

$ tree -L 1 .
.
├── madlibs
├── madlibs.tf
├── madlibs.zip
├── templates
├── terraform.tfstate
├── terraform.tfstate.backup
└── terraform.tfvars

2 directories, 5 files

看下 terraform.tfvars 文件的内容:

[root@blog ch03]# cat terraform.tfvars 

words = {
  nouns      = ["army", "panther", "walnuts", "sandwich", "Zeus", "banana", "cat", "jellyfish", "jigsaw", "violin", "milk", "sun"]
  adjectives = ["bitter", "sticky", "thundering", "abundant", "chubby", "grumpy"]
  verbs      = ["run", "dance", "love", "respect", "kicked", "baked"]
  adverbs    = ["delicately", "beautifully", "quickly", "truthfully", "wearily"]
  numbers    = [42, 27, 101, 73, -5, 0]
}

madlibs.tf 文件的内容

[root@blog ch03]# cat madlibs.tf 

terraform {
  required_version = ">= 0.15"
  required_providers {
    random = {
      source  = "hashicorp/random"
      version = "~> 3.0"
    }

    local = {
      source  = "hashicorp/local"
      version = "~> 2.0"
    }

    archive = {
      source  = "hashicorp/archive"
      version = "~> 2.0"
    }
  }
}

variable "words" {
  description = "A word pool to use for Mad Libs"
  type = object({
    nouns      = list(string),
    adjectives = list(string),
    verbs      = list(string),
    adverbs    = list(string),
    numbers    = list(number),
  })

  validation {
    condition     = length(var.words["nouns"]) >= 10
    error_message = "At least 10 nouns must be supplied."
  }
}

variable "num_files" {
  type        = number
  description = "(optional) describe your variable"
  default     = 100
}

locals {
  uppercase_words = { for k, v in var.words : k => [for s in v : upper(s)] }
}

resource "random_shuffle" "random_nouns" {
  count = var.num_files
  input = local.uppercase_words["nouns"]
}

resource "random_shuffle" "random_adjectives" {
  count = var.num_files
  input = local.uppercase_words["adjectives"]
}

resource "random_shuffle" "random_verbs" {
  count = var.num_files
  input = local.uppercase_words["verbs"]
}

resource "random_shuffle" "random_adverbs" {
  count = var.num_files
  input = local.uppercase_words["adverbs"]
}

resource "random_shuffle" "random_numbers" {
  count = var.num_files
  input = local.uppercase_words["numbers"]
}

locals {
  templates = tolist(fileset(path.module, "templates/*.txt"))
}

resource "local_file" "mad_libs" {
  count    = var.num_files
  filename = "madlibs/madlibs-${count.index}.txt"
  content = templatefile(element(local.templates, count.index),
    {
      nouns      = random_shuffle.random_nouns[count.index].result
      adjectives = random_shuffle.random_adjectives[count.index].result
      verbs      = random_shuffle.random_verbs[count.index].result
      adverbs    = random_shuffle.random_adverbs[count.index].result
      numbers    = random_shuffle.random_numbers[count.index].result
  })
}

data "archive_file" "mad_libs" {
  depends_on = [
    local_file.mad_libs
  ]

  type        = "zip"
  source_dir  = "${path.module}/madlibs"

  output_path = "${path.cwd}/madlibs.zip"

}

如何引用变量的值?var.<VARIABLE_NAME>.


注意事项

Terraform 不支持自定义函数。我们只能使用 Terraform 内置的大约 100 个函数进行编程。


Repeat Yourself vs. Don't Repeat Yourself (DRY)

在软件工程中,是不提倡 DRY 的。可是现实中,我们到处可以看到 Ctrl-CCtrl-V 的这样的编程范式(:P)。

下面两个代码示例,哪个更好一点?

48ef6b6288b3a50c0f573e7dd862399b.png98fa9ffb7c7f5c5cfc372dc1dc257c27.png

从上图来看,左边的代码结构是最优的,其符合 DRY 原则;而右边的代码结构则是符合 Ctrl-CCtrl-V 这种模式。针对上述两种场景,我们给出以下建议

  • 当我们的环境没有差异或差异比较小,建议使用左边的代码结构;

  • 当我们的环境差异比较大的时候,就只能选择右边的代码结构了;

接下来我们看看 Terraform 是如何解决上述问题的。


使用 workspace 以复用代码

对于同样的配置文件,workspace 功能允许我们可以有多个状态文件。这就意味着,我们不需要通过复制、粘贴代码,就可以实现多环节部署。每个 workspace 拥有自己的变量及环境信息。如下图所示:

4ff9fa7c562cdbf07892f36e9ab5bcc3.png

我们之前就已经在使用 workspace 了,尽管我们并没有意识到这一点。当执行 terraform init 的时候,Terraform 就已经创建了一个默认的 workspace 并切换到该 workspace 下了。可以验证一下:

[root@blog ch03]# terraform workspace list
* default

多环境部署

接下来我们使用 Terraform 的 workspace 特性进行一个多环境的部署。


一个例子:
[root@blog ch06]# tree .
.
├── environments
│   ├── dev.tfvars
│   └── prod.tfvars
├── main.tf
└── terraform.tfstate.d
    ├── dev
    │   ├── terraform.tfstate
    │   └── terraform.tfstate.backup
    └── prod
        └── terraform.tfstate

4 directories, 6 files
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值