一、写在最前面:为什么要“认真”跑一个游戏服务器
很多教程的目标只有一句话:
“服务器能跑,能进就行。”
但在真实服务器环境中,这种目标是不够的。
本次实践的目标从一开始就明确为:
- 数据必须是第一等公民
- 容器只是可随时丢弃的运行外壳
- 任何异常启动、重启、崩溃都不能影响世界存档
- 即使不连接客户端,也能判断服务器是否真实可用
- 需要时才启动,不需要时彻底停止
这不是“为了折腾”,而是为了避免后期不可控成本。
二、总体设计思想
1. 核心分离原则
在本方案中,Palworld 服务被拆成三层:
| 层级 | 角色 | 处理方式 |
|---|---|---|
| 世界数据 | 核心资产 | 永久保存在宿主机 |
| 配置文件 | 行为定义 | 由管理员手动维护 |
| 容器 | 执行外壳 | 可随时删除 |
一句话总结:
世界不属于容器,容器只是世界的“临时执行环境”。
三、目录结构设计(完全脱敏)
以下为逻辑结构示意,非真实路径:
palworld-root/
├── docker-compose.yml
└── game-data/
└── Pal/
└── Saved/
├── Config/
│ └── LinuxServer/
│ ├── PalWorldSettings.ini
│ └── GameUserSettings.ini
├── SaveGames/
│ └── 0/
│ └── <WORLD_ID>/
│ ├── Level.sav
│ ├── LevelMeta.sav
│ └── Players/
└── Logs/
关键点说明
docker-compose.yml与数据目录同级- 所有世界数据、配置文件只存在于宿主机
- 容器内部不保存任何“唯一性数据”
四、Docker Compose 的设计原则(而不是参数堆砌)
1. 镜像使用原则
- 使用公开的 Palworld Server 镜像
- 不绑定具体 build / manifest
- 使用匿名方式安装服务器文件
- 避免任何需要 Steam 账号的行为
原因很简单:
运行环境应尽量无状态、无外部依赖
2. 环境变量的克制使用
在 compose 中:
- 只保留 UID / GID / 时区 / 基础端口
- 不在环境变量中写入任何游戏参数
- 所有倍率、规则、功能开关 只存在于 ini
这样做的好处是:
- Docker 不参与“游戏逻辑”
- ini 文件即文档,也是配置源
- 迁移环境时不需要“回忆当初写了什么 env”
3. 禁止自动生成 / 覆盖配置
明确禁止镜像在启动时:
- 生成默认 ini
- 覆盖现有 ini
- 根据 env 重写设置
这是防止世界“被重置”的关键步骤之一。
五、端口策略(完全脱敏说明)
1. 对外端口原则
- 只暴露游戏必需的 UDP 端口
- 不暴露 REST / RCON / 查询端口
- 不做端口扫描“猜测式配置”
示意(非真实端口):
HOST_UDP_PORT → CONTAINER_UDP_PORT
2. 关于“日志里出现的其他端口”
即使在 ini 中关闭了某些功能,服务端启动日志中仍可能出现:
- “等待 REST API”
- “检查管理接口端口”
这属于 服务端启动流程的内部逻辑,并不等价于:
- 对外监听
- 安全暴露
- 网络可达
判断标准永远只有一个:
宿主机是否监听 / Docker 是否映射
六、无需客户端的可用性验证(重点)
在不连接任何游戏客户端的前提下,本次实践采用了多重独立验证。
1. 容器状态验证
- 容器处于 running
- 健康检查通过
- 无频繁重启
2. 网络监听验证
- 宿主机 UDP 端口处于监听状态
- 监听进程来自 docker-proxy
- 未监听的端口即使存在日志提示也视为无效
3. 世界存档行为验证(最重要)
对世界主存档文件进行观测:
- 文件存在
- 时间戳持续更新
- 文件大小随时间变化
示意逻辑:
时间 T1:大小 A
时间 T2:大小 B(B ≠ A)
这意味着:
- 世界已加载
- 自动保存机制工作
- 服务端逻辑在持续运行
这是比“端口能连”更强的证据。
七、关于日志的正确理解
1. 不要被旧日志误导
历史 crash log、上传失败、SSL 报错等:
- 只要不是当前运行周期生成
- 不影响现有世界
- 可视为“历史噪音”
2. 日志的真实用途
日志用于:
- 判断是否启动成功
- 判断是否进入运行态
而不是:
- 作为“是否可玩”的唯一依据
八、为什么选择“停止并删除容器”
1. 不使用常驻服务的原因
- 游戏服务器不是基础设施
- 不需要 24/7 在线
- 异常自动重启可能造成资源雪崩
- 运维人员应明确知道什么时候服务在跑
2. 推荐的停止方式
docker compose down
效果:
- 容器被销毁
- 网络被清理
- 数据完全保留
3. 停止后的验证思路
- 无容器
- 无端口监听
- 无游戏进程
九、需要时的“零成本恢复”
当需要重新运行服务器:
docker compose up -d
发生的事情只有:
- 新建容器
- 挂载旧数据
- 世界从原存档继续
不涉及:
- 数据迁移
- 恢复流程
- 初始化风险
十、最终总结
这次实践得到的核心结论是:
- Palworld 世界存档完全可以独立于 Docker 容器存在
- Docker 最适合扮演“随用随起的执行层”
- 世界是否“活着”,应通过存档写入行为判断
- 删除容器是安全操作,只要数据在宿主机
最终状态可以概括为:
服务可用,但不强制在线;
世界存在,但不依赖容器;
资源可控,风险可回滚。
这是一个长期稳定、低风险、可复制的部署方式。