搭建私人实体编译服务器

有一台性能较好的台式机(以下简称 H(ome)),希望在离开它的几天内依旧可以继续在其上的工作。这台 H 没有公网 IP,于是购买一台云服务器(以下简称 C(loud)),获得公网 IP。使用 ssh forwarding 将 H 的 ssh 22 端口映射到的 C 的 2222 端口。之后进行开发部署。

另外链接 C 的笔记本电脑(L(aptop))。

以下介绍部署过程,备忘。

1. 云服务器选购

因为云服务器只是跳板机,只需要良好的连通性,几乎无 CPU 和内存需求。本着合(节)适(约)的原则,选择最便宜配置的服务器,选择阿里云 ECS,在购买界面选择“一键购买”。选择最便宜的1 vCPU 1 GiB的机器。因为当前应用只是个人使用,网络传输量小,也没有稳定长时间的流量,所以带宽处选择按使用流量(固定的配置费用减少 40%)。可以调整带宽到 100Mbps,流量价格与 1Mbps 一致,仅需¥0.800/GB

这个选择与 H 相同的镜像,Ubuntu 18.04。

购买成功后,第一次用密码登录,ssh-keygen 生成密钥对。将 H 与 L 的公钥放置到 C 的 ~/.ssh/authorized_keys 文件中。

同时将 C 的公钥放置到 H 的相同位置,方便 C 登录 H。

在 C 的 ~/.ssh/config 中配置 H 的别名,在 L 的 ~/.ssh/config 中配置 H 的别名。各种需要的别名都配置一下,方便后续配置。

~/.ssh/config 的配置如下。

Host H
Hostname localhost
Port 2222
User jingetu

2. SSH forwarding

在 H 上进行 ssh forwarding 将端口映射到 C 上。命令如下。

# 将 H 的 22 端口映射到 C 的 2222 端口
nohup ssh -NR 2222:localhost:22  -o ExitOnForwardFailure=yes -o ServerAliveInterval=10 C &

这个 forwarding 不稳定,后面命令中的 -o ExitOnForwardFailure=yes -o ServerAliveInterval=10 就是用来保活用的。

为了进一步优化,想到用 crontab 按时检查该进程是否存在。所以写了这么一个 python 脚本 auto_ssh.py,检查是否有该进程,如果没有就再执行一次启动。

#!/usr/bin/python

import subprocess
import os

out = subprocess.check_output("ps -ef | grep NR | grep ssh", shell=True)
if "2222:localhost:22" not in out_str:
    os.system("nohup ssh -NR 2222:localhost:22 -o ExitOnForwardFailure=yes -o ServerAliveInterval=10 C &")

这个 ssh 命令应当是非 root 用户执行的,因为是从 C 以正常用户身份登录 H。

