AWS CLI で VPC を一式作る手順は、create-vpc → create-subnet → create-internet-gateway と attach-internet-gateway → create-route-table と create-route → associate-route-table の順です。 前のコマンドが返した ID を次のコマンドに渡していくので、--query と --output text で ID だけを変数に受け取るのがコツです。

この記事では、VPC からルートテーブルの関連付けまでを最後まで流せる1本の bash スクリプトにまとめ、各段階の出力を載せます。作ったものを依存の逆順で消す削除スクリプト、どのリソースがどれに依存するかの表、順番を入れ替えたときのエラー文、パブリックとプライベートの見分け方、boto3 版も用意しました。

確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11 / boto3 1.43.103。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しています。掲載するコマンドは、実際の AWS でそのまま使える形で書いています。

VPC 作成コマンドの早見表

順番 作るもの コマンド 受け取る ID
1 VPC aws ec2 create-vpc --cidr-block 10.0.0.0/16 Vpc.VpcId
2 サブネット aws ec2 create-subnet --vpc-id VPC --cidr-block 10.0.1.0/24 --availability-zone AZ Subnet.SubnetId
3 インターネットゲートウェイ(IGW) aws ec2 create-internet-gateway InternetGateway.InternetGatewayId
4 IGW を VPC に取り付け aws ec2 attach-internet-gateway --internet-gateway-id IGW --vpc-id VPC (なし)
5 ルートテーブル aws ec2 create-route-table --vpc-id VPC RouteTable.RouteTableId
6 IGW 向けのルート aws ec2 create-route --route-table-id RTB --destination-cidr-block 0.0.0.0/0 --gateway-id IGW (なし)
7 サブネットへの関連付け aws ec2 associate-route-table --route-table-id RTB --subnet-id SUBNET AssociationId

削除はこの逆順(7 → 1)です。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「AWS CLIでVPCを作成する手順|サブネットからIGWまで一式」

作る構成

10.0.0.0/16 の VPC に、サブネットを2つ作ります。片方だけを IGW へのルートを持つルートテーブルに関連付けて、パブリックサブネットにします。

flowchart TB
  subgraph VPC["VPC 10.0.0.0/16"]
    PUB["パブリック用サブネット 10.0.1.0/24"]
    PRI["プライベート用サブネット 10.0.2.0/24"]
    RTB["自作ルートテーブル(0.0.0.0/0 → IGW)"]
    MAIN["メインルートテーブル(local のみ)"]
  end
  IGW["インターネットゲートウェイ"]
  PUB -- 関連付け --> RTB
  PRI -- 自動で使われる --> MAIN
  RTB --> IGW

公式ドキュメントでは、IGW への直接のルートを持つサブネットをパブリックサブネット、持たないサブネットをプライベートサブネット と呼んでいます。サブネットを作っただけでは VPC のメインルートテーブルに自動で関連付けられるので、最初はどちらもプライベートの状態です。

ID を変数に受け取る書き方

create-vpc は VPC の情報を JSON で返します。

aws ec2 create-vpc --cidr-block 10.9.0.0/16 \
  --query 'Vpc.{VpcId:VpcId,State:State,CidrBlock:CidrBlock,IsDefault:IsDefault}'
{
    "VpcId": "vpc-28dc78c4cbf75cc09",
    "State": "available",
    "CidrBlock": "10.9.0.0/16",
    "IsDefault": false
}

次のコマンドで必要なのは VpcId だけです。--query 'Vpc.VpcId' --output text を付けると ID の文字列だけが返るので、$( ) でそのまま変数に入れられます。

VPC_ID=$(aws ec2 create-vpc --cidr-block 10.0.0.0/16 \
  --query 'Vpc.VpcId' --output text)

すべての作成コマンドをこの形にそろえると、ID をコピーして貼り付ける作業がなくなります。

一括作成スクリプト(create_vpc.sh)

VPC からルートテーブルの関連付けまでを一度に作るスクリプトです。名前や CIDR は先頭の変数で変えられます。

