スクエニ ITエンジニア ブログ

[初級] ハマグリ式! VPC 「など」の設定項目をわかりやすくざっくり解説する ~AWS SDK for Python (Boto3) コードもあるよ~

はじめに

この記事を見つけたけど、後で見ようと思ったそこのあなた!

ぜひ下のボタンから、ハッシュタグ #ハマグリ式 でツイートしておきましょう!

こんにちハマグリ。貝藤らんまだぞ。 今回は、ハマグリ式! VPC 「など」の設定項目をわかりやすくざっくり解説する ~AWS SDK for Python (Boto3) コードもあるよ~ をお届けします!

初級って?

ハマグリ式では、下記のようにレベルを設定しています。

  1. 初級者:初めてクラウドサービスを利用する人で、基本的な操作(例:ファイルの保存や、サーバーの起動)をインターフェースを通じて行うことができます。また、シンプルなセキュリティルールの設定や、一部の問題のトラブルシューティングに対応できます。
  2. 中級者:より深い知識を持ち、コードを用いて操作を自動化したり、より複雑なタスク(例:自動でサーバーの数を増減させる)を行います。また、より高度な監視や、全体のシステム設計と実装について理解があります。
  3. 上級者:幅広く深い知識を持ち、大規模で複雑なシステムを設計、実装、維持する能力があります。最先端のテクノロジーを活用し、安全性、耐障害性、効率性を最大化するためのソリューションを提供します。

ハマグリ式って?

貝藤らんまが作成するブログ記事のブランド名です。あまり気にせず読み飛ばしてください。

何を書くの?

以下の通りです。

  • この記事で書くこと
    • AWS VPC 「など」の基本的な設定項目がどういうものか
    • AWS VPC 「など」の設定項目をとりあえずどうすればいいか
    • AWS VPC を作成する AWS SDK for Python (Boto3) コード
  • この記事で書かないこと
    • AWS VPC 「など」のすべての設定項目がどういうものか
    • AWS VPC 「など」の設定項目の選び方
    • AWS VPC 「など」の設定項目の応用
    • AWS VPC 「など」のベストプラクティス
    • AWS VPC 「など」と AWS 他サービスとの連携
    • Python コードの解説

免責事項

  • この記事に書かれていることは弊社の意見を代表するものではありません。
  • この記事に書かれていることには一定の調査と検証を実施しておりますが、間違いが存在しうることはご承知おき下さい。
  • 筆者の専門外の内容については断定を避けておりますが、あらかじめ間違いが存在しうることはご承知おき下さい。
  • 記事の内容は、記事執筆時点 (2023/11) での情報です。ご承知おき下さい。

AWS VPC 「など」の設定項目をざっくり解説する

AWS で最も初めに触るサービスといえば VPC や、サブネット、ルートテーブルだと思います。

これらは VPC の作成コンソールで「作成するリソース」の選択肢から「VPC など」を選ぶと併せて作成されるリソースです。

どれもいわゆる「ネットワーク」を作成できるサービスで、IaaS サービスを使う際には必須となる部品です。

そんなネットワーク周りのサービス群ですが、ちゃんと設定しようと思うとよくわからない設定があってモヤモヤすることもあるのではないでしょうか。

もちろん AWS 公式のドキュメントはありますが、専門用語 & 固有名詞を使って1から100まで説明されているので「初めてだから基本的なものだけ把握したいのに……」といった思いをする人も多いことでしょう。

この記事では初めに設定したほうがいい項目について、実用的な例を交えて少しだけ踏み込んで解説しています。

ドキュメント読み切れないし、まあ迷ったらデフォルトでいっか~。

という状態から、この記事を読んで脱却しましょう!

※2023年11月16日時点のコンソールを参考にわかりやすくざっくり解説します。
※限定的なケースでしか設定しない項目は説明を割愛しています。

作成するリソース

VPC のみを作成するか、関連するリソースを同時に作成するかを選択できます。

結論としては、VPC だけを作るという特殊な要件が無い限り「VPC など」を選択すれば OK です。

というのも以前はこのオプションが無く、必ず必要となる「サブネット」「ルートテーブル」「インターネットゲートウェイ」などを都度作成していました。

便利機能のような立ち位置のオプションってことだぞ。

名前タグの自動生成

作成される関連リソース全てに対し、Name タグの先頭へ共通の文字列を挿入できます。

プロジェクト名や「テスト」など、利用目的が分かるものを入力しておけば十分でしょう。

IPv4 CIDR ブロック

IPv4 の CIDR ブロックを設定します。他の VPC と被らないプライベートIPアドレスのブロックを設定すればよいでしょう。

VPC を多数作成する要件がある場合は、ブロックサイズを調整しましょう。

その場合は、使用する内部 IP の数も忘れずに検討しましょう。

IPV6 CIDR ブロック

