TerraformでEC2インスタンスを作成しようとしたときに、AMI IDが必要となる。EC2コンソールから確認する方法はタイプミスも起こりうるし手間なので、AWS CLIを使って最新かつ無料利用対象のAMIを取得してみる。
はじめに結論
入力
aws ec2 describe-images --owners amazon --filters 'Name=name,Values=al2023-ami-2*' --query 'sort_by(Images,&CreationDate)[-1].[ImageId]' --output text
出力
ami-034c9ca2bdde7b472
やってみた
準備運動
AWS CLIのリファレンスを参考にいろいろ試してみる。
まずは、オプションなしで実行してみる。
aws ec2 describe-images
json形式で情報が出力された。なお、ページネーションされており、出力された情報はここに転記した限りのものではない。なお、全件取得しているから、出力されるまでにちょい時間もかかった。
{ "Images": [ { "Architecture": "arm64", "CreationDate": "2022-10-26T08:50:11.000Z", "ImageId": "ami-0783825db772157e8", "ImageLocation": "aws-marketplace/ARM_Docs_Enterprise_Edition_100-322bee60-8ff7-4367-bce6-0c3d414e7c2f", "ImageType": "machine", "Public": true, "OwnerId": "679593333241", "PlatformDetails": "Linux/UNIX", "UsageOperation": "RunInstances", "ProductCodes": [ { "ProductCodeId": "2yxhenxqx8xwfnu96mclbi2i7", "ProductCodeType": "marketplace" } ], "State": "available", "BlockDeviceMappings": [ { "DeviceName": "/dev/sda1", "Ebs": { "DeleteOnTermination": true, "SnapshotId": "snap-022658c8e17e00925", "VolumeSize": 50, "VolumeType": "gp2", "Encrypted": false } }, :
次は、AWS公式ドキュメントにあるサンプル通りに実行してみる。
aws ec2 describe-images --owners self amazon
--owners self amazon
を追加したため、自身およびAWSが所有するAMIの情報が出力された。
{ "Images": [ { "Architecture": "arm64", "CreationDate": "2022-09-11T18:43:34.000Z", "ImageId": "ami-072fd2ac175987855", "ImageLocation": "amazon/debian-11-arm64-20220911-1135", "ImageType": "machine", "Public": true, "OwnerId": "136693071363", "PlatformDetails": "Linux/UNIX", "UsageOperation": "RunInstances", "State": "available", "BlockDeviceMappings": [ { "DeviceName": "/dev/xvda", "Ebs": { "DeleteOnTermination": true, "SnapshotId": "snap-049f8f94068975a38", "VolumeSize": 8, "VolumeType": "gp2", "Encrypted": false } } ], "Description": "Debian 11 (20220911-1135)", "EnaSupport": true, "Hypervisor": "xen", "ImageOwnerAlias": "amazon", "Name": "debian-11-arm64-20220911-1135", "RootDeviceName": "/dev/xvda", :
ようやく本題
--query
JSON形式でずらっと表示する必要はなく、AMI IDだけがわかればよいため、--query
オプションを使って出力結果を絞る。直前の出力結果から、Images配下のImageIdにAMI IDが格納されていることがわかったため、以下のようなコマンドを発行する。
aws ec2 describe-images --owners amazon --query 'Images[].[ImageId]'
AMI IDだけが出力されるようになった。
[ [ "ami-07f84aef74d43e3f6" ], [ "ami-077b3ac4f90ca037d" ], [ "ami-0c3be11bbde86acc9" ], [ "ami-0536b4ea4c52f3de7" ], [ "ami-00f135819964ee6d4" :
JSON形式だと見づらいため、--output
オプションを用いてtext形式で出力されるようにする。
aws ec2 describe-images --owners amazon --query 'Images[].[ImageId]' --output text
text形式になり、みやすくなった。
ami-096260c2e6846d8cc ami-03d1ed1b9fd997201 ami-0abede41b16d742a4 ami-0eb19f14e6cd47620 ami-06e2e2f7191df1cff ami-0e0b03b0858b9c598 ami-07259a121c2c3b64e ami-0deb2dde49a4fbfc5 ami-01f8e82710fa38050 ami-089caded1bdbfbe5c ami-066623c10b1002216 ami-0b2a4d3ca2a8dee16 ami-0d49ed3d0db984485 ami-0725760eac0602582 ami-019501f824222b0ce :
最新のAMI IDのみ出力すればよいため、--query
オプションをさらに修正する。
クエリではJMESPathなる、JSONのクエリ言語を扱える。
クエリでは、JMESPath 構文を使用して、出力をフィルタリングするための式を作成します
引用:AWS CLI の出力をフィルタリングする https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-usage-filter.html#cli-usage-filter-client-side
まずは、JMESPathの組み込み関数であるsort_byを利用して、出力結果をソートする。ソートキーには、CreationDateを使うこととする。なお、sort_byは昇順ソートのため、末尾のAMI IDを取得する。
aws ec2 describe-images --owners amazon --query 'sort_by(Images,&CreationDate)[-1].[ImageId]' --output text
あるいはJMESPathの組み込み関数であるreverseを組み合わせて、降順にソートしたうえで、先頭のデータを取得する。
aws ec2 describe-images --owners amazon --query 'reverse(sort_by(Images,&CreationDate))[0].[ImageId]' --output text
すると、最新の1件のAMI IDが取得できた。
ami-08667f7205cd9a3f0
--filters
次に、--filters
オプションで、AmazonLinux2023が出力されるようにフィルタリングする。なお、AmazonLinux2023のAMI IDは、al2023-ami-で始まることをEC2コンソールから確認した。
なお、--filters
は、Name=hoge,Values=fuga
を指定する。Nameの値はAWS CLI Command Referenceを参照。また、Valuesの値には*や?といったワイルドカードが使える。
aws ec2 describe-images --owners amazon --filters 'Name=name,Values=al2023-ami-*' --query 'sort_by(Images,&CreationDate)[-1].[ImageId]' --output text
お目当てのAMI IDを取得できたと思ったが、よくみるとEC2コンソールで確認したAMI IDと違った。
ami-092ee79bf91da299e
そこで、それぞれのAMIの情報を比較してみた。
aws ec2 describe-images --owners amazon --filters 'Name=image-id,Values=ami-092ee79bf91da299e' > ami-092ee79bf91da299e.txt aws ec2 describe-images --owners amazon --filters 'Name=image-id,Values=ami-034c9ca2bdde7b472' > ami-034c9ca2bdde7b472.txt diff ami-092ee79bf91da299e.txt ami-034c9ca2bdde7b472.txt
すると、Nameに有意な差がみられた。EC2コンソールで確認した無料利用対象のNameには、minimalという文字列が含まれていなかった。
5,7c5,7 < "CreationDate": "2024-03-13T02:25:01.000Z", < "ImageId": "ami-092ee79bf91da299e", < "ImageLocation": "amazon/al2023-ami-minimal-2023.3.20240312.0-kernel-6.1-x86_64", --- > "CreationDate": "2024-03-13T02:16:23.000Z", > "ImageId": "ami-034c9ca2bdde7b472", > "ImageLocation": "amazon/al2023-ami-2023.3.20240312.0-kernel-6.1-x86_64", 20c20 < "SnapshotId": "snap-0b64bb669a51ba903", --- > "SnapshotId": "snap-0a53ae1296688c3dc", 28c28 < "Description": "Amazon Linux 2023 AMI 2023.3.20240312.0 x86_64 Minimal HVM kernel-6.1", --- > "Description": "Amazon Linux 2023 AMI 2023.3.20240312.0 x86_64 HVM kernel-6.1", 32c32 < "Name": "al2023-ami-minimal-2023.3.20240312.0-kernel-6.1-x86_64", --- > "Name": "al2023-ami-2023.3.20240312.0-kernel-6.1-x86_64", 38c38 < "DeprecationTime": "2024-06-11T02:25:00.000Z", --- > "DeprecationTime": "2024-06-11T02:16:00.000Z",
ので、--filters
の引数を修正した。
aws ec2 describe-images --owners amazon --filters 'Name=name,Values=al2023-ami-2*' --query 'sort_by(Images,&CreationDate)[-1].[ImageId]' --output text
無事、無料利用対象の最新AMI IDを取得できた。
ami-034c9ca2bdde7b472
残課題
今回のように近しい命名規則のAMIが追加された場合や、AWS側でNameの命名規則を変えた場合に、期待通りの出力結果が得られなくなる可能性がある。無料利用対象という条件で絞り込むような、スマートな方法があるのかもしれない。