はじめに
前回の記事(【Pulumi】Pulumi AIが生成したコードでEC2インスタンスを構築したい~第1章:YAML編~)では、
Pulumi AIを用いてYAMLでコードを自動生成しました。
確かに、YAMLでコードを書けるのはシンプルで使いやすいですが、プログラミング言語のメリット(分岐や繰り返し処理など)
を活用できないデメリットがあるので、今回はPythonで書いてみます。
TL;DR
- Pulumiはプログラミング言語でインフラを構築可能なプロビジョニングツールであり、
慣れ親しんだ開発言語(Python/TypeScript/Goなど)やマークアップ言語(YAMLなど)で記述可能 - YAMLで書けるが、プログラミング言語のメリットが活用できない
- 細かい処理をするなら、Pythonなどのプログラミング言語で書いた方がよい
前提条件
PulumiでAWSを操作するには以下が必要です
- Pulumiのアカウントを所持していること
- AWSにてIAMユーザーのアクセスキーが作成してあること
実行環境
- Amazon マシンイメージ(AMI)
- Amazon Linux 2023 AMI
- Pulumi
- v3.112.0
詳細
1. 事前準備
- 前回の記事(【Pulumi】Pulumi AIが生成したコードでEC2インスタンスを構築したい~第1章:YAML編~)における以下の箇所を実施する
- アクセストークンの作成
- EC2インスタンスにPulumiをインストール
2. Pulumi Projectの作成
-
Pulumiにログインする。ここで、事前準備で作成したトークンを入力する
$ pulumi login
-
作業用ディレクトリを作成する
$ mkdir pulumi-python && cd pulumi-python
-
作業用Projectを作成する
- 今回はPythonでAWSリソースの定義ファイルを書くので
aws-python
としています - Pythonでは仮想環境(venv)が作成されます
$ pulumi new aws-python
- 色々と聞かれますが、特に何も入力せずに
Enter
でも問題ありません(ここではRegionをus-west-2
に変更しました)
This command will walk you through creating a new Pulumi project. Enter a value or leave blank to accept the (default), and press <ENTER>. Press ^C at any time to quit. project name (pulumi-python): project description (A minimal AWS Python Pulumi program): Created project 'pulumi-python' Please enter your desired stack name. To create a stack in an organization, use the format <org-name>/<stack-name> (e.g. `acmecorp/dev`). stack name (dev): Created stack 'dev' aws:region: The AWS region to deploy into (us-east-1): us-west-2 ~以下、省略~
- 今回はPythonでAWSリソースの定義ファイルを書くので
-
以下のファイルが作成されたことを確認する
- Pulumi.dev.yaml: 環境変数などを記述するファイル
- Pulumi.yaml: Pulumi プロジェクトの設定ファイル
- __main__.py: AWSリソースの定義ファイル
- requirements.txt: Pythonパッケージの一覧
- venv: Pythonの仮想環境
$ ls Pulumi.dev.yaml Pulumi.yaml __main__.py requirements.txt venv
なお、
Pulumi.dev.yaml
は以下のようになっているので、そのまま使いますPulumi.dev.yamlconfig: aws:region: us-west-2
3. Pulumi AIでAWSリソースの定義ファイル作成
-
Pulumiのホーム画面右上の[Pulumi AI]を選択する
-
[Python]を選択し、処理内容を記述して[Update program]を選択する。処理内容は可能な限り具体的に書くとよい
-
記述した内容
- AWSでインターネット経由で接続可能なEC2インスタインス、VPC、サブネット、セキュリティグループを作成する
-
出力結果
- 結果の見やすさ向上のために、フォーマッター(Black)の処理をしています
import pulumi import pulumi_aws as aws # Create a VPC vpc = aws.ec2.Vpc( "my_vpc", cidr_block="10.0.0.0/16", enable_dns_support=True, enable_dns_hostnames=True, ) # Create an Internet Gateway internet_gateway = aws.ec2.InternetGateway("my_gateway", vpc_id=vpc.id) # Create a Route Table route_table = aws.ec2.RouteTable( "my_route_table", vpc_id=vpc.id, routes=[ aws.ec2.RouteTableRouteArgs( cidr_block="0.0.0.0/0", gateway_id=internet_gateway.id, ) ], ) # Create a Subnet subnet = aws.ec2.Subnet( "my_subnet", vpc_id=vpc.id, cidr_block="10.0.1.0/24", map_public_ip_on_launch=True ) # Enable auto-assign public IP on launch # Associate Subnet with Route Table route_table_association = aws.ec2.RouteTableAssociation( "my_route_table_association", route_table_id=route_table.id, subnet_id=subnet.id ) # Create a Security Group that allows SSH and HTTP traffic security_group = aws.ec2.SecurityGroup( "my_security_group", description="Allow SSH and HTTP", vpc_id=vpc.id, ingress=[ aws.ec2.SecurityGroupIngressArgs( protocol="tcp", from_port=22, to_port=22, cidr_blocks=["0.0.0.0/0"], ), aws.ec2.SecurityGroupIngressArgs( protocol="tcp", from_port=80, to_port=80, cidr_blocks=["0.0.0.0/0"], ), ], egress=[ aws.ec2.SecurityGroupEgressArgs( protocol="-1", # allows all outbound traffic from_port=0, to_port=0, cidr_blocks=["0.0.0.0/0"], ), ], ) # Create an EC2 instance instance = aws.ec2.Instance( "my_instance", ami="ami-0c55b159cbfafe1f0", # example AMI-ID, please replace it with a valid one instance_type="t2.micro", vpc_security_group_ids=[security_group.id], subnet_id=subnet.id, associate_public_ip_address=True, ) # Export the public IP of the EC2 instance pulumi.export("instance_public_ip", instance.public_ip)
-
-
Pulumi AIの結果をPulumiのドキュメント(Pulumi > AWS > API Docs)などをもとに修正し、
__main__.py
に記入する-
細かい修正をしたい場合は、別途Pulumi AIで作成した定義ファイルを参考にしてもよい
import pulumi import pulumi_aws as aws # Create a Config instance to access the Pulumi configuration config = pulumi.Config("aws") # Create Availability Zone from the Pulumi configuration file under the 'aws' namespace availability_zone = config.require("region") + "a" # Create a VPC vpc = aws.ec2.Vpc( "my_vpc", cidr_block="10.0.0.0/16", # enable_dns_support=True, # enable_dns_hostnames=True, tags={"Name": "my_vpc"}, ) # Create an Internet Gateway internet_gateway = aws.ec2.InternetGateway( "my_gateway", vpc_id=vpc.id, tags={"Name": "my_gateway"} ) # Create a Route Table route_table = aws.ec2.RouteTable( "my_route_table", vpc_id=vpc.id, # routes=[ # aws.ec2.RouteTableRouteArgs( # cidr_block="0.0.0.0/0", # gateway_id=internet_gateway.id, # ) # ], tags={"Name": "my_route_table"}, ) # Create a Route in the Route Table pointing to the Internet Gateway route = aws.ec2.Route( "my_route", destination_cidr_block="0.0.0.0/0", gateway_id=internet_gateway.id, route_table_id=route_table.id, ) # Create a Subnet subnet = aws.ec2.Subnet( "my_subnet", vpc_id=vpc.id, cidr_block="10.0.1.0/24", map_public_ip_on_launch=True, # Enable auto-assign public IP on launch availability_zone=availability_zone, tags={"Name": "my_subnet"}, ) # Associate Subnet with Route Table route_table_association = aws.ec2.RouteTableAssociation( "my_route_table_association", route_table_id=route_table.id, subnet_id=subnet.id ) # Create a Security Group that allows SSH and HTTP traffic security_group = aws.ec2.SecurityGroup( "my_security_group", description="Allow SSH and HTTP", vpc_id=vpc.id, ingress=[ aws.ec2.SecurityGroupIngressArgs( protocol="tcp", from_port=22, to_port=22, cidr_blocks=["0.0.0.0/0"], ), aws.ec2.SecurityGroupIngressArgs( protocol="tcp", from_port=80, to_port=80, cidr_blocks=["0.0.0.0/0"], ), ], egress=[ aws.ec2.SecurityGroupEgressArgs( protocol="-1", # allows all outbound traffic from_port=0, to_port=0, cidr_blocks=["0.0.0.0/0"], ), ], tags={"Name": "my_security_group"}, ) # Create an EC2 instance instance = aws.ec2.Instance( "my_instance", ami="ami-0c55b159cbfafe1f0", # example AMI-ID, please replace it with a valid one instance_type="t2.micro", vpc_security_group_ids=[security_group.id], subnet_id=subnet.id, associate_public_ip_address=True, key_name="my_key", availability_zone=availability_zone, tags={"Name": "my_instance"}, ) # Export the EC2 instance information pulumi.export("vpc_id", vpc.id) pulumi.export("subnet_id", subnet.id) pulumi.export("internet_gateway_id", internet_gateway.id) pulumi.export("route_table_id", route_table.id) pulumi.export("route_table_association_id", route_table_association.id) pulumi.export("route_id", route.id) pulumi.export("security_group_id", security_group.id) pulumi.export("instance_id", instance.id) pulumi.export("instance_public_ip", instance.public_ip)
-
補足として、Pulumi.dev.yaml
にあるaws:region
の値は、
pulumi.Config
を使用して取得します(詳細は、Pulumi > Configurationを参照)
4. Pulumiによるリソースの作成
-
IAMユーザーのアクセスキーを登録する
$ export AWS_ACCESS_KEY_ID="<YOUR_ACCESS_KEY_ID>" $ export AWS_SECRET_ACCESS_KEY="<YOUR_SECRET_ACCESS_KEY>"
-
リソースを作成する
$ pulumi up
-
リソースが作成されていることを確認する(以下はログの一部)
Type Name Status + pulumi:pulumi:Stack pulumi-python-dev created (69s) + ├─ aws:ec2:Vpc my_vpc created (2s) + ├─ aws:ec2:SecurityGroup my_security_group created (3s) + ├─ aws:ec2:RouteTable my_route_table created (1s) + ├─ aws:ec2:InternetGateway my_gateway created (1s) + ├─ aws:ec2:Subnet my_subnet created (12s) + ├─ aws:ec2:Route my_route created (1s) + ├─ aws:ec2:Instance my_instance created (43s) + └─ aws:ec2:RouteTableAssociation my_route_table_association created (0.77s)
5. Pulumiマイページからの結果確認
- 前回の記事(【Pulumi】Pulumi AIが生成したコードでEC2インスタンスを構築したい~第1章:YAML編~)の
以下の箇所を実施する
6. Pulumiマイページからの結果確認
6. Pulumiによるリソースの削除
-
リソースを削除する
$ pulumi down
-
リソースが削除されていることを確認する(以下はログの一部)
Type Name Status - pulumi:pulumi:Stack pulumi-python-dev deleted (0.43s) - ├─ aws:ec2:Route my_route deleted (1s) - ├─ aws:ec2:Instance my_instance deleted (41s) - ├─ aws:ec2:RouteTableAssociation my_route_table_association deleted (1s) - ├─ aws:ec2:SecurityGroup my_security_group deleted (1s) - ├─ aws:ec2:RouteTable my_route_table deleted (1s) - ├─ aws:ec2:Subnet my_subnet deleted (1s) - ├─ aws:ec2:InternetGateway my_gateway deleted (1s) - └─ aws:ec2:Vpc my_vpc deleted (0.75s)
さいごに
- Pulumiで細かい処理をするならPythonなどのプログラミング言語で書いた方がよいですが、
YAMLと比較するとどうしても難しく感じてしまいます - YAMLで書くのか否かは、処理内容の複雑さなどから判断した方がよさそうです
参考URL
-
Pulumi > AWS > API Docs
- PulumiでAWSを操作するための記述方法
-
Pulumi > Configuration
- Pulumiで環境ごとに異なる変数を使用する方法