使用非 root 用户时无法在 ECS Fragate 上写入绑定挂载

Can't write to bind mount on ECS Fragate when using non-root user

我将 ECS 与 Fargate 结合使用并尝试在临时存储上创建绑定装载,但我的用户 (id 1000) 无法写入该卷。

根据documentation,应该是可以的。

但是文档提到:

By default, the volume permissions are set to 0755 and the owner as root. These permissions can be customized in the Dockerfile.

所以在我的 Dockerfile 中我有

ARG PHP_VERSION=8.1.2-fpm-alpine3.15
FROM php:$PHP_VERSION as php_base

ENV APP_USER=app
ENV APP_USER_HOME=/home/app
ENV APP_USER_UID=1000
ENV APP_USER_GID=1000
ENV APP_HOME=/srv/app

# create the app user
RUN set -eux; \
    addgroup -g $APP_USER_GID -S $APP_USER; \
    adduser -S -D -h "$APP_USER_HOME" -u $APP_USER_UID -s /sbin/nologin -G $APP_USER -g $APP_USER $APP_USER

RUN set -eux; \
    mkdir -p /var/run/php; \
    chown -R ${APP_USER}:${APP_USER} /var/run/php; \
    # TODO THIS IS A TEST
    chmod 777 /var/run/php
# ...

FROM php_base as php_prod

# ...

VOLUME ["/var/run/php"]
USER $APP_USER
WORKDIR "${APP_HOME}"
ENTRYPOINT ["/usr/local/bin/docker-php-entrypoint"]
CMD ["php-fpm"]

在我的任务定义中我有:

{
    "taskDefinitionArn": "arn:aws:ecs:us-east-1:999999999999:task-definition/app:2",
    "containerDefinitions": [
        {
            "name": "app-php",
            "image": "999999999999.dkr.ecr.us-east-1.amazonaws.com/php:latest",
            "cpu": 0,
            "portMappings": [],
            "essential": true,
            "environment": [
                {
                    "name": "DATABASE_PORT",
                    "value": "3306"
                },
                {
                    "name": "DATABASE_USERNAME",
                    "value": "app"
                },
                {
                    "name": "DATABASE_NAME",
                    "value": "app"
                },
                {
                    "name": "DATABASE_HOST",
                    "value": "db.xxxxxxxxxxxx.us-east-1.rds.amazonaws.com"
                }
            ],
            "mountPoints": [
                {
                    "sourceVolume": "php_socket",
                    "containerPath": "/var/run/php",
                    "readOnly": false
                }
            ],
            "volumesFrom": [],
            "secrets": [
                {
                    "name": "DATABASE_PASSWORD",
                    "valueFrom": "arn:aws:ssm:us-east-1:999999999999:parameter/db-password"
                }
            ],
            "readonlyRootFilesystem": false,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "app",
                    "awslogs-region": "us-east-1",
                    "awslogs-stream-prefix": "app"
                }
            },
            "healthCheck": {
                "command": [
                    "docker-healthcheck"
                ],
                "interval": 10,
                "timeout": 3,
                "retries": 3,
                "startPeriod": 15
            }
        },
        {
            "name": "app-proxy",
            "image": "999999999999.dkr.ecr.us-east-1.amazonaws.com/proxy:latest",
            "cpu": 0,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80,
                    "protocol": "tcp"
                }
            ],
            "essential": true,
            "environment": [],
            "mountPoints": [
                {
                    "sourceVolume": "php_socket",
                    "containerPath": "/var/run/php",
                    "readOnly": false
                }
            ],
            "volumesFrom": [],
            "dependsOn": [
                {
                    "containerName": "app-php",
                    "condition": "HEALTHY"
                }
            ],
            "readonlyRootFilesystem": false,
            "logConfiguration": {
                "logDriver": "awslogs",
                "options": {
                    "awslogs-group": "app",
                    "awslogs-region": "us-east-1",
                    "awslogs-stream-prefix": "app"
                }
            },
            "healthCheck": {
                "command": [
                    "curl",
                    "-s",
                    "localhost/status-nginx"
                ],
                "interval": 10,
                "timeout": 3,
                "retries": 3,
                "startPeriod": 15
            }
        }
    ],
    "family": "bnc-stage-remises-app",
    "taskRoleArn": "arn:aws:iam::999999999999:role/app-task",
    "executionRoleArn": "arn:aws:iam::999999999999:role/app-exec",
    "networkMode": "awsvpc",
    "revision": 2,
    "volumes": [
        {
            "name": "php_socket",
            "host": {}
        }
    ],
    "status": "ACTIVE",
    "requiresAttributes": [
        {
            "name": "com.amazonaws.ecs.capability.logging-driver.awslogs"
        },
        {
            "name": "ecs.capability.execution-role-awslogs"
        },
        {
            "name": "com.amazonaws.ecs.capability.ecr-auth"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.19"
        },
        {
            "name": "com.amazonaws.ecs.capability.task-iam-role"
        },
        {
            "name": "ecs.capability.container-health-check"
        },
        {
            "name": "ecs.capability.container-ordering"
        },
        {
            "name": "ecs.capability.execution-role-ecr-pull"
        },
        {
            "name": "ecs.capability.secrets.ssm.environment-variables"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.18"
        },
        {
            "name": "ecs.capability.task-eni"
        },
        {
            "name": "com.amazonaws.ecs.capability.docker-remote-api.1.29"
        }
    ],
    "placementConstraints": [],
    "compatibilities": [
        "EC2",
        "FARGATE"
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "2048",
    "registeredAt": "2022-02-15T15:54:47.452Z",
    "registeredBy": "arn:aws:sts::999999999999:assumed-role/OrganizationAccountAccessRole/9999999999999999999",
    "tags": [
        {
            "key": "Project",
            "value": "project-name"
        },
        {
            "key": "Environment",
            "value": "stage"
        },
        {
            "key": "ManagedBy",
            "value": "Terraform"
        },
        {
            "key": "Client",
            "value": "ClientName"
        },
        {
            "key": "Namespace",
            "value": "client-name"
        },
        {
            "key": "Name",
            "value": "app"
        }
    ]
}

然而,在 ECS 中,我不断收到

2022-02-15T20:36:14.679Z    [15-Feb-2022 20:36:14] ERROR: unable to bind listening socket for address '/var/run/php/php-fpm.sock': Permission denied (13)   app-php
2022-02-15T20:36:14.679Z    [15-Feb-2022 20:36:14] ERROR: unable to bind listening socket for address '/var/run/php/php-fpm.sock': Permission denied (13)   app-php
2022-02-15T20:36:14.679Z    [15-Feb-2022 20:36:14] ERROR: FPM initialization failed app-php
2022-02-15T20:36:14.679Z    [15-Feb-2022 20:36:14] ERROR: FPM initialization failed app-php

原来 /var/run 是我容器中 /run 的符号链接,而 ECS 无法处理这个问题。我将我的设置更改为使用 /run/php 而不是 /var/run/php 并且一切正常。