AWS ECS (Fargate) не может смонтировать файловую систему EFS Не удалось устранить

В моем тестовом проекте я пытаюсь смонтировать EFS в свой контейнер Fargate с помощью AWS Javascript SDK. Я использовал это сообщение в блоге как ссылку на то, что я реализую: https://aws.amazon.com/blogs/containers/developers-guide-to-using-amazon-efs-with-amazon-ecs-and-aws-fargate-part-3/

Кажется, у меня те же шаги, что и в части EFS в блоге AWS. Но я столкнулся со следующей ошибкой, которая отображается в статусе задачи ECS:

ResourceInitializationError: не удалось вызвать команды EFS utils для настройки томов EFS: stderr: Не удалось разрешить fs-XXXXX.efs.us-east-1.amazonaws.com - проверьте правильность идентификатора вашей файловой системы. См. https://docs.aws.amazon.com/console/efs/mount-d...%27,%22

Разрешение DNS и имена хостов DNS включены в моем VPC.

Вот самые важные фрагменты кода:

import * as SDK from 'aws-sdk';
import Config from '../config';
import Networking from '../cluster/networking';
import Logging from '../cluster/logging';
import BuildJobParams from './buildJobParams';

import ExecutionRole from '../executionRole/executionRole';

class BuildJob {
    static async run() {
        let taskDefinitionArn = await this.registerJob();
        let params = {
            cluster: Config.default.clusterName,
            taskDefinition: taskDefinitionArn,
            platformVersion: "1.4.0",
            launchType: "FARGATE",
            networkConfiguration: {
                awsvpcConfiguration: {
                    subnets: [
                        await Networking.get()
                        ],
                    assignPublicIp: "ENABLED",
                    securityGroups: [
                        await Networking.getSecurityGroup()
                    ]
                }
            },
        };
        let ECS = new SDK.ECS();
        console.log("Build job starting");
        let task = await ECS.runTask(params).promise();
        await this.watch(task.tasks[0].taskArn);

        return task;
    }

    static async watch(task) {
        let ECS = new SDK.ECS();
        try{

        await ECS.waitFor("tasksRunning", {
            cluster: Config.default.clusterName,
            tasks: [task]
        }).promise();

        console.log("Build job is running, watching logs");
        await Logging.watch(async () => {
            return (await (new SDK.ECS()).describeTasks({ tasks: [task], cluster: Config.default.clusterName }).promise()).tasks[0].lastStatus;
        });


        await ECS.waitFor("tasksStopped", {
            cluster: Config.default.clusterName,
            tasks: [task]
        }).promise();

        console.log("Build job has ended");
        }catch(err){
           console.log( await ECS.describeTasks({
            cluster: Config.default.clusterName,
            tasks: [task]}).promise())
            console.error(err);
        }
    }

    static async registerJob() {
        let ECS = new SDK.ECS();
        let taskDefinitionResult = await ECS.registerTaskDefinition(await BuildJobParams.get()).promise();
        return taskDefinitionResult.taskDefinition.taskDefinitionArn;
    }
}

export default BuildJob
import Config from '../config'
import ElasticFileSystem from '../cluster/fileSystem';
import ExecutionRole from '../executionRole/executionRole';

class BuildJobParams{
    static async get(){
        return {
            containerDefinitions: [
                {
                    name: "BuildWorker",
                    command: Config.default.buildJobCommand,
                    environment: [
                        { name: "ws", value: "" }
                    ],
                    image: "ubuntu",
                    logConfiguration: {
                        logDriver: "awslogs",
                        options: {
                            "awslogs-group": Config.default.logGroupName,
                            "awslogs-stream-prefix": "ecs",
                            "awslogs-region": Config.default.region
                        }
                    },
                    mountPoints: [
                        {
                            containerPath: "/efs/",
                            sourceVolume: 'test'
                        }
                    ],
                    portMappings:[
                        {
                            containerPort: "2049", 
                            hostPort:"2049", 
                            protocol: "tcp"
                            }
                    ]
                }
            ],
            memory: "512",
            cpu: "256",
            family: "GameCI",
            volumes: [
                {
                    name: "test",
                    efsVolumeConfiguration: {
                        fileSystemId: ElasticFileSystem.getFileSystemId(),
                        transitEncryption: "ENABLED",
                        authorizationConfig: {
                            accessPointId: ElasticFileSystem.getAccessPointId(),
                            iam: "DISABLED"
                        }
                    }
                }
            ],
            requiresCompatibilities: ["FARGATE"],
            networkMode: "awsvpc", 
            taskRoleArn: (await ExecutionRole.getRunArn()),
            executionRoleArn : (await ExecutionRole.getLoggingArn())
        };
    }
}
export default BuildJobParams
import * as SDK from 'aws-sdk';
import Config from '../config';
import Networking from './networking';

