问题描述

大家可能和我一样,平时在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. 在 Spring Boot 中使用 Flyway

    一.Flyway 介绍 Flyway 是一个开源的数据库迁移工具,MySQL, SQL Server, Oracle 等二十多种数据库 在 Flyway 中数据库的所有改变均称为迁移(migratio ...

  2. Fiddler 4 对app接口抓取

    一.先打开模拟器 二.在Fiddler 4 选项中修改端口号和去掉一个勾选 三.在终端查看ip 输入ipconfig 四.点开模拟器的设置 五.点击WLAN 六.长按网络,修改网络 七.输入ip端口号 ...

  3. Java读书计划和分享

    写在前面 为什么要写这些呢? 接触java已经有三年多了,感触颇多,比如从0到60,只要勤实践.勤思考,很快就可以入门,从60分到满分极致,则单单不是凭借工作年限或者什么就可以.曾经也有过一段迷茫时期 ...

  4. Python中sorted(iterable, *, key=None, reverse=False)函数参数定义中的独立星号(*)的含义

    老猿在 <Python中函数的参数带星号是什么意思?>中介绍了Python函数中参数带星号的含义,而在实际使用和Python的标准文档中,会看到某写函数(如sorted(iterable, ...

  5. PyQt(Python+Qt)学习随笔:布局控件layoutStretch属性

    在Qt Designer中布局控件有4个,分别是Vertical Layout(垂直布局).Horizontal Layout(水平布局).Grid Layout(网格布局).Form Layout( ...

  6. JVM 垃圾回收?全面详细安排!

    写在前面: 小伙伴儿们,大家好!今天来学习Java虚拟机相关内容,作为面试必问的知识点,来深入了解一波! 思维导图: image-20201207153125210 1,判断对象是否死亡 我们在进行垃 ...

  7. Redis整合MySQL和MyCAT分库组件(来源是我的新书)

    MyCAT是一个开源的分布式数据库组件,在项目里,一般用这个组件实现针对数据库的分库分表功能,从而提升对数据表,尤其是大数据库表的访问性能.而且在实际项目里,MyCAT分库分表组件一般会和MySQL以 ...

  8. CF1000F One Occurrence

    本题解用于记录一下一个优秀的东西--懒标记. 题解 可以很轻易的想到莫队的做法,但是题目让你输出的是满足条件的一个数,而不是满足条件的数的个数,似乎很难去 \(O(1)\) 转移.这个时候我们的懒标记 ...

  9. deepstrem编译缺少gst/gst.h解决方案

    Deepstream在编译程序的程序的显示缺少gst/gst.h 具体情况是Deepstream运行已编译好的deepstream-app可以正常运行,但对源码编译的时候出现以述情况,初步分析是我们安 ...

  10. Elasticsearch.Net

    今天使用Elasticsearch作开发,很简单的查询,就出现Elasticsearch.Net.UnexpectedElasticsearchClientException异常,看样子像是序列化的异 ...