はじめに
今年も赤や白の梅の花が咲き乱れ、花粉が舞う季節がやってまいりました。
あいにく、僕はちょっと目が痒いくらいで済んでます(症状がひどい方、すみません)。
まったく関係ありませんが、3回目のワクチンの副反応もちょっと体がだるいなくらいで済みました。(良いのか悪いのかわかりませんが)
こんにちは、AIエンジニアの山下です。
さて、今回はシェルスクリプト初心者の僕がシェルスクリプトを使用しAmazonEC2を操作することを目的とした記事になります。
普段の業務でシェルスクリプトを書くことはほとんどなく、なぜシェルスクリプトを書こうと思ったかというとAmazonEC2を扱うことがあり、毎回AWSのコンソールから操作するのは面倒だし、AWS CLI(コマンドラインインターフェイス)で行うにしても毎度毎度調べるのもどうかと思い、シェルスクリプトにまとめたら使いやすいのではと思いまとめてみました。
今回初めて0から書くうえで普段使うVScodeでなくVim使ってみたり、Linux screenを使ってみるなど初めてなことが多く刺激的でした(ただ、シェルスクリプトは業務で使うことは少なそう、、、)。余談ですが、Vimはやりがいがありそうで今後取り入れてみてVScodeと比較してみたいです。
*OSはMac。
おさらい
シェルスクリプトとは
- OS(オペレーティングシステム)を操作するためのシェル(zsh、bashなど)上で実行できる簡易なプログラミング言語(スクリプト言語)。
- また、そのような言語によって書かれた、複数のOSコマンドや制御文などを組み合わせた簡易なプログラム。一般的にはLinuxなどUNIX系OSのシェルで実行できるものを指す。
AWS CLI(コマンドラインインターフェイス)とは
シェルスクリプト実行例
$ ./launch_ec2_instance.sh status
stopped
前提
- AWS CLIの設定は済んでいる。
- EC2上にはインスタンスができている。
以下、作成物→簡単な内容説明となります
作成物:その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
# set aws profile
PROFILE=default
- aws CLIを利用する際にプロファイルの切り替えを行いたいのでprofile-nameをPROFILEという変数に代入。(この変数は後で使います、参考:AWS CLIを利用するメリットと導入方法)
# 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 '.[][][]'
}
- インスタンスのステータスを確認するための関数を定義してます。
- (参考:Amazon EC2 インスタンスの起動、一覧表示、および終了)
- *
$1
はシェルスクリプトを実行する際の一番目の引数
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
- 第一引数に 「file_transfer」 を指定する場合はローカル上にある任意のファイルをインスタンス上の指定したパスに転送する。第2、第3引数にパスの指定が必須。
- 第2引数:ローカルのファイルパスを指定
- 第3引数:インスタンス上のパス(ファイルを置きたい場所)
elif [ "$1" == "reboot" ]
then
aws ec2 reboot-instances --instance-ids $IDS --profile $PROFILE
- 引数に 「reboot」 を指定するとインスタンスを再起動します
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引数を指定せずに実行すると指定可能な引数を教えてくれます
作成物:その2
長くなるので詳細な説明は省くうえに、まだ作成途中ですが、以下ではローカルからCLIを利用し、AWS ECRでrepsitoryの作成、または、ECRにログインできるようにしてます。(最終的にはローカルでビルドしたDockerイメージをECRにプッシュ、EC2インスタンスにpullし、コンテナを起動できるようなシェルスクリプトにする予定です。)
#!/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環境も構築しがいがありそうなので機会があれば記事にしたいと思います。
株式会社フォトラクションでは一緒に働く仲間を募集しています