Photoruction工事中!

Photoructionの開発ブログです!

シェルスクリプトを使用してEC2を操作する

はじめに

今年も赤や白の梅の花が咲き乱れ、花粉が舞う季節がやってまいりました。

あいにく、僕はちょっと目が痒いくらいで済んでます(症状がひどい方、すみません)。

まったく関係ありませんが、3回目のワクチンの副反応もちょっと体がだるいなくらいで済みました。(良いのか悪いのかわかりませんが)

こんにちは、AIエンジニアの山下です。

さて、今回はシェルスクリプト初心者の僕がシェルスクリプトを使用しAmazonEC2を操作することを目的とした記事になります。

普段の業務でシェルスクリプトを書くことはほとんどなく、なぜシェルスクリプトを書こうと思ったかというとAmazonEC2を扱うことがあり、毎回AWSのコンソールから操作するのは面倒だし、AWS CLIコマンドラインインターフェイス)で行うにしても毎度毎度調べるのもどうかと思い、シェルスクリプトにまとめたら使いやすいのではと思いまとめてみました。

今回初めて0から書くうえで普段使うVScodeでなくVim使ってみたり、Linux screenを使ってみるなど初めてなことが多く刺激的でした(ただ、シェルスクリプトは業務で使うことは少なそう、、、)。余談ですが、Vimはやりがいがありそうで今後取り入れてみてVScodeと比較してみたいです。

*OSはMac

おさらい

シェルスクリプトとは

AWS CLIコマンドラインインターフェイス)とは

シェルスクリプト実行例

$ ./launch_ec2_instance.sh status
stopped

前提

以下、作成物→簡単な内容説明となります

作成物:その1

*前提としては EC2上にはインスタンスができている状態です

#!/bin/zsh

# set aws profile
PROFILE=default

# Get instance name: yamashta-devのinstance ids
INFOS=(InstanceId ImageId Keyname InstanceType \\
PublicIpAddress PublicDnsName State.Name)

# Define Function
function get_instance_info() {
    aws ec2 describe-instances \\
    --filters "Name=tag:name,Values=yamashita" \\
    --profile $PROFILE \\
    --query 'Reservations[*].Instances[*].'[$1]'' | jq -r '.[][][]'
}

IDS=`get_instance_info InstanceId`
# echo IDS: $IDS
DNS=`get_instance_info PublicDnsName`

# インスタンスの各情報を習得
if [ "$1" == "infos" ]
then
    select info in ${INFOS[@]}
    do
        echo `get_instance_info $info`
        break;
    done

elif [ "$1" == "status" ]
then
    echo `get_instance_info State.Name`

elif [ "$1" == "start" ]
then
    aws ec2 start-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "stop" ]
then
    aws ec2 stop-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "terminate" ]
then
    aws ec2 terminate-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "connect" ]
then
    ssh -i "~/.ssh/yamashita-rsa.pem" ec2-user@$DNS

elif [ "$1" == "file_transfer" ]
then
    # ローカルの任意のファイル($2: file path)をインスタンスに転送 -> :/home/ec2-user/
    scp -i ~/.ssh/yamashita-rsa.pem $2 ec2-user@$DNS:$3

elif [ "$1" == "reboot" ]
then
    aws ec2 reboot-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "transfer_file_locally" ]
then
    # インスタンスから任意のファイル($2: file path)をローカル($3)に転送
    # $2: file path, $3: local path
    scp -i ~/.ssh/yamashita-rsa.pem ec2-user@$DNS:$2 $3

else
    echo "Usage: $0\\ninfos | status | start | stop | terminate | connect | \\
file_transfer | reboot | transfer_file_locally"
fi
  • 上から簡単に内容を説明していきます。
#!/bin/zsh
  • これはスクリプトの一行目に記述する定型文で、この一行目で、実行時どのシェルでスクリプトを実行するかが決まります(bashなら #!/bin/bashとか)
# set aws profile
PROFILE=default
# Get instance name: yamashta-devのinstance ids
INFOS=(InstanceId ImageId Keyname InstanceType \\
PublicIpAddress PublicDnsName State.Name)
# Define Function
function get_instance_info() {
    aws ec2 describe-instances \\
    --filters "Name=tag:name,Values=yamashita" \\
    --profile $PROFILE \\
    --query 'Reservations[*].Instances[*].'[$1]'' | jq -r '.[][][]'
}
IDS=`get_instance_info InstanceId`
# echo IDS: $IDS
DNS=`get_instance_info PublicDnsName`
# インスタンスの各情報を取得
if [ "$1" == "infos" ]
then
    select info in ${INFOS[@]}
    do
        echo `get_instance_info $info`
        break;
    done
elif [ "$1" == "status" ]
then
    echo `get_instance_info State.Name`

elif [ "$1" == "start" ]
then
    aws ec2 start-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "stop" ]
