App Deploy as Code! SAE & Terraform 实现 IaC 式部署应用
作者:宋阳(流鑫)
企业上云是近些年的发展热潮,越来越多的企业把自己的应用部署在各个云厂商中,利用云计算带来的弹性、灵活、安全、低成本等特性,轻松帮助企业搭建自己的应用。
随着企业规模和业务形态的发展,一个应用需要组合多种云资源才能对外提供服务,为了便于研发人员开发调试,每种应用都需要部署到多套环境,单纯通过人工手动管理云资源的方式会使得基础设施管理人员的负担不断加重。
因此越来越多的企业选择使用代码(而非手动流程)来定义基础设施,即 IaC(Infrastructure as Code),像对待应用软件一样对待基础设施,这样不仅能够免去繁杂的人工操作还可以利用代码配置原生带来的版本化和抽象化等能力。
在云计算的时代下,应用的部署往往会依赖多个基础设施(计算、存储、网络)。企业内部往往需要一个 PaaS 平台来交付自己的应用,但是 PaaS 平台的开发和维护需要企业有较大的技术和人力投入。对于快速发展的企业更希望能够把精力专注于企业的核心业务。
阿里云 Serverless 应用引擎 SAE(Serverless App Engine)是一个面向应用的 Serverless PaaS 平台,天然支持通过 IaC 的方式来创建和管理,而 Terraform 作为 IaC 领域的事实标准,已成为了企业 IaC 管理的首选工具,将 Terraform 和 SAE 组合会发生一些奇妙的化学反应,企业可以以一种 ADaC(Application Deploy as Code)的方式,通过简单的代码配置文件管理企业的应用。
下面,我们简单的介绍 IaC 和 SAE 给企业带来的巨大便利,并通过一个使用 Terraform 创建 SAE 应用的例子感受 SAE & Terraform 给传统企业 IT 设施管理带来的降维打击。
基础设施即代码
企业基础设施管理发展历程
应用能够正常对外服务需要依赖计算、存储、网络等基础资源。他们是应用正常运行的基础上下文。这些资源也称为环境基础设施。在传统的管理模式下,大多数公司都会有专门的运维团队来管理自己的正式生产和测试环境。随着业务的升级和公司规模的增长,运维团队在基础资源管理上会经历大概 3 个阶段:
-
手工运维:在企业发展初期,企业的业务种类和规模都处于起步阶段,而且基础环境属于变更频率相对很低的资源,运维团队往往通过人工管理就可以搭建起服务所需的基础资源,使用云服务的企业在云厂商的控制台通过鼠标操作就可以完成云资源的创建。这一阶段研发人员基础设施需求很低,运维人员通过手工运维就能满足。
-
运维操作脚本化:伴随企业规模和业务的发展,运维团队会接收到越来越多的环境创建请求,大部分运维团队的成员为了提升环境创建效率会自发的编写规范化的文档和脚本,或者通过 CLI 来辅助资源的创建,但是因为一个服务往往需要多种基础设施资源配合才能正常对外提供服务,脚本还无法简单的处理不同基础设施之间的依赖关系,这一段运维人员创建环境会逐步变成一个繁琐且低效的工作。
-
基础设施即代码:手工运维和文档脚本化已经极大的影响开发效率。企业会逐步把基础设施抽象成代码,用管理代码的方式配置基础设施,对环境基础设施可以像对待代码一样进行版本控制和回滚,而且多个环境之间可以复用相同的代码模块,实现环境基础设施的快速交付。
Terraform 应运而生
2014 年,HashiCorp 公司推出了产品 Terraform,它是一个可以安全、高效地建立,变更以及版本化管理基础设施的工具,时至今日 Terraform 绝对是 IaC 领域的王者。使用 Terraform 管理企业基础设施可以给企业带来多种好处:
-
使用声明式的 IaC 管理基础设施:声明式的描述能够保证即使代码执行多次也能达到一致的状态,使用代码来描述基础资源,能够更加形象直接的展示出不同环境之间的差异。不论什么环境出现问题,都能快速的复刻出一个新的环境。
-
丰富的 modules 生态:几乎包含所有云厂商的云资源,使用者可以在官方维护的模块仓库 Terraform Registry 中使用各种官方和社区提供的高质量模块。让使用者不用再重复编写其他云厂商的模块,利用开源社区的能力,不断完善和壮大 Terraform 生态。
-
资源依赖管理:Terraform 会根据模板中的定义,构建所有资源的 DAG 拓扑关系图。对于有依赖资源的资源,会根据依赖关系有序执行,对于没有任何依赖关系的资源会以并行的方式创建以保证执行的高效性。
云计算时代下的企业应用部署
应用的部署往往会涉及到 VPC 网络管理和划分,虚拟机的创建,通过负载均衡暴露应用的服务地址。在微服务架构盛行的今天,企业还需要部署和运维一些微服务组件,以提供服务发现、配置管理、无损上下线等功能保证应用能够提供稳定不断流的服务。为了能够监控应用的运行状态,通过 Trace、Metrics、Logs 等信息来了解应用健康状态是必不可少的部分。
一个健康的应用需要组合一系列基础设施的能力,每个应用的测试和上线都会耗费研发和运维管理人员大量的精力。其实不难发现,每个应用的依赖资源都存在相似的地方,很多差异性只表现在一些配置项上。
如果一个产品能够组合这些基础设施的能力,对外提供应用的概念,研发人员只需要关心业务代码的编写,运维管理人员也不需要管理和维护大量的基础设施,企业研发效率会有极致的提升。
阿里云提供的 Serverless 应用引擎 SAE 就是这样一个降低企业 IT 人员心智的产品。
SAE 是面向应用的 Serverless PaaS 平台,能够帮助 PaaS 层用户免运维 IaaS、按需使用、按量计费,做到低门槛微服务应用上云。相对于其他 Serverless 产品,它将应用的概念抽象化,帮助企业屏蔽了大量的基础设施的创建和管理,并提供了一整套微服务解决方案,支持 Spring Cloud、Dubbo、HSF 等主流的微服务开发框架,实现了 Serverless 架构和微服务架构的完美结合。
SAE 提供了保姆级的托管服务,研发人员只需要提供一个编译好的 JAR 包或者 WAR 包,就能够部署一个拥有全套微服务体验的应用,基础设施管理人员的也无需管理大量的基础设施。
SAE&Terraform,应用即代码
现在你可以通过 Terraform 来创建和管理 SAE 上的应用,结合 Terraform IaC 和 SAE 以应用为中心的能力,这样企业就能将应用的全部配置代码化,轻松描述和管理应用,当因为人为或者其他意外因素导致应用处于不健康或者不可用的状态,我们可以快速的复刻出一个相同的应用来把影响最小化。
Terraform 通过声明式的 HCL 语言来描述基础设施,程序员告诉 Terraform 我期望获取的资源状态,剩下的事情就交由 Terraform 来创建即可。不过 Terraform 不关心创建出的应用的运行状态。运行在 Terraform 创建出资源的服务的正常运行需要研发人员来保证。SAE 底层基于 Kubernetes,利用 Kubernetes 声明式的能力,SAE 能够保证应用服务一直保持声明的状态,正常的对外提供服务。Terraform 结合 SAE 更好的发挥了应用资源声明式描述的能力。
下面,请跟上我们的步伐,一起来感受 IaC 的魅力。
准备工作
本节为你演示如何利用 Terraform 的 IaC 和依赖管理能力,快速拉起不同环境的应用以及组合 SAE 和其他云资源来构建你的应用。
开始之前,我们先把演示相关的代码克隆到本地:
git clone git@github.com:yangsoon/terraform-sae.git
把创建云资源必要的 AK,SK 暴露到环境变量中。( Terraform 创建云资源的时候会使用环境变量中指定 AK 和 SK 创建云资源)。
export ALICLOUD_ACCESS_KEY=(your access key id)
export ALICLOUD_SECRET_KEY=(your secret access key)
快速创建多环境应用
进入到项目的根目录并简单看下项目的目录结构。modules 文件夹包含了封装好的环境基础设施模块,包括使用阿里云 SLB 实现负载均衡和外网访问能力的 lb,提供专有网络的 network 模块,webserver 模块对阿里云 SAE 资源进行了进一步封装,方便用户在不同环境创建应用时,能够直接复用,减少不必要的代码拷贝。
stage 和 prod 分别存储企业在预发环境和生产环境的资源配置。预发环境和生产环境的环境基础设施存在较大的差异,并且生产环境的资源配置有更高的安全需求,为了防止误操作导致生产环境的资源被损坏,我们通过文件布局进行隔离。
打开 ./stage/webserver/main.tf 文件,可以看到在预发环境我们指定使用 webserver 组件创建应用。
module "network" {
source = "../../modules/network"
vpc_name = var.vpc_name
}
module "webserver" {
source = "../../modules/webserver"
sg_id = module.network.SG_ID
vpc_id = module.network.VPC_ID
vswitch_id = module.network.VSWITCH_ID
app_name = var.app_name
image_url = var.image_url
namespace_name = var.namespace_name
namespace_id = var.namespace_id
}
在 ./stage/webserver/vars.tf 中填入预发环境对应的应用名称和镜像地址(这里以 nginx 为例)。
variable "app_name" {
description = "The name of the application"
type = string
default = "webserver-stage"
}
variable "image_url" {
description = "The image of the application"
type = string
default = "nginx:stable"
}
下面,我们就利用 Terraform 快速构建一个预发环境.
- 进入到 ./stage/webserver 文件夹,初始化 Terraform 工作区
cd terraform-sae/stage/webserver
terraform init
该步骤会帮你初始化 Terraform 子模块已经安装必要的插件,执行成功后显示如下所示信息
- 查看预发环境会创建出的资源类型和个数
terraform plan
执行 terraform plan 之后输出内容较多,这里就截取了部分信息,可以看到预发环境会创建 6 个资源,输出结果会显示新创建的资源的具体配置信息。
- 确认无误之后,我们开始创建预发环境所需的资源。
terraform apply
terraform apply 会再次为你展示本次执行会创建出的资源信息,确认无误之后,输入 yes,这时候 Terraform 才会真正的为你创建资源。
这里稍等一段时间,等待资源创建完成,你可以登录阿里云控制台查看刚刚创建的应用。
等一系列调试测试验证通过之后,可以继续创建生产环境的资源。
打开 ./prod/webserver/main.tf 文件,可以看到我们可以直接复用 webserver 模块,并修改一些应用名称和应用镜像为生产环境相关的配置即可,除此之外,我们新建了一个 SLB,允许应用能够被外界访问。下面我们继续创建生产环境的应用。
module "lb" {
source = "../../modules/lb"
slb_name = var.app_name
address_type = "internet"
vswitch_id = module.network.VSWITCH_ID
}
resource "alicloud_sae_load_balancer_internet" "example" {
app_id = module.webserver.app_id
internet_slb_id = module.lb.slb_id
internet {
protocol = "HTTP"
port = var.port
target_port = 80
}
}
module "webserver" {
source = "../../modules/webserver"
sg_id = module.network.SG_ID
vpc_id = module.network.VPC_ID
vswitch_id = module.network.VSWITCH_ID
app_name = var.app_name
image_url = var.image_url
namespace_name = var.namespace_name
namespace_id = var.namespace_id
}
修改./prod/webserver/vars.tf 中填入生产环境对应的应用名称和镜像地址等信息。
- 进入到 ./prod/webserver 文件夹,初始化 Terraform 工作区
cd terraform-sae/prod/webserver
terraform init
- 查看生产环境会创建出的资源类型和个数
terraform plan
这里生产环境会多创建 2 个和 SLB 相关的资源。
- 确认无误之后,我们开始创建生产环境所需的资源。
terraform apply
等待一段时间后,我们创建了一个外网可以访问的应用。输出结果里包含了我们可以访问的外网地址。请求该地址,可以看到一个 nginx 服务器已经搭建成功。
至此,我们利用 Terraform 的能力快速创建了多环境应用。
使用 Terraform 依赖管理能力高效组合 SAE 和其他云资源
SAE 在 Terraform 生态下还有更高阶的玩法,你可以任意组合其他云资源。以 RDS 为例,你可以把 RDS 的一些连接信息以环境变量的形式注入到 SAE 应用中,应用启动之后可以通过环境变量的信息连接到目标数据库。
打开 ./prod/webserver-with-db/main.tf,我们引入了 mysql 模块帮我们创建一个阿里云 RDS 实例,创建 RDS 之后的数据库连接信息,以环境变量的形式注入了 SAE 应用中。
module "mysql" {
source = "../../modules/mysql"
databases = [
{
"name" : "sae-demo",
"character_set" : "utf8",
"description" : "sae demo database"
},
]
rds_instance_name = var.rds_instance_name
rds_account_name = var.rds_account_name
rds_password = var.rds_password
}
module "webserver" {
source = "../../modules/webserver"
sg_id = module.network.SG_ID
vpc_id = module.network.VPC_ID
vswitch_id = module.network.VSWITCH_ID
app_name = var.app_name
image_url = var.image_url
namespace_name = var.namespace_name
namespace_id = var.namespace_id
envs = [{
name = "DB_HOST"
value = module.mysql.DB_HOST
}, {
name = "DB_PORT"
value = module.mysql.DB_PORT
}, {
name = "DB_PASSWORD"
value = module.mysql.DB_PASSWORD
}, {
name = "DATABASE_NAME"
value = module.mysql.DATABASE_NAME
}]
}
下面我们演示一下创建一个使用 RDS 作为数据存储的应用。
- 和之前 2 个例子类似,我们进入到 terraform-sae/prod/webserver-with-db 目录下,执行工作空间初始化工作。
cd terraform-sae/prod/webserver-with-db
terraform init
- 开始创建资源
terraform apply
资源创建完成之后,会输出数据库的公网范围地址。
- 检查 SAE 应用中的环境变量
可以看到创建出的 RDS 的连接信息已经被配置到了环境变量中。
执行完 Demo 指令创建云资源后,为了避免不必要的扣费,记得及时销毁创建的演示资源。
$ cd terraform-sae/stage/webserver && terraform destroy
$ cd terraform-sae/prod/webserver && terraform destroy
$ cd terraform-sae/prod/webserver-with-db && terraform destroy
总结
SAE 和 Terraform 的结合,能够帮助企业像处理代码一样管理自己的应用,对资源的操作都变得可审计,可追溯,可回滚,同时也降低人为操作带来的风险。而 SAE 将应用的概念抽象化,帮助企业屏蔽了大量的环境基础设施的创建和管理,降低了用户使用门槛,助力企业快速上云。
参考文献
[1] Yevgeniy Brikman.《Terraform: Up & Running: Writing Infrastructure as Code》.O'Reilly Media
[2] 乔梁.《持续交付2.0》.人民邮电出版社
关注阿里云云原生公众号,后台回复关键词【飞天云原生】,下载峰会最全资料!