0
0

awsインスタンスタイプのバッチでの変更です。

Posted at

AWSのインスタンス変更で残業したくない。

AWSのインスタンスを変更するために残業したくないですよね。
そこで、インスタンスタイプをバッチで制御してみました。

実際には、aws-cliを入れて、設定さえしていれば、

set instance_id=i-xxxxxxxxxxxxxxxxx
set new_type=t3.micro
aws ec2 modify-instance-attribute --instance-id %instance_id% --instance-type "{\"Value\": \"%new_type%\"}" --no-verify

だけで、出来ます。
※--no-verifyは、proxyの関係でやむを得ず指定してますが、本当は望ましくはないらしいです。

実際は、もう少し複雑になってます。

今回は、状態チェックや稼働中はどうしようとか、色々考慮してます。

仕様はこんな感じ、

「このバッチは、awsのEC2のインスタンスタイプを変更するためのバッチです。
もし、該当EC2が、すでに変更後のインスタンスタイプだった場合は、何もせず終了します。
なお、インスタンスタイプを変更できるのは停止中のみです。
稼動中に一旦停止して変更し、再開させる指定も可能ですが、サーバが停止するので注意ください。

※注意
-forceパラメータを付けると、サーバを一時的に止めることになるので、特に注意が必要です。
また、インスタンス変更後に、そのAZに該当インスタンスの空きが無いと、立ち上がらないことがあります。
これも、重要な注意点の一つです。」

一番面倒なのが、ステータスの読み取りで、「停止をし始めたところ」「停止中」「稼働し始めたところ」の3つのステータスが全て「not_running」で区別がつかないところです。ここは改善してほしいなと思いましたが、そんなこと言ってもしょうがないので、無理やり対応してます。

それと、複数指定可、単数指定しかできないの関係で
--instance-id
だったり、
--instance-ids
だったり、aws-cliのパラメータは統一してほしかったな。

以下が、バッチです。

いつもながら、長いなあ。
すみません。

aws_change_instance_type.bat
@echo off
rem パラメータ無しで起動すると、説明が表示されます。

setlocal

rem リトライが必要なケースがあるので、その間隔と回数を指定します。
rem リトライ用のインターバルは、CPUビジー防止のため、分単位での指定です。
set repeat_interval_minutes=2
rem リトライの最大回数は、3回位が良いと思います。
set retry_maxcount=3

rem ====================================================================
set instance_id=%1
set new_type=%2
set instance_region=%3
set force_change=%4

rem このバッチの前提となる、aws-cliが導入・設定されているか確認します。
if not exist "%HOMEDRIVE%%HOMEPATH%\.aws\config" goto :no_aws_cli

rem 必須パラメータの有無を確認します。
if "%new_type%"=="" goto :usage

rem パラメータ3と4が両方任意なので、調整します。
if "%instance_region%"=="" (
  set instance_region=%AWS_DEFAULT_REGION%
) else if "%instance_region%"=="-force" (
  set force_change=%3
  set instance_region=%AWS_DEFAULT_REGION%
)

rem 環境変数または、パラメータでリージョンが指定されているかを調べます。
if "%instance_region%"=="" goto :no_aws_region

rem aws関連のクレデンシャル情報の有無を調べます。
if "%AWS_ACCESS_KEY_ID%"=="" goto :no_aws_credential
if "%AWS_SECRET_ACCESS_KEY%"=="" goto :no_aws_credential

call :initialize

echo 現在のインスタンス[%instance_id%]のタイプを調べます。
call :get_now_type
rem インスタンスの有無を判定します。
if "%now_type%"=="Not_Exist" goto :no_instance
rem 新タイプと現在のタイプを比較し、変更の必要性を判定します。
if "%now_type%"=="%new_type%" goto :no_change

set old_type=%now_type%

:retry
echo 現在のインスタンス[%instance_id%]の状態をチェックします。
set now_status=not_running
for /f "usebackq tokens=2 delims= " %%A in (`aws ec2 describe-instance-status --region %instance_region% --instance-ids %instance_id% %ssl_verify% ^| find "running"`) do set now_status=%%A

rem 稼動中でなければ、インスタンスタイプを変更し終了します。
rem ※停止直後、稼動直後もこの状態になりますが、停止中ではないため、変更は出来ません。
rem そのことを考慮し、変更後に反映されたかどうか、確認し、変更出来ていなければ、時間を置いて数回リトライします。
if "%now_status%"=="not_running" goto :not_running

rem 稼動中の場合は、第3パラメータで強制変更指定の場合だけ、インスタンスタイプを変更します。
if "%force_change%"=="-force" goto :stop_start

