Fargate: nginxコンテナをreadonlyRootFilesystemで動かす

監査上の理由からFargateがreadonlyRootFilesystemで動いてほしかったので、nginxコンテナを使った検証のメモ。

基本方針

  • nginxイメージそのままでは動かないのでカスタムイメージを作る
  • /var をタスクストレージにマウントする
  • /tmp/var/tmp へのsymlink
    • 二つ以上のタスクストレージをマウントできなかったため(二つ目以降のmountPointは無視された)

Dockerfile

FROM --platform=linux/amd64 nginx

VOLUME /var
# `VOLUME` を指定しておかないと
# 元々のイメージにあるファイルが
# マウントしたボリュームにコピーされなかった

RUN rmdir /tmp && \
    ln -s /var/tmp /tmp && \
    rm /var/run /var/lock && \
    mv /run /var/run && \
    ln -s /var/run/lock /var/lock

# このイメージでは `/var/run` `/var/lock` は
# ぞれぞれ `/var/run` 配下へのsymlinkになっているので
# 構成を変更する

ECSタスク定義 (ecspresso)

{
  containerDefinitions: [
    {
      cpu: 0,
      essential: true,
      image: '123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-nginx:latest',
      name: 'my-nginx-ro',
      portMappings: [
        {
          containerPort: 80,
          hostPort: 80,
          protocol: 'tcp',
        },
      ],
      readonlyRootFilesystem: true,
      mountPoints: [
        { sourceVolume: 'var', containerPath: '/var' },
      ],
    },
  ],
  cpu: '256',
  memory: '512',
  taskRoleArn: 'arn:aws:iam::123456789012:role/MyTaskRole',
  executionRoleArn: 'arn:aws:iam::123456789012:role/MyExecRole',
  family: 'my-nginx-ro',
  networkMode: 'awsvpc',
  requiresCompatibilities: [
    'FARGATE',
  ],
  volumes: [
    { name: 'var' },
  ],
  // 必須ではない
  // ephemeralStorage: {
  //   sizeInGiB: 50,
  // },
}

動作確認

root@ip-10-0-3-229:/# touch x
touch: cannot touch 'x': Read-only file system
root@ip-10-0-3-229:/# touch /tmp/x
root@ip-10-0-3-229:/# touch /var/tmp/x
root@ip-10-0-3-229:/#

その他

  • 何もマウントしないと /etc/hots がタスクストレージにマウントされているように見えたが、なぜ…
  • /varがread onlyになるとECS execできなくなるということがわかった
  • タスクストレージで複数のmountPointを使う方法はわからなかった
    • タスクストレージ以外でマウントするとなるとEFSかsidecarのボリュームか
    • DockerボリュームはFargateでは使えないっぽい*1

参考

2023/05/28 追記

ephemeralStorageをマウントしなくても書き込み可にはなった あとVOLUMEを複数書けば symlinkをごにょごにょしなくても、書き込み可のディレクトリ増やせた