amareloのブログ(仮)

IT系勉強会で感じた想いや知見をメインに書いていきます。

JAWS-UG CLI専門支部 #156R EC2基礎(VPC) 参加レポート

6/8(月)、JAWS-UG CLI専門支部 #156R EC2基礎(VPC)に参加しました。今回もハンズオンの感想と学んだコマンドについて書こうと思います。

目次

イベントページ

jawsug-cli.connpass.com

ハンズオンでやったこと

以下の通りです。事前準備として、Cloud9上にハンズオン環境を構築しました。 ハンズオンでは、Cloud9のターミナルでコマンド実行しました。

  • VPC管理
  • ルーティング情報の管理
  • セキュリティグループの管理
  • サブネット管理
  • インターネットゲートウェイの管理

VPC(Virtual Private Cloud)とは

  • EC2インスタンスを配置するための仮想ネットワーク
  • VPCはリージョン単位のサービス
    • 仮想データセンタというイメージ
  • 1リージョンあたり5VPCまで作成可能
  • 他の仮想ネットワークと完全に分離されている。そのため、VPC単体で使う分にはIPアドレスが重複しても問題ない。
    • VPCどうしを接続したり、様々なネットワークと接続するケースが増えているので、その場合はアドレッシングを検討する必要はある。
  • サブネットはAZ単位のサービス

    • サブネットは一つのデータセンタというイメージ
    • インスタンスはサブネット内に構築
    • 一般的には、パブリックサブネットとプライベートサブネットで分ける。
    • インスタンスごとのグルーピング(Webサーバ、DBサーバ等)でサブネットを分けるのがよい。
    • 東京リージョンはAZが3つなので、3サブネット作成可能
  • インターネットゲートウェイはインターネットの出入口

    • サイジングや冗長化は不要(AWS側で冗長対応しているため、設定そのものがない)
  • ルートテーブル

    • サブネットのルーティングテーブル情報
    • 1つのサブネットはルートテーブルを1つだけ関連付けることができる。
    • マスタルートテーブルを使わずに、ルールごとにルートテーブルを作るのが一般的
  • セキュリティグループ

    • EC2インスタンスのステートフルアクセス制御
    • インスタンスに紐づけてアクセス制御(厳密にはENIに紐づいている)
    • 外部通信はCIDR指定、VPC内部はグループ指定が基本

感想

コマンドを駆使してネットワーク構築をする感覚で面白かったです。VPCやEC2の構築をCLIで実施するケースは少ないかもしれませんが、どのような設定を入れて何がマネジメントコンソール裏で動いているのか確認できて良い経験になりました。

ハンズオンでやったこと

今回はボリュームが多いため、主要コマンドのみ触れていこうと思います。ハンズオン手順は、こちらを参照してください。

事前作業
1.VPCの構築
  • VPCを作成するためにはcreate-vpcコマンドを使います。
    • --cidr-blockでCIDRを指定します。
aws ec2 create-vpc --cidr-block ${EC2_VPC_CIDR} \
  • ec2 create-tagsコマンドを使ってVPCタグを作ります。
    • --resourcesVPC_IDを指定します。
    • --tagsでタグキーに入れるタグ値を指定します。
aws ec2 create-tags \
  --resources ${EC2_RESOURCE_ID} \
  --tags "Key=${EC2_TAG_KEY},Value=${EC2_TAG_VALUE}"
  • 作成したVPCの存在確認をするために、describe-vpcsコマンドを実行します。
    • --filtersでタグキーとタグ値を指定します。
    • --queryVPCのタグ値を抜き出し、--output textでテキスト表示します。
aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=${EC2_VPC_TAG_NAME}  \
  --query 'Vpcs[].Tags[?Key == `Name`].Value' \
  --output text
2.インターネットゲートウェイ(IGW)の作成
  • create-internet-gatewayコマンドでインターネットゲートウェイを作成します。
aws ec2 create-internet-gateway \
  • create-tagsコマンドでインターネットゲートウェイにタグ付けをします。
    • --resourcesでインターネットゲートウェイのIDを指定します。
    • --tagsでタグキーとタグ値を指定します。
aws ec2 create-tags \
  --resources ${EC2_RESOURCE_ID} \
  --tags "Key=${EC2_TAG_KEY},Value=${EC2_TAG_VALUE}"
  • describe-internet-gatewaysコマンドでIGWの存在確認をします。
    • --filterでタグキーとタグ値を指定します。
    • Tagの値を取得し、テキストで表示します。
aws ec2 describe-internet-gateways \
  --filters Name=tag:Name,Values=${EC2_IGW_TAG_NAME}  \
  --query "InternetGateways[].Tags[].Value" \
  --output text
3.IGWのアタッチ
  • VPC_IDを取得し、変数[EC2_VPC_ID]に指定します。
    • describe-vpcsコマンドでVPC情報を取得し、VpcIdの値をテキスト出力します。
EC2_VPC_ID=$( \
  aws ec2 describe-vpcs \
    --filters Name=tag:Name,Values=${EC2_VPC_TAG_NAME}  \
    --query 'Vpcs[].VpcId' \
    --output text \
) 
  • IGW_IDを取得します。
    • descrive-internet-gatewaysコマンドでIGW情報を取得し、InternetGatewayIdの値をテキスト表示します。
EC2_IGW_ID=$( \
  aws ec2 describe-internet-gateways \
    --filters Name=tag:Name,Values=${EC2_IGW_TAG_NAME} \
    --query "InternetGateways[].InternetGatewayId" \
    --output text \
) 
  • IGWをVPCにアタッチします。
    • attach-internet-gatewayコマンドを使って、IGWをVPCにアタッチします。
      • --internet-gateway-idでアタッチするIGWを指定します。
      • --vpc-idでIGWをアタッチするVPCを指定します。
aws ec2 attach-internet-gateway \
  --internet-gateway-id ${EC2_IGW_ID} \
  --vpc-id ${EC2_VPC_ID}
  • VPCにIGWがアタッチされていることを確認します。
aws ec2 describe-internet-gateways \
  --filters Name=tag:Name,Values=${EC2_IGW_TAG_NAME}  \
  --query "InternetGateways[].Attachments[?VpcId == \`${EC2_VPC_ID}\`].VpcId" \
  --output text
4. ルートテーブルの作成
  • create-route-tableコマンドでルートテーブルを作成します。
    • --vpc-idでルートテーブルを作成するVPCを指定します。
aws ec2 create-route-table --vpc-id ${EC2_VPC_ID} 
  • 作成したルートテーブルにタグ付けをします。
    • --resourcesでタグ付けするルートテーブルを指定します。
    • --tagsでタグキーとその値を指定します。
aws ec2 create-tags --resources ${EC2_RESOURCE_ID} \
  --tags "Key=${EC2_TAG_KEY},Value=${EC2_TAG_VALUE}"
  • describe-route-tablesコマンドでルートテーブルがVPC内に存在することを確認します。
aws ec2 describe-route-tables --filters Name=vpc-id,Values=${EC2_VPC_ID} \
            Name=tag:Name,Values=${EC2_ROUTE_TABLE_TAG_NAME}  \
  --query "RouteTables[].Tags[?Key == \`Name\`].Value" \
  --output text
5. ルートの作成
  • create-routeコマンドでルートテーブルにルートを作成します。
    • --route-table-idでルートを作成するルートテーブルを指定します。
    • --destination-cidr-block送信先CIDRを指定します。
    • --gateway-idでターゲットのIGWを指定します。
aws ec2 create-route \
  --route-table-id ${EC2_ROUTE_TABLE_ID} \
  --destination-cidr-block ${EC2_ROUTE_DEST_CIDR} \
  --gateway-id ${EC2_IGW_ID}
  • describe-route-tablesコマンドを使って、ルートテーブルに指定したルートが存在することを確認します。
    • --filterVPCとタグキー及びルートテーブルのタグ値を指定します。
    • 宛先CIDRが${EC2_ROUTE_DEST_CIDR}(ハンズオンでは、0.0.0.0/0)のルートがあるルートテーブルをテキストで出力します。
