0.写在前面:
在云巧资产市场中对项目进行交付过程中,能够快速复用已有组件和一键部署组件一直是我们追求的目标(关于云巧相关的理念可移步了解云巧 详细了解),因此以IaC理念出圈的Terraform,成为关注的重点。
本文将介绍Terraform核心理念并结合运行demo完成对Terraform的探索和初级实践,为后续云巧市场更好的交付奠定基础。
1.Terraform介绍:
1.1 IAC
Infrastructure As Code(IaC)基础设施即代码(IaC)是通过机器可读的定义文件来管理和置备基础设施的过程。IaC通过定义可以版本化、重用和共享的资源配置,允许您以安全、一致和可重复的方式构建、更改和管理基础架构。
tips:“基础设施”这个词汇稍微有点拗口,不是很直观。其实它就是指系统或应用所依赖的环境,如服务器,数据库等,在云上,环境由各个云产品资源(简称云资源)组成,如服务器ECS,数据库RDS,负载均衡SLB。从技术上讲,任何能够通过API进行控制的东西都可以算作基础设施。
1.2 什么是Terraform?
Terraform 是一种安全有效地构建、更改和版本控制基础设施的工具(基础架构自动化的编排工具)。它的目标是 "Write, Plan, and create Infrastructure as Code", 基础架构即代码。具体的说就是可以用代码来管理维护 IT 资源,把之前需要手动操作的一部分任务通过程序来自动化的完成,这样的做的结果非常明显:高效、不易出错。
Terraform 是用 Go 语言开发的开源项目,可以在 github上访问到它的源代码。
常见的使用场景如下:
Terraform可以对基础设施进行编码,利用代码对IT资源实现增删查改:
-
创建基础设施:如支持创建和管理ECS、RDS、Redis、OSS等;
1.3 Terraform的优势
-
管理多个云平台上的基础设施:Terraform适用于多类型云方案,将相类似的基础结构部署到阿里云、其他云提供商或者本地数据中心。开发人员能够使用相同的工具和相似的配置文件同时管理不同云提供商的资源。减少了升级或修改服务和基础设施的复杂性。
-
自动标准化配置:Terraform提供可读的配置语言,能够创建配置文件的模板,以可重复、可预测的方式定义、预配和配置ECS资源,减少因人为因素导致的部署和管理错误。能够多次部署同一模板,创建相同的开发、测试和生产环境(幂等、支持失败重试)。(可使用Terraform Registry中的公共模块,也可以自定义模块)
-
资源状态可见:Terraform支持跟踪整个部署过程中的资源变化。
-
版本控制:配置文件支持版本控制,可以 创建可应用的增量执行计划。 与其他人在基础架构上安全协作,降低开发成本。
1.4 Terraform核心概念
-
Configuration:基础设施的定义和描述
IaC,其中的Code就是对基础设施资源的代码定义和描述,也就是通过代码表达我们想要管理的资源。举个如下:
# VPC 资源
resource "alicloud_vpc" "vpc" {
name = "tf_vpc"
cidr_block = "172.16.0.0/16"
}
# VSwitch 资源
resource "alicloud_vswitch" "vswitch" {
vpc_id = alicloud_vpc.vpc.id
cidr_block = "172.16.1.0/24"
availability_zone = "cn-beijing-a"
}
对所有资源的代码描述都需要定义在一个以 tf 结尾的文件用于Terraform加载和解析,这个文件我们称之为“Terraform模板”或者“Configuration”。
-
Provider :基础设施管理组件,是一个与Open API直接交互的后端驱动,Terraform 就是通过Provider来完成对基础设施资源的管理的。目前支持的provider有160种以上,如aliyun的provider是 alicloud 。具体可查: 官方provider手册 ,
-
Resource :基础设施资源和服务的管理,定义具体资源的属性
-
Data Source :基础设施资源和服务的查询
通过data关键词声明,如下所示,ECS Instance 没有指定镜像ImageID,而是通过 data引用,Terraform运行时将首先根据镜像名称前缀选择系统镜像,如果同时有多个镜像满足条件,则选择最新的镜像。
// Images data source for image_id
data "alicloud_images" "default" {
most_recent = true
owners = "system"
name_regex = "^ubuntu_18.*_64"
}
resource "alicloud_instance" "web" {
image_id = data.alicloud_images.default.images[0].id
instance_name = "my-first-vm"
system_disk_category = "cloud_ssd"
...
}
-
State :保存资源关系及其属性文件的数据库
Terraform创建和管理的所有资源都会保存到自己的数据库上,这个数据库不是通常意义上的数据库(MySQL,Redis等),而是一个文件名为 terraform.tfstate 的文件,在Terraform 中称之为 state,默认存放在执行Terraform命令的本地目录下。这个 state 文件非常重要,如果该文件损坏,Terraform 将认为已创建的资源被破坏或者需要重建(实际的云资源通常不会受到影响),因为在执行Terraform命令是,Terraform将会利用该文件与当前目录下的模板做Diff比较,如果出现不一致,Terraform将按照模板中的定义重新创建或者修改已有资源,直到没有Diff,因此可以认为Terraform是一个有状态服务。
当涉及多人协作时不仅需要拷贝模板,还需要拷贝 state 文件,这无形中增加了维护成本。幸运的是,目前Terraform支持把 state 文件放到远端的存储服务 OSS 上或者 consul 上,来实现 state 文件和模板代码的分离。具体细节可参考官方文档Remote State
-
Provisioner: 在机器上执行操作的组件
Provisioner通常用来在本地机器或者登陆远程主机执行相关的操作,如 local-exec provisioner 用来执行本地的命令, chef provisioner 用来在远程机器安装,配置和执行chef client, remote-exec provisioner 用来登录远程主机并在其上执行命令。
Provisioner 通常跟 Provider一起配合使用,provider用来创建和管理资源,provisioner在创建好的机器上执行各种操作。
1.5 terraform工作流:
Terraform核心工作流包括三个阶段:
-
write:即定义资源(在以.tf配置文件中定义和预编排依赖资源,用于Terraform加载和解析,这个文件称之为“Terraform模板”或者“Configuration”。),这些资源可以是横跨多个云提供商和服务。
-
通过丰富的 Providers 来管理多种类型的资源,像是插件一样,如GCP、Docker、Kubernetes等。
-
plan:是Terraform创建的一个执行计划,描述它将基于现有基础设施和配置文件进行创建、更新或销毁基础设施。
-
apply:在确认执行计划后,Terraform将按照正确的顺序执行预定义操作,并保持任何资源之前的依赖性。例如,如果更新VPC的属性并需要更改该VPC中的虚拟机数量,那么Terraform将在缩放虚拟机之前重新创建VPC。
阿里云目前已经提供了超过 163 个 Resource 和 113 个 Data Source,覆盖计算,存储,网络,负载均衡,CDN,容器服务,中间件,访问控制,数据库等超过35款产品,已经满足了大量大客户的自动化上云需求。支持资源类型见:https://help.aliyun.com/document_detail/335111.html
2. 实践demo
2.1 实验一:入门demo
实验目标:
本地安装terraform,并在本地docker上部署nginx服务器,熟悉Terraform工作机制和部署流程
实验过程:
本地环境:
-
系统版本:macOS 11.5.1
-
内核版本:Darwin 20.6.0
操作过程:
Step1:本地安装terraform:
-
安装hashicorp/tap基础依赖包
brew tap hashicorp/tap
-
安装terraform:
brew install hashicorp/tap/terraform
安装成功后,可查看terraform对应的版本:
说明:存在待升级版本时,可通过以下直接升级版本:
Step2:本地Docker下创建一个nginx集群:
-
启动本地docker
open -a Docker
-
创建项目目录 /terraform-work-dir
-
编写执行脚本.tf文件:
terraform {
required_providers {
docker = {
source = "kreuzwerker/docker"
}
}
}
provider "docker" {}
resource "docker_image" "nginx" {
name = "nginx:latest"
keep_locally = false
}
resource "docker_container" "nginx" {
image = docker_image.nginx.latest
name = "tutorial"
ports {
internal = 80
external = 8000
}
}
执行脚本组成:
-
terraform: Terraform设置
-
required_providers:包括Terraform将用于提供的基础设施所需的来源和版本。
-
source:属性定义了一个可选的主机名,命令空间和提供者类型。默认情况下,Terraform从Terraform Registry安装提供程序。例子中,docker提供程序的源定义为kreuzwerker/docker,其实是registry.terraform.io/kreuzwerker/docker 的简写方式。
-
version:是提供程序的版本,可选配置,默认Terraform下载最新版本。
-
-
provider: 基础设施管理组件, 是一个与Open API直接交互的后端驱动 ,本例中为docker。可以配置多个。里面可以用来配置一些信息,比如token,access_token,username,password等信息。
-
resource: 定义基础架构的组件 。可以是物理或者虚拟组件。格式为 resource “资源类型” “资源名称” { },本例中的docker_image 为资源类型,nginx为资源名称。类型的前缀映射到提供者的名称。本例中是docker_image使用的docker提供程序管理资源。资源类型和资源名称共同组成了资源的唯一ID,例如你的docker镜像id就是docker_image.nginx。resource主要用于配置资源的参数,可以是机器大小,VPC ID 等内容。比如我们的docker_container设置镜像源。
-
执行命令:terraform init。初始化项目,下载脚本中定义的Docker依赖的provider
初始化命令执行成功后,配置文件指定的provider则下载成功:
-
执行 terraform plan 查看当前执行计划资源变更预览:
6. 执行terraform apply,
确认后开始创建nginx镜像:
8. terraform show :资源的展示——用于展示当前state中所有被管理的资源及其所有属性值。
9. terraform destroy:用于对资源的释放操作,为了安全起见,在命令执行过程中,也增加了人工交互的过程,如果想要跳过手动确认操作,可以通过--force参数来跳过
注:其他资源常用管理命令见文档附件
2.2 实验二:在阿里云创建RDS实例并初始化数据库
实验目标:
在本地模拟项目初始化创建RDS实例并完成初始化数据库,实现一键初始化依赖资源。
实验过程:
前提条件,创建有数据库管理权限的阿里云账号,参考:创建阿里云RAM账号
Step1:write tf脚本
terraform {
required_providers {
alicloud={
source="aliyun/alicloud"
}
}
}
provider "alicloud" {
access_key = "${var.access_key}"
secret_key = "${var.secret_key}"
region = "${var.region}"
}
resource "alicloud_vpc" "main" {
vpc_name = "alicloud"
cidr_block = "10.1.0.0/24"
}
resource "alicloud_vswitch" "main" {
vpc_id = alicloud_vpc.main.id
cidr_block = "10.1.0.0/24"
zone_id = "cn-hangzhou-b"
depends_on = [alicloud_vpc.main]
}
resource "alicloud_db_instance" "instance" {
engine = "MySQL"
engine_version = "5.6"
instance_type = "rds.mysql.t1.small"
instance_storage = "10"
vswitch_id = alicloud_vswitch.main.id
security_ips = ["X.X.X.X"]
}
resource "alicloud_db_account" "account" {
db_instance_id = alicloud_db_instance.instance.id
account_name = "tf_account_rds"
account_password = "XXXX"
}
resource "alicloud_db_database" "db" {
instance_id = alicloud_db_instance.instance.id
name = "tf_database"
}
resource "alicloud_db_account_privilege" "privilege" {
instance_id = alicloud_db_instance.instance.id
account_name = alicloud_db_account.account.account_name
privilege = "ReadWrite"
db_names = [alicloud_db_database.db.name]
}
resource "alicloud_db_connection" "connection" {
instance_id = alicloud_db_instance.instance.id
connection_prefix = "tf-example"
}
resource "null_resource" "init_db" {
depends_on = [alicloud_db_database.db]
provisioner "local-exec" {
command = "mysql -u${alicloud_db_account.account.account_name} -p${alicloud_db_account.account.account_password} -h${alicloud_db_connection.connection.connection_prefix}.mysql.rds.aliyuncs.com -P3306 -D${alicloud_db_database.db.name} < testCreateTable.sql"
}
}
以上脚本的核心逻辑是:
-
指定provider:aliyun/alicloud
-
设置alicloud关键参数,主要与权限和指定部署的地域相关
-
创建专有网络vpc
-
创建交换机
-
创建数据库实例,并设置ip白名单(为连接数据库,远程直接执行初始化数据库脚本做准备,默认白名单为空,不支持远程连接)
-
创建数据库访问用户,设置账号和密码
-
创建数据库,设置数据库名称
-
为指定数据库账号授权
-
设置数据库公网连接地址
-
执行数据库初始化脚本
在项目执行目录下,除了执行主脚本外,还需要参数文件var.tf和数据库初始化脚本testCreateTable.sql。
准备好文件后,开始运行Terraform实现一键创建和初始化
Step2:远程操作创建数据库实例和初始化数据库
-
执行terraform init,工作目录下的文件如下:
-
执行terraform plan,可以看到要创建的执行计划:
-
执行terraform apply,开始进行创建和初始化
执行成功后,可在远程查看创建成功的数据库实例:
创建的数据库:
初始化完成的数据库:
至此,完成通过Terraform一键创建和初始化阿里云RDS数据库。
3.小结
本文仅是完成Terrafrom的入门学习,了解了什么是Terrafrom和其适用的场景,并通过两个demo了解Terraform的工作机制和核心工作流。从中学习到的IaC理念与当前项目中亟待解决的一键部署问题有可匹配的地方,但要将其与云巧资产市场相互结合,并能够兼容目前的场景,还需要进一步探索,寻求更合适的方案进行结合。
不积硅步无以至千里,万里长城已开启第一步,胜利的日子还会远吗?
附件:
terraform 初始化优化:
terraform init初始化是加载依赖的plugin 可以把所有插件都放在同一个地方,然后通过-plugin-dir来指定,如下:
terraform init -plugin-dir={terraformm-plugin-path}
terraform 常用的资源管理命令:
-
terraform import:资源的导入 import命令用于将存量的云资源导入到terraform state中,进而加入到Terraform的管理体系中
-
terraform taint:标记资源为被污染 taint命令用于把某个资源标记为被污染状态,当再次执行apply命令时,这个被污染的资源将会被先释放,然后再创建一个新的,相当于对这个特定资源做了先删除后新建的操作。 命令的详细格式为: terraform taint <资源类型>.<资源名称> ,如:
terraform taint bigip_ltm_pool_attachment.attach_nodeqat01Resource instance bigip_ltm_pool_attachment.attach_nodeqat01 has been marked as tainted.
-
terraform untaint:取消被污染标记 untaint命令是taint的逆向操作,用于取消被污染标记,使其恢复到正常的状态。命令的详细格式和taint类似为:terraform untaint <资源类型>.<资源名称> ,如:
terraform untaint untaint bigip_ltm_pool_attachment.attach_nodeqat01Resource instance bigip_ltm_pool_attachment.attach_nodeqat01 has been successfully untainted.
-
terraform output:打印出参及其值 如果在模板中显示定义了output参数,那么这个output的值将在apply命令之后展示,但plan命令并不会展示,如果想随时随地快速查看output的值,可以直接运行命令 terraform output Terraform对资源状态的管理,实际上是对State文件中数据的管理。State文件保存了当前Terraform管理的所有资源及其属性,内容都是由Terraform自动存储的,为了保证数据的完整性,不建议手动修改State内容。对State数据的操作可以通过terraform state命令来完成。
-
terraform state list:列出当前state中的所有资源 state list命令会按照 <资源类型>.<资源名称> 的格式列出当前state中存在的所有资源(包括datasource),例如:
terraform state listdata.alicloud_slbs.defaultalicloud_vpc.defaultalicloud_vswitch.this
-
terraform state show:展示某一个资源的属性 state show命令按照Key-Value的格式展示出特定资源的所有属性及其值,命令的完整格式为 terraformstate show <资源类型>.<资源名称>
-
terraform graph:输出当前模板定义的资源关系图
该命令的结果还可以通过命令terraform graph | dot -Tsvg > graph.svg直接导出为一张图片(需要提前安装graphviz: brew install graphviz):
阿里云常用资源指导手册:
参考资料:
若有收获,就点个赞吧