Skip to content

通过 aws cli 启动和停止 EC2

在 EC2 上预先安装了一些服务,但是这些服务只是偶尔使用以下,所以写了各脚本,在需要的时候启动一下 EC2, 由于没有固定的公网 IP,每次重新启动 EC2,都会随机分配一个公网 IP,所以 ssh 隧道将远端的服务映射到本地的端口, 这样在本机访问的时就可以稳定使用localhost:port来访问了

提前准备

  • 购买 EC2 并允许公网访问

    安全组仅开通 ssh 端口

  • 在 EC2 上安装需要的服务,通过1234暴露出来
  • 创建 IAM 用户,并附加 EC2 的StartInstancesStopInstances策略

    正常情况下应该创建角色,然后将角色赋予用户,这里偷懒了

本机安装 aws cli

注意一定一定要安装最新版本,目前是2.x 官方文档连接:https://docs.aws.amazon.com/zh_cn/cli/latest/userguide/getting-started-install.html

shell
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install

$ aws --version
aws-cli/2.15.30 Python/3.11.6 Linux/5.10.205-195.807.amzn2.x86_64 botocore/2.4.5

配置 aws cli

  • 可以使用 config 命令,一步一步配置
    sh
    $ aws config
  • 也可直接将accessKeySecurit配置到 $HOME/.awx/credentials 文件里
    sh
    [default]  # <--- profile, default是默认的,可以写其他的
    aws_access_key_id = xxxx
    aws_secret_access_key = yyyyyyyyyyyyyyyyyyy

编辑脚本

  • 准备(定义全局变量)
sh
INSTANCESTATE_ID=i-xxxxxxxxxxxx
  • 查看 EC2 实例现在的状态(running / stopping ...)
sh
function show_ec2_system_status() {
    aws ec2 describe-instance-status --instance-id $INSTANCESTATE_ID  --region us-east-2  --output text | grep SYSTEMSTATUS | awk '{print $2}'
}

function show_ec2_instance_status() {
    aws ec2 describe-instance-status --instance-id $INSTANCESTATE_ID  --region us-east-2  --output text | grep INSTANCESTATE | awk '{print $3}'
}
  • 启动 EC2 实例
sh
function start_ec2() {
   aws ec2 start-instances --instance-ids i-0abe9dec58900490a --region us-east-2  2>&1 > /dev/null
}
  • 停止 EC2 实例
sh
function stop_ec2() {
   aws ec2 stop-instances  --instance-ids $INSTANCESTATE_ID  --region us-east-2  2>&1 > /dev/null
}
  • 获取实力对应的公网 IP 地址(xxx.xxx.xxx.xxx)
sh
function retrive_ec2_public_ip() {
   aws ec2 describe-instances --instance-ids $INSTANCESTATE_ID --query "Reservations[*].Instances[*].PublicIpAddress"  --region us-east-2  --output text
}
  • 获取当前状态并打印
sh
# show current status
current_instance_status=$(show_ec2_instance_status)

echo "Current INSTANCE status is: $current_instance_status"
  • 判断启动参数如果是stop,则停止服务并退出
sh
if [ "$1" = "stop" ]; then
   #  ↑
   #  ╰─────────────────────────  第一个参数 如`./script.sh stop` 那么`$1`就是`stop`
   echo "STOP $INSTANCESTATE_ID"
   stop_ec2    # ←────────────────   调用前面定义的函数,停止服务
   show_ec2_status    # ←──────────   调用前面定义的函数,再次打印实例的状态
   exit 0
fi
  • 启动服务
sh
if [ "$current_status" = "running" ]; then   # ←─── 判断实例是不是已经启动了,如果已经启动了就不不动
    echo 'Skip starting service.'
else
    echo "START $INSTANCESTATE_ID"
    start_ec2    # ←───────────────   调用前面定义的函数,启动服务
    show_ec2_instance_status    # ←────   调用前面定义的函数,再次打印实例的状态
fi
  • 获取 IP 并打通隧道
sh
for  i  in  $( seq 1 10)   # ←──────────   因为服务不一定会立刻起来,所以循环10去不断检查是否启动成功了
do
    sleep 8

    system_status=$(show_ec2_system_status)
    echo "$i  Current SYSTEM status is : $system_status"
    if [ "$system_status" != "ok" ]; then   # ←────   系统状态检查
      echo '$i System are not prepared continue sleep.'
      continue
    fi

    IP=$(retrive_ec2_public_ip)    # ←──────────   调用前面定义的函数,获取IP赋给IP
    if [[ -z $IP ]]; then
        echo "$i time(s) faild get ip"
       	continue
    fi
    echo "$i time(s) to success get ip: $IP"   # ←──────────   IP获取成功,打印IP
    # kill old channel if it exist
    for pid in $(ps aux |grep "127.0.0.1:4096:127.0.0.1:8080" | grep -v grep | awk '{print $2}')  # ← 取出旧的PID,循环kill掉
    do
        echo "kill old process $pid"
        kill $pid
    done

    # start
    ssh -o StrictHostKeyChecking=no -CfNg -L 127.0.0.1:5678:127.0.0.1:1234 username@$IP
    #             ↑                   ↑    ↑        ↑             ↑           ╰── 跳板机
    #             │                   │    │        │             ╰── 目标服务IP和端口,因为服务就在跳板机上了,所以IP是127.0.0.1
    #             │                   │    │        ╰── 本地的IP和端口,IP可以省略
    #             │                   │    ╰── 本地端口转发
    #             │                   ╰── C:压缩所有数据   f: 后台执行  N: 不执行远程指令,处于等待状态 g: 允许远程逐渐转发端口
    #             ╰── 忽略know host
    # see: https://github.com/qinshulei/ubuntu-cheat/blob/master/ssh
    echo "Success connect to remote."
    exit 0
done

使用脚本

  • 启动服务 ./script.sh
  • 停止服务 ./script.sh stop

参考