labunix's blog

labunixのラボUnix

awscliでAWSリージョンとAZの一覧を取得する

■awscliでAWSリージョンとAZの一覧を取得する。
 グローバルサービスはリージョンやアベイラビリティーゾーン(AZ)を意識する必要はあまり無い。
 また拡張していく分にはAWSのサービス制限を前提に設計していくので特に問題ない。

 AWSのサービス制限の例
  リージョンに固有の以下の変更が必要となる。
   Elastic IP アドレス (EIP) 
   EC2 キーペア
   セキュリティグループ

 AWS EC2インスタンスにElastic IP(固定グローバルIPアドレス)を割り当てる
 https://ac-5.net/aws/aws_elasticip_allocation

■最初に選んだリージョンによってオンデマンド料金の基準が決まる。
 選んだAZによってサブネット範囲と使えるIPアドレスが決まる。

 災害復旧を目的として、本番環境のミラーイメージを別のリージョンに作成したいとか、
 リージョン、インスタンスタイプ、OSで料金が決まるため、
 オンデマンド料金が変動するリスクを考えた場合、
 全体が配置されているAZ数が大から小に移行するには、AWSのサービス制限以外に
 AZの所属するサブネットを統合出来るかなど、
 インフラとなるOSやAPの移行要件も考慮する必要が出てくる。

■リージョン名の一覧

$ aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | sort
ap-northeast-1
ap-northeast-2
ap-south-1
ap-southeast-1
ap-southeast-2
ca-central-1
eu-central-1
eu-west-1
eu-west-2
eu-west-3
sa-east-1
us-east-1
us-east-2
us-west-1
us-west-2

■かなり不親切でちっともシンプルに思えないが、
 料金計算サイトのリージョン選択では、
 例えば「ap-northeast-3」ではなく「Asia Pasific (Osaka Local)」を選択する必要がある。
 また、このサイトではAZについて考慮することは出来ない。

 SIMPLE MONTHLY CALCULATOR
 https://calculator.s3.amazonaws.com/index.html

$ w3m -dump "https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-regions-availability-zones.html" | \
    awk '/[a-z]?-[a-z]*[1-9]/&&!/に|は|が|を|に|と/' | sort -k 1
ap-northeast-1 アジアパシフィック (東京)
ap-northeast-2 アジアパシフィック (ソウル)
ap-northeast-3 アジアパシフィック (大阪: ローカル)
ap-south-1     アジアパシフィック (ムンバイ)
ap-southeast-1 アジアパシフィック (シンガポール)
ap-southeast-2 アジアパシフィック (シドニー)
ca-central-1   カナダ (中部)
eu-central-1   欧州 (フランクフルト)
eu-west-1      欧州 (アイルランド)
eu-west-2      欧州 (ロンドン)
eu-west-3      EU (パリ)
sa-east-1      南米 (サンパウロ)
us-east-1      米国東部(バージニア北部)
us-east-2      米国東部 (オハイオ)
us-west-1      米国西部 (北カリフォルニア)
us-west-2      米国西部 (オレゴン)

■リージョンとアベイラビリティーゾーン(AZ)の組の一覧

$ aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | \
    awk '{print "aws ec2 describe-availability-zones --region "$1}' | \
    sh | jq -r '.AvailabilityZones[] | [ .RegionName , .ZoneName ] | @csv' | sort -t, -k 1,2
"ap-northeast-1","ap-northeast-1a"
"ap-northeast-1","ap-northeast-1c"
"ap-northeast-1","ap-northeast-1d"
"ap-northeast-2","ap-northeast-2a"
"ap-northeast-2","ap-northeast-2c"
"ap-south-1","ap-south-1a"
"ap-south-1","ap-south-1b"
"ap-southeast-1","ap-southeast-1a"
"ap-southeast-1","ap-southeast-1b"
"ap-southeast-1","ap-southeast-1c"
"ap-southeast-2","ap-southeast-2a"
"ap-southeast-2","ap-southeast-2b"
"ap-southeast-2","ap-southeast-2c"
"ca-central-1","ca-central-1a"
"ca-central-1","ca-central-1b"
"eu-central-1","eu-central-1a"
"eu-central-1","eu-central-1b"
"eu-central-1","eu-central-1c"
"eu-west-1","eu-west-1a"
"eu-west-1","eu-west-1b"
"eu-west-1","eu-west-1c"
"eu-west-2","eu-west-2a"
"eu-west-2","eu-west-2b"
"eu-west-2","eu-west-2c"
"eu-west-3","eu-west-3a"
"eu-west-3","eu-west-3b"
"eu-west-3","eu-west-3c"
"sa-east-1","sa-east-1a"
"sa-east-1","sa-east-1c"
"us-east-1","us-east-1a"
"us-east-1","us-east-1b"
"us-east-1","us-east-1c"
"us-east-1","us-east-1d"
"us-east-1","us-east-1e"
"us-east-1","us-east-1f"
"us-east-2","us-east-2a"
"us-east-2","us-east-2b"
"us-east-2","us-east-2c"
"us-west-1","us-west-1a"
"us-west-1","us-west-1b"
"us-west-2","us-west-2a"
"us-west-2","us-west-2b"
"us-west-2","us-west-2c"

