You need to enable JavaScript to run this app. Ubuntu下Docker与docker-compose运行Rails容器权限报错及热更新失效问题咨询
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu下Docker与docker-compose运行Rails容器权限报错及热更新失效问题咨询

问题根因

  • Dockerfile中构建阶段设置的目录属主权限,会被docker-compose的bind mount挂载完全覆盖:bind mount直接将宿主机本地项目目录映射到容器内的目标路径时,容器内该路径的文件属主、权限完全继承宿主机本地目录的配置,镜像构建时写入的权限设置会被直接冲掉。
  • 当前Dockerfile中创建的运行用户是写死uid=1001的api用户,当宿主机本地项目目录的属主uid和1001不匹配时,容器内的api用户对挂载进来的目录没有写权限,自然无法在tmp/pids路径下创建server.pid文件,触发Errno::EACCES权限报错。
  • 之前通过调整挂载路径解决问题的方案,本质是绕开了bind mount对镜像内路径的覆盖逻辑,但会丢失本地代码修改同步到容器的热更新能力。
  • 原Dockerfile的额外疏漏:执行了rm -rf tmp操作后没有预创建Rails运行必需的tmp/pids、log目录,即使权限匹配,容器启动后面对挂载进来的空项目目录,也可能因为没有目录创建权限无法生成pid文件。

可落地的修复方案(保留代码热同步能力)

核心思路是对齐容器内运行用户的uid/gid和宿主机项目目录的属主信息,不需要改动宿主机的文件权限,所有调整都在Dockerfile和docker-compose配置内完成:

  • 先获取宿主机本地项目目录的属主uid/gid
    在项目根目录(存放docker-compose.yml的路径)执行命令查看:
    stat -c "%u:%g" ./
    通常Ubuntu系统的默认用户uid/gid为1000:1000,不同环境的数值可能有差异,以实际查询结果为准。
  • 调整Dockerfile的用户创建逻辑,取消写死的uid
    将原Dockerfile中写死uid=1001的用户创建逻辑,改为通过构建参数动态传入宿主机的uid/gid,同时预创建Rails需要的可写目录:
    # 引入构建参数,替换原写死的用户创建逻辑
    ARG HOST_UID=1000
    ARG HOST_GID=1000
    RUN groupadd -g ${HOST_GID} api \
        && useradd -Ms /bin/bash api -u ${HOST_UID} -g ${HOST_GID}
    
    # 预创建Rails运行必需的可写目录
    RUN mkdir -p $INSTALL_PATH/tmp/pids $INSTALL_PATH/log
    # 对需要写权限的路径统一设置属主
    RUN chown -R api:api /home/api /usr/local/bundle $INSTALL_PATH/tmp $INSTALL_PATH/log
    USER api
    
    EXPOSE 3000
    CMD rails server -p 3000 -b 0.0.0.0
    
  • 调整docker-compose.yml的构建配置,自动传递宿主机的uid/gid
    保留原有的bind mount配置不变,在api服务的build节点下添加构建参数传递,实现权限自动对齐:
    api:
      container_name: limpar-api
      build:
        context: .
        args:
          HOST_UID: ${HOST_UID:-1000}
          HOST_GID: ${HOST_GID:-1000}
      # 以下原有配置完全保留,不影响代码热同步能力
      command: bundle exec rails s -p 3000 -b '0.0.0.0'
      env_file:
        - .env
      volumes:
        - ./:/home/api/limpar/current
      ports:
        - "3000:3000"
      depends_on:
        - db
        - redis
      networks:
        - limpar_network
    
    执行构建启动时,只需要在命令前带上当前宿主机的uid/gid即可,例如:
    HOST_UID=$(id -u) HOST_GID=$(id -g) docker-compose up --build
  • 兜底权限处理
    如果遇到本地残留的tmp/log目录权限不匹配的问题,可以微调启动命令,在Rails启动前临时修正可写目录的权限,避免偶发报错:
    将原command替换为:
    command: bash -c "mkdir -p tmp/pids log && bundle exec rails s -p 3000 -b '0.0.0.0'"
    
    这个逻辑会在容器启动时自动创建缺失的目录,不需要手动在本地调整文件权限。

内容的提问来源于stack exchange,提问作者queroga_vqz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 07:36:07