15 10 月 2026

容器删了数据没了、容器之间 ping 不通、数据库连不上、端口映射改了不生效——Docker 的坑一半在数据卷,一半在网络。这篇把卷(volume/bind/tmpfs)和五种网络模式讲透,配可抄的 compose 模板。游戏服、网站部署都用得上。

需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。

一、数据卷:容器里的数据怎么活下来

容器是「用后即焚」的:删了容器,容器内部文件系统一起消失。要留的数据必须放卷上。

三种挂载方式:

类型写法特点适用
命名卷-v mydata:/var/lib/mysqlDocker 管理,路径在 /var/lib/docker/volumes/数据库、应用数据
绑定挂载-v /host/path:/container/path直接映射宿主机目录配置文件、代码目录
tmpfs--tmpfs /tmp内存盘,容器停就没了临时文件、敏感缓存

1.1 命名卷(推荐默认)

services:
  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql        # 数据库文件进卷,删容器不丢
  web:
    image: nginx:1.27
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf:ro   # 配置文件绑定挂载,只读
volumes:
  db_data:                              # 声明命名卷
# 卷管理命令
docker volume ls                        # 列出所有卷
docker volume inspect db_data           # 看详情和宿主机路径
docker volume rm db_data                # 删除(数据真没了,慎用)
docker volume prune                     # 清所有没人用的卷

1.2 绑定挂载的权限坑

# 现象:容器里写不了挂载目录
# Permission denied

# 原因:容器内用户 UID 和宿主机目录属主不匹配
ls -ld /host/path                      # 看宿主机目录属主
# 解法一:目录给对 UID(容器内跑 UID 1000 就 chown 1000)
sudo chown -R 1000:1000 /host/path
# 解法二:容器指定用户
docker run --user 1000:1000 ...

游戏服场景:存档目录、配置目录用绑定挂载(方便直接改文件看效果),数据库用命名卷(不关心文件位置,只要不丢)。

1.3 游戏服存档持久化模板

services:
  palworld:
    image: thijsvanloef/palworld-server-docker:latest
    volumes:
      - ./data:/palworld/Pal/Saved      # 存档+配置全在这,升级容器不丢档
      - ./mods:/palworld/Pal/Mods       # MOD 也挂出来,加 MOD 不用进容器
    restart: unless-stopped

升级服务端 = 删容器拉新镜像重建,数据卷岿然不动——这就是容器化最大的爽点,完整玩法见Docker 部署游戏服务器。

二、Docker 网络:五种模式

模式隔离性性能适用
bridge(默认)容器独立网段,NAT 上网好单机多容器,默认用这个
host共享宿主机网络栈最好高性能游戏服(省一层 NAT)
none无网络——离线任务
container:和指定容器共享网络——sidecar 模式
自定义 bridge同 bridge 内可用容器名互访好compose 默认,多服务互联用这个

2.1 端口映射:-p 的完整语法

docker run -p 8080:80 nginx
#           宿主机:容器

# 只绑本地(反代/安全场景)
docker run -p 127.0.0.1:8080:80 nginx

# 指定协议(UDP 游戏端口必须写!)
docker run -p 8211:8211/udp palworld

# 映射整个端口段(NAT 型映射多个端口)
docker run -p 8210-8220:8210-8220/udp palworld

UDP 不写 /udp 默认走 TCP——游戏服连不上的经典原因之一。端口意义见端口速查表。

2.2 容器之间怎么通信

同一个 compose 项目里,直接用服务名当域名(自定义 bridge 内置 DNS):

services:
  web:
    image: nginx
    environment:
      - DB_HOST=db              # 服务名直接当主机名!
      - REDIS_HOST=cache
  db:
    image: mysql:8.0
  cache:
    image: redis:7

web 容器里连 db:3306、cache:6379,Docker 自动解析。不要写 IP——容器重建 IP 就变。

跨 compose 项目/独立容器互联:

# 1. 建共享网络
docker network create appnet

# 2. 两个容器都接入
docker run -d --name db --network appnet mysql:8.0
docker run -d --name web --network appnet -e DB_HOST=db nginx
# 网络排查命令
docker network ls                              # 列出网络
docker network inspect appnet                  # 看接了哪些容器
docker exec web ping db                        # 容器内测连通(要有 iputils)
docker exec web nc -zv db 3306                 # 测端口通不通

2.3 host 模式:游戏服的性能选项

