使用 Podman Quadlet 部署多实例自动扩缩容的 Minecraft 服务器(itzg/minecraft-server + mc-router)
【免费下载链接】docker-minecraft-serverDocker image that provides a Minecraft Server for Java Edition that automatically installs/upgrades versions, modloaders, modpacks and more at startup项目地址: https://gitcode.com/GitHub_Trending/do/docker-minecraft-server
导读
本指南基于仓库中的 Podman Quadlet 示例,讲解如何利用 Podman 的 Quadlet 声明式单元文件,在单台宿主机上部署多套可自动扩缩容的 Minecraft Java 版服务器,并让它们共同挂在 mc-router 之后,通过不同域名分发玩家流量。读完本文,你将掌握 Quadlet 模板文件、网络单元、实例环境文件与 systemd 用户级服务的完整配置方式,并能独立把一套"休眠唤醒"式(autoscale)的 Minecraft 集群跑起来。
Quadlet:用 systemd 单元描述容器
Quadlet 是 Podman 提供的一种声明式容器编排方式:把容器的启动参数写进扩展名为.container(以及配套的.network、.volume等)的 systemd 单元文件,由podman在systemctl daemon-reload时自动翻译成可被 systemd 托管的 service 单元。这样容器获得了 systemd 的依赖管理、自动重启、日志集成与开机自启能力,非常适合"一组长期运行的容器服务"这一场景。
本示例正是利用了这一机制,把"多个 Minecraft 服务器实例 + 一个路由代理"声明成一组可复制的 systemd 用户单元。示例中的命令默认面向 rootless(无 root 权限)Podman,如需 rootful 只需去掉命令中的--user并调整文件安装目录。
部署拓扑:mc-router 统一入口 + 按需启停的实例
整套方案由三类组件组成:
- mc-router:Minecraft 感知的路由/多路复用器,根据玩家连接时使用的 hostname 将流量转发到对应后端容器;同时具备 autoscale 能力——玩家连接时自动拉起后端(scale up),后端空闲超时后自动停止(scale down)。
- N 个 Minecraft 服务器实例:使用仓库主镜像
itzg/minecraft-server(即本仓库构建的 Docker 镜像),每个实例由mc@.container模板实例化,通过mc-router.host标签声明自己的路由域名。 - 共享网络:所有容器接入同一个名为
minecraft.network的用户自定义 bridge 网络。
对应的 autoscale 模式在仓库文档 docs/misc/autoscale/autoscale.md 中有专门介绍,本示例是 mc-router 路线在 Podman 环境下的具体落地。
文件清单与逐项配置解析
示例目录 examples/podman-quadlets 下共 4 个文件,部署时需全部安装到 Quadlet 搜索目录(rootless 用户为${XDG_CONFIG_HOME}/containers/systemd/,通常即~/.config/containers/systemd/):
| 文件 | 作用 |
|---|---|
| minecraft.network | 声明桥接网络单元 |
| mc@.container | 带@的实例化模板:Minecraft 服务器单元 |
| mc-router.container | 路由与自动扩缩容代理单元 |
| mc/example.env | 单个服务器实例的环境文件示例 |
网络单元:minecraft.network
[Network] Driver=bridge这是最简的桥接网络声明。所有容器都通过Network=minecraft.network加入该网络,使 mc-router 与各 Minecraft 实例在私有网络中互通。
模板单元:mc@.container
mc@.container是带@的实例化模板文件,systemd 约定@后的部分为实例名(instance name),可通过%i引用。一个模板可派生任意多个实例,例如实例example对应mc@example.service。完整内容如下:
[Unit] Description=Minecraft server instance Before=mc-router.service [Container] Image=docker.io/itzg/minecraft-server ContainerName=%p-%i AutoUpdate=registry UserNS=auto Volume=%p-%i:/data:Z,U Network=minecraft.network PodmanArgs=--tty --interactive HealthCmd="/usr/local/bin/mc-health" HealthInterval=10s HealthRetries=20 HealthStartPeriod=1m HealthTimeout=10s Label=mc-router.host=%p-%i.example.com EnvironmentFile=./mc/%i.env [Service] Restart=on-abnormal RemainAfterExit=yes [Install] WantedBy=default.target关键字段说明:
Before=mc-router.service:保证路由器先于实例完成依赖排序,避免后端未就绪时路由目标不存在。Image=docker.io/itzg/minecraft-server:即本仓库itzg/minecraft-server镜像,启动时自动完成版本、模组加载器、整合包等的安装与升级。ContainerName=%p-%i:%p是去掉@后的模板名前缀(即mc),%i是实例名,因此实例名必须唯一,容器名形如mc-example。AutoUpdate=registry:利用 Podman 的 auto-update 机制跟踪 registry 镜像更新。UserNS=auto:自动启用用户命名空间,配合 rootless 环境提升隔离性。Volume=%p-%i:/data:Z,U:每个实例挂载独立的卷(卷名同样为mc-example形式);Z让容器拥有独占的 SELinux 标签,U自动匹配卷所有者与容器内用户,避免 rootless 下的权限问题。Network=minecraft.network:加入共享桥接网络。PodmanArgs=--tty --interactive:等价于 docker 的-it,因为 Minecraft 服务器以交互式进程运行。- 健康检查三件套:
HealthCmd调用镜像内置的mc-health(详见下文"健康检查的源码支撑"),配合HealthInterval=10s、HealthRetries=20、HealthStartPeriod=1m、HealthTimeout=10s,保证在启动阶段(1 分钟)与运行阶段都能被准确判活。 Label=mc-router.host=%p-%i.example.com:这是路由与自动扩缩容的关键标签。mc-router 依据该标签识别后端,并据此路由玩家。原 README 明确要求:把example.com替换成你自己的域名。EnvironmentFile=./mc/%i.env:按实例名加载对应环境文件——实例example会读取mc/example.env,这正是"每个实例一个同名 env 文件"约定的来源(README 中亦有脚注说明)。相对路径./基于 Quadlet 文件所在目录解析。
[Service]段中Restart=on-abnormal表示仅在异常退出时由 systemd 重启;RemainAfterExit=yes让服务在容器"休眠"停止后仍保持 active 状态,便于 systemd 管理与依赖编排。WantedBy=default.target使实例在启用后随用户默认 target 启动。
路由与扩缩容单元:mc-router.container
[Unit] Description=Minecraft proxy with autoscaling support [Container] Image=docker.io/itzg/mc-router ContainerName=%N AutoUpdate=registry UserNS=host Volume=%t/podman/podman.sock:/var/run/docker.sock:ro Network=minecraft.network PublishPort=25565:25565 SecurityLabelDisable=true Environment=\ "IN_DOCKER=true" \ "AUTO_SCALE_DOWN=true" \ "AUTO_SCALE_UP=true" \ "AUTO_SCALE_DOWN_AFTER=10m" \ "AUTO_SCALE_ASLEEP_MOTD='Server is asleep. Join again to wake it up!'" [Service] Restart=always [Install] WantedBy=default.target关键字段说明:
Volume=%t/podman/podman.sock:/var/run/docker.sock:ro:把 Podman 的 API socket 以只读方式挂载进 mc-router,使它可以像操作 Docker 容器一样发现/启停后端实例。这是 autoscale 得以工作的前提。PublishPort=25565:25565:对外暴露默认 Minecraft 端口,玩家统一从该端口进入,由 mc-router 按 hostname 分流。Environment中通过多行续接符\一次注入 5 个变量,与仓库的 Docker Compose 示例 examples/mc-router-autoscale/compose.yml 中 router 服务的配置一一对应:AUTO_SCALE_DOWN=true/AUTO_SCALE_UP=true开启全局自动缩/扩容;AUTO_SCALE_DOWN_AFTER=10m设置空闲 10 分钟后的缩容阈值(该参数是全局设置,不能被单后端覆盖);AUTO_SCALE_ASLEEP_MOTD定义后端休眠时向玩家展示的提示消息。UserNS=host与SecurityLabelDisable=true:rootless 环境下访问宿主机 socket 与进行端口发布所需的特殊处理。
实例环境文件:mc/example.env
每个实例的环境文件完全复用镜像的整套环境变量体系(仓库文档 docs/variables.md 有完整清单)。示例文件展示了通用配置与服务器配置两类变量:
# General options INIT_MEMORY=1G MAX_MEMORY=4G # Server options EULA=TRUE VIEW_DISTANCE=16 DIFFICULTY=normal MOTD=Example Server!\nRunning version %VERSION%EULA=TRUE:必须接受 Minecraft EULA 才能启动服务器。INIT_MEMORY/MAX_MEMORY:JVM 初始与最大堆内存(镜像脚本据此拼接 JVM 参数,详见 docs/configuration/jvm-options.md)。VIEW_DISTANCE/DIFFICULTY:会由镜像的 start-setupServerProperties 流程写入server.properties。MOTD支持%VERSION%等占位符插值,相关内容见 docs/configuration/interpolating.md。
由于 Quadlet 模板按%i匹配mc/%i.env,新增一个实例只需三步:新建一个mc/新实例名.env环境文件、用ln -s从模板生成对应 service(见下文)、替换mc-router.host中的域名即可。
部署步骤(rootless 用户)
1. 安装单元文件并重载
把 4 个文件放入${XDG_CONFIG_HOME}/containers/systemd/,然后让 systemd 生成对应单元:
systemctl --user daemon-reload2. 修复自动移除问题(必要步骤)
原 README 特别提醒:生成的 service 文件总是自带--rm(Podman 社区已知行为,相关讨论见 podman-container-tools/podman 的 discussion 28837)。在 autoscale 场景下,容器会被 mc-router 正常停止,此时--rm会在退出时把容器直接删除,与"休眠待唤醒"的预期冲突。因此需要对模板服务打一个 drop-in:
systemctl --user edit mc@.service在编辑器中写入如下内容(核心是先用空的ExecStart=清空原启动命令,再提供把--rm替换为--restart=unless-stopped的新命令,...处保留原命令其余部分不变):
[Service] ExecStart= ExecStart=/usr/bin/podman run --name %p-%i --replace --restart=unless-stopped ...这样实例被停止后不会删除容器,下次被唤醒时可直接复用。
3. 启动路由器与实例
systemctl --user enable --now podman.socket systemctl --user start mc@example.service mc-router.service # 实例通过从模板符号链接的方式启用 ln -s ${XDG_CONFIG_HOME}/containers/systemd/mc@.service ${XDG_CONFIG_HOME}/containers/systemd/mc@example.servicepodman.socket提供 API socket,供 mc-router 挂载;ln -s从模板生成具名实例的启用链接,之后该实例即可随用户登录会话自动管理。
4. Rootless 环境的额外注意
开启 lingering:无图形登录会话时 systemd 用户服务会在用户登出后终止,需要执行
sudo loginctl enable-linger $USER才能让这些服务在后台持续运行。
源 IP 丢失:由于 rootless Podman 对自定义网络的处理方式,当前经 mc-router 转发的连接会丢失真实客户端源 IP(社区正在推进修复,见 podman-container-tools/podman 的 pull 28478)。如需基于真实 IP 的功能(如 GeoIP 限制、白名单审计),在 rootless 模式下需要额外注意;rootful 模式则不受此限制。
健康检查的源码支撑
mc@.container中引用的HealthCmd="/usr/local/bin/mc-health"对应镜像内置脚本 scripts/shims/mc-health。该脚本首先加载公共函数库,并支持通过DISABLE_HEALTHCHECK=true环境变量整体关闭健康检查;当ENABLE_AUTOPAUSE开启且 Java 进程处于T(TASK_STOPPED,即被 autopause 挂起)状态时,健康检查直接判为通过,避免"休眠中实例被误判为故障";其余情况则调用mc-monitor status向服务器发送状态查询,结合MC_HEALTH_EXTRA_ARGS、SERVER_HOST/SERVER_PORT完成探测。更多健康检查细节可参考 docs/misc/healthcheck.md。
与 Docker Compose 方案的对照
同一套 mc-router + autoscale 思路在 Docker 侧有对应的 Compose 写法,见 examples/mc-router-autoscale/compose.yml(以及精简版compose-minimal.yml)。两者核心差异:
- 路由发现机制:Compose 版通过容器 label
mc-router.host与 docker.sock 挂载实现;Quadlet 版通过Label=mc-router.host=%p-%i.example.com与%t/podman/podman.sock挂载实现,机制一致,仅 socket 路径与声明方式不同。 - 按实例覆盖扩缩容:Compose 版可为单个后端设置
mc-router.auto-scale-up、mc-router.auto-scale-down、mc-router.auto-scale-asleep-motd标签做个性化覆盖(如示例中 fabric 实例显式关闭扩缩容、paper 实例自定义休眠 MOTD);Quadlet 版同样可在mc@.container模板中为每个实例添加同名 label 实现,但注意AUTO_SCALE_DOWN_AFTER是全局设置,不可按后端覆盖。 - 编排方式:Compose 强调"一套应用多容器";Quadlet 强调"systemd 原生单元 + 模板复制",对实例扩缩、开机自启、日志 journald 集成的体验更接近 Linux 系统服务。
小结
通过 examples/podman-quadlets 这套示例,你可以用纯 systemd 单元文件的方式在 Podman 上获得"多实例 Minecraft 集群 + 统一路由入口 + 空闲休眠/连入唤醒"的完整能力。核心要点可归纳为:模板文件mc@.container负责实例化与路由标签、mc-router.container负责分流与自动扩缩容、mc/%i.env按实例注入镜像环境变量、生成服务后必须用 drop-in 修正--rm为--restart=unless-stopped,rootless 环境还需开启 lingering 并留意源 IP 限制。照此步骤操作,即可在单台宿主机上运行一个按需启停、按域名分流的 Minecraft 服务器集群。
【免费下载链接】docker-minecraft-serverDocker image that provides a Minecraft Server for Java Edition that automatically installs/upgrades versions, modloaders, modpacks and more at startup项目地址: https://gitcode.com/GitHub_Trending/do/docker-minecraft-server
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考