🔥

aws-cdk-goでEC2インスタンスをたてる

2022/04/10に公開

Go版CDKが発表されて1年くらい経つが全く触れていなかったので、素振りとしてEC2インスタンスをたててみる。
ちなみにこれまでもCDKは使ってきたけど、全てTypeScriptで書いていた。

実行環境

  • macOS Monterey 12.0.1
  • cdk 2.19.0
  • go1.18

雛形を作ろう

まずは cdk init する。

$ mkdir cdk-go-example
$ cdk init --language=go

ファイルが自動生成される。

.
├── README.md
├── cdk-go-example.go
├── cdk-go-example_test.go
├── cdk.json
└── go.mod

go.modだけ作ってくれているので、go mod tidyしておく。

$ go mod tidy

Stackを実装しよう

初期化時に作成されたファイルにスタックの雛型とかも作られる。
以下の通り。(コメントは削除済み)

package main

import (
	"github.com/aws/aws-cdk-go/awscdk/v2"
	"github.com/aws/constructs-go/constructs/v10"
)

type CdkGoExampleStackProps struct {
	awscdk.StackProps
}

func NewCdkGoExampleStack(scope constructs.Construct, id string, props *CdkGoExampleStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	return stack
}

func main() {
	app := awscdk.NewApp(nil)

	NewCdkGoExampleStack(app, "CdkGoExampleStack", &CdkGoExampleStackProps{
		awscdk.StackProps{
			Env: env(),
		},
	})

	app.Synth(nil)
}

func env() *awscdk.Environment {
	return nil
}

NewCdkGoExampleStackに作成するリソースを定義していく感じみたい。
https://pkg.go.dev/github.com/aws/aws-cdk-go/awscdk/v2 を見ながら進める。

EC2インスタンスを定義しよう

awsec2.NewInstance関数でインスタンスを作る。
今回はt3.microAMAZON_LINUX_2にする。

func NewCdkGoExampleStack(scope constructs.Construct, id string, props *CdkGoExampleStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	// EC2インスタンスを作成
	awsec2.NewInstance(scope, jsii.String("ExampleInstance"), &awsec2.InstanceProps{
		InstanceType: awsec2.NewInstanceType(jsii.String("t3.micro")),
		MachineImage: awsec2.NewAmazonLinuxImage(&awsec2.AmazonLinuxImageProps{
			Generation: awsec2.AmazonLinuxGeneration_AMAZON_LINUX_2,
		}),
        
	})

	return stack
}

VPCを設定しよう

前節のソースコードのままcdk deployコマンドを叩くと、panicとなりデプロイに失敗する。

panic: "Missing required properties for aws-cdk-lib.aws_ec2.InstanceProps: vpc"

VPCの指定が必須と仰っている。
確かにインスタンスを配置するVPCを自動で決定されると困る。
とりあえずやってみた記事なので、デフォルトのVPCを指定する。
awsec2.Vpc_FromLookup関数で既に存在しているVPCをインポートできる。
今回はデフォルトVPCを使うので、awsec2.VpcLookupOptions構造体のIsDefaultにbool値trueのポインタを渡す。
また、awsec2.VpcLookupOptions構造体のフィールドにはVpcNameVpcIdもあり、IDや名前でインポートすることもできる様だ。

func NewCdkGoExampleStack(scope constructs.Construct, id string, props *CdkGoExampleStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	// デフォルトのVPCをインポート
	defaultVpc := awsec2.Vpc_FromLookup(stack, jsii.String("DefaultVPC"), &awsec2.VpcLookupOptions{
		IsDefault: jsii.Bool(true),
	})

	// EC2インスタンスを作成
	awsec2.NewInstance(stack, jsii.String("ExampleInstance"), &awsec2.InstanceProps{
		InstanceType: awsec2.NewInstanceType(jsii.String("t3.micro")),
		MachineImage: awsec2.NewAmazonLinuxImage(&awsec2.AmazonLinuxImageProps{
			Generation: awsec2.AmazonLinuxGeneration_AMAZON_LINUX_2,
		}),
		Vpc: defaultVpc,
	})

	return stack
}

環境値を設定しよう

スタック作成先のアカウントIDとリージョンを指定する。
雛形として自動で作られたenv関数がアカウントIDとリージョンの情報を持った*awscdk.Environmentを返す様に実装する。
値は環境変数から取ることにする。

func env() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("ACCOUNT_ID")),
		Region:  jsii.String(os.Getenv("REGION")),
	}
}

完成ソースコード

package main

import (
	"os"

	"github.com/aws/aws-cdk-go/awscdk/v2"
	"github.com/aws/aws-cdk-go/awscdk/v2/awsec2"
	"github.com/aws/constructs-go/constructs/v10"
	"github.com/aws/jsii-runtime-go"
)

type CdkGoExampleStackProps struct {
	awscdk.StackProps
}

func NewCdkGoExampleStack(scope constructs.Construct, id string, props *CdkGoExampleStackProps) awscdk.Stack {
	var sprops awscdk.StackProps
	if props != nil {
		sprops = props.StackProps
	}
	stack := awscdk.NewStack(scope, &id, &sprops)

	// デフォルトのVPCをインポート
	defaultVpc := awsec2.Vpc_FromLookup(stack, jsii.String("DefaultVPC"), &awsec2.VpcLookupOptions{
		IsDefault: jsii.Bool(true),
	})

	// EC2インスタンスを作成
	awsec2.NewInstance(stack, jsii.String("ExampleInstance"), &awsec2.InstanceProps{
		InstanceType: awsec2.NewInstanceType(jsii.String("t3.micro")),
		MachineImage: awsec2.NewAmazonLinuxImage(&awsec2.AmazonLinuxImageProps{
			Generation: awsec2.AmazonLinuxGeneration_AMAZON_LINUX_2,
		}),
		Vpc: defaultVpc,
	})

	return stack
}

func main() {
	app := awscdk.NewApp(nil)

	NewCdkGoExampleStack(app, "CdkGoExampleStack", &CdkGoExampleStackProps{
		awscdk.StackProps{
			Env: env(),
		},
	})

	app.Synth(nil)
}

func env() *awscdk.Environment {
	return &awscdk.Environment{
		Account: jsii.String(os.Getenv("ACCOUNT_ID")),
		Region:  jsii.String(os.Getenv("REGION")),
	}
}

スタックをデプロイ

cdkコマンドを使ってスタックをデプロイする。
ここは他の言語を選択している時と変わらない。

$ cdk deploy

存在確認

雑だけどLaunchTimeInstanceTypeを取って存在確認する。

$ aws ec2 describe-instances --query 'Reservations[].Instances[].[LaunchTime, InstanceType]'
[
    [
        "2022-04-10T11:14:20.000Z", 
        "t3.micro"
    ]
]

できてた🆗

所感

今回は本当に触りくらいしか書いてない上に、TypeScriptで書くことに慣れているので、これからは全部Goで書こう!とまでは思わなかった。今まで作ったことあるリソースなら、TypeScriptの方が早く書ける筈。
ただテストコードに関しては、Goで書いてみたいという思いがあるので、GoでCDKのテストコード書いてみた的な記事も上げようと考えている。

参考

GitHubで編集を提案

Discussion