# Pulumi

## **Pulumiとは**

PulumiはInfrastructure as Code (IaC)を支援するオープンソースのツールであり、クラウドリソースの作成、デプロイメント、管理を行うためのプラットフォームです。あらゆるクラウドプロバイダー（AWS、Google Cloud、Azure等）と互換性があります。また、JavaScript、TypeScript、Python、Go、C#など、複数の人気のあるプログラミング言語での利用が可能です。

例えば、新しいPulumiプロジェクトを作成するには以下のコマンドを使用します：

```bash
$ pulumi new aws-typescript
```

### **Infrastructure as Code (IaC)とは**

Infrastructure as Code (IaC)は、ソフトウェア開発の手法の一つで、インフラストラクチャをコードで定義し、バージョン管理を行うことで、安定した開発環境を構築・運用することを可能にします。コードによるインフラストラクチャの管理は、手動での設定作業を減らし、一貫性と再現性を確保します。

### **Pulumiの利点と主な使用ケース**

Pulumiの利点は以下の通りです：

1. **プログラミング言語**: 複数の主流のプログラミング言語を使用してインフラをコード化できます。これにより、開発者は既に知っている言語を使用してインフラを管理することができます。
2. **クラウドプロバイダーに対するサポート**: Pulumiは多くの主流のクラウドプロバイダーをサポートしています。これにより、マルチクラウドのデプロイメントを一貫性を持って管理することができます。
3. **再利用可能なコンポーネント**: Pulumiではコードを共有して再利用することが可能です。これにより、開発者は特定のインフラストラクチャーパターンを再利用して、迅速に新しいサービスをデプロイできます。

主な使用ケースは以下の通りです：

1. **インフラの作成と管理**: Pulumiはインフラストラクチャの作成と管理を一貫性を持って行うことができます。
2. **マルチクラウドデプロイメント**: PulumiはAWS、Google Cloud、Azureなど、複数のクラウドプロバイダーをサポートしているため、一元的に管理することができます。
3. **継続的デリバリー/継続的デプロイメント(CD)**: PulumiはCDパイプラインに組み込むことができ、インフラの変更を自動化することが可能です。

## **Pulumiのインストールと設定**

* **システム要件** PulumiはmacOS、Linux、Windows上で動作します。また、Pulumiを利用するためには、対象とするクラウドプロバイダー（例えばAWS、GCP、Azure等）へのアクセスが必要です。このアクセスは通常、プロバイダーから提供されるAPIキーまたは認証情報を利用して確立します。
* **Pulumiのインストール方法(Ubuntu)** Pulumiのインストールはシェルスクリプトを用いて行います。以下のコマンドを実行することでインストールできます:

```bash
curl -fsSL https://get.pulumi.com | sh
```

このコマンドは、PulumiのCLIツールをダウンロードし、システムのパスに追加します。

* **Pulumiの初期設定** Pulumiを使用するための初期設定は、新しいプロジェクトの作成と対象のクラウドプロバイダーへの接続を含みます。

  新しいPulumiプロジェクトを作成するには、以下のコマンドを実行します:

```bash
pulumi new <cloud-provider> -n <project-name> -d <project-description>
```

ここで `<cloud-provider>` は対象のクラウドプロバイダー（`aws`, `azure`, `gcp` 等）、`<project-name>` はプロジェクトの名前、`<project-description>` はプロジェクトの説明を指します。

次に、特定のクラウドプロバイダーへの接続を設定します。これは、通常、プロバイダーから提供されるAPIキーまたは認証情報を使用して行います。たとえば、AWSを対象とする場合、AWS CLIを既に設定していれば、Pulumiはその設定を使用します。他の方法として、環境変数を設定する方法もあります:

```bash
export AWS_ACCESS_KEY_ID=<your-key-here>
export AWS_SECRET_ACCESS_KEY=<your-secret-key-here>
```

これらの設定後、Pulumiは対象とするクラウドプロバイダーと通信できます。初期設定はこれで完了です。

## **基本的なPulumiの概念と用語**

### **スタックとは**

スタックは、Pulumiが管理するインフラストラクチャの独立したインスタンスを指します。各スタックは独自の設定を持ち、通常は開発(`dev`), ステージング(`staging`), 本番(`prod`)などの環境ごとに別々のスタックが作成されます。スタックは以下のコマンドで作成、選択、削除が可能です。

新しいスタックを作成:

```bash
$ pulumi stack init dev
```

スタックを選択:

```bash
$ pulumi stack select dev
```

スタックを削除:

