启用只读根文件系统后ECS中Spring容器运行报错排查
问题描述
我们有一个基于Spring框架的Java应用,正尝试为ECS容器启用只读根文件系统。已修改Dockerfile为应用指定可写临时路径,但仍启动报错,错误栈如下:
{"dateTime":"2023-04-21T00:53:12.922Z","type":"ERROR","stage":"dev","logger":"org.springframework.boot.SpringApplication","class":"org.springframework.boot.SpringApplication","method":"reportFailure","file":"SpringApplication.java","line":865,"thread":"main","message":"Application run failed","stack_trace":"j.n.f.FileSystemException: /tmp/tomcat.8091.7261574515025557054: Read-only file system\n\tat s.n.fs.UnixException.translateToIOException(Unknown Source)\n\tat s.n.fs.UnixException.rethrowAsIOException(Unknown Source)\n\tat s.n.fs.UnixException.rethrowAsIOException(Unknown Source)\n\tat s.n.f.UnixFileSystemProvider.createDirectory(Unknown Source)\n\tat java.nio.file.Files.createDirectory(Unknown Source)\n\tat j.n.f.TempFileHelper.create(Unknown Source)\n\tat j.n.f.TempFileHelper.createTempDirectory(Unknown Source)\n\tat java.nio.file.Files.createTempDirectory(Unknown Source)\n\tat o.s.b.w.s.AbstractConfigurableWebServerFactory.createTempDir(AbstractConfigurableWebServerFactory.java:189)\n\t... 19 common frames omitted\nWrapped by: o.s.b.w.s.WebServerException: Unable to create tempDir. java.io.tmpdir is set to /tmp\n\tat o.s.b.w.s.AbstractConfigurableWebServerFactory.createTempDir(AbstractConfigurableWebServerFactory.java:195)\n\tat o.s.b.w.e.t.TomcatServletWebServerFactory.getWebServer(TomcatServletWebServerFactory.java:188)\n\tat o.s.b.w.s.c.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182)\n\tat o.s.b.w.s.c.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160)\n\t... 16 common frames omitted\nWrapped by: o.s.c.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to create tempDir. java.io.tmpdir is set to /tmp\n\tat o.s.b.w.s.c.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163)\n\tat o.s.c.s.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577)\n\tat o.s.b.w.s.c.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145)\n\tat o.s.b.SpringApplication.refresh(SpringApplication.java:775)\n\tat o.s.b.SpringApplication.refreshContext(SpringApplication.java:448)\n\tat o.s.b.SpringApplication.run(SpringApplication.java:339)\n\tat o.s.b.SpringApplication.run(SpringApplication.java:1365)\n\tat o.s.b.SpringApplica...\n"}
当前Dockerfile配置:
RUN addgroup -S spring && adduser -S spring -G spring USER spring:spring ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} xxx.jar # Create a writable directory for temporary files WORKDIR /usr/src/app/tmp && chown spring:spring /usr/src/app/tmp # Configure the application to use the new directory for temporary files ENV JAVA_OPTS="-Djava.io.tmpdir=/usr/src/app/tmp" ENTRYPOINT ["java","-jar","/xxx.jar"]
请问还需要做哪些配置才能让应用使用指定的临时路径?
解决方案
1. 让Dockerfile里的JAVA_OPTS生效
当前ENTRYPOINT用了数组格式,不会自动读取JAVA_OPTS环境变量,有两种修复方式:
- 改用shell执行格式:
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar /xxx.jar"] - 直接在ENTRYPOINT里硬编码JVM参数:
ENTRYPOINT ["java","-Djava.io.tmpdir=/usr/src/app/tmp","-jar","/xxx.jar"]
2. 直接配置Spring Boot的Tomcat临时目录
除了设置系统临时目录,还可以显式指定Tomcat的工作目录,避免依赖java.io.tmpdir:
- 配置文件方式:在
application.properties中添加:
或者server.tomcat.basedir=/usr/src/app/tmpapplication.yml:server: tomcat: basedir: /usr/src/app/tmp - 代码配置方式:写一个配置类自定义Tomcat工厂:
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class TomcatConfig { @Bean public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatCustomizer() { return factory -> factory.setBaseDirectory(new java.io.File("/usr/src/app/tmp")); } }
3. 修正Dockerfile的目录创建逻辑
原Dockerfile里的WORKDIR和chown写在一起有问题,若父目录不存在,可能导致/usr/src/app/tmp权限配置失效,建议拆分:
RUN mkdir -p /usr/src/app/tmp && chown spring:spring /usr/src/app/tmp WORKDIR /usr/src/app
4. 确认容器运行时目录权限
在ECS容器配置中,确保/usr/src/app/tmp是可写的——要么镜像中已通过RUN命令赋予spring用户读写权限,要么将该目录挂载为可写卷(如果需要临时文件持久化)。
内容的提问来源于stack exchange,提问作者YusufDoc
相关产品推荐
相关产品推荐

