【CloudFormation / Terraform】EC2の最新版のAMI IDを自動的に取得、構築する (Windows / Linux)

記事タイトルとURLをコピーする

こんにちは!クラウドインテグレーション部技術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でもお見せしたいと思いますので、是非最後まで読んでください。

f:id:swx-korotkov:20220204155043j:plain

問題点

最新版の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))。

f:id:swx-korotkov:20220128150402p:plain

それぞれの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)が最新であることを下記の画像でも確認できます。

f:id:swx-korotkov:20220128154209p:plain
CLI出力結果と同じAMI ID

さて、理論情報からCloud Formationテンプレートの作成に行きましょう!

CloudFormationの方法

CloudFormationの基本

CloudFormationについてまったくご存知ではない方の場合、下記の記事を読めばCloudFormationの基本が分かると思いますので、ご参考ください。

blog.serverworks.co.jp

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を入力します。

f:id:swx-korotkov:20220128154209p:plain

もちろんAWSコンソール/CLIでできることはCloudFormationでも実現可能なので、EC2をカスタマイズしたい場合、下記のドキュメントをご参考ください。

docs.aws.amazon.com

では、本題へ移りましょう!

上記の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-windows-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」が一番分かりやすいなと思いました。

f:id:swx-korotkov:20220128163715p:plain

上記のテンプレート②をどうやって使うかについてはそれぞれの方法がありますので、環境によって使い方が異なると思います。

ざっくり考えてみると下記のパターンが「あり」かなと思いました。

①OS毎にテンプレートを準備する Windows Server 2016, Windows Server 2022, Amazon Linux 2などでテンプレートを分ける

② 既存テンプレートで「スタックの詳細を指定」の画面で「2022」から適切な数字を入力

  1. 例えば、下記の画像の通り、2022から2016に変更します。 f:id:swx-korotkov:20220128164421p:plain

  2. 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テンプレート

registry.terraform.io

Data Source: aws_ami

registry.terraform.io

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の基本についてご説明させて頂きます。

以上、御一読ありがとうございました。

イーゴリ (記事一覧)

クラウドインテグレーション部・技術4課・エンジニア

特にTerraform(自動化)、ネットワーク系、VDI、Windows Serverに興味があります

日本国内旅行・ドライブが好きです