AWS Tools for PowerShellを使ってEC2インスタンスを作成する
しばたです。
EC2インスタンスを作成する場合、環境をゼロから新規構築したりある程度まとまった規模で管理する場合であればCloudFormationやTerraformといった構成管理ツールを使うかと思いますが、一時的な検証環境であったり既存の環境に追加でインスタンスを増やす場合はAWS CLIやPowerShellを使ってコマンドやスクリプトで作成することも多いかと思います。
本記事では既存の環境に新たに1台のEC2インスタンスを作成するシナリオでAWS Tools for PowerShellの使い方を紹介します。
前提条件
VPCやサブネット、セキュリティグループの設定は一通り設定済みの環境を想定しています。
EC2キーペアを新しく発行し、新規のEC2インスタンスを作成する流れを紹介します。
AWS Tools for PowerShellのインストールと初期設定
本記事で使うPowerShellは最新のPowerShell Core 6.1.3とします。
これから紹介する手順は古いPowerShellでも動作しますが、最新のPowerShell CoreであればWindows以外の環境からも試すことができより多くの人にリーチできるので最新バージョンを選択します。
PowerShell Coreのインストール手順はGitHubのドキュメントか私が使ってるスクリプトを参考にしてください。
AWS Tools for PowerShellはPowerShell Galleryからインストールします。
(本記事公開時点のバージョンはVer.3.3.462.0)
#Requires -Version 6.0
# AWS Tools for PowerShell インストール
Install-Module -Name AWSPowerShell.NetCore -Scope CurrentUser
認証の設定などは私の個人ブログを参照してください。
- AWS Tools for PowerShellを試してみる
- ちょっと古いですがDevelopers.IOの記事もあります : AWS Tools for Windows PowerShellを使ってみた
以降の手順ではSet-DefaultAWSRegionとSet-AWSCredentialを呼び出し既定のリージョンとプロファイルが指定済みの前提とします。
#Requires -Version 6.0
# モジュールをインポート
Import-Module AWSPowerShell.NetCore
# 既定のリージョンおよびプロファイルの指定は環境に合わせて行ってください
Set-DefaultAWSRegion -Region ap-northeast-1
Set-AWSCredential -ProfileName test-profile
AMIの検索
作成するインスタンスのAMIはGet-EC2Imageコマンドレットで検索することができます。
このコマンドレットを引数なしで実行すると全種類、全バージョンのAMIを検索して使い物になりませんのでFilter
パラメーターを使い検索条件を指定してやるのが良いです。
このFilter
パラメーターはAmazon.EC2.Model.Filter[]
と独自の型の配列を受け取るのですが、ハッシュテーブルで代用できるため以下の例の様に使う方がPowerShellとして自然ですし記述も楽になるかと思います。
指定可能なパラメーターについてはリファレンスを参照してください。
本記事ではAmazonが提供する日本語版Windows Server 2019を検索する例を紹介します。
短いコードですので記載してるコメントだけで十分意味は通るとかと思います。
# AMIの検索 : Filterパラメーターを使わないとすごく遅いので注意
# 日本語版Windows Server 2019を検索する場合
# イメージ情報をすべて出力すると冗長なので ImageId, Name, Description のみ表示する様にしています
$filter = (
@{ Name = 'platform'; Values = 'windows' },
@{ Name = 'name'; Values = 'Windows_Server-2019-Japanese*Base*' }
)
Get-EC2Image -Owner amazon -Filter $filter |
Sort-Object CreationDate -Descending | Select-Object ImageId, Name, Description | Format-List
また、とりあえずWindows AMIが欲しい場合であればGet-EC2ImageByNameコマンドレットも使えます。
(最新バージョンの英語版Windowsのみが検索対象となります)
# 引数なしですべての名前をリストアップ
Get-EC2ImageByName
# 引数を付けると最新のAMIを取得
Get-EC2ImageByName -Name WINDOWS_2016_BASE | Select-Object ImageId, Name, Description | Format-List
EC2キーペアの作成
EC2キーペアの作成はNew-EC2KeyPairコマンドレットで行えます。
何も考えずに実行すると「フィンガープリントと鍵情報がコンソールに出力されて終わり」となってしまうので以下の様にキー情報を変数に格納してファイル出力してやると良いでしょう。
# キーペアを作成
# ※結果を変数に入れないと二度と取得できなくなり、鍵を作り直すことになるので注意
$keyName = 'your-key'
$keyPair = New-EC2KeyPair -KeyName $keyName
# フィンガープリントを表示
Write-Output ("Fingerprint : {0}" -f $keyPair.KeyFingerprint)
# 秘密鍵を保存
$keyPair.KeyMaterial | Out-File (".\{0}.pem" -f $keyName) -Encoding ascii
EC2インスタンスの作成 (Windows)
ここから本題のEC2インスタンスの作成について説明します。
インスタンスの作成はNew-EC2Instanceコマンドレットで行えます。
このコマンドレットはAMIイメージIDを指定するパターンと起動テンプレートを指定する2パターン存在するのですが今回はAMIイメージを指定するパターンを紹介します。
また、EC2インスタンスを作成するだけあって指定可能なパラメーターが多いため、個々のパラメーターについてはリファレンスで確認してください。
本記事では少し実践的な例を紹介します。
- 現時点で最新の日本語版 Windows Server 2019 を作成
- インストールするサブネットはNameタグに
your-subnet
が設定されているものを選択 - 設定するセキュリティグループはNameタグに
your-security-group
が設定されているものを選択 - 30GiBのCドライブ以外に10GiBの追加ドライブも同時作成
- ユーザーデータで追加ドライブの初期化処理を記述
- おまけで柴田個人作成のPowerShell Coreインストールスクリプトも追記
- インスタンス追加後にNameタグに
your-windows-server2019
を設定 - インスタンス追加後に削除保護を設定
上記の条件でインスタンスを作成するスクリプトが以下になります。
コメントである程度説明してますが補足は後述します。
#Requires -Version 6.0
# EC2インスタンスを作成
# ※パラメーターが多いのでスプラッティングを使用
$params = @{
KeyName = 'your-key' # EC2キーペア
ImageId = 'ami-0080a567a9989e1d5' # Windows_Server-2019-Japanese-Full-Base-2019.02.13
InstanceType = 't2.medium' # 無償枠から外れるが Windows ServerならCPU2コアはないと厳しい
# 基本的にMinCountとMaxCountは同じで良い
MinCount = 1
MaxCount = 1
# NameタグからサブネットIDを取得して指定
SubnetId = (Get-EC2Subnet -Filter @{Name = 'tag:Name'; Values = 'your-subnet'}).SubnetId
# NameタグからセキュリティグループIDを取得して指定
SecurityGroupId = (Get-EC2SecurityGroup -Filter @{Name = 'group-name'; Values = 'your-security-group'}).GroupId
EbsOptimized = $false
#
# デバイス指定は Amazon.EC2.Model.EbsBlockDevice 型のオブジェクトを直接使う必要があり、
# PowerShellらしい記述ができないのが少し残念である
#
BlockDeviceMapping = & {
# EBS1 : ルートデバイス(/dev/sda1)
$bd1 = [Amazon.EC2.Model.EbsBlockDevice]::new()
$bd1.VolumeSize = 30
$bd1.VolumeType = [Amazon.EC2.VolumeType]::Gp2
$bd1.DeleteOnTermination = $true
$bdm1 = [Amazon.EC2.Model.BlockDeviceMapping]::new()
$bdm1.DeviceName = '/dev/sda1'
$bdm1.Ebs = $bd1
# EBS2 : 追加ディスク (xvdf)
$bd2 = [Amazon.EC2.Model.EbsBlockDevice]::new()
$bd2.VolumeSize = 10
$bd2.VolumeType = [Amazon.EC2.VolumeType]::Gp2
$bd2.DeleteOnTermination = $true
$bdm2 = [Amazon.EC2.Model.BlockDeviceMapping]::new()
$bdm2.DeviceName = 'xvdf'
$bdm2.Ebs = $bd2
return @($bdm1, $bdm2)
}
# ユーザーデータの設定
EncodeUserData = $true
UserData =
@'
# Initialize disks
& (Join-Path $env:ProgramData 'Amazon\EC2-Windows\Launch\Scripts\InitializeDisks.ps1')
# Install the latest PowerShell Core
[Net.ServicePointManager]::SecurityProtocol=[Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12;
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/stknohg/PSCoreUpdate/master/FirstTimeInstaller/Install-LatestPowerShell.ps1'))
'@
}
# インスタンス作成
$reservation = New-EC2Instance @params
$reservation.Instances | ForEach-Object {
# Nameタグを追加
New-EC2Tag -Resource $_.InstanceId -Tag @{Key = 'Name'; Value = 'your-windows-server2019'}
# 削除保護の追加
Edit-EC2InstanceAttribute -InstanceId $_.InstanceId -DisableApiTermination $true
}
MinCount、MaxCount
New-EC2Instanceでは一回の実行で複数インスタンスを同時に作成することができ、コマンドレットの戻り値もインスタンスそのものではなくReservationを返します。
一応最小作成数がMinCount、最大作成数がMaxCountで、基本的にMaxCountの作成を試みるのですがリソース制限に引っかかった際の挙動についてはよくわかりません。(別途検証したいと思います)
AWS CLIではこの様なパラメーターは無く単純に--count
引数で作成数を指定するだけです。
このパラメーターについては両方同じ数にしておくのが無難だと思います。
サブネット、セキュリティグループの指定
SubnetId
パラメーターでインスタンスを配置するサブネットを、SecurityGroupId
パラメーターで関連付けるセキュリティグループを指定します。
どちらもID指定ですが、一般的な環境であればNameタグを使って名前付けしてると思いますので、それぞれGet-EC2Subnet、Get-EC2SecurityGroupコマンドレットを使い、名前からIDを取得する様にしています。
BlockDeviceMapping
ルートデバイスおよび追加EBSボリュームの設定はBlockDeviceMapping
パラメーターで指定します。
このパラメーターにはAWS SDK for .NETのAmazon.EC2.Model.EbsBlockDevice
型をそのまま指定します。
この型では追加するディスクを表すAmazon.EC2.Model.EbsBlockDevice
型のオブジェクトをEbs
プロパティに、デバイス名をDeviceName
プロパティに設定してやります。
この記述は生のSDKそのままであまりPowerShellらしくないため若干わかりにくいです。
本記事ではやりませんが簡単な関数を作ってこの記述をラップしてやるとよりPowerShellらしくなると思います。
ユーザーデータ
ユーザーデータはUserData
プロパティに処理を記述します。
デフォルトではBASE64エンコードした後の値を入れるのですが、EncodeUserData
パラメーターを指定することでエンコード前の値を設定でき、より直感的なコードになります。
ディスクの初期化についてはこちらの記事をご覧ください。
おまけで私個人作成のPowerShell Coreのインストールスクリプトを記述してます。
これでインスタンス作成と同時にPowerShell Coreが利用可能になります。
タグ付け
【2019.03.08修正】
EC2インスタンスのタグを作成と同時に行うことはできません。
New-EC2Instance
の戻り値(Reservation)から作成したインスタンスを取得し、インスタンスを更新する形を採る必要があります。
TagSpecification
パラメーターを指定するとインスタンスの作成と同時にタグ付けすることができます。(パラメーターを見逃してました...すいません)
作成するインスタンスが1つだけの場合であればこのパラメーターを使う方が楽でしょう。
同時に複数インスタンス作成する場合はループ内でタグを更新する方がより柔軟に処理できると思います。
【修正ここまで】
前述した様にNew-EC2Instance
では複数のインスタンスを同時に作成できます。
このため戻り値(Reservation)のInstances
プロパティに対してForEach-Object
でループ処理をしてやる必要があります。
New-EC2Tagで作成したインスタンスに対してタグ付けをしてやります。
このコマンドレットはEC2インスタンス以外のリソースでも使えるためパラメーター名がResource
となっています。
削除保護の指定
Edit-EC2InstanceAttributeコマンドレットでEC2インスタンスの属性変更を行うことができます。
DisableApiTermination
パラメーターで削除保護の有効・無効を切り替えることができます。
他にも様々な属性を変更できますので詳細はリファレンスを参照してください。
EC2インスタンスの作成 (Linux)
続けてLinuxインスタンスの作成スクリプトを紹介します。
Windowsの場合と概ね同じ条件のインスタンスを作成します。
- 現時点で最新のAmazon Linux 2を作成
- インストールするサブネットはNameタグに
your-subnet
が設定されているものを選択 - 設定するセキュリティグループはNameタグに
your-security-group
が設定されているものを選択 - 10GiBのルートディスク以外に10GiBの追加ディスクを
/data
にマウント - ユーザーデータで追加ディスクのマウント処理を追加
- おまけで柴田個人作成のPowerShell Coreインストールスクリプトも追記
- インスタンス追加後にNameタグに
your-amazonlinux2
を設定 - インスタンス追加後に削除保護を設定
スクリプトは以下。
Windowsの場合とほとんど変わらないので同様の部分の補足は省略します。
#Requires -Version 6.0
# EC2インスタンスを作成
# ※パラメーターが多いのでスプラッティングを使用
$params = @{
KeyName = 'your-key' # EC2キーペア
ImageId = 'ami-097473abce069b8e9' # amzn2-ami-hvm-2.0.20190228-x86_64-gp2
InstanceType = 't1.micro' # 無償枠
# 基本的にMinCountとMaxCountは同じで良い
MinCount = 1
MaxCount = 1
# NameタグからサブネットIDを取得して指定
SubnetId = (Get-EC2Subnet -Filter @{Name = 'tag:Name'; Values = 'your-subnet'}).SubnetId
# NameタグからセキュリティグループIDを取得して指定
SecurityGroupId = (Get-EC2SecurityGroup -Filter @{Name = 'group-name'; Values = 'your-security-group'}).GroupId
EbsOptimized = $false
#
# デバイス指定は Amazon.EC2.Model.EbsBlockDevice 型のオブジェクトを直接使う必要があり、
# PowerShellらしい記述ができないのが少し残念である
#
BlockDeviceMapping = & {
# EBS1
$bd1 = [Amazon.EC2.Model.EbsBlockDevice]::new()
$bd1.VolumeSize = 10
$bd1.VolumeType = [Amazon.EC2.VolumeType]::Gp2
$bd1.DeleteOnTermination = $true
$bdm1 = [Amazon.EC2.Model.BlockDeviceMapping]::new()
$bdm1.DeviceName = '/dev/xvda'
$bdm1.Ebs = $bd1
# EBS2
$bd2 = [Amazon.EC2.Model.EbsBlockDevice]::new()
$bd2.VolumeSize = 10
$bd2.VolumeType = [Amazon.EC2.VolumeType]::Gp2
$bd2.DeleteOnTermination = $true
$bdm2 = [Amazon.EC2.Model.BlockDeviceMapping]::new()
$bdm2.DeviceName = '/dev/xvdf'
$bdm2.Ebs = $bd2
return @($bdm1, $bdm2)
}
# ユーザーデータの設定
EncodeUserData = $true
UserData =
@'
#!/bin/bash
sudo yum update -y
# mkfs
sudo mkfs -t xfs /dev/xvdf
sudo mkdir /data
sudo mount /dev/xvdf /data
# set fstab
sudo cp /etc/fstab /etc/fstab.orig
echo "UUID=$(sudo blkid | grep '/dev/xvdf' | sed -n 's/.*UUID=\"\([^\"]*\)\".*/\1/p') /data xfs defaults,nofail 1 2" | sudo tee -a /etc/fstab
# install PowerShell Core
curl https://packages.microsoft.com/config/rhel/7/prod.repo | sudo tee /etc/yum.repos.d/microsoft.repo
sudo yum install -y powershell
'@
}
# インスタンス作成
$reservation = New-EC2Instance @params
$reservation.Instances | ForEach-Object {
# Nameタグを追加
New-EC2Tag -Resource $_.InstanceId -Tag @{Key = 'Name'; Value = 'your-amazonlinux2' }
# 削除保護の追加
Edit-EC2InstanceAttribute -InstanceId $_.InstanceId -DisableApiTermination $true
}
ユーザーデータ
ユーザーデータに記述している追加ディスクのマウント手順はAWS公式ドキュメントの手順をベースにしています。
mkfs
でファイルシステムを作ってマウント、fstabの記述を追加して永続化、とLinuxでの一般的な設定方法かと思います。
こちらもおまけでPowerShell Coreのインストールをしています。
最後に
ちょっと長くなりましたがAWS Tools for PowerShellを使ってEC2インスタンスを作成するスクリプトを紹介しました。
本記事で紹介したようなスクリプトを手元に持っておくとちょっとした環境を作る時に非常に役に立ちますので、みなさんも自分の環境に合わせたスクリプトを作ってみてください。