Terraform 介绍

录屏

介绍

terraform 是什么

Terraform是由HashiCorp公司在2014年左右推出的开源资源编排工具, 目前几乎所有的主流云服务商都支持Terraform,包括阿里云、腾讯云、华为云、AWS、Azure、百度云、火山引擎等等。遵循 IaC (基础设施即代码)的理念,编写 Terraform 特定语法的 DSL 配置文件即可轻松部署上百家云厂商的服务。

HashiCorp 目前总共有八款主打产品,囊括了从开发 (Packer, Vagrant)、部署 (Terraform)、安全 (Boundary, Vault)、网络 (Consul)、应用 (Nomad, Waypoint)等各个环节。

解决什么问题

将云资源、服务或者操作步骤以代码的形式定义在模板中,借助编排引擎,实现资源的自动化管理,这就是基础设施即代码(Infrastructure as Code,简称IaC),也是资源编排最高效的实现模式。然而,多种云编排服务带来的是高昂的学习成本、低效的代码复用率和复杂的多云协同工作流程。每一种服务仅限于管理自家的单一云平台上,无法满足对多个云平台,多种层级(如IaaS,PaaS)资源的统一管理,比如AWS CloudFormation。如何解决如上问题,是否可以使用统一的编排工具,共用一套语法实现对多云的统一管理呢?所以这个时候就诞生Terraform,来解决这些问题。

同类型的工具有什么

  • Salt-Stack:自动化编排工具(没有找到火山的module)

  • Ansible:自动化编排工具(没有找到火山的module)

  • AWS CloudFormation: aws 的云资源编排工具,只能在aws 上使用,其他云上无法使用

如何工作

Terraform通过插件调用 target api 在云平台和其他服务上创建和管理资源。

  • 编写配置:编写 Terraform 的配置文件

  • 生成计划:根据配置生成执行计划,进行review

  • 执行:review 通过后执行该计划

核心概念

架构

Terraform本身是基于插件的架构,可扩展性很强,可以方便对Terraform进行扩展。Terraform从逻辑上可以分为两层,核心层(Terraform Core)和插件层(Terraform Provider)。

核心层

核心层其实就是terraform的命令行工具,它是用go语言开发的,它负责:

  1. 读取.tf配置,进行变量替换

  2. 资源状态文件管理

  3. 分析资源关系,绘制图谱

  4. 对于依赖关系图谱的资源,根据依赖关系创建资源;对于没有依赖关系的资源,会并行进行创建(缺省10个并行进程),这也是Terraform能够高效快速管理云资源的原因。

  5. 用RPC调用插件层

插件层

插件层也是由go语言开发的,Terraform有超过250个不同的插件,它们负责:

  • 接受核心层的RPC调用

  • 具体提供某一项服务的执行

插件层又有两种:

Provider

Provider,负责与外界API的集成,比如阿里云Provider就提供了在阿里云创建、修改、删除云资源的功能。这个插件负责和云API的接口交互,并提供一层抽象,这样我们可以在不了解API细节的情况下,通过terraform来编排资源。

常见provider:

ruby 复制代码
火山引擎:https://github.com/volcengine/terraform-provider-volcengine
阿里云: https://github.com/aliyun/terraform-provider-alicloud
百度云:https://github.com/baidubce/terraform-provider-baiducloud
腾讯云:https://github.com/tencentcloudstack/terraform-provider-tencentcloud
华为云:https://github.com/huaweicloud/terraform-provider-huaweicloud
ucloud:https://github.com/ucloud/terraform-provider-ucloud
qingcloud:https://github.com/yunify/terraform-provider-qingcloud
AWS:https://github.com/hashicorp/terraform-provider-aws
Azure:https://github.com/terraform-providers/terraform-provider-azurerm
GoogleCloud:https://github.com/hashicorp/terraform-provider-google

Provisioner