IPV6 CIDR ブロックを使用するか選択する。

特に要件がなければブロックなしで OK。

IPv6 へ移行していくという世の中の流れはあるけど、いくつか考慮すべきポイントがあるのでまだ今の段階では IPv4 が無難だぞ。

テナンシー

VPC 上で作成されるEC2インスタンスが、他のユーザーと共有の物理サーバー上で実行されるか、専有した物理サーバー上かどうかを選択できる。

特に要件がなければ「デフォルト」で OK です。

専有すると特定のライセンス持ち込みなどが可能になる場合があるが、コストは増加します。

アベイラビリティゾーン (AZ) の数

いくつのゾーンにネットワークを横断するかの設定。

結論としては 3AZ にしておくのが無難。

たとえばロードバランサーでは基本的に3AZが推奨されているので、それに合わせておくのがよいでしょう。

参考:[初級編] なぜ「AWS で負荷分散は3AZ にまたがるのがベストプラクティス」と言われるのか 可用性の面から考えてみた | DevelopersIO

サブネット

パブリックサブネットの数

インターネットゲートウェイを介して外部と通信する、いわゆる公開サブネットの数。

公開されたリソースを絶対に作らないなどの要件がなければ、ゾーンの数×1 (画像では合計2、推奨は3) を選択しておけば OK。

プライベートサブネットの数

いわゆる非公開サブネットの数。

環境ごとにサブネットを分けるなどの要件がなければ、ゾーンの数×1 (画像では合計2、推奨は3) を選択しておけば OK。

NAT ゲートウェイ ($)

プライベートサブネットが外部と通信するための NAT ゲートウェイをいくつ作成するか。

($) とあるように、NAT ゲートウェイは無視できない額の費用が発生する。

開発環境では1AZ内で十分。

本番環境では冗長性を確保するため「AZごとに1」がよいでしょう。

何も考えずに作成するとお金が無くなっていくぞ。

DNS オプション

DNS ホスト名を有効化

結論としては、とりあえずチェックボックスを埋めておけば OK。

チェックボックスを埋めると VPC 内のインスタンスを DNS で名前解決できる。

必要になるケースも無効にしなければいけないケースも限定的なのでニッチな要件があれば考慮するといいでしょう。

DNS 解決を有効化

基本的に「DNS ホスト名を有効化」に連動して合わせれば OK。

DNS に関して独自の仕組みを導入する場合は、片方のみ有効化する場面もあり得ますが、一般的な構築では遭遇しないでしょう。

AWS SDK for Python (Boto3) コード例

上記で説明した、基本的な設定を仮置きした AWS SDK for Python (Boto3) コードを参考に記載します。

※生成 AI で出力したものを編集しています。

import boto3

# AWS の認証情報。この情報を使って AWS サービスにアクセスします。
AWS_ACCESS_KEY_ID = '****'
AWS_SECRET_ACCESS_KEY = '****'

# AWS のリージョン情報。このリージョンで EC2 インスタンスが起動します。
REGION_NAME = 'us-east-1'
ZONES = ['a', 'c', 'd']

