_作者はhttps://www.brightfunds.org/funds/diversity-in-tech [技術基金の多様性]を選択して、https://do.co/w4do-cta [Donationsの書き込み]の一部として寄付を受け取りました]プログラム。

前書き

Pulumiは、汎用プログラミング言語で記述されたコードを使用してインフラストラクチャを作成、展開、管理するためのツールです。 アプリケーションの構成に加えて、Droplet、管理データベース、DNSレコード、Kubernetesクラスターなど、DigitalOceanのすべての管理サービスの自動化をサポートしています。 展開は使いやすいコマンドラインインターフェイスから実行されます。このインターフェイスは、さまざまな一般的なCI / CDシステムとも統合されています。

Pulumiは複数の言語をサポートしていますが、このチュートリアルでは、https://www.typescriptlang.org/ [TypeScript]を使用します。これは、https://developer.mozilla.org/en-US/docs/Web/JavaScript [ Node.jsランタイムを使用するJavaScript]。 これは、適切なリソースの設定、正しいスラッグの使用などを確実に行うのに役立つIDEサポートとコンパイル時のチェックを取得しながら、https://www.npmjs.com/ [にアクセスできることを意味しますNPM]ユーティリティタスク用のモジュール。

このチュートリアルでは、DigitalOcean Kubernetesクラスター、負荷分散Kubernetesアプリケーション、および選択した安定したドメイン名でアプリケーションを使用できるようにするDigitalOcean DNSドメインをプロビジョニングします。 これはすべて、60行のインフラストラクチャとしてのコードと1つの「+ pulumi up +」コマンドラインジェスチャでプロビジョニングできます。 このチュートリアルを完了すると、DigitalOceanとKubernetesの全領域を活用するPulumi as-codeを使用して強力なクラウドアーキテクチャを生産的に構築する準備が整います。

前提条件

このチュートリアルを実行するには、次のものが必要です。

  • リソースをデプロイするDigitalOceanアカウント。 まだお持ちでない場合は、https://cloud.digitalocean.com/registrations/new [こちらから登録]をご覧ください。

  • 自動展開を実行するDigitalOcean APIトークン。 https://www.digitalocean.com/docs/api/create-personal-access-token/ [ここに個人用アクセストークンを生成]を使用して、手順2で使用するときに手元に置いておきます。

  • Kubernetesクラスターを作成および使用するため、https://kubernetes.io/docs/tasks/tools/install-kubectl/ [install + kubectl +]が必要です。 さらに設定することについて心配する必要はありません。後で設定します。

  • TypeScriptでインフラストラクチャとしてコードを記述するため、Node.js 8以降が必要になります。 https://nodejs.org/en/download/ [ここからダウンロード]またはhttps://nodejs.org/en/download/package-manager/ [システムのパッケージマネージャーを使用]をインストールします。

  • Pulumiを使用してインフラストラクチャを展開するため、https://www.pulumi.com/docs/reference/install/ [オープンソースPulumi SDKをインストールする]が必要です。

  • オプションのステップ5を実行するには、DigitalOceanネームサーバーを使用するように構成されたドメイン名が必要です。 https://www.digitalocean.com/community/tutorials/how-to-point-to-digitalocean-nameservers-from-common-domain-registrars [このガイド]は、選択したレジストラでこれを行う方法を説明しています。

ステップ1-新しいプロジェクトの足場

最初のステップは、Pulumiプロジェクトを保存するディレクトリを作成することです。 このディレクトリには、プロジェクトとそのNPM依存関係を説明するメタデータファイルに加えて、インフラストラクチャ定義のソースコードが含まれます。

まず、ディレクトリを作成します。

mkdir do-k8s

次に、新しく作成されたディレクトリに移動します。

cd do-k8s

これから、新しく作成した `+ do-k8s +`ディレクトリからコマンドを実行します。

次に、新しいPulumiプロジェクトを作成します。 これを実現するにはさまざまな方法がありますが、最も簡単な方法は、 `+ typescript `プロジェクトテンプレートで ` pulumi new +`コマンドを使用することです。 このコマンドは、最初にPulumiにログインするように促し、プロジェクトとデプロイメントの状態を保存してから、現在のディレクトリに単純なTypeScriptプロジェクトを作成します。

