サカトラ

自動化したり統計したり

Pulumiに入門する

最近目にしたこの記事の最後にPulumiなるものが出てきていて、恥ずかしながら私はまったくこの存在を知りませんでした。
いい機会なのでPulumiについて公式の手順を参考に入門していきます。

zenn.dev

What is Pulumi?

Pulumi - Infrastructure as Code in Any Programming Language

Pulumiとは何か、
トップページ曰く

Infrastructure as code in any programming language Build infrastructure intuitively on any cloud using familiar languages.

これがPulumiを使うとできるみたいです。

Get Start

環境はWSL(Ubuntu22.04)

Pulumiをインストール

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

インストールできたらpulumi versionで確認

$ pulumi version
v3.78.1

今回はAWS上にリソースを構築する予定なので、環境変数としてAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYを設定しておきます。 ここはaws cliをインストールしている場合はその設定を利用することが可能なようです。

プロジェクトを作成する

Pulumiがインストールできたら次にプロジェクトを作成します。

冒頭にあった通り、Pulumiでは様々な言語で構成を記述することができます。
現状、TypeScript, JavaScript, Python, Go, C#,Java, YAMLから選択できます。

個人的な好みでYAMLで構成を採用します。

pulumi newのコマンドでひな形を作ることができます。
この時にどのプロバイダーを利用するのかとどの言語で書くかを指定します。

プロジェクトを置くディレクトリを作ってそこにプロジェクトを作成していきます。

mkdir pulumi_aws && cd pulumi_aws
pulumi new aws-yaml

このpulumi newのコマンドは実行するとPulumi Cloudへのログインを求められます。
Pulumi Cloudについてパッと見の感想になりますが、その立ち位置はTerraform Cloudに近いなと思っています。 Pulumi Cloudは個人利用がタダなので、サクッとアカウントも作ってログインしましたが、Pulumi Cloudを利用したくない場合は事前にpulumi login --localを実行してローカル環境をおくと良いそうです。

Pulumi CLI & Pulumi Cloud FAQ | Pulumi Docs

その他、プロジェクト名やプロジェクトのDescription、利用するAWSのロケーション(例: ap-northeast-1)などをインタラクティブに設定します。
Pulumi Cloudを利用するかどうか、利用するプロバイダーや言語によっても変わるようですが大体下記のことを聞かれます。

project name: (pulumi_aws) 
project description: (A minimal AWS Pulumi YAML program) 
stack name: (dev) 
aws:region: The AWS region to deploy into: (us-east-1) 

これで下記のようにファイルが作られました。

.
├── Pulumi.dev.yaml
└── Pulumi.yaml

stack名をdevで作ってしまったのでややこしいですが、Pulumi.dev.yamldevの部分はstack名によって変わるようです。

Pulumi.yamlがリソースなどを記述するメインのファイルで、Pulumi.dev.yamlは構成の設定が入ってくるようです。

pulumi new aws-yamlした直後が下記。

Pulumi.yaml

name: aws-test
runtime: yaml
description: A minimal AWS Pulumi YAML program
outputs:
  # Export the name of the bucket
  bucketName: ${my-bucket.id}
resources:
  # Create an AWS resource (S3 Bucket)
  my-bucket:
    type: aws:s3:Bucket

Pulumi.dev.yaml

config:
  aws:region: ap-northeast-1

なるほど、構成の設定とはクラウドのロケーションなどの情報を指すみたいです。

AWSのConfiguration Optionはこちらから

AWS Classic Installation & Configuration | Pulumi Registry

pulumi new直後の状態でもS3についてのリソースは記述されているのでこの状態でpulumi upすることでAWSにS3バケットを作ることができます。

このあたりのコマンドはTerraformほとんど同じ感覚で使えます。
若干文言が違うので対応表にしました。

Terraform Pulumi
plan preview
apply up
destroy destory

ただこれだとPulumi.yamlがS3バケットのみなのでもうちょっとリソース色々組んでみたいと思います。