aws ec2 describe-route-tables \
  --filters Name=vpc-id,Values=${EC2_VPC_ID} \
            Name=tag:Name,Values=${EC2_ROUTE_TABLE_TAG_NAME}  \
  --query "RouteTables[].Routes[?DestinationCidrBlock == \`${EC2_ROUTE_DEST_CIDR}\`].DestinationCidrBlock" \
  --output text
  • 送信先へのルートが指定のIGWに設定されていることを確認します。
aws ec2 describe-route-tables \
  --filters Name=vpc-id,Values=${EC2_VPC_ID} \
            Name=tag:Name,Values=${EC2_ROUTE_TABLE_TAG_NAME}  \
  --query "RouteTables[].Routes[?DestinationCidrBlock == \`${EC2_ROUTE_DEST_CIDR}\`].GatewayId" \
  --output text
6. サブネットの作成
  • create-subnetコマンドでサブネットを作成します。
    • --vpc-idでサブネットを作成するVPCを指定します。
    • --cidr-blockでサブネットのアドレスレンジを指定します。
    • --availability-zoneでサブネットを作成するAZを指定します。
aws ec2 create-subnet \
  --vpc-id ${EC2_VPC_ID} \
  --cidr-block ${EC2_SUBNET_CIDR} \
  --availability-zone ${EC2_AZ_NAME} 
  • サブネットのタグを作成するためにcreate-tagsコマンドを使います。
    • resources でEC2のリソースが必要だし、
aws ec2 create-tags \
  --resources ${EC2_RESOURCE_ID} \
  --tags "Key=${EC2_TAG_KEY},Value=${EC2_TAG_VALUE}"
VPCに指定のサブネットが存在することを確認します。
  • describe-subnetsコマンドでサブネット情報を取得します。
    • --filterVPCとタグキーとタグ値を指定します。
aws ec2 describe-subnets \
  --filters Name=vpc-id,Values=${EC2_VPC_ID} \
            Name=tag:Name,Values=${EC2_SUBNET_TAG_NAME}  \
  --query 'Subnets[].Tags[?Key == `Name`].Value' \
  --output text
7. ルートテーブルとサブネットの関連付け
  • associate-route-tableコマンドを使ってルートテーブルとサブネットの関連付けをします。
    • --subnet-idで関連付けするサブネットを指定します。
    • --route-table-idで関連付けするルートテーブルを指定します。
aws ec2 associate-route-table \
  --subnet-id ${EC2_SUBNET_ID} \
  --route-table-id ${EC2_ROUTE_TABLE_ID}
  • 指定のサブネットとルートテーブルが関連付いていることを確認します。
aws ec2 describe-route-tables \
  --route-table-ids ${ARRAY_EC2_ROUTE_TABLE_IDS} \
  --query "RouteTables[].Associations[?SubnetId == \`${EC2_SUBNET_ID}\`].RouteTableAssociationId" \
  --output text
8. サブネット属性の有効化
  • modify-subnet-attributeコマンドでサブネット属性の設定変更をします。
    • --subnet--idで設定変更するサブネットを指定します。
    • --map-public-ip-on-launchで「パブリック IPv4 アドレスの自動割り当て」を有効にします。
aws ec2 modify-subnet-attribute \
  --subnet-id ${EC2_SUBNET_ID} \
  --map-public-ip-on-launch
  • サブネットのmap-public-ip-on-launch属性(パブリック IPv4 アドレスの自動割り当て)が有効(True)になっていることを確認します。
    • describe-subnetsコマンドを使います。
      • --filterでタグキーと値を指定します。
      • パブリック IPv4 アドレスの自動割り当てのステータスを取り出します。
