DEBUG.WIKI
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →

ECS 已配 tmpfs,Nginx 仍报 client_temp 只读文件系统

ECS 的 tmpfs 必须位于目标容器的 linuxParameters 中,并使用正确的数组与字段类型。核对实际任务修订,修复挂载结构,保留只读根文件系统。

ECS 任务已经设置 readonlyRootFilesystem: true,又为 Nginx 配了临时可写目录,启动时仍报:

mkdir() "/var/cache/nginx/client_temp" failed (30: Read-only file system)

如果任务配置把 tmpfs 直接写在容器定义的顶层,或用多个同名 tmpfs 键表示多个挂载,需要先修正结构。ECS 的挂载列表位于每个容器的 linuxParameters.tmpfs 中;只把一个对象改成数组,却仍放错层级,并不能得到所需的挂载。

下文以 Linux EC2 任务为例,讨论 ECS 任务定义,不是 Docker Compose 文件。错误配置可能在客户端或注册阶段就被拒绝,也可能在生成配置的中间环节丢失;不要根据本地模板里出现了 tmpfs,就认定运行任务已经用上它。

查正在失败的任务用了哪个修订

在已配置好 AWS CLI 凭据和区域的环境中,查询目标任务实际引用的任务定义。集群和任务 ID 都是占位值,替换后再使用:

aws ecs describe-tasks \
  --cluster example-cluster \
  --tasks TASK_ID \
  --query 'tasks[].{task:taskArn,definition:taskDefinitionArn,status:lastStatus}' \
  --output json

如果没有返回任务,或命令报告权限、区域、资源不存在等错误,先修正查询目标。不能把空数组当成“配置为空”。从输出中取得任务定义 ARN,再查询这个精确修订,而不是只查询 family 的最新版本:

aws ecs describe-task-definition \
  --task-definition TASK_DEFINITION_ARN \
  --query 'taskDefinition.containerDefinitions[].{name:name,readonly:readonlyRootFilesystem,linux:linuxParameters}' \
  --output json

确认报错容器对应的 linux 对象里,确实有包含 /var/cache/nginx 的 tmpfs 数组。若挂载只配置给同任务中的另一个容器,也不会自动出现在 Nginx 容器里。

挂载已存在却仍失败时,要重新对照完整报错路径、其他挂载及镜像配置。Permission denied 与 Read-only file system 不是同一类错误:可写挂载仍受运行用户和目录权限限制,但修改 chmod 不能把只读文件系统变成可写。

正确的结构是 linuxParameters 下的数组

以下是需要合入现有 containerDefinitions 中目标容器对象的片段,不是一份完整可注册的任务定义:

{
  "name": "nginx",
  "readonlyRootFilesystem": true,
  "linuxParameters": {
    "tmpfs": [
      {
        "containerPath": "/var/cache/nginx",
        "size": 64,
        "mountOptions": ["rw"]
      },
      {
        "containerPath": "/run",
        "size": 16,
        "mountOptions": ["rw"]
      }
    ]
  }
}

保留容器原有的镜像、资源限制、日志、端口和健康检查设置;已有 linuxParameters 时,应合并其中的 tmpfs,不能用这段片段覆盖掉其他字段。

这里有三个容易写错的地方:tmpfs 是对象数组;size 是以 MiB 为单位的整数;mountOptions 是字符串数组。不要写成重复的两个 tmpfs 键,也不要将大小写成 "64"、将选项写成单个字符串 "rw"。containerPath 必须是容器内的绝对路径。

示例中的两个目录与容量只用于说明结构。实际应沿镜像的 Nginx 配置和启动脚本确认 PID、临时请求文件及其他运行时写入路径;并非所有 Nginx 镜像都只写这两处。非 root 镜像还需要使挂载目录的所有者和权限符合运行用户,不能通过放宽整个根文件系统来跳过判断。

不要把空 tmpfs 挂到包含业务必需文件的整个配置或静态资源目录。挂载会遮住镜像中该路径原有的内容;确实需要覆盖时,必须设计初始化过程,并确认服务读取的是预期文件。

注册成功后还要让新任务采用该修订

保存当前可回退的任务定义、服务部署设置和镜像引用,再按现有 IaC 或 ECS 部署流程注册新修订。注册新任务定义不会让现有任务自动变更挂载;需要让服务部署或独立任务明确使用新修订。

在隔离环境启动采用新修订的任务,重复前面的只读查询,确认它的 taskDefinitionArn 已改变,并检查新容器日志。原来的 client_temp 只读错误应消失,Nginx 应能够启动并通过业务所需的请求检查。任务进入 RUNNING 本身不能证明每个目标容器或所有请求路径均正常。

如果接着出现另一个写入路径错误,逐项确认该目录用途,再决定是否增加临时挂载。不要直接把根目录改成可写,也不要把每个报错路径都挂成 tmpfs:持久状态、配置输入与可丢弃的临时文件需要不同的保存方式。

这里的例子限定 EC2,不能据此把其他 ECS 运行环境一概判为不支持。Linux Fargate 和 ECS Managed Instances 从 2026 年 1 月 6 日起新增了 tmpfs 挂载支持;使用这些环境时,应核对实际任务平台及当前支持条件,不沿用较早配置资料里的限制。Windows 容器不适用这个 Linux 参数块。

容量和回退需要一起考虑

tmpfs 适合可以随任务退出丢弃的临时文件,不适合存放必须保留的日志、上传文件或数据库数据。容量上限要结合请求体大小、并发和容器内存预算决定;把 size 调大并不会给容器增加额外内存。Linux tmpfs 还可能使用宿主交换空间,不能把它当成保证秘密永不落盘的机制。

回退时恢复原来验证过的任务定义修订并按既有部署策略替换任务。新任务退出后,其 tmpfs 数据不会作为持久内容保留;有业务数据误写进去时,不能先停止任务再期待从下一次启动找回。若旧修订本来就缺少必要挂载,回退只恢复旧配置,不会自动修好原故障。