services:
  palworld:
    network_mode: host        # 容器直接用宿主机网络,无 NAT 损耗
  • 优点:少一层网络转发,延迟略低;UDP 游戏协议更稳
  • 代价:-p 失效(端口就是宿主机的),多实例会端口冲突
  • 适合:单游戏服独占机器;不适合:一机多服

2.4 NAT 型服务器 + Docker

NAT 型映射到宿主机的端口,Docker 再把宿主机端口映射进容器——两层映射:

玩家 → 公网IP:8211 →(NAT映射)→ 宿主机:8211 →(docker -p)→ 容器:8211
# 宿主机 8211 必须映射进容器,且 UDP
docker run -p 8211:8211/udp palworld
# 控制台再配 NAT 映射: 外部8211/UDP → 内部8211/UDP

任何一层漏了都连不上,排查方法见NAT 端口映射完全指南。

三、完整模板:Web + DB + Cache 一套

services:
  web:
    image: nginx:1.27-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html:/usr/share/nginx/html:ro
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - app
    restart: unless-stopped
    networks: [frontend]

  app:
    image: php:8.3-fpm
    volumes:
      - ./html:/var/www/html
    environment:
      - DB_HOST=db
      - REDIS_HOST=cache
    networks: [frontend, backend]

  db:
    image: mysql:8.0
    volumes:
      - db_data:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db_root_pw
    secrets:
      - db_root_pw
    networks: [backend]           # 数据库只在后端网络,不对外

  cache:
    image: redis:7-alpine
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks: [backend]

volumes:
  db_data:
  redis_data:

networks:
  frontend:
  backend:                        # internal 网络更安全,配 internal: true

secrets:
  db_root_pw:
    file: ./secrets/db_root_pw.txt

结构解读:

  • db/cache 只在 backend 网络,没有 ports 映射,外界碰不到
  • 密钥走 secrets,不进镜像历史,安全实践见Docker 安全加固与资源限制
  • 挂载分「数据卷(不丢)」+「绑定挂载(好改)」两类,各司其职
docker compose up -d          # 启动
docker compose ps             # 看状态
docker compose logs -f web    # 看日志
docker compose down           # 停并删容器(卷不删)
docker compose down -v        # 连卷一起删(数据全没!)

四、常见问题速查

现象原因解法
删容器数据没了数据在容器层,没挂卷加 volumes
容器写不了挂载目录UID 不匹配chown 或 --user
容器内连不上另一个容器不在同一网络 / 用了 IP服务名互联,别用 IP
改了 -p 不生效容器没重建docker compose up -d 重建
游戏端口 TCP 通了 UDP 不通-p 没写 /udp-p 8211:8211/udp
磁盘一直涨卷和镜像堆积docker system df + prune
MySQL 连不上容器刚起,初始化要十几秒加 healthcheck + depends_on condition: service_healthy
# 磁盘占用分析
docker system df
docker system df -v           # 明细到每个镜像/容器/卷

Dockerfile 编写规范见Dockerfile 编写与镜像优化,网站部署全流程见Docker 部署网站实战,Compose 编排基础见Docker Compose 编排实战。


数据卷和网络是 Docker 的两条命脉:卷决定数据活多久,网络决定容器怎么说话。记住三件事——要留的数据进卷、容器互访用服务名、UDP 端口必须写 /udp——Docker 运维就没什么能绊倒你了。

需要现成的游戏云服务器,可以看看财富云计算:一键开服面板,NAT 型无独立公网 IP,价格比独立 IP 机型省一半以上,主流游戏都能快速部署。延伸阅读:Docker 部署游戏服务器、Docker 常见故障排查、多游戏共存一台服务器。

延伸阅读
  1. 网站环境怎么选:LNMP 手动 / 宝塔面板 / Docker / 云开发
  2. 问卷表单系统搭建:SurveyKing / Formbricks,数据自己收
  3. 图床搭建:Lsky Pro / Lychee,自托管图片托管方案
  4. 邮件列表搭建:listmonk 自托管 Newsletter,把读者握在自己手里
  5. 文档站点搭建:MkDocs / VuePress / Docsify,产品文档与技术手册方案
  6. RSS 阅读器搭建:FreshRSS 自托管,把信息流拿回自己手里
  7. 短链接服务搭建:Shlink 自托管,链接数据自己掌握
  8. 网站状态监控页搭建:Uptime Kuma,服务器挂了第一时间知道
更多阅读
  1. 上一篇:Redis 大 Key 与热 Key 处理:延迟毛刺和主从 lag 的元凶
  2. 下一篇:Docker 镜像仓库与 CI 自动构建:推代码自动出镜像自动部署
发表评论 4

取消回复