目次
アイキャッチ画像が Systems Manager になってますが実際はほぼ AWS CLI の記事です。那須です。
とある作業で、Systems Manager(以下SSM)でたくさんある EC2 インスタンスを管理しようと思って準備していたら、どうも EC2 インスタンスの数と SSM のマネージドインスタンスの数が合わないことに気がつきました。 インスタンス数が少なければどれが正しく設定できていないかすぐに分かるんですが、100 台近くの EC2 インスタンスがあって 98 台は SSM のマネージドインスタンスとして見えてるけど残りの 2 台はどれ?ってなりましたので、どうやって設定がうまくいっていない EC2 インスタンスを特定したのかをご紹介します。
Excel をうまく使えば特定できるんですが、どうせ EC2 インスタンスの一覧を AWS CLI で取得するなら欲しい情報もそのまま bash でやろうと思ったので、今回は bash メインです。mac や Windows PC で WSL2 を使っている方が対象の記事になっていますが、PowerShell でも似たようなことができるはずですよ。(私は Windows 10 に WSL2 を入れて bash を使ってます。zsh では試してませんが、たぶんできるんじゃないでしょうか…)
まずは EC2 インスタンスの一覧を作ろう
SSM マネージドインスタンスの一覧と比較するための情報を取得します。 何も考えずに describe-instances を実行すると停止中の EC2 インスタンスまで表示されるので、running 状態の EC2 インスタンスの ID 一覧を取ってきましょう。 出力を text にしている理由は、あとで簡単に bash の array に入れるためです。 人が見るだけなら json で出力するのがいいと思います。
$ aws ssm describe-instance-information --filters
"Key=PingStatus,Values=Online"
--query
'sort(InstanceInformationList[*].InstanceId[])'
--output text
i-11111111111111111 i-22222222222222222 i-33333333333333333 i-44444444444444444 i-55555555555555555 ....
さあこれで比較する 2 つの一覧が作れましたね。
さっそく差分を出してみる
さきほどの一覧を配列に入れて、それぞれの差分を表示しています。uniq -u がめちゃくちゃ便利ですね(今日知りました
$
declare
-a ssm=(`aws ssm describe-instance-information --filters
"Key=PingStatus,Values=Online"
--query
'sort(InstanceInformationList[*].InstanceId[])'
--output text`)
$
declare
-a ec2=(`aws ec2 describe-instances --filters
"Name=instance-state-name,Values=running"
--query
"sort(Reservations[].Instances[].InstanceId)"
--output text`)
$
echo
${ssm[@]} ${ec2[@]} |
tr
' '
'\n'
|
sort
|
uniq
-u
i-00000000000000000
i-99999999999999999
この例では 2 つのインスタンスが起動しているけど SSM マネージドインスタンスとして登録されていないことがわかりました。 EC2 インスタンス ID だけで十分特定できているのですが、人が見た時に「ID だけじゃわからん…」って気持ちになりますよね?(私はなりました
そこで、出てきた EC2 インスタンス ID の名前を一緒に出力することにしました。Name タグを取ってくるようにしていますが、もし他にわかりやすいタグがあればそれを指定しましょう。
$
declare
-a diff_ec2_ssm=(`
echo
${ssm[@]} ${ec2[@]} |
tr
' '
'\n'
|
sort
|
uniq
-u`)
$
for
diff_instance_id
in
"${diff_ec2_ssm[@]}"
;
do
> name_tag=`aws ec2 describe-instances --instance-ids ${diff_instance_id} --query
"Reservations[].Instances[].Tags[?Key=='Name'].Value[]"
--output text`
>
echo
"$name_tag $diff_instance_id"
>
done
nasutest0 i-00000000000000000
nasutest9 i-99999999999999999
スクリプト化するとこうなります
スクリプト名は ssm_unmanaged_instances.sh にしました。 各 AWS CLI 実行時に –profile がついていますが、それぞれの環境にあわせて実行できるようにプロファイル名を指定できるようにしています。
#!/bin/bash
declare
-a ssm=(`aws ssm describe-instance-information --filters
"Key=PingStatus,Values=Online"
--query
'sort(InstanceInformationList[*].InstanceId[])'
--output text --profile $1`)
declare
-a ec2=(`aws ec2 describe-instances --filters
"Name=instance-state-name,Values=running"
--query
"sort(Reservations[].Instances[].InstanceId)"
--output text --profile $1`)
declare
-a diff_ec2_ssm=(`
echo
${ssm[@]} ${ec2[@]} |
tr
' '
'\n'
|
sort
|
uniq
-u`)
for
diff_instance_id
in
"${diff_ec2_ssm[@]}"
;
do
name_tag=`aws ec2 describe-instances --instance-ids ${diff_instance_id} --query
"Reservations[].Instances[].Tags[?Key=='Name'].Value[]"
--output text --profile $1`
echo
"$name_tag $diff_instance_id"
done
実行するには、以下のように第 1 引数にプロファイル名を指定しましょう。 本当は引数のチェックとかを入れるべきですが、さすがにこれくらいの量のソースならすぐわかるだろうと思うので usage 表示まで作ってません。
$ .
/ssm_unmanaged_instances
.sh nasu_admin
nasutest0 i-00000000000000000
nasutest9 i-99999999999999999
実際に実行してもらうとわかるのですが、結果が出るまで結構時間がかかります。 差分があればあるほど時間がかかるのでもう少し違ったやり方で Name タグを取ってくるのがよさそうですが、時間があまりなかったのでひとまず最低限結果がわかるスクリプトになっています。
2020/09/29追記:PowerShell でもできます!
社内にいる PowerShell マスターが作ってくれました! 以下の内容を PowerShell で実行しても同じ結果が得られます!
#!/usr/bin/env pwsh
<#
.SYNOPSIS
ssm_unmanaged_instances.ps1
.DESCRIPTION
SSMが無効になっているインスタンス一覧
.EXAMPLE
PS >./ssm_unmanaged_instances.ps1 -Profile aws-cli-profile-name
PS >./ssm_unmanaged_instances.ps1 -Profile aws-cli-profile-name --region ap-northeast-1
.PARAMETER Profile
AWSプロファイル名を設定
.PARAMETER Region
AWS-リージョンを指定
.INPUTS
None
You cannot pipe objects
.OUTPUTS
none
.NOTES
none
#>
PARAM
(
[
Parameter
(
Mandatory
=
$True
)]
[String]
$Profile
,
[
Parameter
(
Mandatory
=
$False
)]
[String]
$Region
=
"ap-northeast-1"
)
PROCESS
{
# StrictMode設定
Set-StrictMode
-Version
Latest
# エラー時に処理をstop
$ErrorActionPreference
=
"stop"
# ssm一覧 取得
[array]
$ssm
= aws ssm describe-instance-information --filters
'Key=PingStatus,Values=Online'
--query
'InstanceInformationList[].{InstanceId:InstanceId} | sort_by(@,&InstanceId)'
--output json --profile
$Profile
--region
$Region
|
ConvertFrom-Json
# ec2一覧 取得
[array]
$runningEC2
= aws ec2 describe-instances --filters
'Name=instance-state-name,Values=running'
--query
'Reservations[].Instances[].{InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value} | sort_by(@,&InstanceId)'
--output json --profile
$Profile
--region
$Region
|
ConvertFrom-Json
# 一覧が取得出来た場合のみ結果比較
if
(
[boolean]
$ssm
-and
[boolean]
$runningEC2
) {
# PingStatusNG リスト取得
[array]
$pingStatusNG
=
Compare-Object
-ReferenceObject
$runningEC2
.InstanceId
-DifferenceObject
$ssm
.InstanceId
-PassThru
# 対象表示
$runningEC2
|
Where-Object
InstanceId
-In
$pingStatusNG
}
else
{
Write-Host
"SSM-PingStatus/RunningEC2Instance is not found"
}
}
実際に実行した場合の出力例です。
> .\ssm_unmanaged_instances.ps1
-Profile
nasu_admin
InstanceId Name
---------- ----
i-00000000000000000 nasutest0
i-99999999999999999 nasutest9
さいごに
マネジメントコンソールでこの情報を確認できればいいのですが、どこで見れるかわからなかったので簡単ではありますがスクリプトを作ってみました。 AWS CLI を使えばマネジメントコンソールでは確認できない情報もすぐに確認できるので本当に重宝します。 運用作業では GUI での手作業だけでは辛い場面も多々ありますので、日々の運用の中で AWS CLI を積極的に使っていきましょう!
- カテゴリー