```bash
$ pulumi stack rm dev
```

### **プロジェクトとは**

プロジェクトは、Pulumiで管理されるコードの集合体を指します。プロジェクトは特定のリポジトリやディレクトリに対応し、設定ファイル(`Pulumi.yaml`)によって定義されます。プロジェクトには、使用するクラウドプロバイダーやプログラミング言語の情報が含まれます。

### **プロバイダーとは**

プロバイダーは、特定のクラウドプロバイダー（AWS、GCP、Azureなど）またはインフラサービス（Kubernetes、MySQLなど）とのインターフェースを提供します。プロバイダーは、リソースを作成、更新、削除するためのAPIを抽象化します。プロバイダーは、Pulumiのプログラム内でインスタンス化され、そのインスタンスを通じてリソースが管理されます。

例（AWSプロバイダーのインスタンス化）:

```typescript
import * as aws from "@pulumi/aws";

const provider = new aws.Provider("my-provider", {
  region: "us-west-2",
});
```

### **リソースとは**

リソースは、クラウドリソース（例：EC2インスタンス、S3バケットなど）を表すPulumiの抽象化です。リソースはプロバイダーによって作成、更新、削除が管理されます。

例（AWS S3バケットの作成）:

```typescript
import * as aws from "@pulumi/aws";

const bucket = new aws.s3.Bucket("my-bucket");
```

## **Pulumiの使用方法**

### **新しいPulumiプロジェクトの作成**

新しいPulumiプロジェクトを作成するには、以下のコマンドを使用します：

```bash
$ pulumi new <template> 
```

ここで `<template>` は使用するプログラミング言語とクラウドプロバイダーに基づくテンプレートを指定します。例えば、AWSでTypeScriptを使用する場合、コマンドは次のようになります：

```bash
$ pulumi new aws-typescript
```

### **リソースの追加と削除**

リソースの追加や削除は、Pulumiプログラム内で行います。例えば、AWSのS3バケットを追加する場合、次のようなコードを追加します：

```typescript
import * as aws from "@pulumi/aws";

const bucket = new aws.s3.Bucket("my-bucket");
```

このコードを追加した後、`pulumi up` コマンドを実行すると、Pulumiは新しいS3バケットを作成します：

```bash
$ pulumi up
```

リソースを削除するには、Pulumiプログラムから対応するコードを削除します。その後、`pulumi up` コマンドを再度実行すると、Pulumiは該当のリソースを削除します。

### **スタックの操作**

スタックは、以下のコマンドを使用して作成、選択、削除を行います：

新しいスタックを作成：

```bash
$ pulumi stack init <stack-name>
```

スタックを選択：

```bash
$ pulumi stack select <stack-name>
```

スタックを削除：

```bash
$ pulumi stack rm <stack-name>
```

ここで `<stack-name>` はスタックの名前を指定します。

## **Pulumiによるクラウドプロバイダーとの連携**

Pulumiは、AWS、GCP、Azureなどの主要なクラウドプロバイダーと連携します。これらの各プロバイダーとの連携は、該当するプロバイダーのPulumiパッケージをプロジェクトにインポートし、認証情報を設定することで行います。

* **AWSとの連携** AWSと連携するには、AWSのPulumiパッケージをインポートします：

  ```typescript
  import * as aws from "@pulumi/aws";
  ```

  AWSの認証情報は、通常、既存のAWS CLI設定を使用します。特に指定がなければ、Pulumiはデフォルトのプロファイルを使用します。特定のプロファイルを使用するには、`AWS_PROFILE` 環境変数を設定します：

  ```bash
  export AWS_PROFILE=<profile-name>
  ```
* **GCPとの連携** GCPと連携するには、GCPのPulumiパッケージをインポートします：

  ```typescript
  import * as gcp from "@pulumi/gcp";
  ```

  GCPの認証情報は、通常、環境変数`GOOGLE_CREDENTIALS` に設定されたサービスアカウントのJSONキーを使用します：

  ```bash
  export GOOGLE_CREDENTIALS=<service-account-json-key>
  ```
* **Azureとの連携** Azureと連携するには、AzureのPulumiパッケージをインポートします：

  ```typescript
  import * as azure from "@pulumi/azure";
  ```

  Azureの認証情報は、通常、既存のAzure CLI設定を使用します。特に指定がなければ、Pulumiはデフォルトのプロファイルを使用します。

### 既存のクラウドリソースの取り込み

既に手動で作られているリソースを取り込む場合、以下のプログラムを活用してimport.jsonを生成して必要なものを選択し編集します。

{% embed url="<https://github.com/pulumi/pulumi-cloud-import>" %}

その後 `pulumi import -f import.json` コマンドで取り込みましょう。

## **プログラミング言語とPulumi**

Pulumiは、JavaScript、TypeScript、Pythonなど、複数の人気のあるプログラミング言語をサポートしています。

* **JavaScript/TypeScriptとPulumi** JavaScriptやTypeScriptを使用して、Pulumiでインフラストラクチャを定義できます。以下に、TypeScriptでAWS S3バケットを作成する例を示します。

  ```typescript
  import * as pulumi from "@pulumi/pulumi";
  import * as aws from "@pulumi/aws";

  const bucket = new aws.s3.Bucket("my-bucket");

  export const bucketName = bucket.id;
  ```

  このスクリプトは、新しいS3バケットを作成し、バケットの名前をエクスポートします。スクリプトを保存したら、以下のコマンドでPulumiを実行します。

  <pre class="language-bash"><code class="lang-bash"><strong>$ pulumi up
  </strong></code></pre>
* **PythonとPulumi** Pythonでも同様にPulumiを使用できます。以下に、PythonでAWS S3バケットを作成する例を示します。

  ```python
  import pulumi
  from pulumi_aws import s3

  bucket = s3.Bucket('my-bucket')

  pulumi.export('bucket_name', bucket.id)
  ```

  このスクリプトも新しいS3バケットを作成し、バケットの名前をエクスポートします。スクリプトを保存したら、以下のコマンドでPulumiを実行します。

  ```bash
  $ pulumi up
  ```

それぞれの言語でのPulumiの使用は似ていますが、各言語の特性と慣習に基づく違いがあります。たとえば、非同期処理の扱いやエラーハンドリングなどが異なります。具体的な使い方は、各言語でのPulumiの公式ドキュメンテーションを参照してください。

## **Pulumiの高度なトピック**

* **ステート管理** Pulumiは「ステート」を使用して、管理されているインフラストラクチャの現在の状態を追跡します。ステートは、Pulumiのサービス（デフォルト）、Amazon S3、Google Cloud Storage、Azure Storageなどに保存できます。

  ステートの場所を設定するには、Pulumiの設定ファイル(`Pulumi.yaml`)で `backend` オプションを設定します。例えば、ステートをS3に保存するには、以下のように設定します：

  ```yaml
  backend: "s3://my-pulumi-state"
  ```

  ステートを変更したい場合は、 `pulumi login` コマンドを使用します：

  ```bash
  $ pulumi login s3://my-pulumi-state
  ```
* **マルチクラウドデプロイメント** Pulumiを使用すれば、単一のプロジェクトで複数のクラウドプロバイダーと連携できます。以下に、AWSのS3バケットとGCPのGCSバケットを同時に作成するTypeScriptの例を示します：

  ```typescript
  import * as aws from "@pulumi/aws";
  import * as gcp from "@pulumi/gcp";

  const awsBucket = new aws.s3.Bucket("my-aws-bucket");
  const gcpBucket = new gcp.storage.Bucket("my-gcp-bucket");

  export const awsBucketName = awsBucket.id;
  export const gcpBucketName = gcpBucket.name;
  ```
* **テストとデバッグ** Pulumiは標準的なデバッグツールを使用できます。TypeScriptの場合、Node.jsのデバッガを使用します。Pythonの場合は、pdbやipdbなどの標準的なPythonデバッグツールを使用します。

  テストの場合、PulumiはUnitテストと統合テストの両方をサポートしています。以下に、TypeScriptとPythonでのUnitテストの例を示します。

  TypeScriptのUnitテストの例：

  ```typescript
  import * as pulumi from "@pulumi/pulumi";
  import * as aws from "@pulumi/aws";
  import { assert } from "chai";

  pulumi.runtime.setMocks({
      newResource: function(type: string, name: string, inputs: any): {id: string, state: any} {
          return {id: inputs.name + "_id", state: inputs};
      },
      call: function(token: string, args: any, provider?: string): any {
          return args;
      },
  });

  describe("Bucket Tests", function() {
      let bucket: aws.s3.Bucket;

      before(async function() {
          bucket = new aws.s3.Bucket("my-bucket");
      });

      it("Must have a resource name", function(done) {
          pulumi.all([bucket.id]).apply(([id]) => {
              assert.equal(id, "my-bucket_id");
              done();
          });
      });
  });
  ```

  PythonのUnitテストの例：

  ```python
  import pulumi
  from pulumi_aws import s3
  import unittest

  class MyMocks(pulumi.runtime.Mocks):
      def new_resource(self, type_, name, inputs, provider, id_):
          return ['{}_id'.format(name), inputs]
      def call(self, token, args, provider):
          return {}

  pulumi.runtime.set_mocks(MyMocks())

  class BucketTests(unittest.TestCase):
      @pulumi.runtime.test
      def test_bucket_id(self):
          def check_bucket_id(args):
              bucket_id, = args
              assert bucket_id == 'my-bucket_id'
          return pulumi.Output.from_input('my-bucket_id').apply(check_bucket_id)

  if __name__ == '__main__':
      unittest.main()
  ```

  デバッグやテストは開発プロセスの重要な一部であり、Pulumiはこれらのツールをフルに活用できるように設計されています。

