【5分钟玩转Lighthouse】开车也能跑程序
0x00 背景概述
这两天,工程师小刘时常在自己的笔记本上编译Linux内核。由于编译执行的时间比较长,他通勤时经常需要笔记本部开着盖放在车座上,以便程序不断。他奋斗的场景让人甚是同情,因为我上大学时也是通宵开着笔记本编译内核,不敢锁屏更怕断电断网。
那么到底该如何优雅地在开车(骑车/游泳/喝奶茶)时依然保证程序运行不断呢?
解决这个问题的终极解决方案就是:在云服务器上执行需要长时间执行的程序。不论是长时间的计算任务、编译内核、训练模型、还是运行各类的小型网络服务程序等等,只要你有云服务器,这些都可以一站式解决。
那么,让我们首先在腾讯云创建一台可以把玩的云服务器吧!
(当然,如果你已经有了一台可以远程登录并使用的云服务器,可以直接跳过下一节,直接开始运行程序的初体验~)
0x01 服务器准备
服务器的选择其实有很多种:不过作为Lighthouse的体验教程,当然还是选用咱们的主角:腾讯云轻量应用服务器(Lighthouse)。当然也可以用CVM(云服务器)产品等。
Lighthouse实例是当下最流行最方便的创建云主机方式,一起体验下吧~
购买机器
下图是Lighthouse的创建页面,到这里选择一款喜欢的吧->
这里我们创建一台香港地域的镜像为Ubuntu 20.04LTS版本的实例,这是Ubuntu最新的LTS(长期维护)版本,可以体验更多新特性,后续我们也会在这个系统上做些简单实验。套餐选择上,可以根据自己的需求选择,本教程以4核的套餐举例。可以感到相当清简的购买流程,需要输入实例名称并选择下时长即可,购买体验非常流畅。
我们创建完成后,可以在实例列表页面看到实例状态,当实例状态为运行中
时,点击更多
->管理
即可进入管理页面了。我们将在管理页面为我们的Lighthouse主机重置密码,以方便后续的SSH登录。
重置密码
Lighthouse实例默认仅能从腾讯云控制台免密登录(本质是使用了默认密钥),为了可以后续通过SSH命令进行代理访问,最方便的方法是通过密码登录。
我们需要为我们的实例重置密码,可以在控制台的实例详情页面完成此类操作。
我们通过“指定用户名”更新lighthouse用户的密码,即可。
注意:此步骤需要重启实例。然后即可通过SSH客户端软件验证密码登录了。
另外:这里也完全可以选择为其他(已创建的)用户更新密码。
0x02 初体验
首先需要明确,通过在程序命令后添加&
执行是完全达不到效果的,因为这只是设置再当前shell中后台运行而已,程序的进程仍然是当前shell的子进程,在当前shell退出(如Ctrl+D或断网时)我们的进程还是会被杀掉。我们需要的是真正的后台运行,达到在连接断开时还能继续执行的目的。
介绍两个最简单的命令,作为一针见效的体验~
setsid
setsid
命令的作用是:在一个新的会话运行程序。它可以打开一个新的会话并把它关联到一个进程。这样运行的程序自然和当前的shell会话进程无关了,也不会受其进程生命周期的管理。通过setsid执行程序是后台运行某个程序的最简单的方式之一。
brooke@VM-0-6-ubuntu:~$ setsid dd if=/dev/zero of=/dev/null bs=1M
brooke@VM-0-6-ubuntu:~$ ps -ef | grep "dd if"
brooke 188655 1 99 10:06 ? 00:00:15 dd if=/dev/zero of=/dev/null bs=1M
brooke 188691 188289 0 10:06 pts/1 00:00:00 grep --color=auto dd if
brooke@VM-0-6-ubuntu:~$
可以看到,我们的程序(dd
命令)的进程被1号进程收养了,即便当前shell退出,也依然会继续执行。注意,这里的ps
命令一定要加-ef
选项,才能看到整个服务器的全部进程,否则只能看到当前shell会话的进程,是无法列出dd进程的。
nohup
nohup
+ &
的组合也可达到类似的效果。
brooke@VM-0-6-ubuntu:~$ nohup dd if=/dev/zero of=/dev/null bs=1M &
[1] 189691
brooke@VM-0-6-ubuntu:~$ nohup: ignoring input and appending output to 'nohup.out'
brooke@VM-0-6-ubuntu:~$ ps -ef | grep "dd if"
brooke 189691 188289 99 10:13 pts/1 00:00:06 dd if=/dev/zero of=/dev/null bs=1M
brooke 189704 188289 0 10:13 pts/1 00:00:00 grep --color=auto dd if
brooke@VM-0-6-ubuntu:~$ logout
# 重新登录
brooke@VM-0-6-ubuntu:~$ ps -ef | grep "dd if"
brooke 189691 1 99 10:13 ? 00:00:21 dd if=/dev/zero of=/dev/null bs=1M
brooke 189836 189820 0 10:13 pts/0 00:00:00 grep --color=auto dd if
注意,第一次执行的时候并不会马上成为1号进程的子进程,但会话退出时就会被托管了。再次登录后可以验证。
0x03 tmux工具
tmux简介
tmux(terminal multiplexer)是一个终端分屏工具,它可以很方便地进行服务器端多窗口地管理。tmux有几个小概念:
- 会话(session):即一次tmux的登录会话,一个会话的全部窗口都关闭了会话结束
- 窗口(window):一个会话下会有多个窗口,有点类似浏览器里的Tab,同一时间只能一个窗口可见
- 窗格(pane):一个窗口可以再分成多个小窗格,即窗口里那些能看到的横竖的最小分屏单元
一次tmux会话大致如下图,红色标记这当前的窗口,蓝色标记了一个工作窗格:
这里重要的点在于:它的连接会话都保存在服务器端,每个tmux会话可以从屏幕终端分离解绑(detach),后续如果需要,可以随时在将这个进行中的会话绑定(attach)到任何新的屏幕终端,即恢复。当因为网络不稳定、或者客户端主动断开时,tmux仅仅会解邦当前的会话终端,而该会话下的所有运行中的程序不会有任何影响。
tmux操作
你可以通过man tmux
了解到绝大部分tmux操作命令,这里我们简单举些例子,如:
# 列出进行中的会话
tmux list-sessions
# 绑定至某一会话,即恢复会话
tmux attach
# 或更简单地: tmux a
tmux会话内部的操作通常是用前缀键(默认时ctrl+b)加上命令键组合完成的。如想从detach当前窗口,先同时按下ctrl
和b
键,松手,再按下d
键即可。
tips: 更改前缀组合键可以在用户主目录的.tmux.conf文件中设置,如改前缀为ctrl+g
set-option -g prefix C-g
列举几个tmux常用的操作:
- 新建窗口:prefix + c
- 删除窗口:prefix + x(其实通常用直接Ctrl+D退出方便,但是当程序卡住无法Ctrl+D时,就很有用了)
- 下一窗口:prefix + n
- 上一窗口:prefix + p
- 切换到copy模式:prefix + [ (可以支持翻页,用于看日志很方便,退出按q即可)
- 垂直分屏:prefix + %
- 水平分屏:prefix + "
- 选择分屏:prefix + 方向键
0x04 示例:编译Linux内核源码
这一章节,我们以一个示例演示tmux是如何帮助我们在服务器上安心地执行命令的。
编译Linux内核的过程通常是冗长的,对于一般的笔记本通常要数个小时,虽然在云服务器上可以加速,但也是一个相当长时间的任务。这类工作很适合结合tmux这类终端会话工具来完成。我们开始~
下载源码
首先,下载解压内核源码:
sudo apt install linux-source-5.4.0
mkdir kernel
cd kernel
tar -xaf /usr/src/linux-source-5.4.0.tar.bz2
cd linux-source-5.4.0
(可选)你可以尝试修改一些内核代码, 比如加些自己的测试标识日志之类的。
然后是配置:我们直接复制当前系统地配置。当然(可选地)如果你是高端玩家,也完全可以通过make menuconfig
来细粒度地调整选择每一个kernel配置项。
cp /boot/config-5.4.0-48-generic .config
内核编译
接下来,我们开始编译:
time make -j4 bindeb-pkg LOCALVERSION=-custom KDEB_PKGVERSION=$(make kernelversion)-$(date +%Y%m%d)
time
命令用于结束后输出程序的运行时长,-j4
是指定4个线程并行编译,可以更高效地利用多核CPU。编译内核时的截图如下。注意到,我们这里还用了tmux的水平分屏功能,右边展示了top
命令地结果,可以看到4个核心都在满负荷地工作。
此时编译开始,各种CC命令开始刷屏。由于我们所有的操作都是在tmux的终端下操作,得益于其服务器端会话保持的功能,我们完全不用担心SSH客户端连接断了导致服务器端的程序/命令执行有任何影响,可以直接关闭SSH客户端,或者(更优雅些)ctrl+b d
解邦终端后退出ssh登录会话,都可以高枕无忧。
你可以安心地合上笔记本,开车出发,约上朋友去尽情地感受这个秋天的第N杯奶茶的浓郁与浪漫吧~
而你73分钟后回来,重新连上服务器tmux -2 a
,会发现一切尽在掌控,如下图所示:
新内核安装
编译完成后,可以看到父目录出现了几个deb安装包:分别是新内核的headers包、image包、带调试信息的image包以及用户空间library的安装包。
我们通过dpkg -i
命令:
sudo dpkg -i ../linux-image-5.4.60-custom_5.4.60-20201013_amd64.deb
就可以像安装普通deb包那样容易地,直接将新内核的vmlinuz、initrd等系统内核启动所需地文件解压至/boot目录。Debian系统这点做得的确是非常的方便和人性化。
最后一步:reboot服务器后登录。我们可以看到内核已经升级到我们刚刚最新编译安装的5.4.60-custom版本了,如图:
至此,任务结束~
0x05 小结
看到这里,相信你已经熟悉了通过常用的screen/tmux等终端会话保持工具,或者通过setsid等方法让你的程序长时间地运行在云服务器上了。
从表现上看起来,这样运行着的程序已经非常接近后台常驻地服务程序(daemon program/service)了,还有很多更加功能强大的工具,如systemd、pm2、docker等,可以帮助我们daemon化一个应用程序。从工程实践地角度看,这些工具能更好地帮我们管理云服务器上的各类后台服务,我们在后续的教程中还会根据各类场景进行针对性地讲解。
最后,祝你玩地愉快,并在Lighthouse实例跑上越来越多的程序,提升工作地效率,然后尽情地开车去远方吧!
0x06 参考资料
- 腾讯云轻量级应用服务器
- 腾讯云云服务器产品
- setsid(1) Linux manual page
- GNU Screen wiki
- tmux mannual page
- tmux github wiki
- Compile Kernel with Kali Linux
- 我的第一次ChIP-seq实践
- SparkStreaming窗口操作
- 史上最全Git使用手册
- 我所理解的 PHP Trait
- 算法 | 数据结构常见的八大排序算法
- 高通量数据下载还能这样操作?
- ofbiz实体引擎(八) 创建表
- ofbiz实体引擎(七) 检查数据源
- ofbiz实体引擎(六) GenericHelper的初始化创建
- ofbiz实体引擎(五) ModelGroupReader
- HBitcoin:C#高级比特币钱包库 - 保护您的财产安全
- ofbiz实体引擎(四) ModelReader的作用
- ofbiz实体引擎(三) GenericDelegator实例化的具体过程
- 机器学习实战 | 第五章:模型保存(持久化)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Python通讯录作业
- 振兴杯试题分析:制作简单的登陆页(一)
- Python作业:BMI评估
- Python笔记
- JavaScript 技术篇-chrome利用ClipboardEvent写入剪切板,没成功的你就差一步
- 搭建一个高可用负载均衡的集群架构(第三部分)
- C语言学习笔记
- JavaScript 技术篇-js获取窗口标题名,获取页面URL地址
- Pyhon海龟绘制木叶村徽章
- MIT大神写给女神的Q版Python画图库—Cutecharts【技术创作101训练营】
- JavaScript 技术篇-js创建dom节点,并设置属性
- 容器中的数据管理
- Java基础 方法
- Python 技术篇-pyperclip库实现读取写入剪切板,超简单
- 基于consul的Docker-overlay跨多宿主机容器网络