用Docker开个MC服务器

用Docker开个MC服务器

前段时间好好学了下Docker,于是想试着用它去部署一些比较麻烦的服务端。所以首先就是试试MC了,毕竟能实现服务端跟地图数据分离以及服务端自动化部署,便于迁移确实很爽。

虽然MC服务端的性能敏感性比较高,但是Docker+MC的性能问题比较小,因为基于KVM,虚拟化由内核支持,所以Docker性能开销相当小,日用基本可以忽略。

目标

部署好之后,目录下应该只有一个地图文件夹,一个服务端程序,以及一个明确指示了地图文件夹和服务端程序路径的dockerfile。如果使用docker-compose去实现包括mc服务端的外围功能(比如bluemap等地图功能,以及geyser这样的be兼容转换服务端),那也可以,不过得保证数据程序的分离,以及可维护、易于修改的特质。

基于上面的目标,可以使用Volume完成资源的映射。我们需要的只是一个基础的jre镜像。

代码

Dockerfile很简单,就是基础的jre镜像,以及启动指令。

1
2
3
4
5
6
FROM openjdk:17

WORKDIR /app
RUN echo "eula=true" > /app/eula.txt

CMD ["java", "-jar", "server.jar"]

然后是启动脚本,我将几个常用指令封装成一个Bash脚本了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#!/bin/bash

# 获取第一个参数
action=$1

# 根据参数执行不同的操作
case $action in
run) # 运行容器
docker run -d \
-p 25565:25565 \
-v $(pwd)/world:/app/world \
-v $(pwd)/server.jar:/app/server.jar \
-v $(pwd)/server.properties:/app/server.properties \
--name mc \
mc-server
;;
build) # 构建镜像
docker build -t mc-server .
;;
stop) # 停止容器
docker stop mc
;;
start) # 启动容器
docker start mc
;;
restart) # 重启容器
docker restart mc
;;
backup) # 备份文件
timestamp=$(date +%Y%m%d%H%M%S)
zip -r [backup]mc-server-$timestamp.zip world server.properties mc.sh Dockerfile server.jar
;;
log) # 输出日志
docker logs -f mc
;;
sh) # 进入shell
docker exec -it mc sh
;;

*) # 输出帮助信息并退出
echo "Usage: $0 {run|build|stop|start|restart|log|sh}"
exit 1
;;
esac

然后,在保证目录下有server.jarserver.properties的前提下,使用./mc.sh run来初始化并运行服务端。剩下的用法参考上面的代码,或者参考这里

外围

开了服务器之后,肯定需要对公网/内网开放。我在这里用了一个frp的镜像,同样也将它封装为了启动脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash

# 定义容器名称和配置文件路径
CONTAINER_NAME=frpc
CONFIG_FILE=$(pwd)/frpc.ini

# 检查参数个数
if [ $# -eq 0 ]; then
echo "Usage: $0 run|start|stop|restart"
exit 1
fi

# 根据参数执行相应操作
case $1 in
run)
# 部署容器
docker run --restart=always --network host -d -v $CONFIG_FILE:/etc/frp/frpc.ini --name $CONTAINER_NAME snowdreamtech/frpc
;;
start)
# 启动容器
docker start $CONTAINER_NAME
;;
stop)
# 停止容器
docker stop $CONTAINER_NAME
;;
restart)
# 重启容器
docker restart $CONTAINER_NAME
;;
log) # 输出日志
docker logs -f $CONTAINER_NAME
;;
sh) # 进入shell
docker exec -it $CONTAINER_NAME sh
;;
*)
# 无效参数
echo "Invalid argument: $1"
echo "Usage: $0 run|start|stop|restart|log"
exit 2
;;
esac

# 打印容器状态
docker ps -a | grep $CONTAINER_NAME

同样,保证目录下有一个frpc.ini文件。每次编辑完成后,需要删除原来的容器重新启动一个。

还有一个使用pushplus简单的监控脚本:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

token="your_token_here"
url=http://www.pushplus.plus/send

bash mc.sh log | grep -E --line-buffered "error|fail|warn" |\
while read line;
do json="{\"token\": \"$token\", \"title\": \"MC服务端异常报警\", \"content\": \"$line\"}"
curl -H "Content-Type: application/json" -X POST -d "$json" $url
done

它会每次从日志开始读取日志,将报错信息发送给PushPlus API。我一般会在微信上收报警消息。不过每次从日志开始读取日志确实不太好(会重复发送以前的错误信息)。这个回头得改一改。要么每次退出时清空日志,要么设置个读取行指示的全局变量。

就是这样啦。

作者

xeonds

发布于

2023-06-07

更新于

2024-10-08

许可协议

评论