rem 稼動中で、第3パラメータで強制変更指定が無ければ、インスタンスタイプを変更せず終了します。
echo インスタンス[%instance_id%]は、タイプ[%now_type%]で稼動中です。
echo -force指定が無かったので、[%new_type%]に変更せず、このまま終了します。
echo.
echo 稼動中でも変更したい場合は、-force指定が必要です。
echo -force指定があると、稼動中はインスタンスを一度停止して、インスタンスタイプを変更して、再稼働します。
echo -force指定があると、稼動中のサーバを停止することになるので、注意が必要です。
goto :end

:stop_start
echo[-force]指定があったので、サーバ稼働中ですが、強制的にインスタンスタイプを変更します。
echo.
echo インスタンス[%instance_id%]は、稼動中なので、一時的に停止して、インスタンスタイプ[%old_type%][%new_type%]に変更します。
echo 変更後は、再度稼働させます。
echo 以後、awsコマンドの進捗を表示しながら、進めます。
echo.
echo インスタンスを停止指示して、停止を待ちます。(停止するまで、確認を繰り返します。停止には数分~かかります。)
aws ec2 stop-instances --region %instance_region% --instance-ids %instance_id% %ssl_verify% && aws ec2 wait instance-stopped --instance-ids %instance_id% %ssl_verify%
echo 停止しました。
echo インスタンスタイプを変更します。
aws ec2 modify-instance-attribute --region %instance_region% --instance-id %instance_id% --instance-type "{\"Value\": \"%new_type%\"}" %ssl_verify%
echo インスタンスタイプを変更しました。
set kekka=0
echo 変更が正常に反映されたか、調べます。
call :get_now_type
if not "%now_type%"=="%new_type%" (
  echo インスタンスを停止して変更を試みましたが、正常に変更出来ませんでした。
  echo.
  echo 変更後のインスタンスタイプ指定[%new_type%]の問題の可能性がありますが、
  echo 変更失敗の原因は、不明なので、リトライは行いません。
  echo インスタンスタイプは[%old_type%]のまま、再度起動します。
  set kekka=99
)
echo インスタンスを起動します。
aws ec2 start-instances --region %instance_region%--instance-ids %instance_id% %ssl_verify% && aws ec2 wait instance-running --instance-ids %instance_id% %ssl_verify%
echo インスタンス起動し始めました。起動チェックの結果を確認します。(okになるまで、確認を繰り返します。数分~かかります。)
aws ec2 wait instance-status-ok --region %instance_region% --instance-ids %instance_id% %ssl_verify%
echo 起動チェックokになりました。利用できます。
set kekka=2
goto :end

:not_running
rem この場合、
rem ①既に停止している(stopped)
rem ②停止指示したばかりでこれから停止する(stopping)
rem ③スタート指示したばかりでこれから起動する。(pending)
rem という3つのパターンがあることが分かった。
rem しかし、状態に名称があるのに、上記の状態のいずれかを調べる方法が無く、全て"not_running"になってしまう。
rem そこで、状態に関係なく変更コマンドを実行し、失敗したら、リトライを行うことにする。

echo インスタンス[%instance_id%]のインスタンスタイプ[%old_type%][%new_type%]に変更します。
aws ec2 modify-instance-attribute --region %instance_region% --instance-id %instance_id% --instance-type "{\"Value\": \"%new_type%\"}" %ssl_verify%

echo 変更が正常に反映されたか、調べます。
call :get_now_type
if not "%now_type%"=="%new_type%" goto :change_ng
echo インスタンス[%instance_id%]noインスタンスタイプ[%old_type%][%new_type%]に変更出来ました。
set kekka=0
goto :end

:change_ng
rem 変更失敗した場合は、指定時間間隔で、%retry_maxcount%回リトライする。
echo 正常に変更できていないため、%repeat_interval_minutes%分後に、リトライします。
echo 変更できない理由は、起動開始直後、あるいは、停止処理開始直後で完全に停止していないためと考えられます。
set /a retry_count+=1
if retry_count==%retry_maxcount% goto :retry_ng
timeout /t %repeat_interval%
goto :retry

:retry_ng
echo %repeat_interval_minutes%分間隔で、%retry_count%回、リトライしましたが、変更できませんでした。
echo インスタンスの状態が停止にならない、あるいは変更後のインスタンスタイプ指定[%new_type%]の問題と思われます。
echo 調査が必要です。
echo.
set kekka=99
goto :end

:no_aws_cli
echo このバッチに必要な、aws cli(AWS Command Line Interface)のインストールと設定が見つかりません。
echo 利用にあたって、このPCに「aws cli」のインストールと設定をしておいてください。
echo テストはv2で行っていますので、aws cli v2を推奨します。
echo.
echo なお、このバッチの使い方は、以下の通りです。
echo.
goto :usage

:no_aws_region
echo リージョン指定が必要です。
echo コマンドでリージョンを指定するか、環境変数「AWS_DEFAULT_REGION」に情報をセットください。
echo.
echo なお、このバッチの使い方は、以下の通りです。
echo.
goto :usage