def create_vpc_with_resources():
    # ec2_resource または ec2_client を使用してリソース操作を実施
    ec2_resource = boto3.resource(
        'ec2',
        aws_access_key_id=AWS_ACCESS_KEY_ID,
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
        region_name=REGION_NAME
    )
    # ec2_resource (class EC2.Resources) にない操作は ec2_client (class EC2.Client) を利用
    ec2_client = boto3.client(
        'ec2',
        aws_access_key_id=AWS_ACCESS_KEY_ID,
        aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
        region_name=REGION_NAME
    )

    print('Creating VPC...')
    vpc = ec2_resource.create_vpc(CidrBlock='10.0.0.0/16')
    vpc.create_tags(Tags=[{'Key': 'Name', 'Value': 'my_vpc'}])
    vpc.wait_until_available()

    print('Enabling DNS hostnames and support...')
    ec2_client.modify_vpc_attribute(VpcId=vpc.id, EnableDnsHostnames={'Value': True})
    ec2_client.modify_vpc_attribute(VpcId=vpc.id, EnableDnsSupport={'Value': True})

    print('Creating and attaching Internet Gateway...')
    igw = ec2_resource.create_internet_gateway()
    vpc.attach_internet_gateway(InternetGatewayId=igw.id)
    igw.create_tags(Tags=[{'Key': 'Name', 'Value': 'my_vpc_igw'}])

    # パブリックサブネットを冗長化して作成
    public_subnets = []
    for i, zone in enumerate(ZONES):
        print(f'Creating public subnet in zone {zone}...')
        subnet = vpc.create_subnet(CidrBlock=f'10.0.{i*2}.0/24', AvailabilityZone=f'{REGION_NAME}{zone}')
        subnet.create_tags(Tags=[{'Key': 'Name', 'Value': f'my_vpc_public_subnet_{zone}'}])
        public_subnets.append(subnet)

    # プライベートサブネットを冗長化して作成
    private_subnets = []
    for i, zone in enumerate(ZONES):
        print(f'Creating private subnet in zone {zone}...')
        subnet = vpc.create_subnet(CidrBlock=f'10.0.{i*2 + 1}.0/24', AvailabilityZone=f'{REGION_NAME}{zone}')
        subnet.create_tags(Tags=[{'Key': 'Name', 'Value': f'my_vpc_private_subnet_{zone}'}])
        private_subnets.append(subnet)

    # ルートテーブルを作成し、パブリックサブネットに関連付け
    for i, subnet in enumerate(public_subnets):
        print(f'Creating route table for public subnet in zone {ZONES[i]}...')
        route_table = vpc.create_route_table()
        route = route_table.create_route(DestinationCidrBlock='0.0.0.0/0', GatewayId=igw.id)
        route_table.associate_with_subnet(SubnetId=subnet.id)
        route_table.create_tags(Tags=[{'Key': 'Name', 'Value': f'my_vpc_public_route_table_{ZONES[i]}'}])

    # NATゲートウェイとElastic IPを作成し、プライベートサブネットに関連付け
    nat_gw_ids = []
    for i, subnet in enumerate(public_subnets):
        print(f'Allocating Elastic IP and creating NAT Gateway in zone {ZONES[i]}...')
        eip_allocation = ec2_client.allocate_address(Domain='vpc')
        allocation_id = eip_allocation['AllocationId']
        ec2_client.create_tags(
            Resources=[eip_allocation['AllocationId']],
            Tags=[{'Key': 'Name', 'Value': f'my_vpc_eip_{ZONES[i]}'}]
        )
        nat_gw = ec2_client.create_nat_gateway(
            SubnetId=subnet.id,
            AllocationId=allocation_id
        )
        nat_gw_id = nat_gw['NatGateway']['NatGatewayId']
        nat_gw_ids.append(nat_gw_id)

        ec2_client.create_tags(
            Resources=[nat_gw_id],
            Tags=[{'Key': 'Name', 'Value': f'my_vpc_nat_gw_{ZONES[i]}'}]
        )

        # NATゲートウェイの作成状態を確認
        ec2_client.get_waiter('nat_gateway_available').wait(NatGatewayIds=[nat_gw_id])

        print(f'Creating route table for private subnet in zone {ZONES[i]}...')
        private_subnet = private_subnets[i]
        route_table = vpc.create_route_table()
        route_table.create_route(DestinationCidrBlock='0.0.0.0/0', NatGatewayId=nat_gw_id)
        route_table.associate_with_subnet(SubnetId=private_subnet.id)
        route_table.create_tags(Tags=[{'Key': 'Name', 'Value': f'my_vpc_private_route_table_{ZONES[i]}'}])

    print('Creating S3 Gateway Endpoint...')
    s3_endpoint = ec2_client.create_vpc_endpoint(
        VpcEndpointType='Gateway',
        VpcId=vpc.id,
        ServiceName=f'com.amazonaws.{REGION_NAME}.s3',
        RouteTableIds=[rt.id for rt in vpc.route_tables.all()],
        PolicyDocument='{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":"*","Action":"s3:*","Resource":"*"}]}'
    )

    s3_endpoint_id = s3_endpoint['VpcEndpoint']['VpcEndpointId']
    ec2_client.create_tags(
        Resources=[s3_endpoint_id],
        Tags=[{'Key': 'Name', 'Value': 'my_vpc_s3_endpoint'}]
    )

    print(f'VPC ID: {vpc.id}')
    print(f'Public Subnet IDs: {[subnet.id for subnet in public_subnets]}')
    print(f'Private Subnet IDs: {[subnet.id for subnet in private_subnets]}')
    print(f'NAT Gateway IDs: {nat_gw_ids}')
    print(f'S3 Endpoint ID: {s3_endpoint_id}')

# 関数を実行してリソースを作成
create_vpc_with_resources()

まとめ

以上、ハマグリ式! VPC 「など」の設定項目をわかりやすくざっくり解説する ~AWS SDK for Python (Boto3) コードもあるよ~ でした!

ぜひ下のボタンから、ハッシュタグ #ハマグリ式 で感想をツイートしてください!

今後ともハマグリ式をどうぞよろしくお願いいたします!

関連記事

[初級] ハマグリ式! EC2 の設定項目をわかりやすくざっくり解説する ~AWS SDK for Python (Boto3) コードもあるよ~

この記事を書いた人

記事一覧
SQUARE ENIXでは一緒に働く仲間を募集しています!
興味をお持ちいただけたら、ぜひ採用情報ページもご覧下さい!