1. pulumi介绍
github项目介绍: Universal Infrastructure as Code. Your Cloud, Your Language, Your Way 🚀
通用基础设施即代码,你云你素,用熟悉的方式、熟悉的语言通过pulumi去管理自己的云平台。 通俗点来说,pulumi是一个基础设施资源编排器,写好编排代码,例如定义的yaml、或者编程语言golang等,通过动作触发即能完成各种云资源的增删改查等基础设施的管理,使用pulumi可以轻松构建自己的多云平台。较于已有的编排器,pulumi有如下几个明显的特点。
- 高兼容性
- 用户侧 – 无需学习新编程语言
- 命令行工具
pulumi
- 主流语言sdk
Node.js
Python
Go
.NET
Java
YAML
- 命令行工具
- 云侧 – 兼容主流厂商与代表性开源软件
- AWS
- Azure
- Google Cloud
- Kubernetes
- OpenStack
- 阿里云
- 华为云
- 腾讯云
- …
- 用户侧 – 无需学习新编程语言
- 抽象 – 各云厂商都提供了自己的驱动,作为使用者无需对接云厂商sdk,仅需了解pulumi的通用sdk即可
2. pulumi运行机制
2.1. 术语
- Project 项目为stack的集合
- Stack pulumi的服务主体、所有操作围绕stack展开,一个stack可以有多个资源,产品化过程中一个stack对应一个resource相对比较合理
- Resource 真实的云资源,例如腾讯云主机、COS、OpenStack实例等等
- Plugin 云厂商插件,resource操作时需要调用云厂商sdk,plugin则是针对云厂商sdk的封装,使用前都需要安装对应的插件,例如aws资源需要提前安装aws插件
- Program 实际的资源操作模板,program会调用Plugin进行资源操作,被stack调用,使用自己熟悉的语言编写,可以通过pulumi命令触发
- Pulumi云端 pulumi服务主体是stack,pulumi资源的操作实际上是通过修改stack状态来完成的,stack状态存储在pulumi云端,存储方式决定了 要使用pulumi需要与https://www.pulumi.com/交互,操作记录存储在这里而不是本地
- pulumi cli pulumi客户端命令行,pulumi所有操作都通过pulumi命令完成
- pulumi automation API pulumi各语言sdk,是对pulumi命令的封装
2.2. 系统架构
这张图说明了 project program resource stack的关系,所有的资源都属于project,stack既可以认为是单个资源的逻辑表示,也能当作环境,program处理实际资源。
2.3. 逻辑架构
- Language Host 执行program的服务器,即执行自定义的编排代码的服务器,由语言环境,例如go、python等和语言执行器两部分组成,语言环境负责运行program,语言执行器则是pulumi如何调用不同语言来达成特定动作的关键。
- CLI and Engine CLI即pulumi cli,Engine为状态检查器,例如要创建Stack时首先要检查Stack存不存在,更新Stack时如果实际状态和目标状态一致则不做处理。
- Last Deployed State 最后一次部署状态,存储在pulumi云端
- Provides 各云厂商的驱动,包括两部分:resource plugin 和 SDK
要使用pulumi有如下几步,以pulumi cli 操作腾讯云为例:
- 初始化 pulumi项目
pulumi new
- 首先写好创建虚拟机的代码,这部分遵循plugin模板格式,调用腾讯云插件sdk
- 使用pulumi cli或者 automation sdk 运行编排代码
pulumi up
或者auto.NewStackInlineSource->stack.Up
2.3.1. pulumi cli 示例
首先初始化项目
# 创建文件夹
mkdir pulumi-qcloud
cd pulumi-qcloud
# 初始化项目,需要登陆pulumi,选择go模板即可
pulumi new
编写program代码
package main
import (
"fmt"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/cos"
"github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/user"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := user.GetInfo(ctx, nil, nil)
if err != nil {
fmt.Printf("the first error: %v\n", err)
return err
}
_, err = cos.NewBucket(ctx, "myBucket", &cos.BucketArgs{
Acl: pulumi.String("private"),
Bucket: pulumi.String(fmt.Sprintf("%v%v", "pulumi-created-", info.AppId)),
})
if err != nil {
fmt.Printf("the second error: %v\n", err)
return err
}
return nil
})
}
运行
pulumi up
2.3.2. automation api
automation api是对pulumi cli的封装,通过automation api调用更简单: sdk操作比调用二进制方便,更安全: 不用直接与文件系统文件进行直接访问。 pulumi 不经可以通过 rest api方式、cli方式提供使用,还能继承带ci/cd系统中,方便CD。
使用rest api方式提供服务见 pulumi_over_http
腾讯云 rest api示例 multistack-example
3. 产品化思路
3.1. 需求
- 管理多云
- 管理混合云
- 不需要自己写sdk
- 可私有化
- 以rest api方式提供服务
其中可私有化不能满足,因为操作记录都会存储在pulumi云端,其他均满足,如果忽略这点,pulumi可称为完美的多云管理利器
3.2. 研发思路
- project作为资源隔离单位
- 一个stack为一个资源,资源的所有增删改查都通过stack操作
- 使用automation api嵌入已由业务代码 demo
3.3. 可预见问题
- pulumi 输出大都在文件中,需要读取文件解析
- pulumi 不能直接列举资源,例如获取一个project的所有资源,需先列举project的stack,在列觉stack中的资源,在通过资源get接口get资源信息
- pulumi 本身日志输出格式比较花里胡哨,适合人类直接读,但结构化差不适合分析
- pulumi 文档和示例较少
4. 商业模式
软件开源,但所有操作需要和云端交互,数据状态存储在云端,所以收费也在云端,pulumi的收费模式为限制quota收费,具体如下图
主要按以下纬度收费
- 人数
- update并发
- stacks个数
- CICD助手功能
- webhook功能
等基础功能,高级功能见 pricing
收费模式决定了企业要使用pulumi必须付费
5. 与同类软件对比
对比最多的为terraform
5.1. 相似点
- 都是IaC
- 都开源
- 都提供期望资源状态管理模型
- 都支持主流云厂商
- 都很流行,备受厂商青睐
5.2. 差异点
这里仅列举了几个在选型中起决定性因素的差异点,详细的对比参照 Pulumi vs. Terraform
功能 | pulumi | Terraform |
---|---|---|
语言支持 | Python, TypeScript, JavaScript, Go, C#, F#, Java, YAML | HashiCorp Configuration Language (HCL) |
IDE支持 | 代码补齐、强类型、错误提示、丰富的资源文档 | 受限 |
状态管理 | 可视化状态管理 | 功能弱、可视化支持差 |
嵌入业务代码 | 可嵌入 | 不可嵌入 |
secrets管理 | 有 | 无 |
最大的区别在于语言支持、状态管理、可嵌入业务代码中三点
- terraform需要学习hcl,pulumi则支持多种语言,选择顺手的语言操作即可,无语言学习成本
- pulumi提供了完备的状态管理,且在云端可视化,terraform状态管理则支持非常不完善
- terraform不能嵌入到业务代码中,只能作为运维工具使用,pulumi则可以完美嵌入
6. 附录
6.1. 附录1: 简单使用示例
6.1.1. Tencent CLoud
6.1.1.1. 初始化项目
❯ pulumi new --force
Please choose a template (113/205 shown):
go A minimal Go Pulumi program
This command will walk you through creating a new Pulumi project.
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project name: (pulumitest)
project description: (A minimal Go Pulumi program)
Created project 'pulumitest'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev)
Created stack 'dev'
Installing dependencies...
go: downloading github.com/pulumi/pulumi/sdk/v3 v3.53.0
go: finding module for package github.com/mattn/go-isatty
go: found github.com/mattn/go-isatty in github.com/mattn/go-isatty v0.0.17
Finished installing dependencies
Your new project is ready to go! ✨
To perform an initial deployment, run `pulumi up`
6.1.1.2. 编写program代码
package main
import (
"fmt"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
"github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/cos"
"github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/user"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := user.GetInfo(ctx, nil, nil)
if err != nil {
fmt.Printf("the first error: %v\n", err)
return err
}
_, err = cos.NewBucket(ctx, "myBucket", &cos.BucketArgs{
Acl: pulumi.String("private"),
Bucket: pulumi.String(fmt.Sprintf("%v%v", "pulumi-created-", info.AppId)),
})
if err != nil {
fmt.Printf("the second error: %v\n", err)
return err
}
return nil
})
}
6.1.1.3. 准备运行
- 配置腾讯云凭证
❯ pulumi config set tencentcloud:secretId xxxxx --secret
❯ pulumi config set tencentcloud:secretKey xxxxxxx --secret
❯ pulumi config set tencentcloud:region ap-hongkong
- 下载sdk依赖包
❯ go mod tidy
go: finding module for package github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/cos
go: finding module for package github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/user
go: found github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/cos in github.com/tencentcloudstack/pulumi-tencentcloud/sdk v0.1.2
go: found github.com/tencentcloudstack/pulumi-tencentcloud/sdk/go/tencentcloud/user in github.com/tencentcloudstack/pulumi-tencentcloud/sdk v0.1.2
6.1.1.4. 运行创建
可以提前安装plugin,否则运行pulumi up的时候会安装,命令为
pulumi plugin install resource tencentcloud v0.1.2
, 不翻墙的话很慢
❯ pulumi up
Previewing update (dev)
View Live: https://app.pulumi.com/elrondwong/pulumitest/dev/previews/f129cbae-67d8-42aa-b78a-c082e598a08f
# 安装plugin
Downloading plugin: 21.15 MiB / 43.45 MiB [==========>-----------] 48.67% 18m8s
Downloading plugin: 43.45 MiB / 43.45 MiB [=====================] 100.00% 37m32s
[resource plugin tencentcloud-0.1.2] installing
Type Name Plan
pulumi:pulumi:Stack pulumitest-dev
+ └─ tencentcloud:Cos:Bucket myBucket create
Resources:
+ 1 to create
1 unchanged
Do you want to perform this update? yes
Updating (dev)
View Live: https://app.pulumi.com/elrondwong/pulumitest/dev/updates/2
Type Name Status
pulumi:pulumi:Stack pulumitest-dev
+ └─ tencentcloud:Cos:Bucket myBucket created (4s)
Resources:
+ 1 created
1 unchanged
Duration: 11s
这里仅展示了资源创建,对资源的销毁可以看下面OpenStack的例子
6.1.2. OpenStack
6.1.2.1. pulumi项目创建
pulumi new --dir pulumiopenstack
Please choose a template (113/205 shown):
openstack-go A minimal OpenStack Go Pulumi program
This command will walk you through creating a new Pulumi project.
Enter a value or leave blank to accept the (default), and press <ENTER>.
Press ^C at any time to quit.
project name: (pulumiopenstack)
project description: (A minimal OpenStack Go Pulumi program)
Created project 'pulumiopenstack'
Please enter your desired stack name.
To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`).
stack name: (dev)
Created stack 'dev'
Installing dependencies...
Finished installing dependencies
Your new project is ready to go! ✨
To perform an initial deployment, run 'cd pulumiopenstack', then, run `pulumi up`
6.1.2.2. program代码编写
package main
import (
"fmt"
"github.com/pulumi/pulumi-openstack/sdk/v3/go/openstack/blockstorage"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_, err := blockstorage.NewVolume(ctx, "volume1", &blockstorage.VolumeArgs{
Description: pulumi.String("first test volume"),
Region: pulumi.String("RegionOne"),
Size: pulumi.Int(3),
})
if err != nil {
return err
}
return nil
})
}
6.1.2.3. 运行准备
- 安装plugin
pulumi plugin install resource openstack v3.9.0
- 安装依赖包
go mod tidy
- 配置凭证
export OS_USERNAME=admin
export OS_PASSWORD=passwd
export OS_PROJECT_NAME=admin
export OS_USER_DOMAIN_NAME=Default
export OS_PROJECT_DOMAIN_NAME=Default
export OS_AUTH_URL=http://172.16.10.10:5000/v3
export OS_IDENTITY_API_VERSION=3
export PS1='[\u@\h \W(keystone_admin)]\$ '
6.1.2.4. 运行
- 创建卷
❯ pulumi up
Previewing update (dev)
View Live: https://app.pulumi.com/elrondwong/pulumiopenstack/dev/previews/cc39ba12-d292-43ad-b962-a9d5d66653a5
Downloading plugin openstack v3.9.0: 17.95 MiB / 17.95 MiB [=====] 100.00% 7m24s
Type Name Plan
+ pulumi:pulumi:Stack pulumiopenstack-dev create
+ └─ openstack:blockstorage:Volume volume1 create
Resources:
+ 2 to create
Do you want to perform this update? yes
Updating (dev)
View Live: https://app.pulumi.com/elrondwong/pulumiopenstack/dev/updates/1
Type Name Status
+ pulumi:pulumi:Stack pulumiopenstack-dev created (0.62s)
+ └─ openstack:blockstorage:Volume volume1 created (11s)
Resources:
+ 2 created
Duration: 15s
- 销毁资源
❯ pulumi destroy
Previewing destroy (dev)
View Live: https://app.pulumi.com/elrondwong/pulumiopenstack/dev/previews/4673ac44-90a7-438a-8166-01e7cdf1f89d
Type Name Plan
- pulumi:pulumi:Stack pulumiopenstack-dev delete
- └─ openstack:blockstorage:Volume volume1 delete
Resources:
- 2 to delete
Do you want to perform this destroy? yes
Destroying (dev)
View Live: https://app.pulumi.com/elrondwong/pulumiopenstack/dev/updates/2
Type Name Status
- pulumi:pulumi:Stack pulumiopenstack-dev deleted
- └─ openstack:blockstorage:Volume volume1 deleted (11s)
Resources:
- 2 deleted
Duration: 13s
The resources in the stack have been deleted, but the history and configuration associated with the stack are still maintained.
If you want to remove the stack completely, run `pulumi stack rm dev`.
- 销毁stack
❯ pulumi stack rm dev
This will permanently remove the 'dev' stack!
Please confirm that this is what you'd like to do by typing `dev`: dev
Stack 'dev' has been removed!
# https://app.pulumi.com/elrondwong/projects
stack里面少了一个
7. 参考
- how-pulumi-works
- hello-pulumi
- Pulumi vs. Terraform
- pulumi-tencentcloud
- pulumi-openstack
- automation-api-examples