问题描述

大家可能和我一样,平时在AWS上启动一台安装有Linux EC2实例作为远程开发机。

(注:这里的EC2实例是配置用私钥进行登录的)

通常,你可以选择申请一个Elastic IP绑定到这台开发机上,同时,在本地配置好ssh config的配置文件

  • windows: C:\Users{yourname}.ssh\config
  • Mac\Linux: /home/{yourname}/.ssh/config

节点配置:

  1. Host workstation
  2. HostName {elastic_ip_address}
  3. User ec2-user
  4. Port 22
  5. IdentityFile C:\Users\{yourname}\.ssh\{private_key_name}.pem

然后打开各种终端输入ssh命令,远程连接到EC2 Linux实例

(windows上安装GIT后,就可以使用ssh命令了; Mac\Linux的终端自带ssh命令)

  1. ssh workstation

一般性,不工作的时候,会关闭EC2节省开支。但大家有没有注意到,Elastic IP在没有绑定到EC2实例的空置期是要付费的,虽然付费不多,一个月20多人民币左右,但蚊子肉也是肉啊!哈哈。

妥协的方案是:不绑定Elastic IP, 每次启动完EC2实例后,到AWS Console查看IP地址,接着手动修改ssh config文件,然后用ssh命令连接。

我开始的确就是这么做的,但每天都要来一次,很不爽!秉着Don't repeat yourself 的做事原则,决定自动化整个过程。

思路和解决方案

大体思路是这样的:

  • 用awscli启动远程EC2实例
  • 获取动态IP地址
  • 将IP地址设置到ssh config文件中

封装了一个启动、停止、获取IP 的EC2实例脚本, 保存为 ec2.sh

  1. COMMAND=$1
  2. EC2_NAME=$2
  3. function start() {
  4. local INSTANCE_ID=$1
  5. local EC2_NAME=$2
  6. echo "starting ${EC2_NAME}"
  7. local EC2_STATUS=$(status ${INSTANCE_ID})
  8. if [[ ${EC2_STATUS} != "running" ]]; then
  9. aws ec2 start-instances --instance-ids ${INSTANCE_ID}
  10. aws ec2 wait instance-running --instance-ids ${INSTANCE_ID}
  11. fi
  12. echo "${EC2_NAME} has started"
  13. }
  14. function stop() {
  15. local INSTANCE_ID=$1
  16. echo "stopping ${EC2_NAME}"
  17. aws ec2 stop-instances --instance-ids ${INSTANCE_ID}
  18. aws ec2 wait instance-stopped --instance-ids ${INSTANCE_ID}
  19. echo "${EC2_NAME} has stopped"
  20. }
  21. function status() {
  22. echo $(aws ec2 describe-instances \
  23. --filters "Name=tag:Name,Values=${EC2_NAME}" \
  24. --query 'Reservations[*].Instances[*].[State.Name]' \
  25. --output text)
  26. }
  27. function getInstanceId() {
  28. local EC2_NAME=$1
  29. INSTANCE_ID=$(aws ec2 describe-instances \
  30. --filters "Name=tag:Name,Values=${EC2_NAME}" \
  31. --query 'Reservations[*].Instances[*].[InstanceId]' \
  32. --output text)
  33. echo ${INSTANCE_ID}
  34. }
  35. function restart() {
  36. local INSTANCE_ID=$1
  37. local EC2_NAME=$2
  38. local EC2_STATUS=$(status ${INSTANCE_ID})
  39. if [[ ${EC2_STATUS} = "running" ]]; then
  40. stop ${INSTANCE_ID}
  41. fi
  42. start ${INSTANCE_ID} ${EC2_NAME}
  43. }
  44. function ipAddress() {
  45. local EC2_NAME=$1
  46. ipAddress=$(aws ec2 describe-instances \
  47. --filters "Name=tag:Name,Values=${EC2_NAME}" \
  48. --query Reservations[*].Instances[*].[PublicIpAddress] \
  49. --output text)
  50. echo ${ipAddress}
  51. }
  52. INSTANCE_ID=$(getInstanceId ${EC2_NAME})
  53. case ${COMMAND} in
  54. start)
  55. start ${INSTANCE_ID} ${EC2_NAME}
  56. ;;
  57. stop)
  58. stop ${INSTANCE_ID}
  59. ;;
  60. status)
  61. status ${EC2_NAME}
  62. ;;
  63. restart)
  64. restart ${INSTANCE_ID} ${EC2_NAME}
  65. ;;
  66. ipAddress)
  67. ipAddress ${EC2_NAME}
  68. ;;
  69. *)
  70. echo "wrong command, current supported commands: start, stop, status, restart"
  71. ;;
  72. esac

