使用非 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
并且一切正常。
我将 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
并且一切正常。