既に存在するリソースをPulumiで管理してみよう

2023年10月19日(木)
大関 研丞 (Kenneth Ozeki)
第8回となる今回は、既にクラウド環境にデプロイされているリソースをPulumiで管理(import)する方法について、ハンズオンで実践していきます。

Pulumiコマンドによるimport

これまではProgramにimport option(リソースID)を追記してimport実施しましたが、pulumiコマンドによるimportも実施できます。import方法は概ね各リソースのAPIリファレンスに記載されています。今回はS3 Bucketのimportを実施します。

  1. stateは空(リソースの情報がない)の状態で、AWSマネジメントコンソールには未だPulumiで管理されていないbucketが存在している状態です。
    $ pulumi stack export
    
    {
        "version": 3,
        "deployment": {
            "manifest": {
                "time": "2023-09-28T17:27:51.298182+09:00",
                "magic": "1fce246d436c6e46d168db13ed1014131c96be0ccf8401639052718fba57ac37",
                "version": "v3.72.2"
            },
            "secrets_providers": {
                "type": "service",
                "state": {
                    "url": "https://api.pulumi.com",
                    "owner": "***",
                    "project": "pulumi-import",
                    "stack": "dev"
                }
            }
        }
    }
  2. 以下pulumi importコマンドを実行します。文法は「pulumi import [type] [name] [id] [option]」になります。コマンドを実行すると、先ほどのケース「import option(リソースID)を付与した場合のPulumi up」と同様の実行結果が表示され、既存リソースの「import」が実行されることが分かります。
    $ pulumi import aws:s3/bucket:Bucket bucket my-bucket-pulumi
    
    Previewing import (***/dev)
    
    View in Browser (Ctrl+O): https://app.pulumi.com/***/pulumi-import/dev/previews/***
    
         Type                 Name               Plan       
     +   pulumi:pulumi:Stack  pulumi-import-dev  create     
     =   └─ aws:s3:Bucket     bucket             import     
    
    
    Resources:
        + 1 to create
        = 1 to import
        2 changes
    
    Do you want to perform this import? yes
    Importing (***/dev)
    
    View in Browser (Ctrl+O): https://app.pulumi.com/***/pulumi-import/dev/updates/6
    
         Type                 Name               Status            
     +   pulumi:pulumi:Stack  pulumi-import-dev  created (3s)      
     =   └─ aws:s3:Bucket     bucket             imported (1s)     
    
    
    Resources:
        + 1 created
        = 1 imported
        2 changes
    
    Duration: 5s
  3. import完了後、stateにリソースの情報が追加されていることが確認できます。
    $ pulumi stack export
    {
        "version": 3,
        "deployment": {
            "manifest": {
                "time": "2023-09-28T17:29:55.135701+09:00",
                "magic": "1fce246d436c6e46d168db13ed1014131c96be0ccf8401639052718fba57ac37",
                "version": "v3.72.2"
            },
            "secrets_providers": {
                "type": "service",
                "state": {
                    "url": "https://api.pulumi.com",
                    "owner": "***",
                    "project": "pulumi-import",
                    "stack": "dev"
                }
            },
            "resources": [
                {
                    "urn": "urn:pulumi:dev::pulumi-import::pulumi:pulumi:Stack::pulumi-import-dev",
                    "custom": false,
                    "type": "pulumi:pulumi:Stack",
                    "created": "2023-09-28T08:29:51.720228Z",
                    "modified": "2023-09-28T08:29:51.720228Z"
                },
                {
                    "urn": "urn:pulumi:dev::pulumi-import::pulumi:providers:aws::default_6_2_1",
                    "custom": true,
                    "id": "17e2170c-0dfc-4a37-873c-242eb1fb2eec",
                    "type": "pulumi:providers:aws",
                    "inputs": {
                        "region": "ap-northeast-1",
                        "skipCredentialsValidation": "false",
                        "skipMetadataApiCheck": "true",
                        "skipRegionValidation": "true",
                        "version": "6.2.1"
                    },
                    "outputs": {
                        "region": "ap-northeast-1",
                        "skipCredentialsValidation": "false",
                        "skipMetadataApiCheck": "true",
                        "skipRegionValidation": "true",
                        "version": "6.2.1"
                    },
                    "created": "2023-09-28T08:29:52.86169Z",
                    "modified": "2023-09-28T08:29:52.86169Z"
                },
                {
                    "urn": "urn:pulumi:dev::pulumi-import::aws:s3/bucket:Bucket::bucket",
                    "custom": true,
                    "id": "my-bucket-pulumi",
                    "type": "aws:s3/bucket:Bucket",
                    "inputs": {
                        "__defaults": [],
                        "arn": "arn:aws:s3:::my-bucket-pulumi",
                        "bucket": "my-bucket-pulumi",
                        "hostedZoneId": "Z2M4EHUR26P7ZW",
                        "requestPayer": "BucketOwner",
                        "serverSideEncryptionConfiguration": {
                            "__defaults": [],
                            "rule": {
                                "__defaults": [],
                                "applyServerSideEncryptionByDefault": {
                                    "__defaults": [],
                                    "sseAlgorithm": "AES256"
                                },
                                "bucketKeyEnabled": true
                            }
                        }
                    },
                    "outputs": {
                        "accelerationStatus": "",
                        "arn": "arn:aws:s3:::my-bucket-pulumi",
                        "bucket": "my-bucket-pulumi",
                        "bucketDomainName": "my-bucket-pulumi.s3.amazonaws.com",
                        "bucketRegionalDomainName": "my-bucket-pulumi.s3.ap-northeast-1.amazonaws.com",
                        "corsRules": [],
                        "grants": [],
                        "hostedZoneId": "Z2M4EHUR26P7ZW",
                        "id": "my-bucket-pulumi",
                        "lifecycleRules": [],
                        "loggings": [],
                        "objectLockConfiguration": null,
                        "region": "ap-northeast-1",
                        "replicationConfiguration": null,
                        "requestPayer": "BucketOwner",
                        "serverSideEncryptionConfiguration": {
                            "rule": {
                                "applyServerSideEncryptionByDefault": {
                                    "kmsMasterKeyId": "",
                                    "sseAlgorithm": "AES256"
                                },
                                "bucketKeyEnabled": true
                            }
                        },
                        "versioning": {
                            "enabled": false,
                            "mfaDelete": false
                        },
                        "website": null
                    },
                    "parent": "urn:pulumi:dev::pulumi-import::pulumi:pulumi:Stack::pulumi-import-dev",
                    "protect": true,
                    "provider": "urn:pulumi:dev::pulumi-import::pulumi:providers:aws::default_6_2_1::17e2170c-0dfc-4a37-873c-242eb1fb2eec",
                    "created": "2023-09-28T08:29:55.135649Z",
                    "modified": "2023-09-28T08:29:55.135649Z"
                }
            ]
        }
    }
    ちなみに、お気づきだとは思いますが、importコマンド実行直後にimportしたリソースの以下ProgramがCLIに表示されます。これをそのままProgramにコピーして利用できますので、実際の運用の現場でも初めからリソースをimportするためのProgramを自分で作らず、importコマンドでProgramを出力しちゃうのが便利かもしれません。
    Please copy the following code into your Pulumi application. Not doing so
    will cause Pulumi to report that an update will happen on the next update command.
    
    Please note that the imported resources are marked as protected. To destroy them
    you will need to remove the `protect` option and run `pulumi update` *before*
    the destroy will take effect.
    
    import pulumi
    import pulumi_aws as aws
    
    bucket = aws.s3.Bucket("bucket",
        arn="arn:aws:s3:::my-bucket-pulumi",
        bucket="my-bucket-pulumi",
        hosted_zone_id="Z2M4EHUR26P7ZW",
        request_payer="BucketOwner",
        server_side_encryption_configuration=aws.s3.BucketServerSideEncryptionConfigurationArgs(
            rule=aws.s3.BucketServerSideEncryptionConfigurationRuleArgs(
                apply_server_side_encryption_by_default=aws.s3.BucketServerSideEncryption
    ConfigurationRuleApplyServerSideEncryptionByDefaultArgs(
                    sse_algorithm="AES256",
                ),
                bucket_key_enabled=True,
            ),
        ),
        opts=pulumi.ResourceOptions(protect=True))