#!/usr/bin/env bash
# create_vpc.sh : VPC・サブネット2つ・IGW・ルートテーブルをまとめて作る
set -euo pipefail

NAME=demo
VPC_CIDR=10.0.0.0/16
PUBLIC_CIDR=10.0.1.0/24
PRIVATE_CIDR=10.0.2.0/24
AZ=ap-northeast-1a

echo "1. VPC"
VPC_ID=$(aws ec2 create-vpc --cidr-block "$VPC_CIDR" \
  --tag-specifications "ResourceType=vpc,Tags=[{Key=Name,Value=$NAME-vpc}]" \
  --query 'Vpc.VpcId' --output text)
aws ec2 modify-vpc-attribute --vpc-id "$VPC_ID" --enable-dns-hostnames '{"Value":true}'
echo "   VPC_ID=$VPC_ID"

echo "2. サブネット(パブリック用・プライベート用)"
PUBLIC_SUBNET_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" \
  --cidr-block "$PUBLIC_CIDR" --availability-zone "$AZ" \
  --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=$NAME-public-a}]" \
  --query 'Subnet.SubnetId' --output text)
PRIVATE_SUBNET_ID=$(aws ec2 create-subnet --vpc-id "$VPC_ID" \
  --cidr-block "$PRIVATE_CIDR" --availability-zone "$AZ" \
  --tag-specifications "ResourceType=subnet,Tags=[{Key=Name,Value=$NAME-private-a}]" \
  --query 'Subnet.SubnetId' --output text)
aws ec2 modify-subnet-attribute --subnet-id "$PUBLIC_SUBNET_ID" --map-public-ip-on-launch
echo "   PUBLIC_SUBNET_ID=$PUBLIC_SUBNET_ID"
echo "   PRIVATE_SUBNET_ID=$PRIVATE_SUBNET_ID"

echo "3. インターネットゲートウェイ(作成 → VPC に取り付け)"
IGW_ID=$(aws ec2 create-internet-gateway \
  --tag-specifications "ResourceType=internet-gateway,Tags=[{Key=Name,Value=$NAME-igw}]" \
  --query 'InternetGateway.InternetGatewayId' --output text)
aws ec2 attach-internet-gateway --internet-gateway-id "$IGW_ID" --vpc-id "$VPC_ID"
echo "   IGW_ID=$IGW_ID"

echo "4. ルートテーブル(作成 → 0.0.0.0/0 を IGW へ)"
RTB_ID=$(aws ec2 create-route-table --vpc-id "$VPC_ID" \
  --tag-specifications "ResourceType=route-table,Tags=[{Key=Name,Value=$NAME-public-rtb}]" \
  --query 'RouteTable.RouteTableId' --output text)
aws ec2 create-route --route-table-id "$RTB_ID" \
  --destination-cidr-block 0.0.0.0/0 --gateway-id "$IGW_ID" \
  > /dev/null
echo "   RTB_ID=$RTB_ID"

echo "5. ルートテーブルをパブリック用サブネットに関連付け"
ASSOC_ID=$(aws ec2 associate-route-table --route-table-id "$RTB_ID" \
  --subnet-id "$PUBLIC_SUBNET_ID" --query 'AssociationId' --output text)
echo "   ASSOC_ID=$ASSOC_ID"

cat > vpc_ids.env <<EOF
VPC_ID=$VPC_ID
PUBLIC_SUBNET_ID=$PUBLIC_SUBNET_ID
PRIVATE_SUBNET_ID=$PRIVATE_SUBNET_ID
IGW_ID=$IGW_ID
RTB_ID=$RTB_ID
ASSOC_ID=$ASSOC_ID
EOF
echo "完了: ID を vpc_ids.env に保存しました"

実行結果です。

bash create_vpc.sh
1. VPC
   VPC_ID=vpc-53c19bfaa2cbff0e9
2. サブネット(パブリック用・プライベート用)
   PUBLIC_SUBNET_ID=subnet-b921e73f2da192f5b
   PRIVATE_SUBNET_ID=subnet-a398b70f14e46b48b
3. インターネットゲートウェイ(作成 → VPC に取り付け)
   IGW_ID=igw-96174631a41381cb8
4. ルートテーブル(作成 → 0.0.0.0/0 を IGW へ)
   RTB_ID=rtb-9dee8ec155d27f53a
5. ルートテーブルをパブリック用サブネットに関連付け
   ASSOC_ID=rtbassoc-ea7052c1d84d8513a
完了: ID を vpc_ids.env に保存しました

スクリプトのポイント

書き方 ねらい
set -euo pipefail どこかのコマンドがエラーになったら、その場で止める
--query '...' --output text ID だけを受け取って変数に入れる
--tag-specifications 作成と同時に Name タグを付け、あとで探しやすくする
modify-subnet-attribute --map-public-ip-on-launch パブリック用サブネットで起動するインスタンスに、パブリック IPv4 アドレスを自動で割り当てる
vpc_ids.env に書き出す 削除スクリプトが同じ ID を読み込めるようにする

各段階の結果を確認する

サブネット

source ./vpc_ids.env

aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC_ID \
  --query 'Subnets[].{ID:SubnetId,CIDR:CidrBlock,AZ:AvailabilityZone,PublicIp:MapPublicIpOnLaunch,Free:AvailableIpAddressCount,Name:Tags[?Key==`Name`]|[0].Value}' \
  --output table
------------------------------------------------------------------------------------------------------
|                                           DescribeSubnets                                          |
+-----------------+--------------+-------+----------------------------+-----------------+------------+
|       AZ        |    CIDR      | Free  |            ID              |      Name       | PublicIp   |
+-----------------+--------------+-------+----------------------------+-----------------+------------+
|  ap-northeast-1a|  10.0.1.0/24 |  251  |  subnet-b921e73f2da192f5b  |  demo-public-a  |  True      |
|  ap-northeast-1a|  10.0.2.0/24 |  251  |  subnet-a398b70f14e46b48b  |  demo-private-a |  False     |
+-----------------+--------------+-------+----------------------------+-----------------+------------+

/24 は 256 個のアドレスですが、Free(使えるアドレス数)は 251 です。公式ドキュメントによると、各サブネットでは5つのアドレスが予約されます。10.0.0.0/24 の場合の内訳は次のとおりです。

アドレス 用途
10.0.0.0 ネットワークアドレス
10.0.0.1 VPC ルーター用
10.0.0.2 DNS サーバー用
10.0.0.3 将来の利用のために予約
10.0.0.255 ブロードキャストアドレス(VPC では使われない)

インターネットゲートウェイ

aws ec2 describe-internet-gateways --internet-gateway-ids $IGW_ID \
  --query 'InternetGateways[0].{ID:InternetGatewayId,Attachments:Attachments}'
{
    "ID": "igw-96174631a41381cb8",
    "Attachments": [
        {
            "State": "available",
            "VpcId": "vpc-53c19bfaa2cbff0e9"
        }
    ]
}

Attachments に VPC の ID が入っていれば、取り付けが済んでいます。公式ドキュメントには、IGW そのものに料金はかからず、IGW を使うインスタンスのデータ転送に料金がかかると書かれています。

パブリックとプライベートの違いをルートテーブルで見比べる

サブネットがパブリックかプライベートかは、そのサブネットが使うルートテーブルに 0.0.0.0/0 → igw-… のルートがあるかどうか で決まります。

パブリック用サブネットのルート

サブネット ID からルートテーブルを引きます。

aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=$PUBLIC_SUBNET_ID \
  --query 'RouteTables[].Routes[].[DestinationCidrBlock,GatewayId,State,Origin]' --output table
------------------------------------------------------------------------
|                          DescribeRouteTables                         |
+-------------+-------------------------+---------+--------------------+
|  10.0.0.0/16|  local                  |  active |  CreateRouteTable  |
|  0.0.0.0/0  |  igw-96174631a41381cb8  |  active |  CreateRoute       |
+-------------+-------------------------+---------+--------------------+

1行目の local は VPC 内どうしの通信用で、ルートテーブルを作ると自動で入ります。2行目が、スクリプトの create-route で追加した IGW 向けのルートです。

プライベート用サブネットのルート

同じフィルターをプライベート用サブネットで実行すると、0件です。

aws ec2 describe-route-tables \
  --filters Name=association.subnet-id,Values=$PRIVATE_SUBNET_ID \
  --query 'length(RouteTables)'
0

明示的に関連付けたルートテーブルがないサブネットは、VPC のメインルートテーブルを使います。メインルートテーブルの中身を見ます。

aws ec2 describe-route-tables \
  --filters Name=vpc-id,Values=$VPC_ID Name=association.main,Values=true \
  --query 'RouteTables[].Routes[].[DestinationCidrBlock,GatewayId,State,Origin]' --output table
--------------------------------------------------------
|                  DescribeRouteTables                 |
+--------------+--------+---------+--------------------+
|  10.0.0.0/16 |  local |  active |  CreateRouteTable  |
+--------------+--------+---------+--------------------+

local だけで、IGW へのルートがありません。これがプライベートサブネットの状態です。

VPC 全体を1枚で見る

aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC_ID \
  --query 'RouteTables[].{RTB:RouteTableId,Main:Associations[0].Main,Subnet:Associations[0].SubnetId,ToInternet:Routes[?DestinationCidrBlock==`0.0.0.0/0`]|[0].GatewayId}' \
  --output table
-----------------------------------------------------------------------------------------
|                                  DescribeRouteTables                                  |
+------+-------------------------+----------------------------+-------------------------+
| Main |           RTB           |          Subnet            |       ToInternet        |
+------+-------------------------+----------------------------+-------------------------+
|  True|  rtb-6854fd2b0638ac76b  |  None                      |  None                   |
|False |  rtb-9dee8ec155d27f53a  |  subnet-b921e73f2da192f5b  |  igw-96174631a41381cb8  |
+------+-------------------------+----------------------------+-------------------------+
見る場所 パブリックサブネット プライベートサブネット
使うルートテーブル 自分で作って関連付けたもの メインルートテーブル(または IGW ルートのない別のテーブル)
0.0.0.0/0 のルート igw-… を向いている なし
パブリック IP の自動割り当て 有効にしておくと便利 無効のまま

公式ドキュメントでは、パブリックサブネットのリソースがインターネットと通信するには、IGW へのルートに加えて、そのリソース自身がパブリック IPv4 アドレス(または IPv6 アドレス)を持っている必要があるとされています。

どのリソースがどれに依存するか

削除の順番は、この依存関係で決まります。「依存されている側」は、依存している側を先に片付けてからでないと削除できません。

リソース 依存先(これがないと作れない) 削除の前に済ませること
ルートテーブルの関連付け ルートテーブル、サブネット (最初に外せる)
ルートテーブル VPC サブネットへの関連付けを外す
IGW の取り付け IGW、VPC (ルートテーブル削除のあとに外す)
IGW (単体で作れる) VPC から取り外す
サブネット VPC サブネット内のリソース(インスタンスなど)を削除する
VPC (単体で作れる) サブネット、自作のルートテーブル、IGW をすべて片付ける

削除スクリプト(delete_vpc.sh)

作成の逆順で消します。create_vpc.sh が書き出した vpc_ids.env を読み込むので、ID を打ち直す必要はありません。

#!/usr/bin/env bash
# delete_vpc.sh : create_vpc.sh で作ったものを依存の逆順で消す
set -euo pipefail
source ./vpc_ids.env

echo "1. 関連付けを外す";            aws ec2 disassociate-route-table --association-id "$ASSOC_ID"
echo "2. ルートテーブルを削除";      aws ec2 delete-route-table --route-table-id "$RTB_ID"
echo "3. IGW を VPC から取り外す";   aws ec2 detach-internet-gateway --internet-gateway-id "$IGW_ID" --vpc-id "$VPC_ID"
echo "4. IGW を削除";                aws ec2 delete-internet-gateway --internet-gateway-id "$IGW_ID"
echo "5. サブネットを削除";          aws ec2 delete-subnet --subnet-id "$PUBLIC_SUBNET_ID"
                                     aws ec2 delete-subnet --subnet-id "$PRIVATE_SUBNET_ID"
echo "6. VPC を削除";                aws ec2 delete-vpc --vpc-id "$VPC_ID"
rm -f vpc_ids.env
echo "完了"
bash delete_vpc.sh
1. 関連付けを外す
2. ルートテーブルを削除
3. IGW を VPC から取り外す
4. IGW を削除
5. サブネットを削除
6. VPC を削除
完了

Name タグで探して、残っていないことを確かめます。

aws ec2 describe-vpcs --filters Name=tag:Name,Values=demo-vpc --query 'length(Vpcs)'
0

順番を入れ替えるとどうなるか(DependencyViolation)

削除スクリプトを流す前の状態で、わざと順番を入れ替えて実行した結果です。

サブネットが残ったまま VPC を削除する

aws ec2 delete-vpc --vpc-id $VPC_ID
An error occurred (DependencyViolation) when calling the DeleteVpc operation: The vpc 'vpc-53c19bfaa2cbff0e9' has dependencies and cannot be deleted.

関連付けが残ったままルートテーブルを削除する

aws ec2 delete-route-table --route-table-id $RTB_ID
An error occurred (DependencyViolation) when calling the DeleteRouteTable operation: The routeTable 'rtb-9dee8ec155d27f53a' has dependencies and cannot be deleted.

どちらも DependencyViolation です。公式のエラーコード一覧では「指定したオブジェクトに依存するリソースがある。先に依存を取り除いてから再実行する」と説明されています。IGW を VPC に取り付けたまま delete-internet-gateway を実行した場合も、同じ DependencyViolation で止まりました。

何が残っているかを調べる

エラー文には「何が残っているか」までは出ないので、VPC の ID で絞って一覧にします。

# サブネット
aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC_ID \
  --query 'Subnets[].SubnetId' --output text

# 取り付けられている IGW
aws ec2 describe-internet-gateways --filters Name=attachment.vpc-id,Values=$VPC_ID \
  --query 'InternetGateways[].InternetGatewayId' --output text

# メイン以外のルートテーブル
aws ec2 describe-route-tables --filters Name=vpc-id,Values=$VPC_ID \
  --query 'RouteTables[?Associations[0].Main!=`true`].RouteTableId' --output text
subnet-b921e73f2da192f5b    subnet-a398b70f14e46b48b
igw-96174631a41381cb8
rtb-9dee8ec155d27f53a

スクリプトが途中で止まって vpc_ids.env が作られなかったときも、この3つのコマンドで残りを見つけて、依存関係の表の順に消していけます。

そのほかのエラー文と直し方

InvalidSubnet.Conflict(CIDR が既存のサブネットと重なる)

10.0.1.0/24 がすでにある VPC に、その範囲に含まれる 10.0.1.128/25 を作ろうとした例です。

aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.0.1.128/25
An error occurred (InvalidSubnet.Conflict) when calling the CreateSubnet operation: The CIDR '10.0.1.128/25' conflicts with another subnet

既存のサブネットの CIDR を一覧にして、重ならない範囲を選び直します。

aws ec2 describe-subnets --filters Name=vpc-id,Values=$VPC_ID \
  --query 'Subnets[].CidrBlock' --output text

/24 で区切る場合は、3番目の数字を 1、2、3… と変えていけば重なりません(10.0.1.0/24、10.0.2.0/24、10.0.3.0/24)。

InvalidSubnet.Range(VPC の範囲の外)

VPC が 10.0.0.0/16 なのに、その外の 10.1.0.0/24 を指定した例です。

aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block 10.1.0.0/24
An error occurred (InvalidSubnet.Range) when calling the CreateSubnet operation: The CIDR '10.1.0.0/24' is invalid.

サブネットの CIDR は VPC の CIDR の内側に収めます。公式ドキュメントによると、サブネットに使えるブロックサイズは /28 から /16 までです。

RouteAlreadyExists(同じ宛先のルートがすでにある)

aws ec2 create-route --route-table-id $RTB_ID \
  --destination-cidr-block 0.0.0.0/0 --gateway-id $IGW_ID
An error occurred (RouteAlreadyExists) when calling the CreateRoute operation: The route identified by 0.0.0.0/0 already exists

向き先を変えたいときは、create-route ではなく replace-route を使います。

エラーコードのまとめ

エラーコード 起きる操作 直し方
DependencyViolation delete-vpc、delete-route-table、delete-internet-gateway など 依存しているリソースを先に片付ける
InvalidSubnet.Conflict create-subnet 既存サブネットと重ならない CIDR にする
InvalidSubnet.Range create-subnet VPC の CIDR の内側で、/28〜/16 にする
RouteAlreadyExists create-route 既存のルートを使うか、replace-route で向き先を変える
Resource.AlreadyAssociated attach-internet-gateway(取り付け済みの IGW をもう一度取り付けたとき) すでに取り付いているので、そのまま次へ進む

boto3 で同じ手順を書く

Python(boto3)でも、流れと引数の名前はほぼそのままです。作成と削除を1ファイルにまとめました。

import boto3

ec2 = boto3.client("ec2", region_name="ap-northeast-1")


def name_tag(resource_type, name):
    return [{"ResourceType": resource_type, "Tags": [{"Key": "Name", "Value": name}]}]


def create():
    vpc_id = ec2.create_vpc(
        CidrBlock="10.0.0.0/16", TagSpecifications=name_tag("vpc", "demo-vpc")
    )["Vpc"]["VpcId"]
    ec2.get_waiter("vpc_available").wait(VpcIds=[vpc_id])
    ec2.modify_vpc_attribute(VpcId=vpc_id, EnableDnsHostnames={"Value": True})

    public_id = ec2.create_subnet(
        VpcId=vpc_id, CidrBlock="10.0.1.0/24", AvailabilityZone="ap-northeast-1a",
        TagSpecifications=name_tag("subnet", "demo-public-a"),
    )["Subnet"]["SubnetId"]
    private_id = ec2.create_subnet(
        VpcId=vpc_id, CidrBlock="10.0.2.0/24", AvailabilityZone="ap-northeast-1a",
        TagSpecifications=name_tag("subnet", "demo-private-a"),
    )["Subnet"]["SubnetId"]
    ec2.modify_subnet_attribute(SubnetId=public_id, MapPublicIpOnLaunch={"Value": True})

    igw_id = ec2.create_internet_gateway(
        TagSpecifications=name_tag("internet-gateway", "demo-igw")
    )["InternetGateway"]["InternetGatewayId"]
    ec2.attach_internet_gateway(InternetGatewayId=igw_id, VpcId=vpc_id)

    rtb_id = ec2.create_route_table(
        VpcId=vpc_id, TagSpecifications=name_tag("route-table", "demo-public-rtb")
    )["RouteTable"]["RouteTableId"]
    ec2.create_route(RouteTableId=rtb_id, DestinationCidrBlock="0.0.0.0/0", GatewayId=igw_id)
    assoc_id = ec2.associate_route_table(RouteTableId=rtb_id, SubnetId=public_id)["AssociationId"]

    return {"vpc": vpc_id, "public": public_id, "private": private_id,
            "igw": igw_id, "rtb": rtb_id, "assoc": assoc_id}


