目次
アイキャッチ画像が 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 texti-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 -ui-00000000000000000i-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"> donenasutest0 i-00000000000000000nasutest9 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_adminnasutest0 i-00000000000000000nasutest9 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 nasutest0i-99999999999999999 nasutest9さいごに
マネジメントコンソールでこの情報を確認できればいいのですが、どこで見れるかわからなかったので簡単ではありますがスクリプトを作ってみました。 AWS CLI を使えばマネジメントコンソールでは確認できない情報もすぐに確認できるので本当に重宝します。 運用作業では GUI での手作業だけでは辛い場面も多々ありますので、日々の運用の中で AWS CLI を積極的に使っていきましょう!
- カテゴリー