【参考】その他state関連操作について

参考として、stateの操作に関連したその他のPulumiコマンドについて一部紹介します。

pulumi state delete [URN]

特定リソースのURN(Uniform Resource Name)を用いて、stateからリソースの情報を削除できます(実際にクラウド環境にデプロイされているリソース自体は削除されません)。

「実際にリソース自体は削除したくないが、Pulumiの管理からは外したい」場合などに利用します。

  1. 削除したいリソースのURNを調べます(今回はbucketのstate情報を削除)。stateから該当リソースのURNを確認できます。
    $ pulumi stack export
    {
    ~~(略)~~
    "resources": [
    ~~(略)~~
    {
            "urn": "urn:pulumi:dev::quickstart2::gcp:storage/bucket:Bucket::my-bucket-0927",
            "custom": true,
            "id": "my-bucket-0927",
            "type": "gcp:storage/bucket:Bucket",
            "inputs": {
                "__defaults": [
                    "forceDestroy"
                ],
                "forceDestroy": false,
                "location": "ASIA-NORTHEAST1",
                "name": "my-bucket-0927",
                "storageClass": "STANDARD",
                "uniformBucketLevelAccess": true
            },
    ~~(略)~~
    }
    または、以下pulumiコマンドでURNを表示させることもできます。
    $ pulumi stack --show-urns
    Current stack is dev:
        Owner: ***
        Last updated: 23 minutes ago (2022-09-28 01:03:49.870847 +0900 JST)
        Pulumi version: v3.39.1
    Current stack resources (3):
        TYPE                          NAME
        pulumi:pulumi:Stack           quickstart2-dev
        │  URN: urn:pulumi:dev::quickstart2::pulumi:pulumi:Stack::quickstart2-dev
        ├─ gcp:storage/bucket:Bucket  my-bucket-0927
        │     URN: urn:pulumi:dev::quickstart2::gcp:storage/bucket:Bucket::my-bucket-0927
        └─ pulumi:providers:gcp       default_6_29_0
              URN: urn:pulumi:dev::quickstart2::pulumi:providers:gcp::default_6_29_0
    
    Current stack outputs (0):
        No output values currently in this stack
    
    More information at: https://app.pulumi.com/***/quickstart2/dev
    
    Use `pulumi stack select` to change stack; `pulumi stack ls` lists known ones
  2. URNを指定して、以下コマンドを実行します。
    $ pulumi state delete urn:pulumi:dev::quickstart2::gcp:storage/bucket:Bucket::<Bucket名>
     warning: This command will edit your stack's state directly. Confirm? Yes
    Resource deleted
  3. stateから対象のリソース情報(bucket)が削除されました。
    $ pulumi stack export
    {
        "version": 3,
        "deployment": {
            "manifest": {
                "time": "2022-09-28T01:40:56.95378+09:00",
                "magic": "c57d2cc6e4ddc1ad908bcf42d81d39304d5e92a1de5a6e1d5a5c485a70ff807b",
                "version": "v3.39.1"
            },
            "secrets_providers": {
                "type": "service",
                "state": {
                    "url": "https://api.pulumi.com",
                    "owner": "***",
                    "project": "quickstart2",
                    "stack": "dev"
                }
            },
            "resources": [
                {
                    "urn": "urn:pulumi:dev::quickstart2::pulumi:pulumi:Stack::quickstart2-dev",
                    "custom": false,
                    "type": "pulumi:pulumi:Stack"
                },
                {
                    "urn": "urn:pulumi:dev::quickstart2::pulumi:providers:gcp::default",
                    "custom": true,
                    "id": "f8f41b6d-87d4-4cd2-93b8-ebdbf766398c",
                    "type": "pulumi:providers:gcp",
                    "inputs": {
                        "project": "pulumi-test",
                        "version": "6.29.0"
                    },
                    "outputs": {
                        "project": "pulumi-test",
                        "version": "6.29.0"
                    },
                    "parent": "urn:pulumi:dev::quickstart2::pulumi:pulumi:Stack::quickstart2-dev"
                }
            ]
        }
    }

pulumi preview [URN]

stateの情報とProgramのコードの差分を確認できます。pulumi upコマンドでも差分を確認できますが、間違えて実際のデプロイを実行してしまう場合もありますので、pulumi previewで差分を確認する方が無難かと思います。

$ pulumi preview
Previewing update (dev)
View Live: https://app.pulumi.com/***/quickstart2/dev/previews/f8807e3a-5045-4e63-ae14-******
     Type                   Name             Plan
     pulumi:pulumi:Stack    quickstart2-dev
 +   └─ gcp:storage:Bucket  my-bucket-0927   create
Resources:
    + 1 to create
    1 unchanged

おわりに

今回は、Pulumiによるリソース更新の流れについておさらいし、既存リソースのPulumi管理化について紹介しました。基本的には「stateとprogramの比較で実体の更新が行われる」という認識があれば、Pulumi管理化の流れも比較的理解しやすいと思います。どちらかと言うと「既にクラウド環境に存在するリソースをIaCで管理したい」というようなケースが多いと思うので、今回の記事を参考にしていただければと思います。次回もお楽しみに!

【参考】Pulumi公式ホームページ(英語)

著者
大関 研丞 (Kenneth Ozeki)
クリエーションライン株式会社 Data Platform Team
前職では保険や金融エンタープライズのミッションクリティカルシステム(オンプレミス、仮想サーバー、CDN等のインフラ系業務)の設計/構築を経験。クリエーションラインに転職後はクラウドエンジニアとしてGCP関連の案件でインフラの設計/構築、IaCやCI/CDを用いたDevOpsの導入、コンテナ(Kubernetes)基盤の構築、運用自動化ツールの作成などを担当。
クリエーションラインの技術ブログをチェック

連載バックナンバー

システム運用技術解説
第10回

Pulumiの最新機能「Pulumi ESC」を使ってみよう

2023/12/26
最終回となる今回は、2023年12月時点でリリースされている新機能の紹介と、その新機能の中から「Pulumi ESC」を用いたハンズオンを実践していきます。
システム運用技術解説
第9回

TerraformからPulumiへの移行

2023/11/28
第9回となる今回は、既にTerraformでAWS環境に作成されているリソースをPulumiへ移行するケースを想定して、CoexistenceとConversionのハンズオンを実践していきます
システム運用技術解説
第8回

既に存在するリソースをPulumiで管理してみよう

2023/10/19
第8回となる今回は、既にクラウド環境にデプロイされているリソースをPulumiで管理(import)する方法について、ハンズオンで実践していきます。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています