less is more

心のフルスタックエンジニア👨‍💻バイブスでコードを書いています🤘

Amazon Linuxの最新のAMI IDを正しく取得する

言わずと知れたAWS製のLinuxマシンイメージですが、
結構頻繁にアップデートされるので、最新のIDを追う必要があります。

f:id:bluepixel:20200513202721p:plain

特にIaCが当たり前のいまでは、CloudFormationでもTerraformでもAMI IDをあらかじめ変数化しておくことが多いと思いますが、ついついコードの使い回しで新しいプロジェクトに最新ではないAMIを埋め込みがちです。

AMI IDの調べ方は3つあります。

マネジメントコンソールからウィザードで起動する

IaCでない場合はこれが楽です。

f:id:bluepixel:20200513203911p:plain

ただし、クイックスタートに出てこないタイプのAMIを使いたい場合はサイドバーから詳細な検索をする必要があります。あまりここの使い勝手はよくないです。

f:id:bluepixel:20200513203932p:plain

クイックスタートの一番上に出てくるのは、Amazon Linuxv2で、アーキテクチャx86_64、ルートデバイスタイプがebsgp2(汎用SSD)で、ミニマルではない通常のイメージです。

EC2 APIによる検索

docs.aws.amazon.com

EC2のAPIdescribe-imageというものがあり、これで検索することができます。

aws ec2 describe-images

AWS所有のパブリックイメージに絞るオプションとかつけられます。

aws ec2 describe-images --owners self amazon

前述のタイプのAMIの最新のイメージを調べるには以下のような複雑なクエリを投げる必要があります。AMIの名前を正規表現でマッチさせて、作成日時の降順でソートして最初のもの、という感じです。

aws ec2 describe-images \
    --owners amazon \
    --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????.?-x86_64-gp2' 'Name=state,Values=available' \
    --query 'reverse(sort_by(Images, &CreationDate))[:1].ImageId' \
    --output text

ぶっちゃけめちゃめちゃ使いづらくないですか?
名前の部分arm64だとどうなるんだっけーとか結局調べないといけないし 。

ドキュメント用意されてる割にはあまり良いプラクティスではない感じがします。

パラメータストアから取得

docs.aws.amazon.com

AMIはパブリックパラメータとして定義されているので、Systems ManagerのAPI経由で参照することができます。

パラメータストアでは、パラメータをパスとして扱い、階層構造を作れるようになっているので検索はこちらの方が捗ります。

最新のAmazon Linux AMIは/aws/service/ami-amazon-linux-latest/を親として、以下のパラメータが定義されています。

  • amzn-ami-hvm-x86_64-ebs
  • amzn-ami-hvm-x86_64-gp2
  • amzn-ami-hvm-x86_64-s3
  • amzn-ami-minimal-hvm-x86_64-s3
  • amzn-ami-minimal-pv-x86_64-s3
  • amzn-ami-pv-x86_64-s3
  • amzn2-ami-hvm-arm64-gp2
  • amzn2-ami-hvm-x86_64-ebs
  • amzn2-ami-hvm-x86_64-gp2
  • amzn2-ami-minimal-hvm-arm64-ebs
  • amzn-ami-minimal-hvm-x86_64-ebs
  • amzn-ami-minimal-pv-x86_64-ebs
  • amzn-ami-pv-x86_64-ebs
  • amzn2-ami-minimal-hvm-x86_64-ebs

親を指定すると再帰的に検索されるので、全ての結果が含まれてきます。 EC2 APIを用いるよりもだいぶ使い勝手が良くなりました。

$aws ssm get-parameters-by-path --path /aws/service/ami-amazon-linux-latest | jq '.Parameters[] | {Name,Value}'
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-ebs",
  "Value": "ami-0923830d7114f09d2"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-gp2",
  "Value": "ami-0318ecd6d05daa212"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-s3",
  "Value": "ami-089402c666ec00be9"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-hvm-x86_64-s3",
  "Value": "ami-0ceddc27dc1f7852f"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-pv-x86_64-s3",
  "Value": "ami-0a14693c2d4a85d4d"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-pv-x86_64-s3",
  "Value": "ami-0691fa0c29ff644ef"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2",
  "Value": "ami-08360a37d07f61f88"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-ebs",
  "Value": "ami-06aa6ba9dc39dc071"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2",
  "Value": "ami-0f310fced6141e627"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-arm64-ebs",
  "Value": "ami-07fe0b0aed2e82d18"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-hvm-x86_64-ebs",
  "Value": "ami-06a0756c2d7ea1c30"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-minimal-pv-x86_64-ebs",
  "Value": "ami-00699c69c98dcddd0"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn-ami-pv-x86_64-ebs",
  "Value": "ami-0ca3d0d6f5f1459e8"
}
{
  "Name": "/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-x86_64-ebs",
  "Value": "ami-03494c35f936e7fd7"
}