在Github上找到一个开源项目,可以方便操作ssh config文件,做了轻微修改,用来适配windows的Git Bash,保存为sshconfig

  1. #!/bin/bash
  2. # Copyright (C) 2015 Arash Shams <xsysxpert@gmail.com>.
  3. #
  4. # This program is free software: you can redistribute it and/or modify
  5. # it under the terms of the GNU General Public License as published by
  6. # the Free Software Foundation, either version 3 of the License, or
  7. # (at your option) any later version.
  8. #
  9. # This program is distributed in the hope that it will be useful,
  10. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. # GNU General Public License for more details.
  13. #
  14. # You should have received a copy of the GNU General Public License
  15. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. CONFIGFILE="$HOME/.ssh/config"
  17. TEMPFILE="$HOME/.ssh/.ssctemp"
  18. if [ ! -f $CONFIGFILE ]; then
  19. mkdir -p $HOME/.ssh && touch $CONFIGFILE
  20. fi
  21. is_integer() {
  22. printf "%d" $1 > /dev/null 2>&1
  23. return $?
  24. }
  25. do_check_names() {
  26. grep "^Host" $CONFIGFILE | cut -f2- -d " "
  27. exit 0
  28. }
  29. success() {
  30. printf "\n \033[32mSuccess: %s\033[0m\n\n" "$@"
  31. # exit 0
  32. }
  33. error() {
  34. printf "\n \033[31mError: %s\033[0m\n\n" "$@"
  35. exit 1
  36. }
  37. print() {
  38. printf " \033[36m%10s\033[0m : \033[90m%s\033[0m\n" "$1" "$2"
  39. }
  40. do_add_process() {
  41. if [[ "$#" -eq 6 || "$#" -eq 4 ]]; then
  42. name=$2
  43. username=$3
  44. hostname=$4
  45. if [[ -n $6 ]]; then
  46. id=$5
  47. port=$6
  48. else
  49. port=22
  50. fi
  51. elif [[ "$#" -eq 5 ]]; then
  52. if is_integer $5; then
  53. name=$2
  54. username=$3
  55. hostname=$4
  56. port=$5
  57. else
  58. name=$2
  59. username=$3
  60. hostname=$4
  61. id=$5
  62. port=22
  63. fi
  64. else
  65. error "ssc $1 NAME USERNAME HOSTNAME [IdentityKey] [PORT]"
  66. fi
  67. if [[ $(do_check_names | grep --count "^$name$") != 0 ]]; then
  68. error "This name is already used. Try again with another name."
  69. fi
  70. if [ -n "$id" ]; then
  71. cat << EOB >> $CONFIGFILE
  72. Host $name
  73. HostName $hostname
  74. User $username
  75. Port $port
  76. IdentityFile $id
  77. EOB
  78. else
  79. cat << EOB >> $CONFIGFILE
  80. Host $name
  81. HostName $hostname
  82. User $username
  83. Port $port
  84. EOB
  85. fi
  86. success "\"$name\" added successfuly to host list"
  87. }
  88. do_remove_process() {
  89. if [ "$#" != 2 ]; then
  90. error "Usage : ssc $1 NAME"
  91. fi
  92. name=$2
  93. if [[ $(do_check_names | grep --count "^$name$") != 0 ]]; then
  94. sed -ie "/^Host $name$/,/^$/d" $CONFIGFILE
  95. success "\"$name\" Removed successfully"
  96. # exit 0
  97. else
  98. error "Sorry, \"$name\" is not in list"
  99. fi
  100. }
  101. do_list_process() {
  102. if [ -n "$2" ]; then
  103. name=$2
  104. if [[ $(do_check_names | grep --count "^$name$") != 0 ]]; then
  105. awk -v name="$name" -v green="\033[0;32m" -v reset="\033[0m" -v RS='' 'index($0, name) { for (i = 1; i < NF; i += 2) { printf("%s%s%s: %s%s", green, $i, reset, $(i + 1), (i < NF -2)? " ": "\n") } exit }' $CONFIGFILE
  106. exit 0
  107. else
  108. error "Sorry, \"$name\" is not in list"
  109. fi
  110. else
  111. awk -v name="$name" -v green="\033[0;32m" -v reset="\033[0m" -v RS='' '{ for (i = 1; i < NF; i += 2) { printf("%s%s%s: %s\t%s", green, $i, reset, $(i + 1), (i < NF -2)? " ": "\n") } }' $CONFIGFILE | column -t
  112. fi
  113. }
  114. do_connect() {
  115. name=$1
  116. if [[ $(do_check_names | grep --count "^$name$") != 0 ]]; then
  117. ssh $1
  118. exit 0
  119. fi
  120. }
  121. do_search_process() {
  122. name=$2
  123. ssc ls | grep $name
  124. }
  125. do_edit_process() {
  126. name=$2
  127. if [[ $(do_check_names | grep --count "^$name$") != 0 ]]; then
  128. echo "Now, Enter new values ($(ssc | grep -i add | awk -F"-a" '{print $2}'))"
  129. read new_name user host identity port
  130. do_remove_process remove $name 1>/dev/null
  131. do_add_process add $new_name $user $host $identity $port 1>/dev/null
  132. success "\"${name}\" successfully edited."
  133. else
  134. error "Sorry, \"$name\" is not in list"
  135. fi
  136. }
  137. do_show_usage() {
  138. print "Add" "ssc add/-a NAME USERNAME HOSTNAME [IdentityKey] [PORT] "
  139. print "Edit" "ssc edit/-e NAME"
  140. print "Remove" "ssc remove/-r/rm NAME"
  141. print "List" "ssc list/-l/ls [NAME]"
  142. print "Search" "ssc search/-s NAME"
  143. print "Version" "ssc version/-v"
  144. print "Help" "ssc help/-h"
  145. }
  146. do_show_version() {
  147. print "Version" "Version 1.8 Stable"
  148. print "Contribute" "Fork me at Github <https://github.com/Ara4Sh/sshconfig>"
  149. }
  150. action=$1
  151. case $action in
  152. add | -a)
  153. do_add_process $@
  154. ;;
  155. remove | -r | rm)
  156. do_remove_process $@
  157. ;;
  158. list | -l | ls)
  159. do_list_process $@
  160. ;;
  161. search | -s)
  162. do_search_process $@
  163. ;;
  164. version | -v)
  165. do_show_version
  166. ;;
  167. edit | -e)
  168. do_edit_process $@
  169. ;;
  170. help | -h)
  171. do_show_usage
  172. ;;
  173. *)
  174. do_connect $@
  175. do_show_usage
  176. echo ""
  177. do_show_version
  178. ;;
  179. esac
  180. exit 0