pulumi new typescript -y

ここでは、デフォルトのプロジェクトオプションを受け入れるように指示する `+ new `コマンドに ` -y `オプションを渡しました。 たとえば、プロジェクト名は現在のディレクトリの名前から取得されるため、 ` do-k8s `になります。 プロジェクト名にさまざまなオプションを使用する場合は、単に「 -y +」を省略します。

コマンドを実行した後、 `+ ls +`を使用してディレクトリの内容を一覧表示します。

ls

次のファイルが存在するようになります。

OutputPulumi.yaml       index.ts          node_modules
package-lock.json package.json      tsconfig.json

編集するプライマリファイルは* + index.ts + *です。 このチュートリアルではこの単一のファイルのみを使用しますが、Node.jsモジュールを使用して、プロジェクトを適切に編成することができます。 このチュートリアルでは、Pulumiが変更内容のみを検出して段階的に展開できるという事実を活用して、一度に1ステップずつ説明します。 必要に応じて、プログラム全体を入力し、 `+ pulumi up +`を使用してすべてを一度に展開できます。

新しいプロジェクトを足場にしたので、チュートリアルを進めるために必要な依存関係を追加する準備ができました。

ステップ2-依存関係の追加

次のステップは、DigitalOceanおよびKubernetesパッケージのインストールと依存関係の追加です。 最初に、NPMを使用してインストールします。

npm install @pulumi/digitalocean @pulumi/kubernetes

これにより、NPMパッケージ、Pulumiプラグインがダウンロードされ、依存関係として保存されます。

次に、お気に入りのエディターで `+ index.ts +`ファイルを開きます。 このチュートリアルではnanoを使用します。

nano index.ts

`+ index.ts +`の内容を次のものに置き換えます:

index.ts

import * as digitalocean from "@pulumi/digitalocean";
import * as kubernetes from "@pulumi/kubernetes";

これにより、これらのパッケージのすべての内容がプログラムで利用可能になります。 TypeScriptとNode.jsを理解するIDEを使用して `” digitalocean。 “`を入力すると、たとえば、このパッケージでサポートされるDigitalOceanリソースのリストが表示されます。

コンテンツを追加した後、ファイルを保存して閉じます。

次に、Pulumiがアカウントのリソースをプロビジョニングできるように、DigitalOceanトークンを構成します。

pulumi config set digitalocean:token  --secret

`-secret +`フラグに注目してください。これは、Pulumiの暗号化サービスを使用してトークンを暗号化し、暗号化テキストに保存されるようにします。 必要に応じて、代わりに環境変数 ` DIGITALOCEAN_TOKEN +`を使用できますが、プログラムを更新するたびに設定することを忘れないでください。設定を使用すると、プロジェクトに自動的に保存され使用されます。

このステップでは、Kubernetesクラスターをプロビジョニングできるように、必要な依存関係を追加し、PulumiでAPIトークンを構成しました。

ステップ3-Kubernetesクラスターのプロビジョニング

これで、DigitalOcean Kubernetesクラスターを作成する準備が整いました。 `+ index.ts +`ファイルを再度開くことから始めましょう:

nano index.ts

