📘 Docker 数据目录与权限问题复盘(最终版)

日期:2026-01-09
作者:我
主题:Docker + Linux 文件系统 + MySQL / Redis / Elasticsearch


一、问题背景

今天在为项目部署 MySQL、Redis、Elasticsearch 时,我遇到了大量容器启动失败的问题,典型错误集中在:

  • Permission denied (errno 13)
  • MySQL 初始化失败
  • Elasticsearch 拒绝写入数据目录

一开始我尝试从权限、镜像、配置层面排查,但最终发现:
这些问题本质上都不是服务本身的问题,而是数据目录使用方式不正确。


二、踩坑复盘(问题是怎么来的)

1. 在不合适的文件系统上存放 Docker 数据

我曾把 Docker 数据目录放在 NTFS 等非 Linux 原生文件系统上,结果导致:

  • 权限看起来正确,但实际不可用
  • MySQL 因大小写问题被迫降级
  • Elasticsearch / Redis 随机写失败

这一步直接埋下了后续所有问题的根源。


2. 误以为 Docker Volume 会处理权限

我使用了 Docker volume + bind 的方式,但一度误以为 Docker 会自动处理目录权限。
事实是:

Docker 只负责挂载路径,不负责修复权限或文件系统问题。

3. 迷信 chmod 777

我多次尝试通过 chmod 777 解决问题,但事实证明:

  • 权限位不是关键
  • 目录的真实拥有者(UID / GID)才是关键
  • 文件系统能力决定了一切

三、最终结论(只保留一个)

**唯一长期可行、可维护、可复用的方案:
在宿主机提前创建好目录 → 使用 Linux 原生文件系统 → 通过 bind mount 挂载到容器。**

其他尝试全部属于踩坑,不再作为方案考虑。


四、最终有效目录结构(宿主机)

/media/local/data/gamebox/
├── mysql
├── redis
├── elasticsearch
└── elasticsearch-plugins

以上目录均由我 手动提前创建,不交给 Docker 自动生成。


五、最终验证可用的 Docker Compose 配置(已脱敏)

services:
  mysql:
    image: mysql:8.0
    container_name: gamebox-mysql
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD:-******}
      MYSQL_DATABASE: gamebox
      TZ: Asia/Shanghai
    volumes:
      - mysql_data:/var/lib/mysql
      - ../sql:/docker-entrypoint-initdb.d:ro
    ports:
      - "23306:3306"
    command:
      --character-set-server=utf8mb4
      --collation-server=utf8mb4_unicode_ci
      --default-authentication-plugin=mysql_native_password
      --skip-name-resolve
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    container_name: gamebox-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD:-******}
    volumes:
      - redis_data:/data
    ports:
      - "26379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5

  elasticsearch:
    image: elasticsearch:7.17.25
    container_name: gamebox-es
    restart: unless-stopped
    environment:
      - discovery.type=single-node
      - xpack.security.enabled=false
      - ES_JAVA_OPTS=-Xms512m -Xmx512m
      - TZ=Asia/Shanghai
      - cluster.routing.allocation.disk.watermark.low=95%
      - cluster.routing.allocation.disk.watermark.high=97%
      - cluster.routing.allocation.disk.watermark.flood_stage=99%
      - http_proxy=http://***:***@proxy.example.com:PORT
      - https_proxy=http://***:***@proxy.example.com:PORT
      - HTTP_PROXY=http://***:***@proxy.example.com:PORT
      - HTTPS_PROXY=http://***:***@proxy.example.com:PORT
    volumes:
      - es_data:/usr/share/elasticsearch/data
      - es_plugins:/usr/share/elasticsearch/plugins
    ports:
      - "29200:9200"
      - "29300:9300"
    entrypoint: /bin/bash
    command: >
      -c "
      if [ ! -f /usr/share/elasticsearch/plugins/analysis-ik/plugin-descriptor.properties ]; then
        elasticsearch-plugin install --batch https://get.infini.cloud/elasticsearch/analysis-ik/7.17.25;
      fi;
      /usr/local/bin/docker-entrypoint.sh eswrapper
      "
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:9200/_cluster/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 5

volumes:
  mysql_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /media/local/data/gamebox/mysql

  redis_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /media/local/data/gamebox/redis

  es_data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /media/local/data/gamebox/elasticsearch

  es_plugins:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /media/local/data/gamebox/elasticsearch-plugins

networks:
  default:
    name: gamebox-network

六、我真正学到的东西

  • Docker 不会帮我兜底权限问题
  • Volume 只是路径映射,不是权限隔离
  • 数据库对文件系统极度敏感
  • chmod 777 不是解决方案
  • 提前建目录 + bind mount 是唯一正解

七、最终一句话总结

**这次问题让我真正理解了:
Docker 并没有让系统更简单,它只是把底层问题暴露得更清楚。**

尊重文件系统、尊重权限模型,容器才能稳定运行。

最后修改:2026 年 01 月 09 日
反正没人给,你也爱给不给吧。