You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用只读根文件系统后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/tmp
    
    或者application.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:54:56