如何使用 Pulumi 管理 DigitalOcean 和 Kubernetes 基础设施

作者选择了 多样性在技术基金作为 写给捐款计划的一部分接受捐款。

介绍

Pulumi是一款用于创建、部署和管理基础设施的工具,使用代码编写在通用编程语言中。它支持自动化所有DigitalOcean的管理服务,如Droplets、管理数据库、DNS记录和Kubernetes集群,除了应用程序配置之外。

Pulumi 支持多种语言,但在本教程中,您将使用 TypeScript,使用 Node.js运行时间的 JavaScript的静态打字版本。

在本教程中,您将提供一个DigitalOcean Kubernetes集群,一个负荷均衡的Kubernetes应用程序,以及一个DigitalOcean DNS域,使您的应用程序在您选择的稳定域名中可用。所有这些都可以提供60行基础设施代码和单个pulumi up命令行手势。

如果您正在寻找一个管理的Kubernetes托管服务,请查看我们的简单的,用于增长的管理的Kubernetes服务(https://www.digitalocean.com/products/kubernetes)。

前提条件

要遵循本教程,您将需要:

如果你已经没有一个, 注册这里

步骤 1 - 创建一个新的项目

第一步是创建一个目录,该目录将包含基础设施定义的源代码,以及描述项目及其NPM依赖的元数据文件。

首先,创建目录:

1mkdir do-k8s

接下来,进入新创建的目录:

1cd do-k8s

从现在开始,从新创建的do-k8s目录中运行命令。

接下来,创建一个新的Pulumi项目有不同的方法来实现这一点,但最简单的方法是使用pulumi new命令与typescript项目模板一起使用。

1pulumi new typescript -y

在这里,您已将-y选项转移到命令,该命令告诉它接受默认项目选项,例如,项目名称是从当前目录的名称中提取的,所以将是do-k8s

运行命令后,列出目录的内容为ls:

1ls

以下文件现在将存在:

1[secondary_label Output]
2Pulumi.yaml index.ts node_modules
3package-lock.json package.json tsconfig.json

您将编辑的主要文件是 index.ts. 虽然本教程只使用这个单个文件,但您可以通过使用 Node.js 模块以任何您认为合适的方式组织您的项目。 该教程还描述了一次性的一个步骤,利用Pulumi 能够检测并逐步部署只发生了变化。

现在你已经准备好了你的新项目,你已经准备好添加需要遵循教程的依赖。

步骤二:增加依赖性

下一步是在 DigitalOcean 和 Kubernetes 套件上安装并添加依赖性,首先使用 NPM 来安装它们:

1npm install @pulumi/digitalocean @pulumi/kubernetes

这将下载NPM包,Pulumi插件,并将其保存为依赖。

接下来,用你最喜欢的编辑器打开index.ts文件,本教程将使用nano:

1nano index.ts

取代您的index.ts的内容如下:

1[label index.ts]
2import * as digitalocean from "@pulumi/digitalocean";
3import * as kubernetes from "@pulumi/kubernetes";

例如,如果您使用理解 TypeScript 和 Node.js 的 IDE 键入digitalocean

添加内容后保存和关闭文件。

<$>[注] 注: 我们将使用这些包中可用的子集。 有关资源、属性和相关API的完整文档,请参阅 @pulumi/digitaloceanpulumi/kubernetes包的相关API文档。 <$>

接下来,您将配置您的 DigitalOcean 代币,以便 Pulumi 在您的帐户中提供资源:

1pulumi config set digitalocean:token YOUR_TOKEN_HERE --secret

注意--秘密旗帜,它使用Pulumi的加密服务来加密你的代币,确保它存储在cyphertext中. 如果你喜欢,你可以使用DIGITALOCEAN_TOKEN环境变量,但你需要记住每次更新你的程序时设置它,而使用配置会自动存储并用于你的项目。

在此步骤中,您添加了必要的依赖,并与Pulumi配置了您的API代币,以便您可以提供您的Kubernetes集群。

步骤 3 – 提供 Kubernetes 集群

现在你已经准备好创建一个DigitalOcean Kubernetes集群了. 通过重新打开‘index.ts’文件开始:

1nano index.ts

将这些行添加到您的 index.ts 文件的末尾:

 1[label index.ts]
 2...
 3const cluster = new digitalocean.KubernetesCluster("do-cluster", {
 4    region: digitalocean.Regions.SFO2,
 5    version: "latest",
 6    nodePool: {
 7        name: "default",
 8        size: digitalocean.DropletSlugs.DropletS2VPCU2GB,
 9        nodeCount: 3,
10    },
11});
12
13export const kubeconfig = cluster.kubeConfigs[0].rawConfig;

此新代码分配了一个digitalocean.KubernetesCluster的实例,并为其设置了一些属性。 其中包括使用sfo2 区域 slug,Kubernetes的最新的支持版本,s-2vcpu-2gb Droplet 尺寸 slug,并表示您想要的三个 Droplet 实例的数目。 请勿对这些实例进行任何更改,但请注意,DigitalOcean Kubernetes在本文写作时仅在某些地区提供。 您可以参阅 产品文档有关区域可用性的最新信息。

有关您可以在集群中配置的所有属性的完整列表,请参阅 KubernetesCluster API 文档

该代码片段的最后一行将导出结果的 Kubernetes 集群的 kubeconfig 文件,使其易于使用。

现在你已经准备好部署你的集群了,要做到这一点,运行pulumi up:

1pulumi up

此命令会执行程序,生成创建所描述的基础设施的计划,并执行一系列步骤来部署这些更改。

 1[secondary_label Output]
 2Previewing update (dev):
 3
 4     Type Name Plan
 5 +   pulumi:pulumi:Stack do-k8s-dev create
 6 +   └─ digitalocean:index:KubernetesCluster do-cluster create
 7
 8Resources:
 9    + 2 to create
10
11Do you want to perform this update?
12  yes
13> no
14  details

这意味着更新将创建一个名为Do-cluster的Kubernetes集群。Yes/No/Details提示允许我们确认这是在实际进行任何更改之前所需的结果。

 1[secondary_label Output]
 2Updating (dev):
 3
 4     Type Name Status
 5 +   pulumi:pulumi:Stack do-k8s-dev created
 6 +   └─ digitalocean:index:KubernetesCluster do-cluster created
 7
 8Outputs:
 9    kubeconfig: "..."
10
11Resources:
12    + 2 created
13
14Duration: 6m5s
15
16Permalink: https://app.pulumi.com/.../do-k8s/dev/updates/1

创建集群需要几分钟,但然后它将启动并运行,并将完整的kubeconfig打印到控制台上。

1pulumi stack output kubeconfig > kubeconfig.yml

然后用kubectl来执行任何Kubernetes命令:

1KUBECONFIG=./kubeconfig.yml kubectl get nodes

您将收到类似于以下的输出:

1[secondary_label Output]
2NAME STATUS ROLES AGE VERSION
3default-o4sj Ready     <none>    4m5s v1.14.2
4default-o4so Ready     <none>    4m3s v1.14.2
5default-o4sx Ready     <none>    3m37s v1.14.2

在此时,您已经设置了基础设施作为代码,并有可重复的方式来创建和配置新的DigitalOcean Kubernetes集群. 在下一步,您将建立在这个基础设施中,以代码定义Kubernetes基础设施,并学习如何以类似的方式部署和管理它们。

步骤 4 – 部署应用程序到您的集群

接下来,您将描述使用基础设施代码的Kubernetes应用程序的配置,这将由三个部分组成:

一个供应商对象,该对象告诉Pulumi将Kubernetes资源部署到DigitalOcean群集中,而不是默认配置的任何kubectl来使用。 2. A Kubernetes部署,这是Kubernetes的标准方式来部署在任何数量的Pod上复制的Docker容器图像。

这是一个相当标准的 _reference 架构,用于在 Kubernetes 中运行负载均衡服务。

要部署这三种,请重新打开您的 index.ts 文件:

1nano index.ts

打开文件后,将此代码附加到文件的末尾:

 1[label index.ts]
 2...
 3const provider = new kubernetes.Provider("do-k8s", { kubeconfig })
 4
 5const appLabels = { "app": "app-nginx" };
 6const app = new kubernetes.apps.v1.Deployment("do-app-dep", {
 7    spec: {
 8        selector: { matchLabels: appLabels },
 9        replicas: 5,
10        template: {
11            metadata: { labels: appLabels },
12            spec: {
13                containers: [{
14                    name: "nginx",
15                    image: "nginx",
16                }],
17            },
18        },
19    },
20}, { provider });
21const appService = new kubernetes.core.v1.Service("do-app-svc", {
22    spec: {
23        type: "LoadBalancer",
24        selector: app.spec.template.metadata.labels,
25        ports: [{ port: 80 }],
26    },
27}, { provider });
28
29export const ingressIp = appService.status.loadBalancer.ingress[0].ip;

此代码类似于标准的Kubernetes配置,对象及其属性的行为相当,但它与其他基础设施声明一起写在TypeScript中。

保存并关闭文件后进行更改。

就像以前一样,运行pulumi up来预览,然后部署更改:

1pulumi up

选择后,CLI 会打印详细的状态更新,包括有关 Pod 可用性的诊断、IP 地址分配等。

完整的输出将看起来像这样的东西:

 1[secondary_label Output]
 2Updating (dev):
 3
 4     Type Name Status
 5     pulumi:pulumi:Stack do-k8s-dev
 6 +   ├─ pulumi:providers:kubernetes do-k8s created
 7 +   ├─ kubernetes:apps:Deployment do-app-dep created
 8 +   └─ kubernetes:core:Service do-app-svc created
 9
10Outputs:
11  + ingressIp : "157.230.199.202"
12
13Resources:
14    + 3 created
15    2 unchanged
16
17Duration: 2m52s
18
19Permalink: https://app.pulumi.com/.../do-k8s/dev/updates/2

完成此操作后,请注意所需数量的Pod正在运行:

1KUBECONFIG=./kubeconfig.yml kubectl get pods
1[secondary_label Output]
2NAME READY STATUS RESTARTS AGE
3do-app-dep-vyf8k78z-758486ff68-5z8hk 1/1 Running 0 1m
4do-app-dep-vyf8k78z-758486ff68-8982s 1/1 Running 0 1m
5do-app-dep-vyf8k78z-758486ff68-94k7b 1/1 Running 0 1m
6do-app-dep-vyf8k78z-758486ff68-cqm4c 1/1 Running 0 1m
7do-app-dep-vyf8k78z-758486ff68-lx2d7 1/1 Running 0 1m

类似于该程序如何导出集群的kubeconfig文件,该程序还导出由 Kubernetes 服务产生的负载平衡器的 IP 地址。

1curl $(pulumi stack output ingressIp)
 1[secondary_label Output]
 2<!DOCTYPE html>
 3<html>
 4<head>
 5<title>Welcome to nginx!</title>
 6<style>
 7    body {
 8        width: 35em;
 9        margin: 0 auto;
10        font-family: Tahoma, Verdana, Arial, sans-serif;
11    }
12</style>
13</head>
14<body>
15<h1>Welcome to nginx!</h1>
16<p>If you see this page, the nginx web server is successfully installed and
17working. Further configuration is required.</p>
18
19<p>For online documentation and support please refer to
20<a href="http://nginx.org/">nginx.org</a>.<br/>
21Commercial support is available at
22<a href="http://nginx.com/">nginx.com</a>.</p>
23
24<p><em>Thank you for using nginx.</em></p>
25</body>
26</html>

从这里,您可以轻松编辑和重新部署您的应用基础设施,例如,尝试更改复制: 5行,说复制: 7,然后重复pulumi up:

1pulumi up

注意,它只显示了发生了什么变化,并且选择细节显示了准确的差异:

 1[secondary_label Output]
 2Previewing update (dev):
 3
 4     Type Name Plan Info
 5     pulumi:pulumi:Stack do-k8s-dev
 6 ~   └─ kubernetes:apps:Deployment do-app-dep update     [diff: ~spec]
 7
 8Resources:
 9    ~ 1 to update
10    4 unchanged
11
12Do you want to perform this update? details
13  pulumi:pulumi:Stack: (same)
14    [urn=urn:pulumi:dev::do-k8s::pulumi:pulumi:Stack::do-k8s-dev]
15    ~ kubernetes:apps/v1:Deployment: (update)
16        [id=default/do-app-dep-vyf8k78z]
17        [urn=urn:pulumi:dev::do-k8s::kubernetes:apps/v1:Deployment::do-app-dep]
18        [provider=urn:pulumi:dev::do-k8s::pulumi:providers:kubernetes::do-k8s::80f36105-337f-451f-a191-5835823df9be]
19      ~ spec: {
20          ~ replicas: 5 => 7
21        }

现在您既有完全功能的 Kubernetes 集群,也拥有一个工作应用程序. 随着应用程序的启动和运行,您可能想要配置一个自定义域以与应用程序一起使用。

步骤 5 — 创建 DNS 域名(可选)

虽然Kubernetes集群和应用程序正在运行,但应用程序的地址取决于集群自动分配IP地址的诱惑。当你调整和重新部署东西时,这个地址可能会发生变化。

<$>[注] 注: 要完成此步骤,请确保您拥有使用 DigitalOcean 的 DNS 名称服务器的域名:ns1.digitalocean.com、ns2.digitalocean.com 和ns3.digitalocean.com。

要配置 DNS,请打开 index.ts 文件,并将下列代码附加到文件的末尾:

1[label index.ts]
2...
3const domain = new digitalocean.Domain("do-domain", {
4    name: "your_domain",
5    ipAddress: ingressIp,
6});

此代码会创建一个新的 DNS 条目,其中包含一个 A 条目,该条目指向您的 Kubernetes 服务的 IP 地址。

通常,需要额外的子域,如www,指向 Web 应用程序. 这是很容易实现的,使用一个 DigitalOcean DNS 记录. 为了使这个例子更有趣,还添加一个CNAME记录,指向www.your_domain.comyour_domain.com:

1[label index.ts]
2...
3const cnameRecord = new digitalocean.DnsRecord("do-domain-cname", {
4    domain: domain.name,
5    type: "CNAME",
6    name: "www",
7    value: "@",
8});

保存并关闭这些更改后的文件。

最后,运行pulumi up来部署 DNS 更改,以指向您的现有应用程序和群集:

 1[secondary_label Output]
 2Updating (dev):
 3
 4     Type Name Status
 5     pulumi:pulumi:Stack do-k8s-dev
 6 +   ├─ digitalocean:index:Domain do-domain created
 7 +   └─ digitalocean:index:DnsRecord do-domain-cname created
 8
 9Resources:
10    + 2 created
11    5 unchanged
12
13Duration: 6s
14
15Permalink: https://app.pulumi.com/.../do-k8s/dev/updates/3

在 DNS 更改扩散后,您将能够在自定义域访问您的内容:

1curl www.your_domain.com

您将收到类似于以下的输出:

 1[secondary_label Output]
 2<!DOCTYPE html>
 3<html>
 4<head>
 5<title>Welcome to nginx!</title>
 6<style>
 7    body {
 8        width: 35em;
 9        margin: 0 auto;
10        font-family: Tahoma, Verdana, Arial, sans-serif;
11    }
12</style>
13</head>
14<body>
15<h1>Welcome to nginx!</h1>
16<p>If you see this page, the nginx web server is successfully installed and
17working. Further configuration is required.</p>
18
19<p>For online documentation and support please refer to
20<a href="http://nginx.org/">nginx.org</a>.<br/>
21Commercial support is available at
22<a href="http://nginx.com/">nginx.com</a>.</p>
23
24<p><em>Thank you for using nginx.</em></p>
25</body>
26</html>

通过此,您已成功设置了一个新的DigitalOcean Kubernetes集群,部署了一个负载平衡的Kubernetes应用程序,并给该应用程序的负载平衡器一个使用DigitalOcean DNS的稳定域名,所有在60行代码和一个pulumi up命令。

下一步将引导您删除资源,如果您不再需要它们。

步骤 6 — 删除资源(可选)

在完成教程之前,您可能想要摧毁上述所有资源,这将确保您不会为未使用的资源收取费用。

运行以下命令来摧毁资源. 要小心使用这个,因为它不能被取消!

1pulumi destroy

命令一样,摧毁在采取行动之前会显示预览和提示:

 1[secondary_label Output]
 2Previewing destroy (dev):
 3
 4     Type Name Plan
 5 -   pulumi:pulumi:Stack do-k8s-dev delete
 6 -   ├─ digitalocean:index:DnsRecord do-domain-cname delete
 7 -   ├─ digitalocean:index:Domain do-domain delete
 8 -   ├─ kubernetes:core:Service do-app-svc delete
 9 -   ├─ kubernetes:apps:Deployment do-app-dep delete
10 -   ├─ pulumi:providers:kubernetes do-k8s delete
11 -   └─ digitalocean:index:KubernetesCluster do-cluster delete
12
13Resources:
14    - 7 to delete
15
16Do you want to perform this destroy?
17  yes
18> no
19  details

假设这是你想要的,选择并观看删除发生:

 1[secondary_label Output]
 2Destroying (dev):
 3
 4     Type Name Status
 5 -   pulumi:pulumi:Stack do-k8s-dev deleted
 6 -   ├─ digitalocean:index:DnsRecord do-domain-cname deleted
 7 -   ├─ digitalocean:index:Domain do-domain deleted
 8 -   ├─ kubernetes:core:Service do-app-svc deleted
 9 -   ├─ kubernetes:apps:Deployment do-app-dep deleted
10 -   ├─ pulumi:providers:kubernetes do-k8s deleted
11 -   └─ digitalocean:index:KubernetesCluster do-cluster deleted
12
13Resources:
14    - 7 deleted
15
16Duration: 7s
17
18Permalink: https://app.pulumi.com/.../do-k8s/dev/updates/4

此时,没有剩下任何东西: DNS 条目已经消失,Kubernetes 集群以及内部运行的应用程序已经消失了。永久链接仍然可用,因此您仍然可以返回并查看此堆栈的完整更新历史记录。

如果您想摧毁整个项目,请删除堆栈:

1pulumi stack rm

您将收到输出,要求您通过键入堆栈名称来确认删除:

1[secondary_label Output]
2This will permanently remove the 'dev' stack!
3Please confirm that this is what you'd like to do by typing ("dev"):

与删除命令不同,该命令删除云基础设施资源,删除堆栈完全从Pulumi的预览中删除您的堆栈的完整历史。

结论

在本教程中,您已部署了DigitalOcean基础设施资源,包括具有A和CNAME记录的Kubernetes集群和DNS域,以及使用该集群的Kubernetes应用程序配置。

从这里开始,你可以采取以下几个步骤:

本教程的全部样本可在GitHub上找到(https://github.com/do-community/pulumi-kubernetes)。 有关如何在今天的项目中使用Pulumi基础设施作为代码的详细信息,请查看 Pulumi 文档, 教程,或 Getting Started指南。

Published At
Categories with 技术
comments powered by Disqus