Pulumiを書く(YAML

Pulumi.yaml

これはどの言語で書く際にも実は生成されています。 トップレベルのキーruntimeで使用言語を決めてプロジェクトの名前や説明も使用言語にかかわらずこのファイルに載ってきます。

Pulumiの公式examplesより

examples/aws-apigateway-py-routes at master · pulumi/examples · GitHub

name: aws-apigateway-py-routes
runtime:
  name: python
  options:
    virtualenv: venv
description: Demonstration of API Gateway routes
template:
    config:
      aws:region:
        description: The AWS region to deploy into
        default: us-east-2

runtime: yamlの場合はこのPulumi.yamlにさらにresourcesoutputsを書いていきます。

このresourcesoutputsの書き方は感覚的にTerraformと近かったです。   ただ、これはなんとなく近いわけではなくPulumiのパッケージはTerraformのものをベースに作られているものが少なからずあるため意図的なもののようです。

PulumiのexampleがあるのでここからYAMLベースのやつを参考にして簡単なものを自分でも書いてみます。

github.com

まずは簡単にVPC, Subnet, SecurityGroup, EC2を作るやつを書いてみました。

name: aws-test
runtime: yaml
variables:
  myIp: myGrobalIp
  ubuntu:
    fn::invoke:
      function: aws:ec2:getAmi
      arguments:
        mostRecent: true
        filters:
          - name: name
            values:
              - ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*
          - name: virtualization-type
            values:
              - hvm
        owners:
          - '000000000000'
  keyPair: myKeyPair
resources:
  myVpc:
    type: aws:ec2:Vpc
    properties:
      cidrBlock: 10.0.0.0/16
      enableDnsHostnames: true
      enableDnsSupport: true
      tags:
        Name: tkd-pulumi-vpc
  
  mySubnet:
    type: aws:ec2:Subnet
    properties:
      vpcId: ${myVpc.id}
      cidrBlock: 10.0.1.0/24
      tags:
        Name: tkd-pulumi-subnet

  mySecurityGroup:
    type: aws:ec2:SecurityGroup
    properties:
      vpcId: ${myVpc.id}
      ingress:
        - description: for HTTP
          fromPort: 80
          toPort: 80
          protocol: tcp
          cidrBlocks:
            - 0.0.0.0/0
        - description: for SSH
          fromPort: 22
          toPort: 22
          protocol: tcp
          cidrBlocks:
            - ${myIp}
      egress:
        - protocol: "-1"
          fromPort: 0
          toPort: 0
          cidrBlocks:
            - 0.0.0.0/0

  myInternetGateway:
    type: aws:ec2:InternetGateway
    properties:
      vpcId: ${myVpc.id}
      tags:
        Name: tkd-pulumi-igw

  myRouteTable:
    type: aws:ec2:RouteTable
    properties:
      vpcId: ${myVpc.id}
      routes:
        - cidrBlock: 0.0.0.0/0
          gatewayId: ${myInternetGateway.id}
      tags:
        Name: tkd-pulumi-route-table

  myRouteAssociation:
    type: aws:ec2:RouteTableAssociation
    properties:
      routeTableId: ${myRouteTable.id}
      subnetId: ${mySubnet.id}

  myEc2:
    type: aws:ec2:Instance
    properties:
      subnetId: ${mySubnet.id}
      ami: ${ubuntu.id}
      instanceType: t2.micro
      vpcSecurityGroupIds:
        - ${mySecurityGroup.id}
      associatePublicIpAddress: true
      keyName: ${keyPair}
      tags:
        Name: tkd-pulumi-Ubuntu

outputs:
  instanceIp: ${myEc2.publicIp}

Pulumiを実行

pulumi upコマンドで実行できます。

実行するとTerraformと同じでリソースの見積をしてから確認を経てプロビジョニングします。

View in Browser (Ctrl+O): https://app.pulumi.com/<username>/aws-test/dev/previews/a0333beb-4e14-4691-b569-ad4c3d3c52ac

     Type                              Name                Plan       
 +   pulumi:pulumi:Stack               aws-test-dev        create     
 +   ├─ aws:ec2:Vpc                    myVpc               create     
 +   ├─ aws:ec2:InternetGateway        myInternetGateway   create     
 +   ├─ aws:ec2:SecurityGroup          mySecurityGroup     create     
 +   ├─ aws:ec2:Subnet                 mySubnet            create     
 +   ├─ aws:ec2:RouteTable             myRouteTable        create     
 +   ├─ aws:ec2:RouteTableAssociation  myRouteAssociation  create     
 +   └─ aws:ec2:Instance               myEc2               create     


Outputs:
    instanceIp: output<string>

Resources:
    + 8 to create

Do you want to perform this update?

今回はPulumi Cloudを利用しているので、ブラウザからも同じ内容を見ることができます。

そしてプロビジョニング

Updating (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/<username>/aws-test/dev/updates/8

     Type                              Name                Status              
 +   pulumi:pulumi:Stack               aws-test-dev        created (48s)       
 +   ├─ aws:ec2:Vpc                    myVpc               created (11s)       
 +   ├─ aws:ec2:Subnet                 mySubnet            created (1s)        
 +   ├─ aws:ec2:InternetGateway        myInternetGateway   created (0.93s)     
 +   ├─ aws:ec2:SecurityGroup          mySecurityGroup     created (3s)        
 +   ├─ aws:ec2:RouteTable             myRouteTable        created (1s)        
 +   ├─ aws:ec2:RouteTableAssociation  myRouteAssociation  created (0.67s)     
 +   └─ aws:ec2:Instance               myEc2               created (32s)       


Outputs:
    instanceIp: "---.---.---.---"

Resources:
    + 8 created

Duration: 49s

これもPulumi Cloudから見るとこんな感じ

これでいい感じにプロビジョニングができていました。

使用感

Terraformと近いけど、それが自分の使いたい言語でできるのでそこは中々良いと感じました。 ただYAMLだと関数などが使いづらいので使用感はあんまりよくない(現時点では)。

Pulumi Cloudはなんとなく触った感じ、Terraform Cloudと近いながらもプロジェクトの追加に関してはTerraform Cloudよりも触りやすい印象。

ちなみ金額がPulumi Cloudの方が安く見えるので、そういう意味ではPulumiは選択肢になるかもなと思いました。 今後PulumiとTerraformはどうなっていくのか注視していきたいところです。

Pulumi Pricing

Terraform Cloud Pricing