EC2_SUBNET_ATTRIBUTE_MAP_PUBLIC_IP_ON_LAUNCH=$( \
  aws ec2 describe-subnets \
    --filters Name=tag:Name,Values=${EC2_SUBNET_TAG_NAME} \
    --query 'Subnets[].MapPublicIpOnLaunch' \
    --output text \
) \
  && echo ${EC2_SUBNET_ATTRIBUTE_MAP_PUBLIC_IP_ON_LAUNCH}
9. セキュリティグループの作成
  • create-security-groupコマンドでセキュリティグループを作成します。
    • --group-nameでセキュリティグループ名を指定します。
    • --descriptionでセキュリティグループの説明を指定します。
    • --vpc-idでセキュリティグループを作成するVPCを指定します。
aws ec2 create-security-group \
  --group-name ${EC2_SECURITY_GROUP_NAME} \
  --description "${EC2_SECURITY_GROUP_DESC}" \
  --vpc-id ${EC2_VPC_ID}
  • describe-security-groupsコマンドで指定のVPCに指定のセキュリティグループ名のグループがある場合は、テキスト表示します。
    • --filterVPC_IDとセキュリティグループ名を指定します。
aws ec2 describe-security-groups \
  --filter Name=vpc-id,Values=${EC2_VPC_ID} \
    Name=group-name,Values=${EC2_SECURITY_GROUP_NAME} \
  --query 'SecurityGroups[].GroupName' \
  --output text
10. セキュリティグループのIngressルール追加(TCP80の許可を追加)
  • authorize-security-groups-ingressコマンドでルールを作成します。
    • --group-idでルールを追加するセキュリティグループIDを指定します。
    • --protocolでルールに追加するプロトコルTCPUDP)を指定します。
    • --portでルールに追加するポート番号(80など)を指定します。
    • --cidrでルールに追加するIPアドレス(CIDR)を指定します。
aws ec2 authorize-security-group-ingress \
  --group-id ${EC2_SECURITY_GROUP_ID} \
  --protocol ${EC2_SECURITY_GROUP_PROTOCOL} \
  --port ${EC2_SECURITY_GROUP_PORT} \
  --cidr ${EC2_SECURITY_GROUP_CIDR}
  • 指定のVPCのセキュリティグループに、許可するプロトコルとポート番号の通信が作成されていることを確認します。
aws ec2 describe-security-groups \
  --filter Name=vpc-id,Values=${EC2_VPC_ID} \
    Name=group-name,Values=${EC2_SECURITY_GROUP_NAME} \
    Name=ip-permission.protocol,Values=${EC2_SECURITY_GROUP_PROTOCOL} \
    Name=ip-permission.to-port,Values=${EC2_SECURITY_GROUP_PORT} \
    Name=ip-permission.cidr,Values=${EC2_SECURITY_GROUP_CIDR} \
  --query "SecurityGroups[].IpPermissions[?IpProtocol == \`${EC2_SECURITY_GROUP_PROTOCOL}\` \
    && ToPort == \`${EC2_SECURITY_GROUP_PORT}\` \
    && IpRanges[?CidrIp == \`${EC2_SECURITY_GROUP_CIDR}\`]].IpRanges[][].CidrIp" \
  --output text
11.ユーザデータの作成

-ファイルのフルパスを変数[FILE_USER_DATA]に格納します。 - ${DIR_USER_DATA}にはユーザデータのディレクトリを事前に格納します。 - ${USER_DATA_NAME}にはユーザデータ名を事前に格納します。

FILE_USER_DATA="${DIR_USER_DATA}/${USER_DATA_NAME}.bash" 
cat << EOF0 > ${FILE_USER_DATA}
#!/bin/bash
yum -y update

EC2_METADATA_SECOND='600'

EC2_METADATA_TOKEN=\$( \\
  curl -s \\
    -X PUT "http://169.254.169.254/latest/api/token" \\
    -H "X-aws-ec2-metadata-token-ttl-seconds: \${EC2_METADATA_SECOND}" \\
)

EC2_METADATA_HEADER="X-aws-ec2-metadata-token: \${EC2_METADATA_TOKEN}"

EC2_AZ_NAME=\$( \\
  curl -s -H "\${EC2_METADATA_HEADER}" \\
    http://169.254.169.254/latest/meta-data/placement/availability-zone \\
)