class ElasticFileSystem {
    static async get() {
        let EFS = new SDK.EFS();
        let params = {
            CreationToken: Config.default.clusterName,
            PerformanceMode: "generalPurpose",
            Encrypted: true,
            Tags: [
                {
                    Key: "Name",
                    Value: "MyFileSystem"
                }
            ]
        };

        let result = await EFS.createFileSystem(params).promise();
        while((await EFS.describeFileSystems().promise()).FileSystems.find(element=>element.FileSystemId==result.FileSystemId).LifeCycleState != "available")
        {
            await (new Promise((resolve) => setTimeout(resolve, 10000)));
            let state = (await EFS.describeFileSystems().promise()).FileSystems.find(element=>element.CreationToken==Config.default.clusterName).LifeCycleState;
            if(state != "creating" && state != "available" && state != "updating"){
                throw `Failed to create file system (${state})`;
            }
        }
        let accessPoint = await EFS.createAccessPoint({
            FileSystemId: result.FileSystemId,
            ClientToken: Config.default.clusterName
        }).promise();
        let mt = await EFS.createMountTarget({
            FileSystemId: result.FileSystemId,
            SubnetId: `${await Networking.get()}`,
            SecurityGroups: [
                `${await Networking.getSecurityGroup()}`
            ],
        }).promise();
        console.log("File System created");
        
        
        Object.assign(ElasticFileSystem, {
            fileSystemId: result.FileSystemId,
            accessPointId: accessPoint.AccessPointId,
            mountTargetId: mt.MountTargetId
        });
        return result;
    }

    static getFileSystemId(){
        console.log(this.fileSystemId);
        return this.fileSystemId;
    }

    static getAccessPointId(){
        console.log(this.fileSystemId);
        return this.accessPointId;
    }

    static getMountTargetId(){
        console.log(this.fileSystemId);
        return this.mountTargetId;
    }

    static async delete() {
        let EFS = new SDK.EFS();
        let params = {
            FileSystemId: this.fileSystemId
        };
        //await EFS.deleteFileSystem(params).promise();
        let fs = await EFS.describeFileSystems().promise();
        for (let index = 0; index < fs.FileSystems.length; index++) {
            const element = fs.FileSystems[index];
            await EFS.deleteFileSystem({FileSystemId:element.FileSystemId}).promise();
        }
    }
}

export default ElasticFileSystem
import * as SDK from 'aws-sdk';

import Logging from './logging';
import ElasticFileSystem from './fileSystem';
import Config from '../config';

class ElasticCluster {
    static async get() {
        console.log("Creating cluster");

        await Logging.get(Config.default.logGroupName);
        let fileSystem = await ElasticFileSystem.get();
        let ECS = new SDK.ECS();
        Object.assign(ElasticCluster, {
            ECS: ECS
        });

        let data = await this.create();
        await ElasticCluster.waitForClusterReady();
        console.log("Created cluster");
        return data;
    }

    static async create() {
        let params = {
            capacityProviders: [
                'FARGATE'
            ],
            clusterName: Config.default.clusterName,
            defaultCapacityProviderStrategy: [
                {
                    capacityProvider: 'FARGATE',
                    base: '0',
                    weight: '1'
                }
            ],
            settings: [],
            tags: [
                {
                    key: 'STRING_VALUE',
                    value: 'STRING_VALUE'
                }
            ]
        };
        return await this.ECS.createCluster(params).promise();
    }

    static async exists(){
        let params = {
            clusters: [
                Config.default.clusterName,
            ]
        };
        return (await this.ECS.describeClusters(params).promise()).clusters.length > 0;
    }