then
    aws ec2 stop-instances --instance-ids $IDS --profile $PROFILE

elif [ "$1" == "terminate" ]
then
    aws ec2 terminate-instances --instance-ids $IDS --profile $PROFILE
elif [ "$1" == "connect" ]
then
    ssh -i "~/.ssh/yamashita-rsa.pem" ec2-user@$DNS
  • 引数に 「connect」 を指定するとローカルのターミナルから起動しているインスタンスSSH接続する。(DNSに関してはこちら
elif [ "$1" == "file_transfer" ]
then
    # ローカルの任意のファイル($2: file path)をインスタンスに転送 -> :/home/ec2-user/
    scp -i ~/.ssh/yamashita-rsa.pem $2 ec2-user@$DNS:$3
  • 第一引数に 「file_transfer」 を指定する場合はローカル上にある任意のファイルをインスタンス上の指定したパスに転送する。第2、第3引数にパスの指定が必須。
    • 第2引数:ローカルのファイルパスを指定
    • 第3引数:インスタンス上のパス(ファイルを置きたい場所)
elif [ "$1" == "reboot" ]
then
    aws ec2 reboot-instances --instance-ids $IDS --profile $PROFILE

		elif [ "$1" == "transfer_file_locally" ]
then
    # インスタンスから任意のファイル($2: file path)をローカル($3)に転送
    # $2: file path, $3: local path
    scp -i ~/.ssh/yamashita-rsa.pem ec2-user@$DNS:$2 $3
  • 引数に「transfer_file_locally」を指定するとインスタンスの任意のファイルをローカルの任意の場所に転送します。第2、第3引数にパスの指定が必要になります。
    • 第2引数:インスタンス上の任意のファイルパス
    • 第3引数:ローカル上の任意のパス(ファイルを置きたい場所)
else
    echo "Usage: $0\\ninfos | status | start | stop | terminate | connect | \\
file_transfer | reboot | transfer_file_locally"
  • 最後に第1引数を指定せずに実行すると指定可能な引数を教えてくれます

    f:id:photoruction_tech_blog:20220315140419p:plain

作成物:その2

長くなるので詳細な説明は省くうえに、まだ作成途中ですが、以下ではローカルからCLIを利用し、AWS ECRでrepsitoryの作成、または、ECRにログインできるようにしてます。(最終的にはローカルでビルドしたDockerイメージをECRにプッシュ、EC2インスタンスにpullし、コンテナを起動できるようなシェルスクリプトにする予定です。)

  • readコマンドでAWS CLIのプロファイル名を入力
  • ECRのログインIDを取得
  • ECRにログイン、または、repositoryを作成
#!/bin/bash

read -p "input profile name! " str

aws_account_id=`aws sts get-caller-identity --query 'Account' --output text --profile="$str"`
echo aws_account_id: $aws_account_id

select var in login create_repo Usage

do
    if [ "$var" == "login" ];then
    	aws ecr get-login-password --region ap-northeast-1 --profile "$str" | docker login --username AWS --password-stdin "$aws_account_id".dkr.ecr.ap-northeast-1.amazonaws.com
	
	elif [ "$var" == "create_repo" ];then
		read -p "input repository name! " r_name
    	# $r_nameにrepository-nameが必要
	    aws ecr create-repository \\
	    --repository-name "$r_name" \\
	    --image-scanning-configuration scanOnPush=true \\
	    --region ap-northeast-1 \\
	    --profile "$str" 

	elif [ "$var" == "Usage" ];then
        echo "Usage: login | create_repo"
    fi
    break
done

感想

  • 記事を書きながら思ったんですが、作成物:その1に関してはif文よりもselectコマンドとreadコマンドを使った方が使い勝手が良かったのではと思いました。
  • 最終的にはローカルでビルドした Dockerイメージを ECRにpush → ECRからイメージをEC2にpull → EC2上にコンテナを起動し、VSCodeからSSH接続するところまでやってみているので、また機会があればその辺りのことを加筆していきたいのと、冒頭でも触れましたが、Vim環境も構築しがいがありそうなので機会があれば記事にしたいと思います。

株式会社フォトラクションでは一緒に働く仲間を募集しています