こんにちは。AWS CLIが好きな福島です。
はじめに
皆様は開発や検証で利用するEC2の起動/停止/確認/ログインはどのようにしていますでしょうか。
私は上記処理をスクリプトで行っているため、それをご紹介したいと思います。
実行環境
# uname -a Linux LAPTOP-CNM26HN6 5.4.72-microsoft-standard-WSL2 #1 SMP Wed Oct 28 23:40:43 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux #
使い方
################################################################### #### #### Usage : ec2-action.sh ${ACTION} ${OPTION} #### ################################################################### case ${ACTION} in ssh ) : SSHアクション rdp ) : RDPアクション start ) : EC2を起動するアクション stop ) : EC2を停止するアクション status ) : EC2の状態を確認するアクション list ) : EC2の一覧を表示するアクション case ${OPTION} in -h ${1} ) : ホスト(EC2のNameタグ)を指定するオプション -u ${1} ) : OSユーザ名を指定するオプション -k ${1} ) : キーペアを指定するオプション -p ${1} ) : aws cliのプロファイル名を指定するオプション -a ) : EC2全台を対象とするで使えるオプション(start,stop,statusアクションで利用可) ※${1}には、任意の値を指定する。
オプションのデフォルトはスクリプトに定義している変数で設定可能です。
## オプションのデフォルト設定 KEY_DIR="[キーペアが保存されているディレクトリ]" KEY="${KEY_DIR}/[キーペア名]" OSUSER="[SSHのOSユーザー名]" RDP_OSUSER="[RDPのOSユーザー名]" HOST="[Nameタグ]" PROFILE="[プロファイル名]"
使用例
前提
以下の変数を設定している前提で使用例を記載いたします。
## オプションのデフォルト設定 KEY_DIR="/mnt/c/Users/serverworker/Desktop/wsl-root/4_key-pea" KEY="${KEY_DIR}/fk-test-key.pem" OSUSER="ec2-user" RDP_OSUSER="administrator" HOST="" PROFILE="kensho"
EC2の一覧
# ./ec2-action.sh list ===================== NAME_TAG ===================== fk-windows fk-linux #
EC2の状態確認
# ./ec2-action.sh -h fk-linux status ===================== ============ NAME_TAG STATUS ===================== ============ fk-linux stopped #
EC2の起動
Nameタグを指定してEC2の起動
# ./ec2-action.sh -h fk-linux start #
プロファイル名を指定して全EC2の起動
# ./ec2-action.sh -p kensho -a start 以下のEC2を [start] しますが、問題ないですか?(yes or no) ==================== 対象EC2 ==================== fk-windows fk-linux yes #
EC2の停止
Nameタグを指定してEC2の停止
# ./ec2-action.sh -h fk-linux stop #
全EC2の停止
# ./ec2-action.sh -a stop 以下のEC2を [stop] しますが、問題ないですか?(yes or no) ==================== 対象EC2 ==================== fk-windows fk-linux no 処理を中断しました。 #
EC2へSSH
※パブリックIPが付与されている前提です。(EIPは不要)
Nameタグを指定してEC2へアクセス
# ./ec2-action.sh -h fk-linux ssh Last login: Sat Jan 28 23:58:26 2023 from m106073017192.v4.enabler.ne.jp __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-10-88-0-59 ~]$
Nameタグ,ユーザー名,キーペアを指定してEC2へSSH
# ./ec2-action.sh -h fk-linux -u ec2-user -k fk-test-key.pem ssh Last login: Sat Jan 28 23:58:26 2023 from m106073017192.v4.enabler.ne.jp __| __|_ ) _| ( / Amazon Linux 2 AMI ___|\___|___| https://aws.amazon.com/amazon-linux-2/ [ec2-user@ip-10-88-0-59 ~]$
EC2へRDP
※パブリックIPが付与されている前提です。(EIPは不要)
Nameタグ,ユーザー名,キーペアを指定してEC2へRDP
# ./ec2-action.sh -h fk-windows -u administrator -k fk-test-key.pem rdp #
※RDPの処理はWindowsのコマンドを利用しています。
/mnt/c/WINDOWS/system32/cmdkey.exe /generic:TERMSRV/${PUBLIC_IP} /user:${OSUSER} /pass:${WIN_PASS} >> /dev/null 2>&1 /mnt/c/WINDOWS/system32/mstsc.exe /v:${PUBLIC_IP} & sleep 3 cmdkey.exe /delete:TERMSRV/${PUBLIC_IP} >> /dev/null 2>&1
スクリプト(ec2-action.sh)の中身
#!/bin/bash TMP="/tmp/ec2-action.tmp" ## オプションのデフォルト設定 KEY_DIR="/mnt/c/Users/serverworker/Desktop/wsl-root/4_key-pea" KEY="${KEY_DIR}/fk-test-key.pem" OSUSER="ec2-user" RDP_OSUSER="administrator" HOST="" PROFILE="kensho" ## スクリプトの引数チェック関数 function option_check { case ${1} in ssh | rdp ) if [[ -z ${OSUSER} ]] || [[ -z ${KEY} ]] || [[ -z ${HOST} ]] ; then echo "-hを指定する必要があります。" echo "また、-kでキーペアを指定、-uでOSユーザを指定できます。" exit 9 fi;; start | stop | status ) if [[ -z ${HOST} ]] && [[ -z ${MODE} ]] ; then echo "-aまたは-hがオプションが必要になります。" exit 9 fi;; * ) if [[ -z ${2} ]] ; then echo "${1}に値を設定してください。" exit 9 fi;; esac } ## EC2にSSHまたはRDPする関数 function os_access { PUBLIC_IP=$(\ aws ec2 describe-instances \ --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=${HOST}" \ --query "Reservations[].Instances[].NetworkInterfaces[].PrivateIpAddresses[].Association[].PublicIp" \ --output text\ --profile ${PROFILE}) INSTANCE_ID=$(\ aws ec2 describe-instances \ --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=${HOST}" \ --query "Reservations[].Instances[].InstanceId" \ --output text \ --profile ${PROFILE}) WIN_PASS=$(aws ec2 get-password-data \ --instance-id ${INSTANCE_ID} \ --priv-launch-key ${KEY} \ --query "PasswordData" \ --output text \ --profile ${PROFILE}) if [[ ${ACTION} == ssh ]] ; then ssh -i ${KEY} -l ${OSUSER} ${PUBLIC_IP} elif [[ ${ACTION} == rdp ]] ; then OSUSER=${RDP_OSUSER} /mnt/c/WINDOWS/system32/cmdkey.exe /generic:TERMSRV/${PUBLIC_IP} /user:${OSUSER} /pass:${WIN_PASS} >> /dev/null 2>&1 /mnt/c/WINDOWS/system32/mstsc.exe /v:${PUBLIC_IP} & sleep 3 cmdkey.exe /delete:TERMSRV/${PUBLIC_IP} >> /dev/null 2>&1 fi } ## EC2を起動または停止する関数 function ec2_action { INSTANCE_ID=$(\ aws ec2 describe-instances \ --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=${HOST}" \ --query "Reservations[].Instances[].InstanceId" \ --output text \ --profile ${PROFILE}) aws ec2 ${ACTION}-instances --instance-ids ${INSTANCE_ID} >> /dev/null 2>&1 } ## EC2の状態を確認する関数 function ec2_status { STATUS=$(\ aws ec2 describe-instances \ --filters "Name=tag-key,Values=Name" "Name=tag-value,Values=${HOST}" \ --query "Reservations[].Instances[].State[].Name[]"\ --output text \ --profile ${PROFILE}) if [[ -z ${HOST} ]] ; then HOST="Nameタグは存在しません。" STATUS="" elif [[ -z ${STATUS} ]] ; then STATUS="左記のNameタグは存在しません。" fi echo "${HOST} ${STATUS}" } ## EC2の一覧を表示する関数 function ec2_list { aws ec2 describe-instances \ --query "Reservations[].Instances[].Tags[?Key=='Name'].Value" \ --output text \ --profile ${PROFILE} } ## スクリプトの引数を変数に入れる処理 while : do case ${1} in -h) option_check ${1} ${2} HOST=${2} ec2_list > ${TMP} if [[ 0 -eq $(echo ${HOST} | grep \, | wc -l) ]] && [[ 0 -eq $(grep ^${HOST}$ ${TMP} | wc -l) ]] ; then echo "${HOST}というNameタグは、存在しません。" exit 9 else for H in $(echo ${HOST} | tr "," " ") do if [[ 0 -eq $(grep "^${H}$" ${TMP} | wc -l) ]] ; then echo "${H}というNameタグは、存在しません。" exit 9 fi done fi rm ${TMP} shift 2;; -u) option_check ${1} ${2} OSUSER=${2} shift 2;; -k) option_check ${1} ${2} KEY="${KEY_DIR}/${2}" shift 2;; -p) option_check ${1} ${2} PROFILE=${2} shift 2;; -a) MODE=all shift 1;; ssh | rdp | start | stop | status | list | pw) if [[ -z ${FLAG} ]] ; then ACTION=${1} FLAG=0 else ACTION_TMP=${1} echo "アクション([${ACTION}],[${ACTION_TMP}])が2つ指定されています。" exit 9 fi shift ;; *) if [[ ! -z ${ACTION} ]] ; then break else cat << EOF ################################################################### #### #### WARN : EC2のNameタグが付与されていることを前提にしてます。 #### ################################################################### ################################################################### #### #### Usage : ec2-action.sh \${ACTION} \${OPTION} #### ################################################################### case \${ACTION} in ssh ) : SSHアクション rdp ) : RDPアクション start ) : EC2を起動するアクション stop ) : EC2を停止するアクション status ) : EC2の状態を確認するアクション list ) : EC2の一覧を表示するアクション case \${OPTION} in -h \${1} ) : ホスト(EC2のNameタグ)を指定するオプション -u \${1} ) : OSユーザ名を指定するオプション -k \${1} ) : キーペアを指定するオプション -p \${1} ) : aws cliのプロファイル名を指定するオプション -a ) : EC2全台を対象とするで使えるオプション(start,stop,statusアクションで利用可) ※\${1}には、任意の値を指定する。 ################################################################### #### #### Example Usage #### ################################################################### ## EC2の一覧を出力 ec2-action.sh list ## aws cliのプロファイルを指定して、EC2の一覧を出力 ec2-action.sh -a status ## 指定したEC2を起動 ec2-action.sh -h host -u ec2-user -k test-key start ## 全てのEC2の状態を確認 ec2-action.sh -a status ## 指定したEC2にSSH接続 ec2-action.sh -h host -u ec2-user -k test-key ssh EOF break fi;; esac done ## スクリプトの引数のアクションに応じた処理 case ${ACTION} in ssh | rdp) option_check ${ACTION} os_access;; start | stop) option_check ${ACTION} if [[ -z ${MODE} ]] ; then ec2_action else echo "以下のEC2を [${ACTION}] しますが、問題ないですか?(yes or no)" HOST=$(ec2_list | sed '/^$/d' | tr "\n" "," | sed 's/,$//g') cat << EOF ==================== 対象EC2 ==================== $(echo ${HOST} | tr "," "\n") EOF read ANSWER if [[ ${ANSWER} != yes ]] ; then echo "処理を中断しました。" exit 9 fi ec2_action fi;; status) option_check ${ACTION} cat << EOF > ${TMP} ===================== ============ NAME_TAG STATUS ===================== ============ EOF if [[ -z ${MODE} ]] ; then if [[ 0 -lt $(echo ${HOST} | grep \, | wc -l) ]] ; then for H in $(echo ${HOST} | tr "," " ") do HOST=${H} ec2_status >> ${TMP} done else ec2_status >> ${TMP} fi else ec2_list | while read LINE do HOST=${LINE} ec2_status >> ${TMP} done fi column -t ${TMP} rm ${TMP};; list) cat << EOF > ${TMP} ===================== NAME_TAG ===================== EOF ec2_list >> ${TMP} column -t ${TMP} rm ${TMP} esac