AWS CDK Goを使ってシンプルにEC2を構築してみた
こんにちは。AWS事業本部コンサルティング部に所属している今泉(@bun76235104)です。
みなさんGo言語好きですか?
AWS CDKではGo言語で構築可能ですが、検索するとTypeScriptの記事が多いですよね?
私はTypeScriptも好きですが、Go言語も好きなのでもうちょっと日本語記事が増えてもよいかなと思っています。
ということで前回AWS CDKのGo言語版でハローワールドしてみました。
今回はもう少し構築するリソースを増やしてみてEC2を構築してみようと思います。
この記事で作るもの
- 以下のように単一のAWSアカウント・単一VPCなシンプルな構成でEC2を構築します。
- VPCにはVPCエンドポイントを構築して、EC2にはSSM Session Managerで接続できるようにします。
なお、今回作成したソースファイル群は以下のリポジトリに格納しています。
ディレクトリ構成
前回の記事では、以下のようにシンプルな単一ファイル構成でした。
. ├── README.md ├── cdk.json ├── cdk.out ├── go.mod ├── go.sum ├── hello_go_cdk.go //このファイルのみ └── hello_go_cdk_test.go
今回はEC2とVPCを作成するにあたりパッケージ分割とソースファイルの分割をしています。
. ├── README.md ├── cdk.json ├── cmd //パッケージを分割 │ ├── network //VPCなどのリソース │ │ └── main.go │ └── server //EC2 │ └── main.go ├── go.mod ├── go.sum ├── vpc_and_ec2.go └── vpc_and_ec2_test.go
この構成については、以下の記事を参考にちょっとずつ大きくなるプロジェクトを想定しています。
各ファイルの中身(リソースの作成)
mainパッケージ
vpc_and_ec2.goが今回のプロジェクトのmain処理を行うファイルとなります。
以下のように、networkとserverパッケージを呼び出すようにしています。
func main() { defer jsii.Close() app := awscdk.NewApp(nil) // 共通タグを設定 awscdk.Tags_Of(app).Add(jsii.String("Project"), jsii.String("Sample"), nil) awscdk.Tags_Of(app).Add(jsii.String("Env"), jsii.String("Dev"), nil) stack := NewVpcAndEc2Stack(app, "Sample", &VpcAndEc2StackProps{ awscdk.StackProps{ Env: env(), }, }) sharedNetwork := network.NewNetwork(stack, "SharedVpc", "10.10.0.0/16", true) sharedVpc := sharedNetwork.CreateNetworkResources() severResource := server.NewServer(stack, sharedVpc) severResource.CreateServerResources() app.Synth(nil) }
vpc_and_ec2.goの全体像
package main import ( "vpc_and_ec2/cmd/network" "vpc_and_ec2/cmd/server" "github.com/aws/aws-cdk-go/awscdk/v2" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) type VpcAndEc2StackProps struct { awscdk.StackProps } func NewVpcAndEc2Stack(scope constructs.Construct, id string, props *VpcAndEc2StackProps) awscdk.Stack { var sprops awscdk.StackProps if props != nil { sprops = props.StackProps } stack := awscdk.NewStack(scope, &id, &sprops) return stack } func main() { defer jsii.Close() app := awscdk.NewApp(nil) // 共通タグを設定 awscdk.Tags_Of(app).Add(jsii.String("Project"), jsii.String("Sample"), nil) awscdk.Tags_Of(app).Add(jsii.String("Env"), jsii.String("Dev"), nil) stack := NewVpcAndEc2Stack(app, "Sample", &VpcAndEc2StackProps{ awscdk.StackProps{ Env: env(), }, }) sharedNetwork := network.NewNetwork(stack, "SharedVpc", "10.10.0.0/16", true) sharedVpc := sharedNetwork.CreateNetworkResources() severResource := server.NewServer(stack, sharedVpc) severResource.CreateServerResources() app.Synth(nil) } func env() *awscdk.Environment { return &awscdk.Environment{ Region: jsii.String("ap-northeast-1"), } }
networkパッケージ
cmd/network/main.goではVPCとVPCエンドポイントを作成します。
構築に際しては公式のドキュメントを参照しています。
Session Managerを利用してEC2に接続するために必要なVPCエンドポイントを作成しています。
なお、次回以降でVPCエンドポイントを作るVPC・作らないVPCの両方を作成予定であるためifで分岐するようにしています。
// 受け取る必要のあるパラメーターを定義した構造体 type Network struct { scope constructs.Construct vpcName string cidr string hasSSMEndpoint bool } // func (nr Network) CreateNetworkResources() awsec2.Vpc { // VPC vpc := awsec2.NewVpc(nr.scope, &nr.vpcName, &awsec2.VpcProps{ IpAddresses: awsec2.IpAddresses_Cidr(jsii.String(nr.cidr)), MaxAzs: jsii.Number(2), EnableDnsSupport: jsii.Bool(true), EnableDnsHostnames: jsii.Bool(true), VpcName: jsii.String("Shared"), SubnetConfiguration: &[]*awsec2.SubnetConfiguration{ { Name: jsii.String("Private"), SubnetType: awsec2.SubnetType_PRIVATE_ISOLATED, CidrMask: jsii.Number(24), }, }, }) // 指定した時のみVPCエンドポイントを追加 if nr.hasSSMEndpoint { vpc.AddInterfaceEndpoint(jsii.String("SSM"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_SSM(), }) vpc.AddInterfaceEndpoint(jsii.String("SSMMessage"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_SSM_MESSAGES(), }) vpc.AddInterfaceEndpoint(jsii.String("EC2Messag"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_EC2_MESSAGES(), }) } return vpc }
cmd/network/main.goの全体像
package network import ( "github.com/aws/aws-cdk-go/awscdk/v2/awsec2" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) type Network struct { scope constructs.Construct vpcName string cidr string hasSSMEndpoint bool } func NewNetwork(scope constructs.Construct, vpcName string, cidr string, hasSSMEndpoint bool) Network { return Network{ scope: scope, vpcName: vpcName, cidr: cidr, hasSSMEndpoint: hasSSMEndpoint, } } func (nr Network) CreateNetworkResources() awsec2.Vpc { // VPC vpc := awsec2.NewVpc(nr.scope, &nr.vpcName, &awsec2.VpcProps{ IpAddresses: awsec2.IpAddresses_Cidr(jsii.String(nr.cidr)), MaxAzs: jsii.Number(2), EnableDnsSupport: jsii.Bool(true), EnableDnsHostnames: jsii.Bool(true), VpcName: jsii.String("Shared"), SubnetConfiguration: &[]*awsec2.SubnetConfiguration{ { Name: jsii.String("Private"), SubnetType: awsec2.SubnetType_PRIVATE_ISOLATED, CidrMask: jsii.Number(24), }, }, }) // 指定した時のみVPCエンドポイントを追加 if nr.hasSSMEndpoint { vpc.AddInterfaceEndpoint(jsii.String("SSM"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_SSM(), }) vpc.AddInterfaceEndpoint(jsii.String("SSMMessage"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_SSM_MESSAGES(), }) vpc.AddInterfaceEndpoint(jsii.String("EC2Messag"), &awsec2.InterfaceVpcEndpointOptions{ Service: awsec2.InterfaceVpcEndpointAwsService_EC2_MESSAGES(), }) } return vpc }
serverパッケージ
こちらでは作成したVPCを引数としてEC2を作成します。
なお、作成に際してはVPCと同様に公式のドキュメントを参照します。
package server import ( "github.com/aws/aws-cdk-go/awscdk/v2/awsec2" "github.com/aws/constructs-go/constructs/v10" "github.com/aws/jsii-runtime-go" ) type Server struct { scope constructs.Construct vpc awsec2.Vpc } func NewServer(scope constructs.Construct, vpc awsec2.Vpc) Server { return Server{ scope: scope, vpc: vpc, } } func (sr Server) CreateServerResources() { awsec2.NewInstance(sr.scope, jsii.String("Server"), &awsec2.InstanceProps{ InstanceType: awsec2.InstanceType_Of(awsec2.InstanceClass_T3, awsec2.InstanceSize_MICRO), MachineImage: awsec2.MachineImage_LatestAmazonLinux(&awsec2.AmazonLinuxImageProps{ Generation: awsec2.AmazonLinuxGeneration_AMAZON_LINUX_2, }), SsmSessionPermissions: jsii.Bool(true), Vpc: sr.vpc, }) }
なおNewIsntance
の関数呼び出しでSsmSessionPermissions
というパラメータを渡しています。
こちらはAWS CDKのver:2.70.0から利用できるようになったパラメータで、trueとすることでEC2インスタンスに割り当てられたIAMロールにAmazonSSMManagedInstanceCoreを簡単にアタッチできます。
詳細は弊社ののんピがブログ化しておりますので、以下の記事をご参照ください。
リソース作成
ここまでファイルを作成したのち、以下コマンドによりリソースを作成します。
cdk diff #作られるリソースを確認 cdk deploy
実際に構成図のようにVPCとEC2などのリソースが作成され、EC2に対してSession Managerで接続できることを確認しました。
- EC2インスタンスの接続画面
- 接続後の様子
最後に
今回はAWS CDKのGo版を利用してシンプルにVPC・EC2を構築しました。
次回はTransit Gatewayなどを利用して他VPC上のEC2との疎通確認などを行う予定です。
これからもCDKのGo版の記事が増えれば良いなと思います。
以上今泉でした。このブログがどなたかの参考になればうれしいです。