Provisioner,负责在资源创建或者删除完成后,执行一些脚本。比如Puppet Provisioner就可以在云虚拟机资源创建完成后,在该资源上下载、安装、配置Puppet agent。也可以理解为一种hook。

基本用法

安装

terraform 下载路径: developer.hashicorp.com/terraform/d...

在官网下载并解压,然后放到 /usr/local/bin 下即可。

执行 terraform 查看是否安装成功

基本命令介绍

Go 复制代码
主要命令:
  init          初始化工作空间,为其他命令做准备,在这一步也会下载 provider 插件
  validate      验证配置文件是否合法
  plan          生成计划进行review
  apply         执行计划
  destroy       删除之前创建的基础设施

其他命令:
  fmt           格式化配置文件
  get           安装 terraform 模块
  graph         生成Graphviz依赖图,默认为 dot 语言,可以用在线网站查看,也可以安装工具
  providers     打印配置文件中的 providers
  show          打印当前配置下的状态

Global options (use these before the subcommand, if any):
  -chdir=DIR    改变工作目录

快速开始

terraform 相关 demo 参考 : code.byted.org/gaoweizong/...

demo1: 安装 nginx

  1. 环境准备,确保自己本地环境已经安装了 terraform 和 docker ,启动 docker open -a Docker

  2. 创建并进入 learn-terraform-docker-container 目录

Go 复制代码
mkdir learn-terraform-docker-container
cd learn-terraform-docker-container
  1. 编写 terraform 配置文件 main.tf
PlainText 复制代码
terraform { # terraform 配置
  # 详细用法参考官网
  required_providers { # 定义需要的 provider , init 时默认从Terraform Registry 仓库下载安装 
    docker = {
      source  = "kreuzwerker/docker"  # 完整的是 registry.terraform.io/kreuzwerker/docker
      version = "~> 2.13.0"
    }
  }
}

provider "docker" {} # 指定使用 docker provider 创建和管理资源,可以使用多个 provider 配合使用。
# docker 插件相关文档 : docker docs

# resource 可以是物理机、虚拟机、逻辑资源
resource "docker_image" "nginx" { # 格式: resource resource_type resource_name
  # resource_type 的参数
  name         = "nginx:latest"
  keep_locally = false
}

resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  name  = "tutorial"
  ports {
    internal = 80
    external = 8000
  }
}
  1. 初始化项目,这一步会下载 docker 插件,方便与docker 进行交互
Go 复制代码
terraform init
  1. 生成计划,进行review
Go 复制代码
 terraform plan

known after apply: 执行后才能知道。

  1. 执行计划
Go 复制代码
terraform apply
  1. 访问 nginx
  1. 修改资源

可以对配置文件进行修改,修改后重新执行 terraform apply ,修改端口: 8000 -> 8080

SQL 复制代码
resource "docker_container" "nginx" {
  image = docker_image.nginx.latest  
  name  = "tutorial"  hostname = "learn-terraform-docker"  
  ports {    internal = 80
  -   external = 8000
  +   external = 8080  }  # 实际配置只需要把端口改下即可
  }
  
  1. 变量注入

配置文件中可以使用变量,执行时动态注入,适配性更强

  1. 定义变量
Go 复制代码
variable "container_name" { # 可以放在 main.tf 或者一个单独的配置文件中 variables.tf
  description = "Value of the name for the Docker container"
  type        = string
  default     = "ExampleNginxContainer"
}
  1. 使用变量
PlainText 复制代码
resource "docker_container" "nginx" {
  image = docker_image.nginx.latest
  - name  = "tutorial"
  + name  = var.container_name   # 实际配置文件直接替换成这一行
  ports {    
  internal = 80    
  external = 8080  }
  }
  1. 创建资源
Go 复制代码
terraform apply -var "container_name=tutorial_dynamic"
# 也可以通过 -var-file=filename 指定变量,把变量写在单独的文件中,默认的 var-file 是 terraform.tfvars
  1. 数据查询,通过 output 可以更方便的查询和展示数据给用户

定义 output

