Loading...

AWS 環境構築 MBC CQRS サーバーレス フレームワーク用ネットワーク環境の準備

AWSにてMBC CQRS サーバーレス フレームワークを稼働させる環境の準備を行います。
MBC CQRS サーバーレス フレームワーク で稼働させる環境を用意する上で事前に準備したおきたいサービスは以下の通りです。

  • Route 53
    • ドメイン名をAWSのCDKで設定出来ると環境構築・切替が楽なので必ず利用したいサービスです。(任意ですが推奨します。)
    • ドメイン取得はRoute 53で行う必要はありませんが、NSレコードをRoute 53に向ける必要があります。
  • ACM
    • SSL証明書の更新処理を行うのは運用上の手間がかかるため、Route 53と共に必ず利用したいサービスです。
  • VPC
    • リージョン内にPublicネットワークとPrivateネットワークを作成し守りたいデータはPrivateネットワークからアクセスできるようにする

ドメイン名をAWSのCDKで設定出来ると環境構築・切替が楽なので必ず利用したい

Route 53の設定

ドメイン名は config に登録するのが良いため、 config/type.tszoneName を追加します。追加後のソースは以下の通りです。

export type Env = 'dev' | 'stg' | 'prod'

export type Config = {
  env: Env,
  zoneName: string,
}

config/dev/index.tszoneName を追加します。

import { Config } from '../type'

const config: Config = {
  env: 'dev',
  zoneName: 'xxxxx.example.com',
}

export default config

続いて Stackにホストゾーン設定を追加します。追加後の lib/mbc-base-infra-stack.ts のソースは以下の通りです。

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Config } from '../config'

export interface MbcBaseInfraStackProps extends cdk.StackProps {
  config: Config
}

export class MbcBaseInfraStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: MbcBaseInfraStackProps) {
    super(scope, id, props);

    const config = props?.config

    if (config) {
      // Route 53の設定
      const hostedZone = new cdk.aws_route53.HostedZone(this, 'HostedZone', {
        zoneName: config.zoneName
      })
    }
  }
}

ホストゾーンを作成するためSSO Profileのログインを実行します。(IAM をProfileに設定している場合は不要)

aws sso login --profile profile_name

次のコマンドでCDK をデプロイします。

cdk deploy --profile profile_name

実行が完了するとCloudFormation画面では以下のように表示されます。

Route53のホストゾーン設定を参照すると以下のような表示を確認出来ます。

ドメイン名のNSレコードをRoute53で表示されているネームサーバーに変更します。

例えば お名前.com であれば「ネームサーバー設定」-「ネームサーバー設定」より以下のように行います。

※ ネームサーバーの切替が完了するまでしばらく時間がかかります。

ACMの設定

SSL証明書の管理をACMにて行いたいと思います。
普段使用するリージョンは ap-northeast-1 (東京) ですが、グローバルで使用するケースもありますので us-east-1 (バージニア北部)についても作成します。

まずは、通常使用するリージョン分(ap-northeast-1)のみACMを作成しましょう。

lib/mbc-base-infra-stack.ts のRoute53の次の行に以下のように追加します。

// ACMの設定
const acm = new cdk.aws_certificatemanager.Certificate(this, 'acm', {
  domainName: config.zoneName,
  subjectAlternativeNames: [`*.${config.zoneName}`],
  validation: CertificateValidation.fromDns(hostedZone),
})

上記追加し、cdk deploy --profile profile_name を実行後にAWS Certificate Manager (ACM)のコンソール画面を見るとSSL証明書が発行されたことを確認出来ます。

VPCの設定

VPCはPublicサブネットとPrivateサブネットを作成します。Publicサブネットにはインターネットゲートウェイを接続し、PriateサブネットにはNATゲートウェイを設置します。

本来であれば、3つのAZを作成しそれぞれにInternet gateway → Publicサブネット→NAT Gateway→Private Subnetを作成すべきです。

ただし、NAT gateway は稼働時間に応じて課金となるため、使用頻度がそれほど高くないサーバーレス構成では3台分のNAT gateway の固定費用が相対的に高くなってしまう傾向があります。

その場合はNAT gawayを1つのAZのみ作成し共有することが出来ます。(これはベストプラクティスではないです。サービスが軌道に乗りミッションクリティカルになったらそれぞれのAZ毎にNATGatewayを作成するようにしましょう。)

ちなみにサブネットのIPアドレスは何でも構いませんが、弊社では10台〜90台はPublicサブネット、110台〜190台はPrivateサブネットにしています。

仮に 172.23.0.0 のVPCを作成した場合は以下のようなサブネットを割り当てます。

  • Publicサブネット: 172.23.0.10/24(1a), 172.23.0.20/24(1c), 172.23.0.30/24(1d)
  • Privateサブネット: 172.23.0.110/24(1a), 172.23.0.120/24(1c), 172.23.0.130/24(1d)

config/constant.ts に以下を追加します。

