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的输出动态决定)

参考

相关推荐
幼儿园老大*2 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
童先生9 小时前
Go 项目中实现类似 Java Shiro 的权限控制中间件?
开发语言·go
幼儿园老大*11 小时前
走进 Go 语言基础语法
开发语言·后端·学习·golang·go
架构师那点事儿16 小时前
golang 用unsafe 无所畏惧,但使用不得到会panic
架构·go·掘金技术征文
于顾而言1 天前
【笔记】Go Coding In Go Way
后端·go
qq_172805591 天前
GIN 反向代理功能
后端·golang·go
follycat2 天前
2024强网杯Proxy
网络·学习·网络安全·go
OT.Ter2 天前
【力扣打卡系列】单调栈
算法·leetcode·职场和发展·go·单调栈
探索云原生2 天前
GPU 环境搭建指南:如何在裸机、Docker、K8s 等环境中使用 GPU
ai·云原生·kubernetes·go·gpu
OT.Ter2 天前
【力扣打卡系列】移动零(双指针)
算法·leetcode·职场和发展·go