Docker部署Haskell Yesod API时Stack报父目录权限错误排查
解决Docker部署Yesod Haskell API时Stack的权限问题
问题重现
部署Yesod后端API时,执行docker-compose up --build api触发权限错误:
Preventing creation of stack root '/.stack/'. Parent directory '/' is owned by someone else.
问题根源
- Docker Compose指定普通用户
1000:1000运行容器,但容器根目录/属于root,Stack默认尝试在/.stack创建根目录,普通用户无写入权限。 - Dockerfile构建阶段以root执行Stack操作,生成的文件权限与运行阶段的普通用户不匹配。
- 挂载的
.stack-root卷未指定正确路径,导致Stack仍试图访问无权限的系统目录。
解决方案
1. 修改Dockerfile,统一用户与Stack根目录
调整Dockerfile,创建专用非root用户,指定Stack根目录到工作目录内,并确保文件权限匹配:
FROM haskell:9 # 创建非root用户并配置环境 RUN useradd -m haskelluser WORKDIR /app # 切换到非root用户 USER haskelluser # 指定Stack根目录到当前工作目录,避免访问系统根目录 ENV STACK_ROOT=/app/.stack-root # 复制项目文件并设置正确权限 COPY --chown=haskelluser:haskelluser . . # 执行Stack构建步骤 RUN stack setup RUN stack install yesod-bin --install-ghc RUN stack build EXPOSE 8000 CMD ["stack", "exec", "--", "yesod", "devel"]
2. 调整Docker Compose配置
修改卷挂载路径,确保与Dockerfile中指定的Stack根目录一致,并使用创建的专用用户:
api: build: context: ./api dockerfile: Dockerfile user: haskelluser:haskelluser stdin_open: true tty: true volumes: - ./api:/app - ./api/.stack-work:/app/.stack-work - ./api/.stack-root:/app/.stack-root ports: - 8000:3000 env_file: ./env/yesod.env depends_on: - database
关键说明
- 通过
ENV STACK_ROOT=/app/.stack-root强制Stack将根目录放在工作目录内,普通用户拥有该目录的写入权限。 COPY --chown确保复制到容器内的项目文件属于运行用户,避免挂载后出现权限冲突。- 卷挂载明确指定到项目目录下的
.stack-work和.stack-root,既保留构建缓存,又保证权限一致。
内容的提问来源于stack exchange,提问作者visensis
相关产品推荐
相关产品推荐