`+ 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 +`のインスタンスを割り当て、それに多数のプロパティを設定します。 これには、 `+ sfo2 + region slug、Kubernetesの `+ latest `サポートバージョン、 ` s-​​2vcpu-2gb +`の使用が含まれますhttps://developers.digitalocean.com/documentation/changelog/api-v2/new-size-slugs-for-droplet-plan-changes/[Droplet size slug]、および3つのDropletインスタンスの必要な数を示します。 これらは自由に変更できますが、この記事の執筆時点では、DigitalOcean Kubernetesは特定の地域でのみ利用可能です。 地域の可用性に関する最新情報については、https://www.digitalocean.com/docs/kubernetes/overview/ [製品ドキュメント]を参照してください。

クラスターで設定できるプロパティの完全なリストについては、https://www.pulumi.com/docs/reference/pkg/nodejs/pulumi/digitalocean/#KubernetesCluster [+ KubernetesCluster + APIドキュメント]を参照してください。

そのコードスニペットの最後の行は、結果のKubernetesクラスターのhttps://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/ [`+ kubeconfig `ファイル]をエクスポートして使いやすくしています。 エクスポートされた変数はコンソールに出力され、ツールからもアクセスできます。 これを一時的に使用して、 ` kubectl +`などの標準ツールからクラスターにアクセスします。

これで、クラスターをデプロイする準備が整いました。 そのためには、 `+ pulumi up +`を実行します:

pulumi up

このコマンドは、プログラムを取得し、説明されているインフラストラクチャを作成するための計画を生成し、それらの変更を展開するための一連の手順を実行します。 これは、後続の更新が行われたときにインフラストラクチャを比較および更新できることに加えて、インフラストラクチャの最初の作成でも機能します。 この場合、出力は次のようになります。

OutputPreviewing 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 +`を選択して展開を開始します。

OutputUpdating (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

次のような出力が表示されます。

OutputNAME           STATUS    ROLES     AGE       VERSION
default-o4sj   Ready     <none>    4m5s      v1.14.2
default-o4so   Ready     <none>    4m3s      v1.14.2
default-o4sx   Ready     <none>    3m37s     v1.14.2

この時点で、Infrastructure-as-Codeをセットアップし、新しいDigitalOcean Kubernetesクラスターを起動して構成するための繰り返し可能な方法を使用できました。 次のステップでは、これに基づいてコードでKubernetesインフラストラクチャを定義し、Kubernetesインフラストラクチャを同様に展開および管理する方法を学習します。

ステップ4-クラスターへのアプリケーションのデプロイ

次に、Infrastructure-as-codeを使用してKubernetesアプリケーションの構成を説明します。 これは3つの部分で構成されます。

  1. `+ kubectl `を使用するように設定されているデフォルトではなく、PulumiにKubernetesリソースをDigitalOceanクラスターにデプロイするよう指示する ` Provider +`オブジェクト。

  2. Kubernetes Deployment。これは、任意の数のPodで複製されるDockerコンテナーイメージをデプロイするKubernetesの標準的な方法です。

  3. Kubernetes Service。これは、Kubernetesにターゲットポッドセット(この場合は上記のデプロイメント)全体でアクセスを負荷分散するよう指示する標準的な方法です。 )。

これは、Kubernetesで負荷分散サービスを起動して実行するためのかなり標準的な_参照アーキテクチャ_です。

これら3つすべてをデプロイするには、 `+ index.ts +`ファイルを再度開きます。

nano index.ts

ファイルが開いたら、このコードをファイルの最後に追加します。

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はポッドの可用性、IPアドレスの割り当てなどに関する診断を含む詳細なステータスの更新を出力します。 これにより、展開の完了に時間がかかったり、停止したりする理由を理解できます。

完全な出力は次のようになります。