def delete(ids):
    ec2.disassociate_route_table(AssociationId=ids["assoc"])
    ec2.delete_route_table(RouteTableId=ids["rtb"])
    ec2.detach_internet_gateway(InternetGatewayId=ids["igw"], VpcId=ids["vpc"])
    ec2.delete_internet_gateway(InternetGatewayId=ids["igw"])
    ec2.delete_subnet(SubnetId=ids["public"])
    ec2.delete_subnet(SubnetId=ids["private"])
    ec2.delete_vpc(VpcId=ids["vpc"])


if __name__ == "__main__":
    ids = create()
    for key, value in ids.items():
        print(f"{key:8}{value}")
    delete(ids)
    left = ec2.describe_vpcs(Filters=[{"Name": "tag:Name", "Values": ["demo-vpc"]}])["Vpcs"]
    print("残っている demo-vpc:", len(left))
python3 vpc_boto3.py
vpc     vpc-ab8e97db83ca1ff46
public  subnet-183a995262f5c4700
private subnet-ea6d2adf2d99c5710
igw     igw-d1e0e71ac03a3f644
rtb     rtb-0d3bb7da5cdf0e334
assoc   rtbassoc-af94d1e1e57f9cb01
残っている demo-vpc: 0
AWS CLI boto3
--query 'Vpc.VpcId' --output text 戻り値の辞書から ["Vpc"]["VpcId"]
--tag-specifications "ResourceType=vpc,Tags=[...]" TagSpecifications=[{"ResourceType": "vpc", "Tags": [...]}]
--cidr-block CidrBlock=
aws ec2 wait vpc-available ec2.get_waiter("vpc_available").wait(...)

よくある質問

Q. サブネットを作っただけでインターネットに出られますか? A. 作っただけのサブネットはメインルートテーブルを使うので、IGW へのルートがありません。IGW を取り付け、0.0.0.0/0 → IGW のルートを持つルートテーブルを関連付けると、パブリックサブネットになります。

Q. メインルートテーブルに直接 IGW のルートを足してもよいですか? A. 動きますが、そのあと作るサブネットもすべてパブリックになります。パブリック用のルートテーブルを別に作って、必要なサブネットだけに関連付けるほうが、意図がはっきりします。

Q. delete-vpc でメインルートテーブルは消えますか? A. 今回の手順では、メインルートテーブルを個別に消す操作はしていません。delete-vpc のあと、VPC が0件になることを確認しています。自分で作ったルートテーブルは、先に削除しておきます。

Q. アベイラビリティゾーンを2つに分けたいときは? A. create-subnet の --availability-zone を変えて、サブネットを追加します(例:ap-northeast-1a と ap-northeast-1c)。CIDR が重ならないようにして、パブリックにしたいサブネットは同じルートテーブルに associate-route-table で関連付けます。

まとめ

  • 作る順番は VPC → サブネット → IGW(作成と取り付け)→ ルートテーブル(作成とルート追加)→ 関連付け
  • ID は --query '...' --output text で変数に受け取る と、最後まで1本のスクリプトで流せる
  • パブリックかどうかは、ルートテーブルに 0.0.0.0/0 → igw-… があるかで決まる
  • 削除は作成の逆順。順番が違うと DependencyViolation で止まる
  • 作成時に Name タグを付け、ID をファイルに残す と、確認と後片付けが楽になる
  • CIDR が重なると InvalidSubnet.Conflict。既存の CIDR を一覧にして選び直す

参考・出典

  • Amazon VPC User Guide: Subnets for your VPC(https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html)
  • Amazon VPC User Guide: Subnet CIDR blocks(https://docs.aws.amazon.com/vpc/latest/userguide/subnet-sizing.html)
  • Amazon VPC User Guide: Enable internet access for a VPC using an internet gateway(https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Internet_Gateway.html)
  • Amazon EC2 API Reference: Error codes(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/errors-overview.html)

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「AWS CLIでVPCを作成する手順|サブネットからIGWまで一式」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?