Docker容器运行Java应用时文件路径异常问题排查与解决
MultipartFile转File在Docker容器中报错的问题解决
问题现象
以下是将MultipartFile转换为java.io.File的代码:
public File convert(MultipartFile multipartFile) { byte[] bytes; try { bytes = multipartFile.getBytes(); try (FileOutputStream fos = new FileOutputStream("files/" + multipartFile.getOriginalFilename())) { fos.write(bytes); } } catch(IOException e) { System.out.println("Exception when converting multipart file to array of bytes"); System.out.println(e.getCause()); System.out.println(e.getMessage()); } return new File("files/" + multipartFile.getOriginalFilename()); }
该代码在本地Ubuntu 22系统运行正常,但在Docker容器中调用时抛出IOException:
file-exchange-web-1 | Exception when converting multipart file to array of bytes file-exchange-web-1 | null file-exchange-web-1 | files/zip.png (No such file or directory)
后续尝试访问文件时触发:
file-exchange-web-1 | java.io.FileNotFoundException: file [/apps/files/zip.png] cannot be resolved in the file system for checking its content length
原Dockerfile内容:
FROM openjdk:21-slim WORKDIR /apps ARG JAR_FILE COPY target/${JAR_FILE} /apps/app.jar COPY /entrypoint.sh /apps/entrypoint.sh RUN adduser --system servuser RUN chmod +x /apps/entrypoint.sh RUN chown -R servuser /apps USER servuser EXPOSE 8080 8080 CMD ["/apps/entrypoint.sh"]
原因解析
- 目录缺失问题:Docker容器是完全隔离的环境,镜像构建时未创建的目录不会自动生成。本地环境中
files/目录可能已手动创建或由项目生成,但Docker镜像中没有这个目录,导致代码写入文件时失败。 - WORKDIR的作用说明:
WORKDIR /apps会在容器根目录(/)下创建apps目录,并将后续所有Docker指令的工作目录切换至/apps。- 容器中Java应用的当前工作目录就是
/apps,代码中使用相对路径files/时,实际指向/apps/files/,该目录在原Dockerfile中未被创建,因此触发“找不到文件或目录”的错误。
解决方法
修改Dockerfile,添加RUN mkdir files指令,在/apps目录下创建files目录。修改后的Dockerfile:
FROM openjdk:21-slim WORKDIR /apps ARG JAR_FILE COPY target/${JAR_FILE} /apps/app.jar COPY /entrypoint.sh /apps/entrypoint.sh RUN adduser --system servuser RUN chmod +x /apps/entrypoint.sh RUN chown -R servuser /apps RUN mkdir files USER root EXPOSE 8080 8080 CMD ["/apps/entrypoint.sh"]
优化建议:创建
files目录后,最好同步修改目录权限,确保运行应用的servuser有读写权限,可添加RUN chown servuser:servuser files指令,避免权限问题。
额外优化建议
- 路径优化:代码中使用相对路径存在不确定性,建议通过
System.getProperty("user.dir")动态获取当前工作目录,拼接成绝对路径使用:String workingDir = System.getProperty("user.dir"); String filePath = workingDir + "/files/" + multipartFile.getOriginalFilename(); try (FileOutputStream fos = new FileOutputStream(filePath)) { fos.write(bytes); } - 持久化文件:如果需要保留容器中的上传文件,建议使用Docker卷(Volume)挂载
/apps/files目录,避免容器重启或销毁后文件丢失。
内容的提问来源于stack exchange,提问作者Onurjan
相关产品推荐
相关产品推荐