:no_aws_credential
echo awsのクレデンシャル情報を環境変数にsetしている必要があります。
echo 環境変数「AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY」に情報をセットください。
echo.
echo なお、このバッチの使い方は、以下の通りです。
echo.
goto :usage


:usage
echo 使い方:%~n0 instance_id instance_type [ instance_region -force]
echo.
echo このバッチは、awsのEC2の「インスタンスタイプ」を変更するためのバッチです。
echo ※このバッチの前提として、aws-cliのインストールと設定が完了している必要があります。
echo また、AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEYを環境変数に設定しておくことが必要です。
echo instance_regionを省略する場合は、環境変数AWS_DEFAULT_REGIONの設定も必要です。
echo.
echo なお、インスタンスタイプを変更できるのはawsの制約で、停止中のみです。
echo -forceパラメータを付けることで、稼動中でも、一旦停止して、変更後に再起動させることが出来ます。
echo  サーバが一時停止する事になるので、利用時は注意ください。
echo  なお、変更先のインスタンスタイプが、AWSに枯渇していると再起動できません。
echo  最悪のケースだと、変更前のインスタンスタイプも枯渇し、しばらく起動できない事があります。
echo.
echo 第1パラメータ:【必須】instance-id(インスタンスID)
echo 第2パラメータ:【必須】instance_type(何に変更するか)
echo                        もし、該当EC2が、すでに変更後のインスタンスタイプだった場合は、何もせず終了します。
echo 第3パラメータ:【任意】instance_region(インスタンスのリージョン)
echo                        もし、リージョン指定が無ければ、環境変数AWS_DEFAULT_REGIONの値を使います。(%AWS_DEFAULT_REGION%)
echo 第4パラメータ:【任意】稼動中でも、一旦停止して変更するかどうかの指定パラメータです。
echo                       -forceを指定すると、状態により以下の様に動作します。
echo                         「稼動中」の場合、一度停止してインスタンスタイプを変更し、変更後、再起動します。
echo                         「停止中」の場合、インスタンスタイプを変更し、停止中のまま終了します。
echo                       -forceを指定しないと、稼動中は何もせず、停止中のみインスタンスタイプを変更します。
echo.
echo 戻り値:0正常に変更、1:正常(変更不要)、2:正常(変更後再起動)、9:異常(コマンドエラー)、99:異常(変更エラー)
echo.
echo 以下、コール例です。windows taskなどを利用することで、夜間に無人で変更するなどが可能です。
echo.
echo @echo off
echo set instance_id=i-xxxxxxxxxxxxxxxxx
echo set new_type=t3.micro
echo call aws_change_instance_type %%instance_id%% %%new_type%% %%instance_region%% -force
echo if errorlevel 9 (
echo    echo ★★★変更できませんでした。★★★
echo    ) else (
echo    echo %%instance_id%%%%new_type%%に変更しました。
echo    )
echo.
set kekka=9
goto :end

:no_change
echo すでに、[%new_type%]になっていますので、何もせず終了します。
set kekka=1
goto :end

:no_instance
echo インスタンス[%instance_id%]は、見つかりませんでした。
echo IDを確認してください。
set kekka=99
goto :end

:end
if "%SESSIONNAME%"=="" pause
exit /b %kekka%

rem =========== sub-routines ===============
:get_now_type
rem 現在のインスタンスタイプを読み取ります。
set now_type=Not_Exist
for /f "usebackq tokens=2 delims= " %%A in (`aws ec2 describe-instances --region %instance_region% --instance-id %instance_id% %ssl_verify% ^| find "InstanceType"`) do set now_type=%%A
rem コマンドから入手した不要な文字を削除し、整形します。
set now_type=%now_type:"=%
set now_type=%now_type:,=%
exit /b

:initialize
rem 初期値を設定します。

rem 途中にproxyが無ければ、多分、以下で大丈夫。
set ssl_verify=
rem proxyの影響で、(CERTIFICATE_VERIFY_FAILED)エラーになる場合、以下のいずれかが必要。
rem 会社のpemがあれば回避できるらしいけど、よくわからん。
set ssl_verify=--ca-bundle %HOMEDRIVE%%HOMEPATH%\company.pem
rem 影響はよくわからないが、--no-verify-sslを指定する。
rem 推奨はされてないようですが、多くの方は、これで逃げるみたい。
set ssl_verify=--no-verify-ssl

set kekka=0
set retry_count=0
set /a repeat_interval=%repeat_interval_minutes% * 60

exit /b

ちなみに、これを、コールする側は、こんな感じ
これを、aws-cliをセットしたPCで好きな時間に、winodows taskとかで動かせばよいです。
(重要)このバッチを利用したために、トラブルになっても責任は取れませんので、十分に理解してからご利用ください。

@echo off
set instance_id=i-xxxxxxxxxxxxxxxxx
set new_type=t3.micro

call aws_change_instance_type %instance_id% %new_type%
0
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0