■リージョン毎のAZ数を集計する。
 リージョンがすべてのオンデマンド料金を左右するので、
 リージョンの選択肢を減らさないように、
 AZは2以内になるように設計すると良さそう。

 Amazon EC2 料金表
 https://aws.amazon.com/jp/ec2/pricing/on-demand/

$ aws ec2 describe-regions | jq -r '.Regions[] | .RegionName' | \
    awk '{print "aws ec2 describe-availability-zones --region "$1}' | \
    sh | jq -r '.AvailabilityZones[] | [ .RegionName , .ZoneName ] | @csv' | \
    tr '"' ' ' | awk -F, '{a[$1]+=1}END{for(n in a){print n,a[n]}}' | sort -k 1
 ap-northeast-1  3
 ap-northeast-2  2
 ap-south-1  2
 ap-southeast-1  3
 ap-southeast-2  3
 ca-central-1  2
 eu-central-1  3
 eu-west-1  3
 eu-west-2  3
 eu-west-3  3
 sa-east-1  2
 us-east-1  6
 us-east-2  3
 us-west-1  2
 us-west-2  3

■リージョン -> AZ -> ec2でプライベートIPアドレス範囲が決まる。
 上記の情報からAZは「[リージョン名][a-z]」形式として考える。

■リージョンを「us-east-1」に指定すると6つのAZに分割されている。

$ aws ec2 describe-subnets --region us-east-1 | jq -r '.Subnets[] | [.SubnetId , .CidrBlock , .AvailabilityZone ] | @csv' | sort -t, -k 3 | \
   sed -e 's/[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]/xxxxxxxx/' \
       -e 's/[0-9]*\.[0-9]*\(\.[0-9]*\)\.0/X.X.\1.0/' \
       -e 's/[a-z][a-z]-[a-z]*-[0-9]/[region-name]/'
"subnet-xxxxxxxx","X.X..16.0/20","[region-name]a"
"subnet-xxxxxxxx","X.X..32.0/20","[region-name]b"
"subnet-xxxxxxxx","X.X..0.0/20","[region-name]c"
"subnet-xxxxxxxx","X.X..80.0/20","[region-name]d"
"subnet-xxxxxxxx","X.X..48.0/20","[region-name]e"
"subnet-xxxxxxxx","X.X..64.0/20","[region-name]f"

■リージョンを「us-west-1」に指定すると2つのAZに分割されている。
 デフォルト設定をそのまま使う前提で、例えばリージョンを跨いで移行することを考えてみる。
 「us-west-1」->「us-east-1」なら、AZはそれぞれ「a->c」、「b->a」に対応する。
 「us-east-1」->「us-west-1」だと「b,d,e,f」はサブネットを再設計する必要が出るかも知れない。

$ aws ec2 describe-subnets --region us-west-1 | jq -r '.Subnets[] | [.SubnetId , .CidrBlock , .AvailabilityZone ] | @csv' | sort -t, -k 3 | \
   sed -e 's/[a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9][a-f0-9]/xxxxxxxx/' \
       -e 's/[0-9]*\.[0-9]*\(\.[0-9]*\)\.0/X.X.\1.0/' \
       -e 's/[a-z][a-z]-[a-z]*-[0-9]/[region-name]/'
"subnet-xxxxxxxx","X.X..0.0/20","[region-name]a"
"subnet-xxxxxxxx","X.X..16.0/20","[region-name]b"

■サブネットは16から28まで指定出来る。
 ホスト数は一般に、サブネットIDと、サブネットブロードキャストアドレスで予約されている2つ分を減算する。
 ipcalcの実行結果の「Hosts/Net:」フィールドには上記が反映されている。

 更にAWSの予約として以下の3つ分を減算して設計する。

 VPCルータ(.1)
 DNSサービス(.2)
 将来の予約(.3)

