如何使用 Pulumi 管理 DigitalOcean 和 Kubernetes 基础设施
共 12587字,需浏览 26分钟
·
2020-09-06 16:10
Pulumi(https://www.pulumi.com) 是一个支持多语言和混合云开发平台,使用通用编程语言编写的代码来创建、部署和管理基础设施的工具。Pulumi 采用了基础设施即代码以及不可变基础设施的概念,并可让您从您最喜欢的语言(而不是 YAML 或 DSL)中获得自动化和可重复性优势。
除应用程序配置外,它还支持自动化所有 DigitalOcean
的托管服务,例如 Droplet、托管数据库、DNS 记录和 Kubernetes 集群。通过易于使用的命令行工具进行部署,该工具还集成了各种流行的 CI/CD 系统。
Pulumi 支持多种语言,在本教程中,我们将使用 TypeScript 来进行说明,此外我们将配置一个 DigitalOcean Kubernetes 集群,一个负载均衡的 Kubernetes 应用程序和一个 DigitalOcean DNS 域。
先决条件
要学习本教程,您需要:
用于部署资源的 DigitalOcean 帐户,如果您还没有,请在此处注册(https://cloud.digitalocean.com/registrations/new) 。 用于执行自动部署的 DigitalOcean API Token,在此处生成个人访问令牌(https://www.digitalocean.com/docs/api/create-personal-access-token/)。 因为要创建和使用 Kubernetes 集群,所以您需要安装 kubectl
。您将在 TypeScript 中编写基础架构代码,因此您需要安装 Node.js 8或更高版本。 您将使用 Pulumi 部署基础架构,因此您需要安装开源 Pulumi SDK(https://www.pulumi.com/docs/reference/install/) 。 将域名配置为使用 DigitalOceanNameservers
(可选)。
第1步 - 创建新项目
第一步是创建一个存储 Pulumi 项目的目录。除了描述项目及其 NPM 依赖项的元数据文件之外,此目录还将包含基础架构定义的源代码。
首先,创建一个目录,然进入新创建的目录:
$ mkdir do-k8s
$ cd do-k8s
后面我们都在这个新创建的do-k8s
目录下运行命令。接下来,创建一个新的 Pulumi 项目,有不同的方法可以实现这一点,但最简单的方法是使用pulumi new
命令和pulumi new
项目模板。此命令将首先提示您登录 Pulumi,以便保存项目和部署状态,然后在当前目录中创建一个简单的 TypeScript 项目:
$ pulumi new typescript -y
在这里,您已将-y
选项传递给new
命令,该命令告诉它接受默认项目选项。例如,项目名称取自当前目录的名称,因此将是do-k8s
。如果您想为项目名称使用不同的选项,只需忽略-y
。
运行该命令后,使用ls
列出目录的内容:
$ ls
Pulumi.yaml index.ts node_modules
package-lock.json package.json tsconfig.json
您要编辑的主要文件是index.ts ,我们也完全可以使用 Node.js 模块中您认为合适的方式来组织项目。
第2步 - 添加依赖项
下一步是在 DigitalOcean 和 Kubernetes 包上安装和添加依赖项。首先,使用 NPM 安装它们:
$ npm install @pulumi/digitalocean @pulumi/kubernetes
这将下载 Pulumi 插件,并将它们保存为依赖项。接下来,使用您喜欢的编辑器打开index.ts
文件,这里我们使用 nano:
nano index.ts
用以下内容替换index.ts
的内容:
import * as digitalocean from "@pulumi/digitalocean";
import * as kubernetes from "@pulumi/kubernetes";
添加内容后保存并关闭文件。
注意:我们将使用这些包中可用内容的子集。有关资源、属性和相关 API 的完整文档,请参阅
@pulumi/digitalocean
(https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/digitalocean/) 和@pulumi/kubernetes
(https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/kubernetes/) 软件包的相关 API 文档。
接下来,将配置您的 DigitalOcean 令牌,以便 Pulumi 可以在您的帐户中配置资源:
$ pulumi config set digitalocean:token YOUR_TOKEN_HERE --secret
注意 --secret
标志,它使用 Pulumi 的加密服务来加密你的令牌,确保它存储在密文中。如果您愿意,可以使用 DIGITALOCEAN_TOKEN
环境变量,但每次更新程序时都需要记住设置它,而使用配置会自动存储并将其用于您的项目。
第3步 - 配置 Kubernetes 集群
现在已准备好创建 DigitalOcean Kubernetes 集群。重新打开index.ts
文件开始:
$ nano index.ts
在index.ts
文件的末尾添加这些行:
…
const cluster = new digitalocean.KubernetesCluster("do-cluster", {
region: digitalocean.Regions.SFO2,
version: "latest",
nodePool: {
name: "default",
size: digitalocean.DropletSlugs.DropletS2VPCU2GB,
nodeCount: 3,
},
});
export const kubeconfig = cluster.kubeConfigs[0].rawConfig;
这个新代码会分配了一个 digitalocean.KubernetesCluster
实例,并在其上设置了许多属性,包括使用区域 slug、最新支持的 Kubernetes 版本、Droplet 大小,以及三个 Droplet 实例数量。
有关可在群集上配置的完整属性列表,请参阅 KubernetesCluster
API 文档**(https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/digitalocean/#KubernetesCluster) 。
该代码段中的最后一行导出生成的 Kubernetes 集群的kubeconfig
文件,导出的变量将打印到控制台,以方便其他工具访问。
现在已经准备好部署群集了,执行如下命令即可:
$ pulumi up
此命令获取程序生成用于创建所述基础架构的计划,并执行一系列步骤来部署这些变更。这适用于初始创建基础架构,此外还可以在进行后续更新时对您的基础架构进行区分和更新。在这种情况下,输出将如下所示:
Previewing update (dev):
Type Name Plan
+ pulumi:pulumi:Stack do-k8s-dev create
+ └─ digitalocean:index:KubernetesCluster do-cluster create
Resources:
+ 2 to create
Do you want to perform this update?
yes
> no
details
这表示继续更新将创建一个名为 do-cluster
的 Kubernetes 集群,yes/no/details
提示允许我们在实际进行任何更改之前确认这是期望的结果。如果选择 details
,将显示资源及其属性的完整列表,选择 yes
开始部署:
Updating (dev):
Type Name Status
+ pulumi:pulumi:Stack do-k8s-dev created
+ └─ digitalocean:index:KubernetesCluster do-cluster created
Outputs:
kubeconfig: "…"
Resources:
+ 2 created
Duration: 6m5s
Permalink: https://app.pulumi.com/…/do-k8s/dev/updates/1
创建群集需要几分钟,随后它将启动并运行,并且完整的 kubeconfig
将打印到控制台。将 kubeconfig
保存到文件:
$ pulumi stack output kubeconfig > kubeconfig.yml
然后使用它与 kubectl
工具即可执行任何 Kubernetes 命令:
$ KUBECONFIG=./kubeconfig.yml kubectl get nodes
NAME STATUS ROLES AGE VERSION
default-o4sj Ready 4m5s v1.14.2
default-o4so Ready 4m3s v1.14.2
default-o4sx Ready 3m37s v1.14.2
现在我们就设置了基础设施即代码,并具有可重复的方式来启动和配置新的 DigitalOcean Kubernetes 集群。在下一步中,您将在此基础上构建在代码中定义的 Kubernetes 集群,并学习如何以类似方式部署和管理它们。
第4步 - 将应用程序部署到群集
接下来,您将使用础设施即代码来描述 Kubernetes 应用程序的配置,这将包括三个部分:
一个 Provider
对象,它告诉 Pulumi 将 Kubernetes 资源部署到 DigitalOcean 集群,而不是kubectl
配置使用的默认值。Kubernetes Deployment
,是部署 Docker 容镜像的标准 Kubernetes 方法,可以部署任意数量的 Pod 副本。Kubernetes Service
,这是告诉 Kubernetes 跨目标 Pod 集合进行负载均衡访问的标准方法。
这是一个相当标准的参考架构用于在 Kubernetes 中启动和运行负载均衡服务,要部署所有这三个,请再次打开index.ts
文件:
$ nano index.ts
文件打开后,将此代码附加到文件末尾:
…
const provider = new kubernetes.Provider("do-k8s", { kubeconfig })
const appLabels = { "app": "app-nginx" };
const app = new kubernetes.apps.v1.Deployment("do-app-dep", {
spec: {
selector: { matchLabels: appLabels },
replicas: 5,
template: {
metadata: { labels: appLabels },
spec: {
containers: [{
name: "nginx",
image: "nginx",
}],
},
},
},
}, { provider });
const appService = new kubernetes.core.v1.Service("do-app-svc", {
spec: {
type: "LoadBalancer",
selector: app.spec.template.metadata.labels,
ports: [{ port: 80 }],
},
}, { provider });
export const ingressIp = appService.status.loadBalancer.ingress[0].ip;
此代码与标准 Kubernetes 配置类似,对象及其属性的行为是等效的,除了它与您的其他基础架构声明一起使用 TypeScript 编写。
进行更改后保存并关闭文件,就像之前一样,运行 pulumi up
进行预览,然后部署更改:
$ pulumi up
选择yes
继续后,CLI 将打印出详细的状态更新,包括有关 Pod 可用性,IP 地址分配等的诊断信息,这将有助于您了解部署可能需要时间来完成或卡住的原因。
完整输出将如下所示:
Updating (dev):
Type Name Status
pulumi:pulumi:Stack do-k8s-dev
+ ├─ pulumi:providers:kubernetes do-k8s created
+ ├─ kubernetes:apps:Deployment do-app-dep created
+ └─ kubernetes:core:Service do-app-svc created
Outputs:
+ ingressIp : "157.230.199.202"
Resources:
+ 3 created
2 unchanged
Duration: 2m52s
Permalink: https://app.pulumi.com/…/do-k8s/dev/updates/2
完成后,查看部署的 Pod 正在运行:
$ KUBECONFIG=./kubeconfig.yml kubectl get pods
NAME READY STATUS RESTARTS AGE
do-app-dep-vyf8k78z-758486ff68-5z8hk 1/1 Running 0 1m
do-app-dep-vyf8k78z-758486ff68-8982s 1/1 Running 0 1m
do-app-dep-vyf8k78z-758486ff68-94k7b 1/1 Running 0 1m
do-app-dep-vyf8k78z-758486ff68-cqm4c 1/1 Running 0 1m
do-app-dep-vyf8k78z-758486ff68-lx2d7 1/1 Running 0 1m
与程序导出群集的 kubeconfig
文件的方式kubeconfig
,此程序还会导出 Kubernetes 服务生成的负载均衡器的 IP 地址,可以使用curl
端点来查看:
$ curl $(pulumi stack output ingressIp)
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
这里可以轻松编辑和重新部署应用程序基础设施,例如,尝试更改 replicas: 5
为 replicas: 7
,然后重新运行pulumi up
:
$ pulumi up
请注意,它只显示已更改的内容:
Previewing update (dev):
Type Name Plan Info
pulumi:pulumi:Stack do-k8s-dev
~ └─ kubernetes:apps:Deployment do-app-dep update [diff: ~spec]
Resources:
~ 1 to update
4 unchanged
Do you want to perform this update? details
pulumi:pulumi:Stack: (same)
[urn=urn:pulumi:dev::do-k8s::pulumi:pulumi:Stack::do-k8s-dev]
~ kubernetes:apps/v1:Deployment: (update)
[id=default/do-app-dep-vyf8k78z]
[urn=urn:pulumi:dev::do-k8s::kubernetes:apps/v1:Deployment::do-app-dep]
[provider=urn:pulumi:dev::do-k8s::pulumi:providers:kubernetes::do-k8s::80f36105-337f-451f-a191-5835823df9be]
~ spec: {
~ replicas: 5 => 7
}
现在,您拥有一个功能齐全的 Kubernetes 集群和一个正常运行的应用程序。启动并运行应用程序后,您可能需要配置要与应用程序一起使用的自定义域名。下一步将指导您使用 Pulumi 配置 DNS。
第5步 - 创建 DNS 域(可选)
虽然 Kubernetes 集群和应用程序已启动并运行,但应用程序的地址取决于集群自动分配 IP 地址。在调整和重新部署内容时,此地址可能会发生变化。在此步骤中,您将看到如何将自定义 DNS 名称分配给负载均衡器 IP 地址,以便即使您随后更改基础架构也能保持稳定。
注意:要完成此步骤,请确保使用 DigitalOcean 的 DNSNameservers:
ns1.digitalocean.com
、ns2.digitalocean.com
和ns3.digitalocean.com
。
要配置 DNS,请打开index.ts
文件并将以下代码添加到文件末尾:
…
const domain = new digitalocean.Domain("do-domain", {
name: "your_domain",
ipAddress: ingressIp,
});
此代码创建一个带有 A 记录的新 DNS 条目,该记录引用您的 Kubernetes 服务的 IP 地址。将此代码段中的your_domain
替换为您选择的域名。通常需要其他子域(如www
)指向 Web 应用程序,使用 DigitalOcean DNS 记录很容易实现。
…
const cnameRecord = new digitalocean.DnsRecord("do-domain-cname", {
domain: domain.name,
type: "CNAME",
name: "www",
value: "@",
});
进行这些更改后保存并关闭文件。最后,运行 pulumi up
以部署 DNS 更改以指向现有应用程序和集群:
Updating (dev):
Type Name Status
pulumi:pulumi:Stack do-k8s-dev
+ ├─ digitalocean:index:Domain do-domain created
+ └─ digitalocean:index:DnsRecord do-domain-cname created
Resources:
+ 2 created
5 unchanged
Duration: 6s
Permalink: https://app.pulumi.com/…/do-k8s/dev/updates/3
当 DNS 更改后,您将能够在自定义域中访问您的内容:
$ curl www.your_domain.com
您将收到类似于以下内容的输出:
Welcome to nginx!
Welcome to nginx!
If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.
For online documentation and support please refer to
nginx.org.
Commercial support is available at
nginx.com.
Thank you for using nginx.
有了这个,您就已经成功建立了一个新的 DigitalOcean Kubernetes 集群,为其部署了一个负载均衡的 Kubernetes 应用程序,并使用 DigitalOcean DNS 为该应用程序的负载均衡器提供了一个稳定的域名,所有这些都在60行代码和一个pulumi up
命令中完成的。
如果您不再需要这些资源,下一步将指导您删除资源。
第6步 - 删除资源(可选)
在结束本教程之前,您可能希望销毁上面创建的所有资源,这将确保您不会因未使用的资源而被收取费用。如果您希望保持应用程序正常运行,请跳过此步骤。
运行以下命令以销毁资源,不过需要小心使用它,因为它无法撤消!
$ pulumi destroy
与up
命令一样, destroy
在执行操作之前会显示预览和提示:
Previewing destroy (dev):
Type Name Plan
- pulumi:pulumi:Stack do-k8s-dev delete
- ├─ digitalocean:index:DnsRecord do-domain-cname delete
- ├─ digitalocean:index:Domain do-domain delete
- ├─ kubernetes:core:Service do-app-svc delete
- ├─ kubernetes:apps:Deployment do-app-dep delete
- ├─ pulumi:providers:kubernetes do-k8s delete
- └─ digitalocean:index:KubernetesCluster do-cluster delete
Resources:
- 7 to delete
Do you want to perform this destroy?
yes
> no
details
选择 yes
观察删除的信息:
Destroying (dev):
Type Name Status
- pulumi:pulumi:Stack do-k8s-dev deleted
- ├─ digitalocean:index:DnsRecord do-domain-cname deleted
- ├─ digitalocean:index:Domain do-domain deleted
- ├─ kubernetes:core:Service do-app-svc deleted
- ├─ kubernetes:apps:Deployment do-app-dep deleted
- ├─ pulumi:providers:kubernetes do-k8s deleted
- └─ digitalocean:index:KubernetesCluster do-cluster deleted
Resources:
- 7 deleted
Duration: 7s
Permalink: https://app.pulumi.com/…/do-k8s/dev/updates/4
可以看到上面的资源都被删除了,DNS 条目消失了、Kubernetes 集群以及在其中运行的应用程序都被删除了。Permalink
仍然可用,因此您仍然可以返回并查看此的完整更新历史记录。如果 destroy
是一个错误的操作,这可以帮助您恢复,因为该服务保留所有资源的完整状态历史记录。
如果您想要完整地销毁项目,请删除:
$ pulumi stack rm
您将收到如下所示的信息,要求您通过键入的名称来确认删除:
This will permanently remove the 'dev' stack!
Please confirm that this is what you'd like to do by typing ("dev"):
与删除云基础架构资源的 destroy 命令不同,rm 命令会从 Pulumi 的权限中完全删除的完整历史记录。
总结
在本教程中,除了使用 Kubernetes 应用程序配置外,还部署了 DigitalOcean 基础架构的资源:Kubernetes 集群和具有 A、CNAME 记录的 DNS 域。使用熟悉的编程语言 TypeScript 编写的基础设施代码完成了这项工作,该编程语言可以与现有的编辑器、工具和库一起使用,并利用现有的社区和软件包。您已使用单个命令行工作流完成所有这些工作,以执行跨应用程序和基础设施的部署。
更多有用的信息可以访问如下几个文档:
探索 Pulumi 支持的全套 DigitalOcean 资源(https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/digitalocean/) 探索 Pulumi 对 Kubernetes 应用程序的支持](https://www.pulumi.com/docs/reference/clouds/kubernetes/) 使用 CI/CD 和 Git 工作流集成自动部署(https://www.pulumi.com/docs/reference/cd/)
有关如何在您自己的项目中使用 Pulumi 将基础设施作为代码的详细信息,请查看 Pulumi 文档(https://www.pulumi.com/docs)、教程(https://www.pulumi.com/docs/reference/tutorials)或入门指南(https://www.pulumi.com/docs/quickstart)。
原文链接:https://www.digitalocean.com/community/tutorials/how-to-manage-digitalocean-and-kubernetes-infrastructure-with-pulumi
K8S进阶训练营,点击下方图片了解详情