剩下的事情就比较简单了,将以上两个文件拷贝到你的工作目录下,然后写脚本调用:

  1. sh ec2.sh start workstation
  2. ipAddress=$(sh ec2.sh ipAddress workstation)
  3. echo "start to config .ssh/config"
  4. sh sshconfig remove workstation
  5. sh sshconfig add workstation ec2-user ${ipAddress} "C:\\Users\\{yourname}\\.ssh\\{private_key_name}.pem"
  6. echo "done"

VS Code插件

以上脚本在Windows的Git Bash和Mac测试通过,在这里介绍几个好用的插件

  • VS code切换终端的类型

    这个插件,可以让你快速打开不同的类型的终端,例如windows上的cmd, PowerShell, Git Bash
  • 远程连接Linux

    方便连接远程Linux,打开一个文件夹,像编辑本地文件一下编辑远程文件

VS Code 自动化连接非固定IP地址EC2实例的解决方案的更多相关文章

  1. vmware虚拟机下linux centos6.6只有lo,没有eth0网卡、随机分配ip地址,固定ip地址等问题

    这个问题卡了我一天多的时间,百度上搜出来的问题五花八门,反而把我给搞糊涂了.最后总算是实践成功了,记录一下配置的过程. 配置网卡和随机分配ip地址 我安装的是basic server版本,用的是NAT ...

  2. Neutron 理解(5):Neutron 是如何向 Nova 虚机分配固定IP地址的 (How Neutron Allocates Fixed IPs to Nova Instance)

    学习 Neutron 系列文章: (1)Neutron 所实现的虚拟化网络 (2)Neutron OpenvSwitch + VLAN 虚拟网络 (3)Neutron OpenvSwitch + GR ...

  3. 初步学习大数据——设置虚拟机固定ip地址

    1.打开本机的网络连接 2.右键以太网,打开属性. 3.右键VMnet8,打开属性.最多不能超过255,最少不能小于0.    0~255之间. 4.找到你要设置固定IP地址的虚拟机 ,选择上方的编辑 ...

  4. Windows 通过命令行设置固定ip地址

    Winserver1709 之后 windows系统取消了GUI界面 设置ip地址 需要使用命令行界面进行 这里简单记录一下 打开win1709的虚拟机 进入命令行控制台 输入 ipconfig 查看 ...

  5. 如何设置电脑的固定IP地址

    大家在上网时电脑的IP地址往往都是自动选择的,但在局域网内有时会方便共享文件和监控流量等操作时需要固定的IP地址.下面将简单介绍如何手设置电脑的固定IP地址. 百度经验:jingyan.baidu.c ...

  6. win10如何在局域网中设置一台电脑的固定ip地址

    在工作和生活中,经常要遇到远程访问一台电脑的情况,但是在局域网中如果不进行设置,通常一台电脑的ip是自动生成的,,没有固定,这就导致下次访问这个地址时,不能正常访问,下面就交大家如何在win10系统中 ...

  7. VMware Workstation安装CentOs7固定ip地址

    今天发现之前hypervisor配置的CentOs7连接不了了,该死的加密系统和杀毒软件又搞事情了,于是决定试下VMware虚拟机,下载安装后,发现可以连上CentOS7界面,很开心,于是决定把之前的 ...

  8. 在Linux虚拟机中添加多个固定ip地址

    1.右键点击设置2.点击添加,再点击网络适配器,最后点击完成.3.选择完成后的网络适配器,选择仅主机模式.4.用roott身份登录,用nmtui进行设置 systemctl start Network ...

  9. docker固定IP地址重启不变

    docker固定IP地址重启不变 代码地址 https://github.com/lioncui/docker-static-ip 宿主机IP为  10.6.17.12 docker IP为 10.6 ...

