搭建MC服务器时,我们有多种选择,其中淘宝的面板服租赁业务提供了便捷的搭建方式。可是面板服的自由度极其低下,最多只允许你跑一个基本的Paper或整合包端。
在“突破面板服的桎梏”系列中,我们将探讨如何一步步突破面板服的限制,搭建一个全功能的服务器。本系列难度逐步递增,适合不同水平的服主。
本篇文章为第三期,需要你拥有一定Linux运维知识,掌握Linux常用命令用法。
本文探讨并架设了PM2,以其为守护程序运行MC服务器与Telnet服务器,解决无法方便地访问子服务器的控制台的问题与无法通过Ctrl+C退出程序的赛博灯泡。
推荐阅读:
上一期我们将服务器进程放到后台运行,避免了面板服重启时子服务器跟着重启的问题。但没有守护进程,服务器崩了就只能手动重启了。既然阅读文章的你已经拥有了一定的Linux运维知识,那应该了解守护程序(Daemon)的用处。下面我们就来挑选守护程序以运行我们的MC服务器。
这是老牌的服务管理方式。但我们没有root权限,所以不好使……
Systemd是Init.d的替代品,虽然很多人都不知道,但实际上Systemd是有用户模式的(systemd --user
),藉由此,即便我们没有root权限,也能使用Systemd的功能。
但是我们的极端精简的Ubuntu容器没有Systemd……这些尴尬了。
也许可以用吧,但我不熟……
容器化是未来的趋势。众所周知,Docker需要root权限,但实际上Docker支持rootless模式。像是Podman,作为Docker的竞品,更是开箱即用地支持rootless模式。
但有个问题,不知道你有没有发现:
1 | I have no name!@xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:~$ whoami |
我们当前的用户没有一个用户名!查阅/etc/passwd
发现用户ID为998的用户压根不存在……
1 | I have no name!@xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx:~$ cat /etc/passwd |
“这有什么大不了的!”你想。但事实上有很大的问题,让我们来看看Rootless Docker的核心:RootlessKit的工作原理:
RootlessKit is a Linux-native implementation of “fake root” using user_namespaces(7).
英语好的话,推荐戳上面的链接看看“用户命名空间”的原理。
简单点说,Rootless Docker需求/etc/subuid
和/etc/subgid
应包含至少65536个当前用户的从属UID/GID,但我们的当前用户不存在!/etc/subuid
和/etc/subgid
这两个文件是空的!所以,不行,忘了Docker吧。
如果非常幸运地,你的面板服中的/etc/subuid
和/etc/subgid
文件已经配置好了,那么恭喜你,你可以使用Rootless Docker了。详见官方教程。
PM2是一个以JavaScript编写的进程管理器,以AGPLv3开源于GitHub,主要适用于Node.js应用程序,但也可以用于其他类型的应用程序,比如我们的Minecraft服务器。
此方法经本人尝试完全可行,下面详细讲解。
参考PM2官方文档。
Node是主流,但这里我们采用更快且支持单二进制文件的Bun。在Releases中下载bun-linux-x64.zip,解压后放到~/bin
目录下,将~/bin
添加到$PATH
就能用了。
如果你的系统不允许你修改
~/.bashrc
,可以尝试~/.profile
。我给
~/.bashrc
和~/.profile
创建了一个硬链接,这样总是能用。如果都不能用也问题不大,打全名就好了。
为了方便使用Bun,建议在~/bin
目录下创建一个指向bun
,名为node
的符号链接,这样就可以强制使用Node的JS脚本使用Bun了。
1 | bun i -g pm2 |
记得将~/.bun/bin
添加到$PATH
。
以第一期的目录结构为例:
1 | . |
1 | pm2 start java -n velocity --namespace minecraft -- -Xmx1G -jar velocity.jar |
执行pm2 l
:
id | name | namespace | version | mode | pid | uptime | ↺ | status | cpu | mem | user | watching |
---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | creative | minecraft | N/A | fork | 238 | 2M | 0 | online | 0% | 1.2gb | con… | disabled |
2 | survival | minecraft | N/A | fork | 340 | 2M | 0 | online | 0% | 1.0gb | con… | disabled |
0 | velocity | minecraft | N/A | fork | 173 | 2M | 0 | online | 0% | 793.1mb | con… | disabled |
接下来执行pm2 save
将当前进程列表保存到~/.pm2/dump.pm2
,在下次重启时可以通过pm2 resurrect
恢复。
考虑将
pm2 resurrect
加入~/.bashrc
。
如果你想通过pm2 logs
查看日志,你就又陷进了赛博灯泡……我们的客户端不好使,必须要搞一个伪终端(pseudo terminal)才行。
SSH呢?前文提到,你的用户不存在,所以基于用户登录的SSH完全不可用。成熟的连接方案只有Telnet了。
可是Telnet太老了,现阶段已经找不到专门的Telnet服务器了……吗?
隆重介绍Busybox!
如果你折腾过路由器,你大概对Busybox并不陌生。它将多个常用的Unix工具集成在一个可执行文件中,非常适合嵌入式设备。当然我们不是嵌入式设备而是一个容器,但这没关系。Busybox静态链接,非常适合我们的应用场合。
在官方下载站下载最新版构建,解压并扔到~/bin
目录下。运行busybox
可以看到有极其大量的可用功能,其中就有我们想要的telnetd
(太多了,我不放了)。
要怎么使用telnetd
呢?非常简单:创建一个指向busybox
,名为telnetd
的符号链接就可以了。现在输入telnetd -h
,可以看到帮助信息了。
你的容器一般会缺少
pstree
、free
这样的实用功能,而Busybox提供了全套的Linux工具,按照和telnetd
一样的步骤使用即可。
1 | pm2 start telnetd -n telnet --namespace shell -- -Fp 12345 -l bash |
别忘了pm2 save
。
在防火墙中放行端口,使用你本地的telnet客户端连接到<你的面板服IP>:12345
,终于,一个完整的伪终端可以用了,再也不用担心赛博灯泡了!
如果在服务器面板吞下了赛博灯泡,只需在Telnet中
kill -2
赛博灯泡的进程就可以了,简单又方便!
然后你就发现世界上所有人都可以登录你的面板服了,服务器秒变RBQ啊喂……
我们启动Telnetd的指令,通过-l
参数指定在启动时使用bash
,进入bash自然不需要密码。那我们需要在启动时启动一个密码认证程序,认证成功后进入bash就可以了。
1 |
|
将这段代码保存为~/bin/auth.sh
,并赋予可执行权限。将pm2脚本改为:
1 | # 如果你还没输入上面那个指令 |
我们希望服务器面板可以快捷地查看群组服所有服务器的日志,并发送后台命令到各个服务器。但PM2做不到这一点:pm2 logs
只能查看日志无法发送命令,pm2 send
只能发送命令无法查看日志,pm2 attach
虽然既能查看日志也能发送命令,但一次只能服务一个进程。如果有办法将这些功能整合在一起就好了。
所以我就做了pm2-logs-attach-input
,并以Apache 2.0协议开源~
我也向PM2官方提交了PR,不过他们还没理我……
pm2-logs-attach-input
1 | bun i -g pm2-logs-attach-input |
pm2-logs-attach-input
1 | # 不再使用 |
进入交互式界面后,可以实时查看浏览各进程发来的日志。若要发送命令,只需要输入:
1 | velocity glist all |
也就向这些进程输入了想要的命令。
本文解决了以下问题:
pm2-logs-attach-input
就可以了。但又引入了一个新问题:
同时一个旧问题仍然存在:
下一期,我将解决剩余的两个顽疾,敬请期待!
因为没有root权限,系统级包管理器不好使,我们就倾向于使用脚本语言的包管理器。本期安装了JavaScript运行时Bun,如果要安装Python的话,建议安装Conda,如果纯英文看不太懂的话,这里有一篇安装Anaconda的教程。
有一个叫做trash-cli的工具,强烈各位使用。这是一个以Python编写的回收站程序,可替代掉危险的rm
指令。安装完Python后使用pip安装即可。