JAWS-UG CLI専門支部 #155R EC2入門に参加してみて
155回目のハンズオン!もうすぐ6年!
オンラインハンズオンは4/27からスタートして1ヵ月が経ちました。
CLI覚えて転職したメンバーが多いのが支部の特徴!
CLIなれるとマネコン操作がめんどくさくなるらしい→そう言えるようになりたい!
オンラインになって今のところ毎回参加できているので、オンラインっていいなーとしみじみおもう。
シェルは冪等性を担保し易い。マイクロサービスとシェルは考え方が近い。
※冪等性とは何回やっても同じ結果が得られること。
EC2は現在402コマンドあるとのこと!
マネジメントコンソールだと
VPCメニュー、EC2メニュー(AutoScaling、ELBが含まれている)、、
APIだとそれぞれわかれている。
EC2、AutoScaling、ELB(CLB)、ELBv2(ALB)、ebs、ec2-instance-connect
生い立ちが違うのかなぁ
できるようになったこと
1.デフォルトVPCの作成(すでにあった)
2.キーペアの作成
3.ユーザデータの設定
4.セキュリティグループの設定(インバウンドルール追加)
5.インスタンス作成
6.インスタンスメタデータの取得
7.インスタンスの破棄
8.セキュリティグループの設定(インバウンドルール削除)
9.キーペアの削除
10.デフォルトVPCの削除
1.デフォルトVPCの作成
作るときは1コマンドで済むが削除するときは1個1個削除する必要がある。
デフォルトVPCは決めることが少ないので検証環境を作る場合に最適。
本番環境には適さない。
VPCは1アカウント5個の上限がある。上限緩和はできる。
デフォルトVPCだと--group-nameが使える。カスタムVPCは--group-idが必要。
aws ec2 create-default-vpc
aws ec2 describe-vpcs \
--filters "Name=isDefault,Values=true" \
--query "Vpcs[].CidrBlock" \
--output text
2.キーペアの作成
OSにログオンするときのsshキー。
事前にキーファイルを置くディレクトリを作成して権限修正。
mkdir -p ${HOME}/.ssh && chmod 700 ${HOME}/.ssh
aws ec2 create-key-pair \
--key-name ${EC2_KEY_PAIR_NAME} \
--query 'KeyMaterial' --output text \
> ${FILE_SSH_KEY_SECRET} \
&& cat ${FILE_SSH_KEY_SECRET} \
&& chmod 400 ${FILE_SSH_KEY_SECRET}
--key-name \${EC2_KEY_PAIR_NAME} → キーの名前を指定(任意)。
--query 'Key Material' --output text → queryとoutputを併用することで秘密鍵を出力。
> ${FILE_SSH_KEY_SECRET} → リダイレクトで秘密鍵をファイルに出力。
aws ec2 describe-key-pairs \
--query "KeyPairs[?KeyName == \`${EC2_KEY_PAIR_NAME}\`].KeyName" \
--output text
3.ユーザデータの作成
ユーザデータとはインスタンス作成時に変更内容をスクリプトで記述しておくと、OS内部の設定を変更してくれる。
たとえばホスト名やyumアップデートなど。
インスタンス作成時に毎回実施する操作はユーザデータに残しておくとよい。
ヒアドキュメントの中にさらにヒアドキュメントで書くというテクニック!(知らなかった)
FILE_USER_DATA="${DIR_USER_DATA}/${USER_DATA_NAME}.bash" \
&& echo ${FILE_USER_DATA}
cat << EOF1 > ${FILE_USER_DATA}
#!/bin/bash
# configure sshd
cat << EOF >> /etc/ssh/sshd_config
Port ${PORT_SSHD}
EOF
systemctl restart sshd.service
# yum
yum update -y
EOF1
cat ${FILE_USER_DATA}
※SSHが使用するポートを変更して、yumアップデートをかける。
4.セキュリティグループの設定
セキュリティグループはAWS版ファイアウォール。通信のインバウンド、アウトバンドはだいたいここで制御。
サブネット単位での通信制限はNetworkACL(NACL)。
セキュリティグループはステートフルなので、インバウンドを許可するとアウトバンドも許可される。
NACLはステートレス。インバウンド、アウトバンドそれぞれ設定が必要。
aws ec2 authorize-security-group-ingress \
--group-name ${EC2_SECURITY_GROUP_NAME} \
--protocol ${EC2_SECURITY_GROUP_PROTOCOL} \
--port ${EC2_SECURITY_GROUP_PORT} \
--cidr ${EC2_SECURITY_GROUP_CIDR}
authorize-security-group-ingress → 指定したプロトコル、ポート、通信元からのインバウンドルールを許可。
--group-name \${EC2_SECURITY_GROUP_NAME} → セキュリグループ名。
--protocol \${EC2_SECURITY_GROUP_PROTOCOL} → セキュリグループのプロトコル(tcp | udp | ICMP)を指定。
--port \${EC2_SECURITY_GROUP_PORT} → 許可するポート番号を指定。
--cidr \${EC2_SECURITY_GROUP_CIDR} → 許可するIPを指定。
EC2_VPC_ID=$( \
aws ec2 describe-vpcs \
--filters Name=isDefault,Values=true \
--query 'Vpcs[].VpcId' \
--output text \
) \
&& echo ${EC2_VPC_ID}
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
--filterの内容
デフォルトVPC、指定したセキュリティグループ名、指定したプロトコル、指定したポート、指定したソース元IPに合致するセキュリティグループを検索
--queryの内容
指定したポートと指定したソース元IPに合致するIPを抽出
5.インスタンス作成
aws ec2 run-instances \
--image-id ${EC2_IMAGE_ID} \
--instance-type ${EC2_INSTANCE_TYPE} \
--tag-specifications ${STRING_TAG_CONF} \
--user-data file://${FILE_USER_DATA} \
--key-name ${EC2_KEY_PAIR_NAME} \
--associate-public-ip-address
--image-id \${EC2_IMAGE_ID} = AMIのIDを指定する。GUIから使いたいAMIのIDを取得しておく。
※AmazonLinux2無料利用枠の対象AMIはami-0a1c2ec61571737d
--instance-type \${EC2_INSTANCE_TYPE} = インスタンスタイプを指定する。無料利用枠だとt2.micro。
--tag-specifications \${STRING_TAG_CONF} = タグを指定。複数指定する場合は、カンマでつなげる。
※"ResourceType=instance,Tags=[{Key=Name,Value=handson-cli-ec2-getting_started-instance},{Key=instancetype,Value=t2.micro}]"
--user-data file://\${FILE_USER_DATA} = 作成したUserdataのファイルを指定する。
--key-name ${EC2_KEY_PAIR_NAME} = 作成したキーペア名を指定する。
--associate-public-ip-address = パブリックIPのアサイン。
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
ssh ${EC2_PUBLIC_IP} \
-i ${FILE_SSH_KEY_SECRET} \
-l ec2-user \
-p ${PORT_SSHD}
-i \${FILE_SSH_KEY_SECRET} = 作成した鍵ファイルを指定。
-l ec2-user = ログインするユーザ名を指定。
-p \${PORT_SSHD} = 使用するポートを指定する。変更している場合に使用。
6.インスタンスメタデータの取得
インスタンスメタデータとはインスタンスがもつ情報を検索するための情報。
インスタンスを作成したときのAMIIDや持っているインスタンスタイプの情報を知りたいといったとき、
メタデータにアクセスするとメタデータをキーに実体となる情報(AMIIDやインスタンスタイプ)が得られる。
インスタンスメタデータにはv1とv2がある。
v2はv1に比べてセキュア。セッショントークン、PUTリクエストを利用してメタデータにアクセスすることで
v1よりもセキュアになっている。
サーバーワークスさんの書いたブログがわかりやすかった。
★InstanceMetaDataV2を分かりやすく解説してみる~Serverworks
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}" \
) \
&& echo ${EC2_METADATA_TOKEN}
${EC2_METADATA_SECOND} = セッショントークンの有効期限。秒指定。
EC2_METADATA_HEADER="X-aws-ec2-metadata-token: ${EC2_METADATA_TOKEN}" \
&& echo ${EC2_METADATA_HEADER}
curl -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/
EC2_INSTANCE_TYPE=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/instance-type \
) \
&& echo ${EC2_INSTANCE_TYPE}
EC2_INSTANCE_ID=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/instance-id \
) \
&& echo ${EC2_INSTANCE_ID}
EC2_IMAGE_ID=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/ami-id \
) \
&& echo ${EC2_IMAGE_ID}
EC2_PUBLIC_IP=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/public-ipv4 \
) \
&& echo ${EC2_PUBLIC_IP}
EC2_AZ_NAME=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/placement/availability-zone \
) \
&& echo ${EC2_AZ_NAME}
EC2_REGION_NAME=$( \
curl -s -H "${EC2_METADATA_HEADER}" \
http://169.254.169.254/latest/meta-data/placement/availability-zone \
| sed -e 's/[a-z]*$//' \
) \
&& echo ${EC2_REGION_NAME}
※リージョンのメタデータはないのでAZのメタデータを取得したあとにAZを示すアルファベットをカットする。
7.インスタンスの破棄
ARRAY_EC2_INSTANCE_IDS=$( \
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[].InstanceId \
--output text \
) \
&& echo ${ARRAY_EC2_INSTANCE_IDS}
${EC2_INSTANCE_TAG_NAME} = インスタンス名
aws ec2 terminate-instances \
--instance-ids ${ARRAY_EC2_INSTANCE_IDS}
実行するとステータスが"shutting-down"に変わる。
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
8.セキュリティグループの設定(インバウンドルール削除)
aws ec2 revoke-security-group-ingress \
--group-name ${EC2_SECURITY_GROUP_NAME} \
--protocol ${EC2_SECURITY_GROUP_PROTOCOL} \
--port ${EC2_SECURITY_GROUP_PORT} \
--cidr ${EC2_SECURITY_GROUP_CIDR}
与える引数はauthorize-security-group-ingressを実行したときと同じ。
--group-name \${EC2_SECURITY_GROUP_NAME} → セキュリグループ名。
--protocol \${EC2_SECURITY_GROUP_PROTOCOL} → セキュリグループのプロトコル(tcp | udp | ICMP)を指定。
--port \${EC2_SECURITY_GROUP_PORT} → 許可するポート番号を指定。
--cidr \${EC2_SECURITY_GROUP_CIDR} → 許可するIPを指定。
9.キーペアの削除
aws ec2 delete-key-pair \
--key-name ${EC2_KEY_PAIR_NAME}
※OS内からも秘密鍵のファイルを削除することを忘れないように。
10.デフォルトVPCの削除
作成は1コマンドだが、依存関係があるため削除はそれぞれ消していく必要がある。
ちなみにコンソールから消すときとAWS CLIから消す場合とでは挙動が異なる。
コンソールからだとインスタンス、VPCピアリング、NATゲートウェイ、インタフェースエンドポイントがない状態であればサブネット、セキュリティグループ、NACL、ルートテーブル、ゲートウェイエンドポイント、IGW、DHCPオプションはAWS側で削除してくれる。
コマンドだと事前に手動で消しておく必要がある。
EC2_VPC_ID=$( \
aws ec2 describe-vpcs \
--filters Name=isDefault,Values=true \
--query 'Vpcs[].VpcId' \
--output text \
) \
&& echo ${EC2_VPC_ID}
EC2_IGW_ID=$( \
aws ec2 describe-internet-gateways \
--filters Name=attachment.vpc-id,Values=${EC2_VPC_ID} \
--query "InternetGateways[].InternetGatewayId" \
--output text \
) \
&& echo ${EC2_IGW_ID}
aws ec2 detach-internet-gateway \
--internet-gateway-id ${EC2_IGW_ID} \
--vpc-id ${EC2_VPC_ID}
aws ec2 delete-internet-gateway \
--internet-gateway-id ${EC2_IGW_ID}
ARRAY_EC2_SUBNET_IDS=$( \
aws ec2 describe-subnets \
--filters Name=vpcId,Values=${EC2_VPC_ID} \
--query 'Subnets[].SubnetId' \
--output text \
) \
&& echo ${ARRAY_EC2_SUBNET_IDS}
for i in ${ARRAY_EC2_SUBNET_IDS}; do
aws ec2 delete-subnet \
--subnet-id ${i}
done
サブネットの数分ループで回して削除する
aws ec2 delete-vpc \
--vpc-id ${EC2_VPC_ID}