// Vpc のIPアドレス
export const VpcAddress = '172.23.0.0/16'
// サブネットのIPアドレスリスト
export const VpcCIDRs = {
  vpc: '172.23.0.0/16',
  subnets: [
    {public: '172.23.11.0/24', private: '172.23.111.0/24', availabilityZone: 'ap-northeast-1a'},
    {public: '172.23.12.0/24', private: '172.23.112.0/24', availabilityZone: 'ap-northeast-1c'},
    {public: '172.23.13.0/24', private: '172.23.113.0/24', availabilityZone: 'ap-northeast-1d'},
  ],

lib/mbc-base-infra-stack.ts のACMの次の行に以下のように追加します。

      // VPC を作成
      const vpc = new cdk.aws_ec2.Vpc(this, 'Vpc-Network', {
        ipAddresses: cdk.aws_ec2.IpAddresses.cidr(VpcAddress),
        vpcName: 'Vpc-Network',
        natGateways: 0,
        subnetConfiguration: [],
      })

      // Public Subnet を作成
      const publicSubnets = VpcCIDRs.subnets.map((subnet, index) => new cdk.aws_ec2.Subnet(this, `Vpc-Network-Public-${index + 1}`, {
        vpcId: vpc.vpcId,
        cidrBlock: subnet.public,
        availabilityZone: subnet.availabilityZone,
        mapPublicIpOnLaunch: false,
      }))

      // Private Subnet を作成
      const privateSubnets = VpcCIDRs.subnets.map((subnet, index) => new cdk.aws_ec2.Subnet(this, `Vpc-Network-Private-${index + 1}`, {
        vpcId: vpc.vpcId,
        cidrBlock: subnet.private,
        availabilityZone: subnet.availabilityZone,
        mapPublicIpOnLaunch: false,
      }))

      // Internet Gateway を作成
      const igw = new cdk.aws_ec2.CfnInternetGateway(this, 'Vpc-Network-IGW', {
        tags: [{key: 'Name', value: 'Vpc-Network-IGW'}]
      })
      const igwAttach = new cdk.aws_ec2.CfnVPCGatewayAttachment(this, 'Vpc-Network-IGW-Attach', {
        vpcId: vpc.vpcId,
        internetGatewayId: igw.ref
      })

      // Public RouteTables を作成
      const publicRouteTables = VpcCIDRs.subnets.map((subnet, index) => new cdk.aws_ec2.CfnRouteTable(this, `Vpc-Network-Public-Route-${index + 1}`, {
        vpcId: vpc.vpcId
      }))

      // Private RouteTables を作成
      const privateRouteTables = VpcCIDRs.subnets.map((subnet, index) => new cdk.aws_ec2.CfnRouteTable(this, `Vpc-Network-Private-Route-${index + 1}`, {
        vpcId: vpc.vpcId
      }))

      // Subnet の紐付け
      VpcCIDRs.subnets.map((_, index) => {
        // Public Subnet に Route Tableを紐付ける
        new cdk.aws_ec2.CfnSubnetRouteTableAssociation(this, `Vpc-Network-Public-Subnet-Association-${index + 1}`, {
          routeTableId: publicRouteTables[index].ref,
          subnetId: publicSubnets[index].subnetId,
        })
        // Private Subnet に Route Tableを紐付ける
        new cdk.aws_ec2.CfnSubnetRouteTableAssociation(this, `Vpc-Network-Private-Subnet-Association-${index + 1}`, {
          routeTableId: privateRouteTables[index].ref,
          subnetId: privateSubnets[index].subnetId,
        })
        // デフォルト RouteはInternetに紐付ける
        new cdk.aws_ec2.CfnRoute(this, `Vpc-Network-PublicRouteToIGW-${index + 1}`, {
          routeTableId: publicRouteTables[index].ref,
          destinationCidrBlock: '0.0.0.0/0',
          gatewayId: igw.ref,
        })
      })

      // 1サブネットに NAT Gatewayを作成する。 IPアドレスをnat.example.com で Route53に登録する
      const eip = new cdk.aws_ec2.CfnEIP(this, 'Vpc-Network-EIP', {
        tags: [{key: 'Name', value: `nat.${config.zoneName}`}],
      })
      const natGateway = new cdk.aws_ec2.CfnNatGateway(this, 'Vpc-Network-Nat-Gateway', {
        allocationId: eip.attrAllocationId,
        subnetId: publicSubnets[0].subnetId,
        tags: [{key: 'Name', value: `Vpc-Network-Nat-Gateway`}],
      })

      VpcCIDRs.subnets.map((_, index) => {
        new cdk.aws_ec2.CfnRoute(this, `Vpc-Route-to-Nat-Gateway-${index + 1}`, {
          routeTableId: privateRouteTables[index].ref,
          destinationCidrBlock: '0.0.0.0/0',
          natGatewayId: natGateway.ref,
        })
      })

      // セキュリティグループ設定
      const securityGroup = new cdk.aws_ec2.SecurityGroup(this, `Vpc-Security-Group`, {
        description: 'Security Group',
        securityGroupName: `Vpc-Security-Group`,
        vpc: vpc,
      })

上記追加し、cdk deploy --profile profile_name を実行後にVPCのリソースマップを見るとVPC、サブネット、NATゲートウェイ、インターネットゲートウェイ、ルートテーブルを確認する事が出来ます。


関連記事

Top