こんにちは!クラウドインテグレーション部技術1課のイーゴリです。
CloudFormationやTerraformなどのIaC(Infrastructure as Code)でどんなに完璧なEC2のテンプレートを作成しても、一つの設定値だけ毎回必ず変更しないといけません。その一つの設定値がAMI IDでございます!最新版AMIを取得したい時に毎回構築する前に新規のAMI IDを検索しないといけないので、私はいつも下記のように思います。
- 手間がかかる
- 不便(作業の直前にAWSコンソールかCLI上でAMI IDを要確認)
- 怖い!→構築の数日前にちゃんと作成したCloudFormationのテンプレートに、作業の直前にAMI IDを変更しないといけない→ヒューマンエラーが起きやすい
- 毎回AMI IDを調べるのはめんどくさーーーい
上記の問題点があるので、構築前にテンプレートを触らないようなEC2の最新版のAMIイメージを自動的に取得する方法があるので、ご紹介したいと思います。
なお、おまけに同じようなことをTerraformでもお見せしたいと思いますので、是非最後まで読んでください。
問題点
最新版のAMIが定期的に変わりますので、IaC(CloudFormation / Terraformなど)を使いたい場合、最新版のAMI IDを調べないといけません。
例えば、CloudFormation / Terraformのテンプレートを1ヶ月前に作った場合、1ヶ月前に調べたAMI IDを入力しましたが、下記の画像のようにWindows Server 2022の場合、2022.01.12付のAMIの次に2022.01.19付のAMIが存在しています(下記画像の(1))。
簡単に説明しますと、AWS側で何かしらのOS上のサービスパックの適用などの作業が発生する場合、新規のAMIが発行されますので、IDも変わります。(下記画像の(2))。
それぞれのAMI IDが異なりますので、EC2テンプレートを作成した日から数日立った場合、すでに最新のAMI IDに変わっています。
また、リージョンが異なれば、AMI IDも異なります。
例えば、東京リージョンにあるWindows Server 2022の最新のAMI IDは、他のリージョンにあるWindows Server 2022の最新のAMI IDと全く違います!
解決方法
テンプレートに毎回最新版のAMI IDの絶対値を入れるのではなく、EC2 Systems ManagerのParameter Storeを使いましょう!
AWSの参考記事: aws.amazon.com
上記の方法はCLIでも確認できますし、CloudFormation / Terraformでも使用できます。
CLIコマンド:
aws ssm get-parameters --names /aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base
出力結果:
{ "Parameters": [ { "Name": "/aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base", "Type": "String", "Value": "ami-02a98226de0ad0acf", "Version": 8, "LastModifiedDate": "2022-01-22T07:27:30.136000+09:00", "ARN": "arn:aws:ssm:ap-northeast-1::parameter/aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base", "DataType": "text" } ], "InvalidParameters": [] }
"Value"に記載してあるAMI ID(ami-02a98226de0ad0acf)が最新であることを下記の画像でも確認できます。