随机推荐

  1. Bootstrap Blazor 组件介绍 Table (二)自定义模板列功能介绍

    Bootstrap Blazor 是一套企业级 UI 组件库,适配移动端支持各种主流浏览器,已经在多个交付项目中使用.通过本套组件可以大大缩短开发周期,节约开发成本.目前已经开发.封装了 70 多个组 ...

  2. python将对象写入文件,以及从文件中读取对象

    原文地址: http://www.voidcn.com/article/p-fqtqpwxp-wo.html 写入文件代码: >>> import sys, shelve >& ...

  3. charles的安装

    1:点击安装文件charles-proxy-4.2.8-win64.msi 2:点击下一步 3:勾选同意,点击"next"按钮 4:指定安装的路径,继续点击"next&q ...

  4. dart时间处理的几个方法

    一.时间处理的方法 1.获取当前时间 new DateTime.now(); 2.设置时间 new DateTime(2020, 11, 11, 12, 37 , 36); 3.解析时间 DateTi ...

  5. 【Alpha冲刺阶段】Scrum Meeting Daily6

    [Alpha冲刺阶段]Scrum Meeting Daily6 1.会议简述 会议开展时间 2020/5/27 8:00 - 8:15 PM 会议基本内容摘要 每日汇报 个人进度.遇到的困难.明日的计 ...

  6. 对象存储COS全球加速助力企业出海

    近年来,中国互联网行业迅猛发展,国内庞大的市场孕育出了许多现象级的产品,也锤炼出了非常成熟的产业链.与此同时,很多海外市场还处于萌芽期,存在着巨大的流量红利,越来越多的互联网企业开始加速"出 ...

  7. 斜率优化DP复习笔记

    前言 复习笔记2nd. Warning:鉴于摆渡车是普及组题目,本文的难度定位在普及+至省选-. 参照洛谷的题目难度评分(不过感觉部分有虚高,提高组建议全部掌握,普及组可以选择性阅读.) 引用部分(如 ...

  8. AcWing 316 .减操作

    题目链接 大型补档计划 没想出来去看题解了... 关键是发现无论怎样括号嵌套,每个元素始终只有对答案的贡献为 + a[i] 或者 - a[i]. 而且第一个必然贡献是 +1, 第二个必然是 -1. 所 ...

  9. ab test压力测试

    之前做性能调试的时候一直用的JMeter压测,最近发现一款简单易用的压力测试工具. ab(Apache benchmark)是一款常用的压力测试工具,是Apache附带的一个小工具 , 专门用于HTT ...

  10. Redis达到最大占用内存后的淘汰策略

    1. 查询Redis最大占用内存 # 查询最大占用内存 config get maxmemory # 为0时在64操作系统中不限制内存,在32位操作系统中最大为3GB 2. Redis设置最大占用内存 ...