OutputUpdating (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
OutputNAME                                   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 」ファイルをエクスポートする方法と同様に、このプログラムはKubernetesサービスの結果のロードバランサーのIPアドレスもエクスポートします。 これを使用してエンドポイントを「 curl +」し、稼働していることを確認します。

curl $(pulumi stack output ingressIp)
Output<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
   body {
       width: 35em;
       margin: 0 auto;
       font-family: Tahoma, Verdana, Arial, sans-serif;
   }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

ここから、アプリケーションインフラストラクチャを簡単に編集および再デプロイできます。 たとえば、 `+ replicas:5 `の行を ` replicas:7 `と言うように変更してから、 ` pulumi up +`を再実行してください。

pulumi up

変更内容を表示するだけであり、詳細を選択すると正確な差分が表示されることに注意してください。

OutputPreviewing 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アドレス割り当ての気まぐれに依存しています。 調整して再デプロイすると、このアドレスが変わる可能性があります。 このステップでは、後でインフラストラクチャを変更しても安定するように、ロードバランサーのIPアドレスにカスタムDNS名を割り当てる方法を確認します。

DNSを設定するには、 `+ index.ts +`ファイルを開き、ファイルの最後に次のコードを追加します。

index.ts

...
const domain = new digitalocean.Domain("do-domain", {
   name: "",
   ipAddress: ingressIp,
});

このコードは、KubernetesサービスのIPアドレスを参照するAレコードを持つ新しいDNSエントリを作成します。 このスニペットの「+ your_domain +」を選択したドメイン名に置き換えます。

`+ www `のような追加のサブドメインがWebアプリケーションを指すようにするのが一般的です。 これは、DigitalOcean DNSレコードを使用して簡単に達成できます。 この例をもっと面白くするには、「 www..com 」を「 .com 」にポイントする「 CNAME」レコードも追加します。

index.ts

...
const cnameRecord = new digitalocean.DnsRecord("do-domain-cname", {
   domain: domain.name,
   type: "CNAME",
   name: "www",
   value: "@",
});

これらの変更を行った後、ファイルを保存して閉じます。

最後に、 `+ pulumi up +`を実行して、既存のアプリケーションとクラスターを指すようにDNSの変更をデプロイします。

OutputUpdating (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..com

次のような出力が表示されます。

Output<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
   body {
       width: 35em;
       margin: 0 auto;
       font-family: Tahoma, Verdana, Arial, sans-serif;
   }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

これで、新しいDigitalOcean Kubernetesクラスターを正常にセットアップし、負荷分散されたKubernetesアプリケーションをデプロイし、そのアプリケーションのロードバランサーにDigitalOcean DNSを使用した安定したドメイン名をすべて60行のコードと「+ pulumi up +」で与えましたコマンド。

次の手順では、不要になったリソースを削除する方法を説明します。

ステップ6-リソースの削除(オプション)

チュートリアルを終了する前に、上記で作成したすべてのリソースを破棄することができます。 これにより、使用されていないリソースに対して課金されることがなくなります。 アプリケーションを稼働したままにする場合は、この手順をスキップしてください。

次のコマンドを実行して、リソースを破棄します。 これは元に戻せないため、使用には注意してください!

pulumi destroy

`+ up `コマンドと同様に、 ` destroy +`はアクションを実行する前にプレビューとプロンプトを表示します:

OutputPreviewing 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 +`を選択して削除が発生するのを見てください:

OutputDestroying (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クラスターは、その内部で実行されているアプリケーションとともに、消えています。 パーマリンクはまだ利用可能ですので、戻ってこのスタックの更新の完全な履歴を見ることができます。 これは、サービスがすべてのリソースの完全な状態履歴を保持するため、破壊が間違いだった場合の回復に役立ちます。

プロジェクト全体を破壊する場合は、スタックを削除します。

pulumi stack rm

スタックの名前を入力して、削除の確認を求める出力を受け取ります。

OutputThis will permanently remove the 'dev' stack!
Please confirm that this is what you'd like to do by typing ("dev"):

クラウドインフラストラクチャリソースを削除するdestroyコマンドとは異なり、スタックを削除すると、Pulumiの範囲からスタックの完全な履歴が完全に消去されます。

結論

このチュートリアルでは、このクラスターを使用するKubernetesアプリケーション構成に加えて、DigitalOceanインフラストラクチャリソース(KubernetesクラスターとAおよびCNAMEレコードを持つDNSドメイン)をデプロイしました。 既存のエディタ、ツール、およびライブラリで動作し、既存のコミュニティとパッケージを活用する、使い慣れたプログラミング言語TypeScriptで記述されたコードとしてのインフラストラクチャを使用してこれを行いました。 アプリケーションとインフラストラクチャにまたがる展開を行うために、単一のコマンドラインワークフローを使用してすべてを完了しました。

ここから、次のいくつかの手順を実行できます。

このチュートリアルのサンプル全体は、https://github.com/do-community/pulumi-kubernetes [GitHubで入手可能]です。 今日のプロジェクトでPulumiインフラストラクチャとしてコードを使用する方法の詳細については、https://www.pulumi.com/docs [Pulumi Documentation]、https://www.pulumi.com/docs/をご覧ください。 reference / tutorials [チュートリアル]、またはhttps://www.pulumi.com/docs/quickstart [はじめに]ガイド。 Pulumiはオープンソースであり、無料で使用できます。