さて、理論情報からCloud Formationテンプレートの作成に行きましょう!
CloudFormationの方法
CloudFormationの基本
CloudFormationについてまったくご存知ではない方の場合、下記の記事を読めばCloudFormationの基本が分かると思いますので、ご参考ください。
EC2の構築
最低限でもCloudFormationのテンプレートを実施できるEC2のテンプレートは下記です。
テンプレート①(AMI IDの入力あり)
AWSTemplateFormatVersion: "2010-09-09" Description: Create EC2 Instance Resources: CreateEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: ami-XXXX InstanceType: t3.medium
※今回の例のために、t3.mediumのインスタンスタイプを選びました。
普通は、ImageIdの「ami-XXXX」の箇所で下記の画像にある固定のAMI IDを入力します。
もちろんAWSコンソール/CLIでできることはCloudFormationでも実現可能なので、EC2をカスタマイズしたい場合、下記のドキュメントをご参考ください。
では、本題へ移りましょう!
上記のCloudFormationテンプレートを下記のように変更しますと、AMI IDを毎回調べなくても良くなります!
テンプレート②(AMI IDの入力なし)
Windows Serverの場合
AWSTemplateFormatVersion: "2010-09-09" Description: Create EC2 Instance Parameters: OS: Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: "/aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base" Resources: CreateEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !Ref OS InstanceType: t3.medium
※例としてWindows Server 2022(日本語版)で設定しましたが、「2022」の代わりに適切なWindows Serverバージョンを入力すればよいです。なお、英語版が必要な場合、
「Japanese-Full-Base-*」
の代わりに、
「English-Full-Base-*」
を入力して頂く必要があります。
Amazon Linux 2の場合
AWSTemplateFormatVersion: "2010-09-09" Description: Create EC2 Instance Parameters: OS: Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2" Resources: CreateEC2Instance: Type: AWS::EC2::Instance Properties: ImageId: !Ref OS InstanceType: t3.medium
テンプレート②にParametersを追記し、「OS」のところを記載しました。CLIコマンドのようにEC2 Systems ManagerのParameter Storeから最新版の(/ami-windows-latest/)対象OS(/Windows_Server-2022-Japanese-Full-Base)バージョンのAMI IDを取得し、テンプレート①にある「ImageId」の箇所に絶対値ではなく、「OS」に記載のパラメーターを参照させるようにしました(ImageId: !Ref OS)。
ちなみに、「Parameters」を記載したため、CloudFormationを実行する時に「スタックの詳細を指定」の画面で「OS」という欄が表示されるようになりました。
「OS」の記載の代わりに「AMI ID」や「EC2 Instance」など、何を書いてもOKですが、「OS」が一番分かりやすいなと思いました。
上記のテンプレート②をどうやって使うかについてはそれぞれの方法がありますので、環境によって使い方が異なると思います。
ざっくり考えてみると下記のパターンが「あり」かなと思いました。
①OS毎にテンプレートを準備する Windows Server 2016, Windows Server 2022, Amazon Linux 2などでテンプレートを分ける
② 既存テンプレートで「スタックの詳細を指定」の画面で「2022」から適切な数字を入力
例えば、下記の画像の通り、2022から2016に変更します。
Amazon Linuxの場合は「/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base」の代わりに、「ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2」を記載します。
③許可されているパラメーターから対象のOSを選びます。
その場合、下記のようなパラメーターを入れる必要があります
Parameters: OS: Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: "/aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base" AllowedValues: - /aws/service/ami-windows-latest/Windows_Server-2022-Japanese-Full-Base - /aws/service/<好きなOSのパスを追記>
Terraformの方法
Terraformの場合、「Data Source」を使用します。HashiCorpページにある下記のURLを参照し、自分のテンプレートを作成します。
EC2テンプレート
Data Source: aws_ami
EC2構築
上記のEC2テンプレートのサンプルの通り、普通は下記のような書き方でEC2のAMIを入力します。
テンプレート①(AMI IDの入力あり)
provider "aws" {} resource "aws_instance" "ec2" { ami = "ami-005e54dee72cc1d00" instance_type = "t3.medium"
※今回の例のために、t3.mediumのインスタンスタイプを選びました。
※Terraformのリソース名として「ec2」を記載しましたが、他の名前(例:webやbastionなど)を記載しても問題ありません。
テンプレート②(AMI IDの入力なし)
上記のAMI IDの代わりに下記のように入力します。
Amazon Linux 2の場合
provider "aws" {} data "aws_ami" "latest_amazon_linux" { owners = ["amazon"] most_recent = true filter { name = "name" values = ["amzn2-ami-hvm-*-x86_64-gp2"] } } resource "aws_instance" "ec2" { ami = data.aws_ami.latest_amazon_linux.id instance_type = "t3.medium"
Windows Serverの場合
provider "aws" {} data "aws_ami" "latest_windows_2016" { owners = ["amazon"] most_recent = true filter { name = "name" values = ["Windows_Server-2016-Japanese-Full-Base-*"] } } resource "aws_instance" "ec2" { ami = data.aws_ami.latest_windows_2016.id instance_type = "t3.medium"
※例としてWindows Server 2016(日本語版)で設定しましたが、「2016」の代わりに適切なWindows Serverバージョンを入力すればよいです。なお、英語版が必要な場合
「Japanese-Full-Base-*」
の代わりに、
「English-Full-Base-*」
を入力して頂く必要があります。
上記の方法をご紹介致しましたが、いかがでしたでしょうか。
本件の記事にはTerraformの基本について詳しい情報が少なかったので、次のTerraformの記事ではTerraformの基本についてご説明させて頂きます。
以上、御一読ありがとうございました。
イーゴリ (記事一覧)
クラウドインテグレーション部・エンジニア
特にTerraform(自動化)、ネットワーク系、DNS、VDI、Windows Serverに興味があります
日本国内旅行・ドライブが好きです