    static async getCluster(){
        let params = {
            clusters: [
                Config.default.clusterName,
            ]
        };
        return (await this.ECS.describeClusters(params).promise()).clusters[0];
    }

    static async waitForClusterReady() {
        let cluster = await this.getCluster();
        if (cluster.status == "ACTIVE" || cluster.status == "INACTIVE") {
            return;
        }
        else {
            await new Promise(res => setTimeout(res, 10000));
            await this.waitForClusterReady();
        }
    }


    static async delete() {
        let ecs = new SDK.ECS();

        try {
            //await this.ECS.deleteCluster({
            //    cluster: Config.default.clusterName
            //}).promise();
            let clusters = (await ecs.listClusters().promise()).clusterArns;
            for (let index = 0; index < clusters.length; index++) {
                const element = clusters[index];
                await ecs.deleteCluster({
                    cluster: element
                }).promise();
            }
        } catch (err) {

        }
        await ElasticFileSystem.delete();
        await Logging.delete();
        console.log("garbage collected");
    }
}

export default ElasticCluster
import * as SDK from 'aws-sdk';
import Config from '../config';


class Networking {
    static async get() {
        return (await this.getAll())[0].SubnetId;
    }

    static async getAll() {
        let EC2 = new SDK.EC2();
        let params = {
            Filters: [
                {
                    Name: "vpc-id",
                    Values: [
                        await this.getVpcId()
                    ]
                }
            ]
        };
        let value = await EC2.describeSubnets(params).promise();
        return value.Subnets;
    }

    static async getSecurityGroup() {
        let EC2 = new SDK.EC2();
        if (this.securityGroup != null){
            return this.securityGroup;
        }
        console.log("creating security group");
        let sg = await EC2.createSecurityGroup({
            GroupName: Config.default.clusterName,
            Description: "test",
            VpcId: await this.getVpcId(),
            
        }).promise();
        await EC2.authorizeSecurityGroupIngress({
            GroupId: sg.GroupId,
            IpPermissions: [{
                
                FromPort: "2049",
                ToPort: "2049",
                IpProtocol: "tcp",
            }]
        }).promise();
        Object.assign(this, {securityGroup:sg.GroupId});
        return sg.GroupId;
    }

    static async getVpcId() {
        return "vpc-XXXXXXX";
    }
}

export default Networking

person Markus Fisher    schedule 03.01.2021    source источник
comment
ошибка может вводить в заблуждение, и могут быть проблемы с настройкой сети, которые не позволяют вашему сценарию разрешить этот URL-адрес. Некоторые основные моменты, на которые следует обратить внимание: разрешение группы безопасности, наличие точки монтирования EFS в той же зоне доступности и обеспечение того, чтобы EFS находилась в том же VPC. Если вы устраните все проблемы с сетью, я бы посмотрел, как настроена служба, и на отсутствие какой-либо политики IAM, необходимой для обслуживания запросов.   -  person ayush3504    schedule 03.01.2021


Ответы (1)


TL; DR: убедитесь, что в вашем наборе параметров DHCP есть AmazonProvidedDNS

У меня такая же проблема с моим стеком CDK. Моя задача выполняется в частной подсети моего VPC, и я подтвердил, что EFS настроен правильно, так как у меня есть лямбда, настроенная для работы в той же частной подсети, и она отлично подключается к EFS.

Я пробовал конечные точки интерфейса VPC для EFS, без сигары.

Я еще не смог протестировать, но ваше решение может быть основано на информации, которую я нашел на acloud.guru, любопытно, что в этом сообщении 2 года назад говорится, что поддержка EFS в Fargate не была добавлена ​​только что 2020?

В моем VPC включены как имена хостов DNS, так и разрешение, но в моем наборе параметров DHCP нет AmazonProvidedDNS в качестве сервера имен, что объясняет, почему мы получаем Failed to resolve fs-XXXXX.efs.us-east-1.amazonaws .com

person w0otness    schedule 01.04.2021
comment
Кроме того, проверьте это: stackoverflow.com/a/67539850/7348119 - person Luigi Lopez; 14.05.2021