$ seq 16 28 | awk '{print "ipcalc 172.16.0.0/"$1}' | sh | awk '/^Netmask|^Wildcard/'
Netmask:   255.255.0.0 = 16     11111111.11111111. 00000000.00000000
Wildcard:  0.0.255.255          00000000.00000000. 11111111.11111111
Netmask:   255.255.128.0 = 17   11111111.11111111.1 0000000.00000000
Wildcard:  0.0.127.255          00000000.00000000.0 1111111.11111111
Netmask:   255.255.192.0 = 18   11111111.11111111.11 000000.00000000
Wildcard:  0.0.63.255           00000000.00000000.00 111111.11111111
Netmask:   255.255.224.0 = 19   11111111.11111111.111 00000.00000000
Wildcard:  0.0.31.255           00000000.00000000.000 11111.11111111
Netmask:   255.255.240.0 = 20   11111111.11111111.1111 0000.00000000
Wildcard:  0.0.15.255           00000000.00000000.0000 1111.11111111
Netmask:   255.255.248.0 = 21   11111111.11111111.11111 000.00000000
Wildcard:  0.0.7.255            00000000.00000000.00000 111.11111111
Netmask:   255.255.252.0 = 22   11111111.11111111.111111 00.00000000
Wildcard:  0.0.3.255            00000000.00000000.000000 11.11111111
Netmask:   255.255.254.0 = 23   11111111.11111111.1111111 0.00000000
Wildcard:  0.0.1.255            00000000.00000000.0000000 1.11111111
Netmask:   255.255.255.0 = 24   11111111.11111111.11111111. 00000000
Wildcard:  0.0.0.255            00000000.00000000.00000000. 11111111
Netmask:   255.255.255.128 = 25 11111111.11111111.11111111.1 0000000
Wildcard:  0.0.0.127            00000000.00000000.00000000.0 1111111
Netmask:   255.255.255.192 = 26 11111111.11111111.11111111.11 000000
Wildcard:  0.0.0.63             00000000.00000000.00000000.00 111111
Netmask:   255.255.255.224 = 27 11111111.11111111.11111111.111 00000
Wildcard:  0.0.0.31             00000000.00000000.00000000.000 11111
Netmask:   255.255.255.240 = 28 11111111.11111111.11111111.1111 0000
Wildcard:  0.0.0.15             00000000.00000000.00000000.0000 1111

■EBS ボリュームの影響範囲はAZなので、
 現時刻の1日前を始点としたLinux/UNIXのスポット価格履歴から、
 それぞれのインスタントタイプ数を集計する。

$ aws ec2 describe-spot-price-history \
    --start-time $(date -d '1 days ago' -u '+%Y-%m-%dT%H:%M:%S.000Z') \
    --product-description "Linux/UNIX" | \
  jq -r '.SpotPriceHistory[] | [ .InstanceType , .ProductDescription , .AvailabilityZone , .SpotPrice ] | @csv' | \
  tr '"' ' ' | awk -F\, '!/large/{a[$1]+=1}END{for(n in a){print n,a[n]}}' | sort -k 1
 c1.medium  4
 m1.medium  4
 m1.small  4
 m3.medium  6
 t1.micro  4
 t2.medium  4
 t2.micro  4
 t2.small  6
 t3.medium  6
 t3.micro  4
 t3.nano  4
 t3.small  6

■スポット価格と比較出来るように価格の安い順に一覧する。
 上記に加え、条件として「us-west-1a」を追加した例

$ aws ec2 describe-spot-price-history \
    --availability-zone us-west-1a \
    --start-time $(date -d '1 days ago' -u '+%Y-%m-%dT%H:%M:%S.000Z') \
    --product-description "Linux/UNIX" \
    --instance-types t3.small t3.micro t3.nano | \
  jq -r '.SpotPriceHistory[] | [ .InstanceType , .ProductDescription , .AvailabilityZone , .SpotPrice ] | @csv' | sort -t, -k 4
"t3.nano","Linux/UNIX","us-west-1a","0.001900"
"t3.nano","Linux/UNIX","us-west-1a","0.001900"
"t3.micro","Linux/UNIX","us-west-1a","0.003700"
"t3.micro","Linux/UNIX","us-west-1a","0.003700"
"t3.small","Linux/UNIX","us-west-1a","0.007500"
"t3.small","Linux/UNIX","us-west-1a","0.007500"
"t3.small","Linux/UNIX","us-west-1a","0.007500"

■nanoを1とすると、microは約2倍、smallは約4倍。

$ echo "19 37 75" | awk '{print "1",$2/$1,$3/$1}'
1 1.94737 3.94737

■デフォルトで用意されている構成をカスタマイズすると
 おおよその料金計算まで出来る。

 リージョンの選択は地図もリージョン名も地域名も日本語で分かりやすい。
 インスタンスタイプの選択は少し分かりにくい。
 OSはLinuxを選択。

 cloudcraft
 https://cloudcraft.co/signup