尝试将Pulumi SDK与Google Cloud SDK结合使用
这篇文章是NTT通信Advent Calendar 2019的第20天。
昨天是@kirikei先生的谷歌数据可视化与模型分析工具What-if Tool中的泰坦尼克号生存预测。
首先
我在公司工作了六年,主要负责基础设施工程师的工作。这次我想介绍一下最近很受关注的 Infrastructure as Code(IaC)工具 Pulumi的简单说明,并介绍如何利用Pulumi的编程语言特性来进行IaC的用法。
「Pulumi是什么」
在官方的HP网站的Architecture & Concepts页面中,有如下所述。
Pulumi云开发平台是一套工具、库、运行环境和服务的结合,为原生云基础设施提供一致的开发和运营控制平面。Pulumi不仅可以让您将基础设施管理为代码,还可以使用真正的编程语言(以及其所有支持工具)来定义和管理基础设施,而不是使用YAML。
简而言之,Infrastructure as Code是指通过实际的编程语言来定义和管理基础设施。目前支持的语言有以下四种,.NET和Go似乎仍处于预览阶段。从2.0版本开始似乎会正式支持。(来源:Pulumi 2.0 Roadmap)
-
- Node.js – JavaScript, TypeScript, or any other Node.js compatible language
-
- Python – Python 3.6 or greater
-
- .NET Core – C#, F#, and Visual Basic on .NET Core 3.0 or greater
- Go – statically compiled Go binaries (documentation coming soon)
此外,似乎愈来愈多的云服务提供商能够进行部署。
尝试在Kubernetes上部署
这次作为例子,我打算将以下结构部署到Kubernetes上。
这是一个将nginx的web服务器(nginx)负载均衡在3个节点上,并且可以从外部访问的结构。
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx
spec:
backend:
serviceName: nginx
servicePort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
ports:
- port: 80
targetPort: http-port
selector:
app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- name: http-port
containerPort: 80
使用Pulumi的Kubernetes SDK进行部署。
将Kubernetes清单的内容几乎完全定义为对象,使得通过”new”关键字可以部署一个实例的概念。
import * as k8s from "@pulumi/kubernetes";
const appName = "nginx";
const appLabels = { app: appName };
const deployment = new k8s.apps.v1.Deployment(appName, {
metadata: { name: appName },
spec: {
selector: { matchLabels: appLabels},
replicas: 3,
template: {
metadata: { labels: appLabels},
spec: {
containers: [{ name: appName,
image: "nginx:alpine",
ports: [{ name: "http-port", containerPort: 80 }]
}]
}
}
}
});
new k8s.core.v1.Service(appName, {
metadata: { name: appName,
labels: deployment.spec.template.metadata.labels
},
spec: {
type: "NodePort",
ports: [{ port: 80, targetPort: "http-port" }],
selector: appLabels
}
});
new k8s.networking.v1beta1.Ingress(appName, {
metadata: { name: appName },
spec: {
backend: { serviceName: appName, servicePort: 80 }
}
});
读取并部署YAML格式的清单文件。
我认为在Kubernetes中,有时候整个生态系统都是基于YAML运行的,所以重新使用Pulumi可能会有些麻烦。在这种情况下,可以直接读取YAML并进行部署。
Pulumi的Kubernetes SDK提供了像“Deploying a YAML Manifest”中的示例代码一样的功能,可以读取本地的YAML文件,并自动解析YAML中的资源类型(Kubernetes的Kind)进行部署。因此,我们只需要编写非常简单的代码即可完成部署操作。
import * as k8s as "@pulumi/kubernetes";
const manifest = "nginx.yml"
new k8s.yaml.ConfigFile(`k8s/app/${manifest}`, {
file: manifest
});
从Google Cloud Storage中读取YAML文件并进行部署。
在生态系统中,如果另一个软件负责处理YAML的创建/验证,并且通过其他存储方式如Google Cloud Storage来交换YAML,那么情况会变得更加复杂。
目前,Node.js的Pulumi SDK只支持从本地文件中读取功能,不支持其他功能。相反,如果有YAML格式的数据,似乎可以通过它来实现类似的功能。
因此,我们将尝试与Google Cloud的SDK结合使用。
import * as gcs from "@google-cloud/storage";
import * as k8s from "@pulumi/kubernetes";
async function readFileFromGcs(bucket: gcs.Bucket, file: string): Promise<string> {
const remoteFile = bucket.file(file);
return new Promise((resolve) => {
let yamlData = '';
remoteFile.createReadStream()
.on('data', function(data) {
yamlData += data;
}).on('end', function() {
resolve(yamlData);
});
});
};
async function main(): Promise<any> {
const storage = new gcs.Storage({keyFilename: './key.json'});
const bucket = storage.bucket('test-pulumi');
const manifest = "nginx.yml"
const yamlData = await readFileFromGcs(bucket, manifest)
new k8s.yaml.ConfigGroup(`k8s/app/${manifest}`, {
yaml: yamlData });
};
main();
执行结果
使用Google Cloud的SDK组合后的执行结果如下。
$ pulumi up
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack manifest_on_gcs-dev create
+ └─ kubernetes:yaml:ConfigGroup k8s/app/nginx.yml create
+ ├─ kubernetes:core:Service nginx create
+ ├─ kubernetes:networking.k8s.io:Ingress nginx create
+ └─ kubernetes:apps:Deployment nginx create
Resources:
+ 5 to create
Do you want to perform this update? yes
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack manifest_on_gcs-dev created
+ └─ kubernetes:yaml:ConfigGroup k8s/app/nginx.yml created
+ ├─ kubernetes:networking.k8s.io:Ingress nginx created
+ ├─ kubernetes:core:Service nginx created
+ └─ kubernetes:apps:Deployment nginx created
Resources:
+ 5 created
Duration: 17s
YAML成功加载并部署完毕。虽然本次省略了,但前文提到的“使用Pulumi的Kubernetes SDK进行部署”和“加载本地YAML格式的Manifest并部署”的模式也会得到相同的执行结果。
最后
这一次,我们介绍了使用Pulumi将应用部署到Kubernetes的方法。尤其是在最后一部分,我们使用了Pulumi的Kubernetes SDK和纯粹的Node.js Google Cloud SDK来读取Google Cloud Storage中的YAML并进行部署。
我觉得Pulumi与其他工具(如terraform)的不同之处在于,它可以实现纯粹的编程方式无法完成的任务。
通过尝试使用Pulumi,我感受到的是在平常所使用的编程语言中部署基础架构,这是作为开发云应用程序的工具之一的一种方法。在企业的服务和系统中,仍然存在许多被称为基础架构工程师的人,但我认为我们应该不断变得无缝,并将编写软件视为理所当然的事情。在NTT通信中,这种趋势正在逐渐加强,我希望自己也能不断进步。
以上是以上内容。明天是@kanatakita的文章。