EC2_INSTANCE_ID=\$( \\
  curl -s -H "\${EC2_METADATA_HEADER}" \\
    http://169.254.169.254/latest/meta-data/instance-id \\
) 

# setup httpd
yum install -y httpd
systemctl start httpd.service
systemctl enable httpd.service

# setup contents
cat << EOF > /var/www/html/index.html
<!DOCTYPE html>
<title>AZ: \${EC2_AZ_NAME}</title>
<h1>AZ: \${EC2_AZ_NAME}</h1>
<p>ID: \${EC2_INSTANCE_ID}</p>
EOF

EOF0

cat ${FILE_USER_DATA}
12. EC2インスタンスの起動
  • run-instancesコマンドでEC2インスタンスを実行します。
    • --image-idでAMI(Amazon Linux2)を指定します。
    • --instance-typeインスタンスタイプ(ハンズオンではt2.micro)を指定します。
    • --security-group-idsでセキュリティグループを指定します。
    • --tag-specificationsでタグの文字列を指定します。
    • --subnet-idインスタンス作成先サブネットを指定します。
    • --user-dataでユーザデータファイルを指定します。
aws ec2 run-instances \
  --image-id ${EC2_IMAGE_ID} \
  --instance-type ${EC2_INSTANCE_TYPE} \
  --security-group-ids ${ARRAY_EC2_SECURITY_GROUP_IDS} \
  --tag-specifications ${STRING_TAG_CONF} \
  --subnet-id ${EC2_SUBNET_ID} \
  --user-data file://${FILE_USER_DATA}
aws ec2 describe-instances \
  --filters Name=tag-key,Values=Name \
            Name=tag-value,Values=${EC2_INSTANCE_TAG_NAME} \
            Name=instance-state-name,Values=running \
  --query Reservations[].Instances[].Tags[].Value \
  --output text
13.EC2インスタンスへのCLIブラウザアクセス
curl ${CURL_TARGET_URL}
  • EC2インスタンスのコンテンツにアクセスし、ステータスコード200が返ってくることを確認します。
    • curlコマンドのオプションは以下の通りです。
      • -L(--location)ステータスコード3xxが返された場合に自動でリダイレクトする。
      • -l(--list-only):LISTコマンドの代わりにNLISTコマンドを使用する。
      • -s(--silent):プログレスメーターを非表示にする。
      • -S(--show-error)プログレスメーターのエラー情報を非表示にせず表示する。
      • -o(--output):ファイルに出力する。
      • -w:出力フォーマットを指定する。以下のコマンドではHTTPのステータスコードを出力する。
curl -LI -Ss -o /dev/null -w '%{http_code}\n' ${CURL_TARGET_URL}
14.EC2インスタンスの終了
aws ec2 terminate-instances \
  --instance-ids ${ARRAY_EC2_INSTANCE_IDS}
  • describe-instancesコマンドで、ステータスが"running"のEC2インスタンスが存在しないことを確認します。
aws ec2 describe-instances \
  --filters Name=tag-key,Values=Name \
            Name=tag-value,Values=${EC2_INSTANCE_TAG_NAME} \
            Name=instance-state-name,Values=running \
  --query Reservations[].Instances[].Tags[].Value \
  --output text
後始末

ハンズオン環境が不要になったら、ハンズオン手順の後始末1と2、Cloud9用ロールからのポリシーのデタッチを実施します。

  • セキュリティグループのIngressルール削除
  • セキュリティグループの削除
  • ルートテーブルの更新
  • サブネットの削除
  • ルートテーブルの削除
  • IGWのデタッチ
  • IGWの削除
  • VPCの破棄
  • ハンズオン用ディレクトリの削除
  • Cloud9用ロールからのポリシーのデタッチ

最後に

次回はEBS、その後はAMI、IAMに関するハンズオンが続きます。楽しみながらハンズオンと復習をしていこうと思います。

最後まで読んでいただきありがとうございました。