ただ、まだ特定のAMIをクエリするにはパスを覚えておく必要があります。

/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-x86_64-ebs

amzn2-ami-minimal-hvm-x86_64-ebsの部分です。

ここは規則的で、{os}{バージョン}-ami-{ミニマルかどうか}-{仮想化タイプ}-{アーキテクチャ}-{ボリューム}-{ルートデバイス}みたいになっているのでハックできそうです。

コマンドを自作する

Goで軽く実装してみました。
cobraを使ってコマンドとして利用できるようにしました。

github.com

abc ami でパスを指定しない全てのAMIを表示します。

$ abc ami | jq '.'
[
  {
    "os": "amzn",
    "version": "1",
    "virtualization_type": "hvm",
    "arch": "x86_64",
    "storage": "ebs",
    "minimal": false,
    "id": "ami-0923830d7114f09d2",
    "arn": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-amazon-linux-latest/amzn-ami-hvm-x86_64-ebs"
  },
...

要はさっきの名前の部分を正規表現で分解して構造体に変換しています。
こうすることによって、「arm64を使いたい」という場合は archでクエリできるようになります。

$ abc ami -a arm64 | jq '.'
[
  {
    "os": "amzn",
    "version": "2",
    "virtualization_type": "hvm",
    "arch": "arm64",
    "storage": "gp2",
    "minimal": false,
    "id": "ami-08360a37d07f61f88",
    "arn": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2"
  },
  {
    "os": "amzn",
    "version": "2",
    "virtualization_type": "hvm",
    "arch": "arm64",
    "storage": "ebs",
    "minimal": true,
    "id": "ami-07fe0b0aed2e82d18",
    "arn": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-amazon-linux-latest/amzn2-ami-minimal-hvm-arm64-ebs"
  }
]

こんな感じで細かく特定することが可能です。

$ abc ami -v 2 -V hvm -a arm64 -s gp2 -m false | jq '.'
[
  {
    "os": "amzn",
    "version": "2",
    "virtualization_type": "hvm",
    "arch": "arm64",
    "storage": "gp2",
    "minimal": false,
    "id": "ami-08360a37d07f61f88",
    "arn": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2"
  }
]

(おまけ)そもそもAmazon Linuxってそんなに種類あるんだっけ...?

現在でも14のAMIが利用できます。

バージョン

2017年にAmazon Linux 2がリリースされ、バージョン番号のない初代Amazon Linuxはサポートが終了することになりました。
当初は2020年6月30日の予定でしたが、12月31日まで延長されたようです。
また、サポート終了後もメンテナンスサポート期間として2023年6月30日までは重大なセキュリティアップデートは行ってくれるようです。

Amazon Linux AMI のサポート期間終了に関する更新情報 | Amazon Web Services ブログ

ということで基本はAmazon Linux 2 を利用します。

仮想化タイプ

専門的な話でよくはわからないのですが、準仮想化 (PV)ハードウェア仮想マシン (HVM)という2つの種類が存在します。
(PV on HVM というものもありますが割愛します。)

ただこれも明確で、HVMを使ってください。 PVは使用できないインスタンスタイプがあり、PVタイプが使用されているのは旧世代のAMIなのでバージョン2ではHVMが基本になります。

アーキテクチャ

x86_64arm64 です。

ルートデバイスボリューム

EBSに置くEBS-backedとS3に置くinstance store-backedがあります。
instance store-backedAmazon Linux 2にないようですが使えなくなったんでしたっけ...?まあ昔からあるのはこっちなのでサポートしなくなったのかな。

Amazon EBS-Backed Linux AMI の作成 - Amazon Elastic Compute Cloud

あとEBS-backedの中でも旧世代のEBSボリュームタイプではなく汎用SSD(gp2)を用いるのが一般的です。

ミニマル

軽量なのがほしい時はコミュニティAMIでminimalというものが提供されています。
詳しくは以下の記事で。

dev.classmethod.jp

結局

2で、HVMで、gp2のやつ。
クイックスタートの一番上に出てくるやつを使っておけば間違いない。

$ abc ami -v 2 -V hvm -a x86_64 -s gp2 -m false | jq '.'
[
  {
    "os": "amzn",
    "version": "2",
    "virtualization_type": "hvm",
    "arch": "x86_64",
    "storage": "gp2",
    "minimal": false,
    "id": "ami-0f310fced6141e627",
    "arn": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
  }
]