crontab 实现定时运行以上脚本,以保活。以正常用户身份输入 crontab -e 进行编辑,添加行 * * * * * python /home/jingetu/auto_ssh.py,表示每分钟执行一次。(关于 crontab 的语法问题,可以通过网站 https://crontab.guru/ 测试,完全不需要记忆 crontab 语法规则。)之后可以使用 crontab -l 查看当前用户的定时任务。

crontab 还有另外一个好处,就是重启机器,crontab 的任务设定依旧存在。所以远程 reboot H,仅需耐心等待 1 - 2 分钟,H 便可自动 forwarding 到 C。

对于重启,还有一些需要设置。1. 在 Settings -> Users 中将当前用户设置成 Automatic Login,重启进入系统无需输出密码;2. H 是双系统,安装一个 Ubuntu 软件 Grub Customizer,调整在 grub 时 Ubuntu 是默认选项。

现在不是很确定以上操作的稳定性。所以还有一种想法是 */30 * * * * killall ssh,每 30 分钟自动断开一次 forwarding,下一分钟会有 auto_ssh.py 脚本自动启动 forwarding。这么做牺牲体验。

3. 开发环境配置

已知 VSCode 有服务器开发功能,可以通过 ssh 修改服务器 C 上的代码。但实际的编译过程应当在 H 上进行,所以就需要做一个代码同步的工作。

3.1. 代码同步

将 H 上的代码整理到 C 的特定位置。安装软件 lsyncd 进行单方向 C -> H 的同步,只要 C 上的目录下有任何变化就会同步到 H 上的目录下。

配置文件 /etc/lsyncd.conf 如下:

settings {
   logfile    = "/tmp/lsyncd.log",
   statusFile = "/tmp/lsyncd.status",
   nodaemon   = true,
   statusInterval = 3
}

sync {
   default.rsync,
   source="/root/code_dir",
   target="H:/home/jingetu/code_dir",
   delay=1,
   exclude={'*.swp', '*.swx', '*~'},
   rsync = {
     archive = true,
     compress = false,
     _extra   = {"--omit-dir-times","-e ssh -i /root/.ssh/id_rsa"}
   }
}

delay=1 表示每隔 1 秒同步一次。C 上的代码目录是 /root/code_dir,H 上的代码目录是 /home/jingetu/code_dir

执行 lsyncd -nodaemon /etc/lsyncd.conf 就可以开启同步。

3.2. VSCode 远程开发

在 L 上,安装 vscode,参考 https://code.visualstudio.com/docs/remote/ssh ,进行配置。也就是安装 vscode 的 extension Remote Development

按操作链接 C,会打开一个新的窗口,按指示打开 C 上的目录 /root/code_dir

然后在 vscode 的底部开启两个 terminal(C 的 terminal).第一个 terminal 执行 lsyncd -nodaemon /etc/lsyncd.conf,前台运行,可以查看 C 到 H 的同步日志。第二个 terminal,执行 ssh H,登录到 H,进行正常的代码修改后的编译、运行工作。

注意,不要在 lsyncd 没有启动的时候,修改服务器上的代码。因为同步是按事件触发的,修改的事件没有被 lsyncd 记录下来,没有同步会造成两处代码不同步。

执行完以上操作就可以开始在 L 的 vscode 窗口写代码。

4. 保活

4.1. WiFi 保活

H 上设置以下脚本 crontab,自动连接 WiFi。第二次检查 ifconfig,如果没有链接上,有可能是网卡没有挂载上,重启一般能挂载上。

#!/usr/bin/python3

import subprocess
import os

content = subprocess.check_output('nmcli radio wifi', shell=True).decode()

if 'disable' in content:
    os.system('nmcli radio wifi on; sleep 5; nmcli c up id TP-LINK_403')

content = subprocess.check_output('nmcli radio wifi', shell=True).decode()

if 'disable' in content:
    os.system("sudo /sbin/shutdown --reboot now")

4.2. 睡眠

有些时候可以将 H 进入到睡眠状态,在睡眠状态无 WiFi 链接,所以 C 就不能控制 H 从睡眠状态中恢复回来。可以在睡眠之前先设定恢复时间,这个恢复由 BIOS 控制,所以时间是 BIOS 时钟(Real Time Clock)的时间。以下是睡眠 3600 秒之后恢复。

sudo rtcwake -m disk -s 3600

睡眠命令如下。(记得这个命令需要谨慎使用,不要一睡不醒,可以可以查看一下 rtcwake 每天固定时间恢复,这样就可以保证最多睡 24 小时。)

systemctl suspend

4.3. ssh

在 C 上清理使用 2222 端口的进程(有些时候会重复链接)。

kill $(lsof -t -i tcp:2222)

4.4. 关机又重启

https://askubuntu.com/questions/111907/automatic-reboot-after-power-failure

sudo vim /etc/default/grub
GRUB_RECORDFAIL_TIMEOUT=0

以上的代码同步并不是一个很好的方法,可以直接用 sshfs 在 C 上挂载 H 的目录。再从 L 上挂载 C 的目录。(macOS 安装 sshfs 有点问题,所以对于代码目录,可以直接挂载在 C 上,再从 L 上选择 VSCode 远程开发
。)

mkdir ~workspace && sshfs -o allow_other,default_permissions H:workspace ~/workspace
posted @ 2020-08-09 20:42  JingeTU  阅读(3878)  评论(0编辑  收藏  举报