Go 复制代码
# outputs.tf
output "container_id" {  
    description = "ID of the Docker container"  
    value       = docker_container.nginx.id
}
output "image_id" {  
    description = "ID of the Docker image"  
    value       = docker_image.nginx.id
}
  1. 销毁资源
Go 复制代码
terraform destroy

demo2: 创建火山资源

通过terraform 创建火山资源

参考: code.byted.org/gaoweizong/...

terraform DSL代码的核心概念

在上面的几个例子中,用到了一些资源类型,这里介绍一些核心的类型:

  • data 数据源允许查询或计算一些数据以供其他地方使用。使用数据源可以使得Terraform代码使用在Terraform管理范围之外的一些信息,或者是读取其他Terraform代码保存的状态。

  • resource 资源用于定义基础设施资源对象,一个resource可以定义一个或多个基础设施资源对象,例如VPC、虚拟机,或是DNS记录、Consul的键值对数据等。

  • module 简单来讲模块就是包含一组Terraform代码的文件夹,Terraform模块是编写高质量Terraform代码,提升代码复用性的重要手段,可以说,一个成熟的生产环境应该是由数个可信成熟的模块组装而成的。样例参考: github.com/hashicorp/t...

代码开发

插件开发

参考文档:

插件工作原理

插件开发的sdk

官方提供了两种SDK

  • SDKv2 : 是大多数现有提供商的基础,并继续提供稳定的开发体验。

  • Framework : 是一个新的SDK,围绕Terraform的更新架构重新调整了提供商开发体验和抽象。它代表了Terraform插件开发未来的愿景。

本地插件目录

如果不能从 terraform 仓库下载插件,可以从指定本地路径,路径可以通过在 cli 配置中指定

Go 复制代码
provider_installation {
  filesystem_mirror {
    path    = "/usr/share/terraform/providers"
    include = ["example.com/*/*"]
  }
  direct {
    exclude = ["example.com/*/*"]
  }
}

如果没有配置,则本地插件默认目录为:

  • ~/.terraform.d/plugins/ <math xmlns="http://www.w3.org/1998/Math/MathML"> h o s t _ n a m e / {host\_name}/ </math>host_name/{namespace}/ <math xmlns="http://www.w3.org/1998/Math/MathML"> t y p e / {type}/ </math>type/{version}/${target}

  • %APPDATA%\terraform.d\plugins\ <math xmlns="http://www.w3.org/1998/Math/MathML"> h o s t _ n a m e / {host\_name}/ </math>host_name/{namespace}/ <math xmlns="http://www.w3.org/1998/Math/MathML"> t y p e / {type}/ </math>type/{version}/${target}

本地插件工作原理解析

这里用 terraform 官方 demo 进行演示,假设环境中已经安装了 docker & docker_compose

参考: developer.hashicorp.com/terraform/t...

  1. 本地启动HashiCups provider 后端服务(类似于 阿里云/火山云的后端接口)

  2. 创建 HashiCups user (上一步启动好服务,这一步做鉴权)

  3. 安装HashiCups provider 插件(类似于 实现插件,这里直接用官方实现好的插件)

  4. 编写 terraform 文件

  5. 执行

Shell 复制代码
terraform init
terraform apply
...

如何开发一个插件

开发插件的原因可能有:

  • 对于内部云,没有现成的 provider ,如火山私有云 ?

  • 扩展已有 provider 的能力

插件开发demo 仓库: github.com/hashicorp/t...

  1. 环境准备,克隆脚手架代码

  2. 启动 hashicups 实例,模拟服务端(开发真实插件这一步不是必须的,通常由云厂商提供)

  3. 定义 data 资源,按照terraform惯例,文件名字需要以 data_source_ 开头,

在本 demo 中 返回的数据为:

Shell 复制代码
curl localhost:19090/coffees
[
    {
        "id": 1,
        "name": "Packer Spiced Latte",
        "teaser": "Packed with goodness to spice up your images",
        "description": "",
        "price": 350,
        "image": "/packer.png",
        "ingredients": [
            {
                "ingredient_id": 1
            },
            {
                "ingredient_id": 2
            },
            {
                "ingredient_id": 4
            }
        ]
    }, ## ...
]

则定义的 schema 为:

Go 复制代码
// hashicups/data_source_coffee.go
Schema: map[string]*schema.Schema{
  "coffees": &schema.Schema{
    Type:     schema.TypeList,
    Computed: true,
    Elem: &schema.Resource{
      Schema: map[string]*schema.Schema{
        "id": &schema.Schema{
          Type:     schema.TypeInt,
          Computed: true,
        },
        "name": &schema.Schema{
          Type:     schema.TypeString,
          Computed: true,
        },
        "teaser": &schema.Schema{
          Type:     schema.TypeString,
          Computed: true,
        },
        "description": &schema.Schema{
          Type:     schema.TypeString,
          Computed: true,
        },
        "price": &schema.Schema{
          Type:     schema.TypeInt,
          Computed: true,
        },
        "image": &schema.Schema{
          Type:     schema.TypeString,
          Computed: true,
        },
        "ingredients": &schema.Schema{
          Type:     schema.TypeList,
          Computed: true,
          Elem: &schema.Resource{
            Schema: map[string]*schema.Schema{
              "ingredient_id": &schema.Schema{
                Type:     schema.TypeInt,
                Computed: true,
              },
            },
          },
        },
      },
    },
  },
},
  1. 实现查询方法

  2. 在 provider 增加刚刚定义的 datasource

  3. 测试 provider

  4. 给 provider 增加身份认证

  5. 实现CRUD,以订单为例

优势与不足

优势

  • 基础架构即代码:基础架构是使用高级配置语法描述的。这允许对数据中心的蓝图进行版本化和处理,就像对任何其他代码一样。此外,基础架构可以共享和重用。

  • 执行计划:Terraform有一个"计划"步骤,它会生成执行计划。执行计划显示了Terraform在我们调用应用时会做什么。这可以让我们在Terraform操作基础架构时避免任何意外。

  • 资源图:Terraform构建所有资源的图,并并行化任何非依赖资源的创建和修改。正因为如此,Terraform尽可能高效地构建基础架构,操作员可以深入了解其基础架构中的依赖关系。

  • 变更自动化:复杂的变更集可以应用到我们的基础架构中,只需最少的人工交互。通过前面提到的执行计划和资源图,我们可以准确地知道Terraform将更改什么以及以什么顺序更改,避免了许多可能的人为错误。

  • 对多云进行管理。

不足

  • Terraform被设计成声明式而非命令式,例如没有常见的if条件语句,后来才加上了count和for_each实现的循环语句(但循环的次数必须是在plan阶段就能够确认的,无法根据其他resource的输出动态决定)

参考

相关推荐
ZQDesigned12 小时前
在 Windows 和 macOS 上配置 Golang 语言环境
后端·go
煎鱼eddycjy2 天前
新提案:由迭代器启发的 Go 错误函数处理
go
煎鱼eddycjy2 天前
Go 语言十五周年!权力交接、回顾与展望
go
不爱说话郭德纲2 天前
聚焦 Go 语言框架,探索创新实践过程
go·编程语言
0x派大星4 天前
【Golang】——Gin 框架中的 API 请求处理与 JSON 数据绑定
开发语言·后端·golang·go·json·gin
IT书架4 天前
golang高频面试真题
面试·go
郝同学的测开笔记4 天前
云原生探索系列(十四):Go 语言panic、defer以及recover函数
后端·云原生·go
秋落风声5 天前
【滑动窗口入门篇】
java·算法·leetcode·go·哈希表
0x派大星6 天前
【Golang】——Gin 框架中的模板渲染详解
开发语言·后端·golang·go·gin
0x派大星7 天前
【Golang】——Gin 框架中的表单处理与数据绑定
开发语言·后端·golang·go·gin