## **ベストプラクティスとパターン**

* **セキュリティ** Pulumiを使用するときのセキュリティのベストプラクティスは、クラウドリソースに関する一般的なセキュリティガイドラインに準拠しています。秘密情報はPulumiの設定システムで暗号化して保存します。以下に設定値を暗号化する例を示します：

  ```bash
  $ pulumi config set --secret mypassword $PASSWORD
  ```

  このコマンドは `mypassword` という名前の設定値を作成し、その値を暗号化します。スクリプト内でこれを参照するには、以下のようにします：

  ```python
  password = pulumi.Config().get_secret("mypassword")
  ```
* **エラーハンドリング** エラーハンドリングはPulumiスクリプトの重要な部分であり、例外を適切にキャッチして処理することが必要です。以下は、PythonでAWS S3バケットを作成するときにエラーをキャッチする例です：

  ```python
  import pulumi
  from pulumi_aws import s3

  try:
      bucket = s3.Bucket('my-bucket')
  except Exception as e:
      pulumi.log.error(f"Failed to create bucket: {str(e)}")
  ```
* **有効なコーディングパターン** Pulumiでは一般的なプログラミングパターンが使用できます。たとえば、リソースを作成する関数を作成し、それを繰り返し使用することで、コードの重複を避けることができます。以下にその例を示します：

  ```typescript
  import * as aws from "@pulumi/aws";

  function createBucket(name: string): aws.s3.Bucket {
      return new aws.s3.Bucket(name);
  }

  const bucket1 = createBucket("my-bucket1");
  const bucket2 = createBucket("my-bucket2");
  ```

  また、Pulumiのプロジェクトとスタックを適切に組織化することも重要です。プロジェクトはサービスまたはアプリケーションに対応し、スタックは環境（dev、staging、prodなど）に対応するというのが一般的なパターンです。

## **Pulumiのトラブルシューティング**

* **よくあるエラーメッセージとその対処法**

  **エラー: "error: no resource plugin 'aws-v3.2.1' found"** このエラーは、指定されたプラグインバージョンが見つからない場合に発生します。プラグインをインストールするには、以下のコマンドを実行します：

  ```bash
  $ pulumi plugin install resource aws v3.2.1
  ```

  **エラー: "error: preview failed: unrecognized resource type"** このエラーは、Pulumiがリソースタイプを認識できない場合に発生します。リソースタイプが正しいこと、必要なプロバイダープラグインがインストールされていることを確認してください。
* **リソース問題の解決** リソースの問題が発生した場合、Pulumiのコマンドラインインターフェースには問題の診断と修正を支援するいくつかのツールがあります。

  たとえば、 `pulumi up` コマンドは実行前にプレビューを表示し、どのリソースが作成、更新、削除されるかを示します。予期しない変更が表示された場合、スクリプトを確認し、問題の原因を特定します。

  さらに、 `pulumi stack export` と `pulumi stack import` コマンドを使用して、スタックの現在のステートをエクスポート、インポートできます。これは、スタックの現在の状態を確認したり、ステートを手動で修正したりするのに便利です。

## **Pulumiの学習リソース**

* **Pulumi Documentation** Pulumiの公式ドキュメンテーション（<https://www.pulumi.com/docs/）は、Pulumiの詳細なガイドとチュートリアルを提供しています。>
* **Pulumi Blog** Pulumiの公式ブログ（<https://www.pulumi.com/blog/）では、新機能、ベストプラクティス、チュートリアルなどについての記事が掲載されています。>
* **Pulumi GitHub** PulumiのGitHubリポジトリ（<https://github.com/pulumi/）には、コード例と、ユーザーや開発者とのディスカッションが含まれています。>
