S3にアップロードしたAWS構成図をCloudFormationに変換するシステムを作ってみた
こんにちは、つくぼし(tsukuboshi0755)です!
以前以下のブログで、マルチモーダルAIであるChatGPT V4を利用して、AWSの構成図からIaCコードを生成する方法を紹介しました。
そして最近、BedrockにもついにマルチモーダルAIを備えたClaude 3がリリースされました!
これにより、AWSのみでマルチモーダルAIを利用したシステムを完結させる事が可能になっています。
そこで今回は、S3にアップロードしたAWS構成図をCloudFormationテンプレートに変換し、別のS3にアップロードするシステムを作ってみたので紹介してみたいと思います。
なお変換したテンプレートは、CloudFormationスタック作成時にオブジェクトURLで指定する事でそのまま使用可能です!
前提条件
今回は下記ソフトウェアの使用を前提としています。
項目 | バージョン |
---|---|
AWS CLI | 2.4 |
AWS SAM CLI | 1.111 |
Python | 3.11 |
構成図
今回の構成図は以下になります。
今回構築するシステムが実施する処理は以下の通りです。
1. インプット用S3バケットにAWS構成図をアップロード 2. LambdaがS3にアップロードされた構成図を取得 3. Lambdaが構成図をloudFormationテンプレートに変換するようBedrock Claude 3にリクエスト 4. Lambdaが変換したテンプレートに対してValidateTemplateを用いて検証し、問題がある場合はテンプレート名にerrorを付与 5. テンプレート名に実行時刻をつけた上でアウトプット用S3バケットにテンプレートをアップロード
コード
今回使用するコードは以下のリポジトリにアップロードしています。
構築の流れ
事前準備
2023年3月現在では、Bedrock Claude 3 (Sonnet)はバージニア及びオレゴンでのみ利用可能です。
今回はオレゴンリージョンを利用するため、以下のリンクを参考にオレゴンでモデルアクセスを有効化します。
以下の通り、対象リージョンでBedrock Claude 3 (Sonnet)が有効化されていればOKです。
デプロイ
リポジトリをクローン後、SAMアプリをビルド及びデプロイします。
ここで構成図には記載されていないがテンプレート生成時に考慮して欲しい情報がある場合、補足プロンプトであるprompt.txt
に補足情報を記載します。
例えば今回以下のWeb3層構成図sample.png
をアップロードするとします。
その場合、構成図に記載されていない補足情報を以下のように記載します。
- VPC及びサブネット含めて新規で作成してください - EC2のAMI IDには`ami-039e8f15ccb15368a`を使用してください - EC2のキーペアは使用せず、SSM Session Managerでアクセスできるようにしてください - ALBのセキュリティグループは、HTTP及びHTTPSのみ受け付けるようにしてください - EC2のセキュリティグループは、ALBのセキュリティグループからのHTTP及びHTTPSのみ許可するようにしてください - RDSのセキュリティグループは、EC2のセキュリティグループからのMySQLのみ許可するようにしてください
補足情報の記載が完了したら、以下コマンドでSAMアプリをビルドします。
sam build
ビルド完了後に以下のコマンドを実行すると、S3バケット×2、Lambda関数、及び関連するリソースがデプロイされます。
sam deploy
なおBedrockのリージョン、モデルID、及び補足プロンプトファイルのパスは変更できるようにパラメータ化しています。
パラメータを上書きしたい場合は、以下のようにデプロイ時に--parameter-overrides
オプションを付与し、対象のパラメータに値を指定してください。
sam deploy --parameter-overrides \ BedrockRegion=us-west-2 \ BedrockModelId=anthropic.claude-3-sonnet-20240229-v1:0 \ PromptPath=prompt.txt
使い方
以下の通り、convert-diagram-to-cfn-input-diagram-bucket-<アカウントID>
バケットに対して構成図をアップロードしてください。
なお構成図の形式は現状png
しか対応していないため、jpeg
等の形式の場合は変換してからアップロードをお願いします。
アップロードするとS3イベント通知によりLambda関数が発火され、構成図及び元にClaudeにテンプレートを生成するようリクエストを投げます。
Claudeからレスポンスが返ってくると、Lambda関数がテンプレートの検証を実施し、問題がなければ以下のようにconvert-diagram-to-cfn-output-template-bucket-<アカウントID>
バケットに実行時刻のファイル名を持つテンプレートをアップロードします。
今回アップロードした構成図sample.png
から生成されたテンプレートの中身は以下のようになっていました。
テンプレート
# VPC設定 Resources: VPC: Type: AWS::EC2::VPC Properties: CidrBlock: 10.0.0.0/16 EnableDnsHostnames: true EnableDnsSupport: true InstanceTenancy: default Tags: - Key: Name Value: ap-northeast-1 PublicSubnetA1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: ap-northeast-1a CidrBlock: 10.0.1.0/24 MapPublicIpOnLaunch: true Tags: - Key: Name Value: Public subnet A1 PublicSubnetC1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: ap-northeast-1c CidrBlock: 10.0.2.0/24 MapPublicIpOnLaunch: true Tags: - Key: Name Value: Public subnet C1 PrivateSubnetA1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: ap-northeast-1a CidrBlock: 10.0.3.0/24 MapPublicIpOnLaunch: false Tags: - Key: Name Value: Private subnet A1 PrivateSubnetC1: Type: AWS::EC2::Subnet Properties: VpcId: !Ref VPC AvailabilityZone: ap-northeast-1c CidrBlock: 10.0.4.0/24 MapPublicIpOnLaunch: false Tags: - Key: Name Value: Private subnet C1 InternetGateway: Type: AWS::EC2::InternetGateway VPCGatewayAttachment: Type: AWS::EC2::VPCGatewayAttachment Properties: VpcId: !Ref VPC InternetGatewayId: !Ref InternetGateway PublicRouteTable: Type: AWS::EC2::RouteTable Properties: VpcId: !Ref VPC Tags: - Key: Name Value: Public Route Table PublicRoute: Type: AWS::EC2::Route DependsOn: VPCGatewayAttachment Properties: RouteTableId: !Ref PublicRouteTable DestinationCidrBlock: 0.0.0.0/0 GatewayId: !Ref InternetGateway PublicSubnetA1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetA1 RouteTableId: !Ref PublicRouteTable PublicSubnetC1RouteTableAssociation: Type: AWS::EC2::SubnetRouteTableAssociation Properties: SubnetId: !Ref PublicSubnetC1 RouteTableId: !Ref PublicRouteTable # セキュリティグループ設定 ALBSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP/HTTPS SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 443 ToPort: 443 CidrIp: 0.0.0.0/0 VpcId: !Ref VPC EC2SecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow HTTP/HTTPS from ALB SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 SourceSecurityGroupId: !Ref ALBSecurityGroup - IpProtocol: tcp FromPort: 443 ToPort: 443 SourceSecurityGroupId: !Ref ALBSecurityGroup VpcId: !Ref VPC RDSSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow MySQL from EC2 SecurityGroupIngress: - IpProtocol: tcp FromPort: 3306 ToPort: 3306 SourceSecurityGroupId: !Ref EC2SecurityGroup VpcId: !Ref VPC # ALB設定 ALB: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing SecurityGroups: - !Ref ALBSecurityGroup Subnets: - !Ref PublicSubnetA1 - !Ref PublicSubnetC1 ALBListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: forward TargetGroupArn: !Ref ALBTargetGroup LoadBalancerArn: !Ref ALB Port: 80 Protocol: HTTP ALBTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckPath: / Name: ALB-TargetGroup Port: 80 Protocol: HTTP TargetType: instance VpcId: !Ref VPC # EC2設定 EC2Instance1: Type: AWS::EC2::Instance Properties: ImageId: ami-039e8f15ccb15368a InstanceType: t2.micro SubnetId: !Ref PublicSubnetA1 SecurityGroupIds: - !Ref EC2SecurityGroup IamInstanceProfile: !Ref EC2InstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash yum install -y httpd systemctl start httpd systemctl enable httpd EC2Instance2: Type: AWS::EC2::Instance Properties: ImageId: ami-039e8f15ccb15368a InstanceType: t2.micro SubnetId: !Ref PublicSubnetC1 SecurityGroupIds: - !Ref EC2SecurityGroup IamInstanceProfile: !Ref EC2InstanceProfile UserData: Fn::Base64: !Sub | #!/bin/bash yum install -y httpd systemctl start httpd systemctl enable httpd EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref EC2Role EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - "sts:AssumeRole" ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore # RDS設定 RDS: Type: AWS::RDS::DBInstance Properties: DBName: mydb Engine: MySQL MasterUsername: rootuser MasterUserPassword: rootpassword DBInstanceClass: db.t2.micro AllocatedStorage: 20 PubliclyAccessible: false VPCSecurityGroups: - !Ref RDSSecurityGroup DBSubnetGroupName: !Ref RDSSubnetGroup RDSSubnetGroup: Type: AWS::RDS::DBSubnetGroup Properties: DBSubnetGroupDescription: RDS Subnet Group SubnetIds: - !Ref PrivateSubnetA1 - !Ref PrivateSubnetC1 # その他設定 Outputs: VPCID: Description: VPC ID Value: !Ref VPC Export: Name: VPCID PublicSubnetA1ID: Description: Public Subnet A1 ID Value: !Ref PublicSubnetA1 Export: Name: PublicSubnetA1ID PublicSubnetC1ID: Description: Public Subnet C1 ID Value: !Ref PublicSubnetC1 Export: Name: PublicSubnetC1ID PrivateSubnetA1ID: Description: Private Subnet A1 ID Value: !Ref PrivateSubnetA1 Export: Name: PrivateSubnetA1ID PrivateSubnetC1ID: Description: Private Subnet C1 ID Value: !Ref PrivateSubnetC1 Export: Name: PrivateSubnetC1ID ALBEndpoint: Description: ALB Endpoint Value: !GetAtt ALB.DNSName Export: Name: ALBEndpoint
なおテンプレートの検証でエラーが発生した場合は、以下の通りアップロードされるテンプレート名の末尾にerror
が付与されます。
この場合は、Lambda関数のCloudWatch Logsのロググループである/aws/lambda/convert-diagram-to-cfn-function
にて、検証エラー内容を確認します。
その上でテンプレートを修正するか、補足プロンプトを修正し再度デプロイした上で構成図をアップロードし直してください。
さらに生成されたテンプレートのオブジェクトURIを以下の通りCloudFormationのスタック作成時のAmazon S3 URL
に指定する事で、そのままスタックをデプロイする事が可能です。
今回出力されたテンプレートでは、以下のようなリソースが正常に作成されました!
なお、テンプレートの検証が正常に通った場合でも、デプロイに失敗する場合があります。
その場合もデプロイエラー内容を確認し、テンプレートを修正するか、補足プロンプトを修正し再度デプロイした上で構成図をアップロードし直してください。
最後に
今回は、S3にアップロードしたAWS構成図をCloudFormationテンプレートに変換し、別のS3にアップロードするシステムを作ってみました。
BedrockでClaude 3 Sonnetを利用できるようになった事で、外部のAPIを利用する事なく今回のようなAWSのみでマルチモーダルAIを利用したシステムを構築する事が可能になりました。
ただ生成されたテンプレートは正確性を欠いたり、必要なリソースが不足している場面が度々見られたため、もし本番利用したい場合はその辺りの欠点を補う手法を別途検討するべきかと思います。
とはいえ検証用途としては十分に利用できますので、気になる方は是非試してみてください!
以上、つくぼし(tsukuboshi0755)でした!