Skip to content
This repository has been archived by the owner on Nov 27, 2023. It is now read-only.

mounting EFS volume in multiple services fails #1054

Closed
AndrchiamusI opened this issue Dec 12, 2020 · 12 comments
Closed

mounting EFS volume in multiple services fails #1054

AndrchiamusI opened this issue Dec 12, 2020 · 12 comments
Assignees
Labels
bug 🐞 App is not working correctly. ecs

Comments

@AndrchiamusI
Copy link

Currently when you author a compose file with a volume mount going to two different services you get the below error on running docker compose up due to duplicate mounting in subnets.

This ticket is a feature request to support mounting between services using volume EFS.

fsmt-1d7dc3ec already exists in stack arn:aws:cloudformation:eu-west-2:xxxx:stack/play/sdfgfd-3cc8-11eb-af6f-dsfgfd

Example compose file

version: "3.8"

services:
  nginx:
    image: nginx:latest
    ports:
      - 80:80
    networks:
      - ngnetwork
    volumes:
      - ngdata:/var/www/html
  nginx2:
    image: nginx:latest
    networks:
      - ngnetwork
    volumes:
      - ngdata:/var/www/html
volumes:            
  ngdata:
networks:
  ngnetwork:
@ndeloof ndeloof added bug 🐞 App is not working correctly. ecs labels Dec 13, 2020
@ndeloof ndeloof self-assigned this Dec 13, 2020
@ndeloof
Copy link
Collaborator

ndeloof commented Dec 13, 2020

Thanks for reporting this issue, I'll look into this tomorrow on business hours.

@ndeloof ndeloof changed the title Feature Request - support EFS mounting for multiple services in compose file mounting EFS volume in multiple services fails Dec 13, 2020
@liannario
Copy link

While I can reproduce this issue, a workaround can be to use external and name in the volume definition, for example:

volumes:            
  ngdata:
    external: true
    name: <EFS fs name> 

Docker compose will skip EFS volume creation and just use the existing one.

@ndeloof
Copy link
Collaborator

ndeloof commented Dec 14, 2020

I tried to run your sample compose.yaml file and get a successful deployment.
This error is weird, as ECS integration creates mount targets in each subnet for the volume, independently for services.
also, error fsmt-1d7dc3ec already exists in stack ... to show the explicit mount ID suggest this one is an input for the cloudformation template. Could you please use docker compose convert to produce the equivalent CloudFormation template and attach it to this issue (please remove any sensible data)

@liannario this syntax is valid but should be used for EFS filesystem you created, but compose up should auto-magically retrieve the one he created for previous deployment and re-attach without such an error.

@liannario
Copy link

liannario commented Dec 14, 2020

I tried to create a stack directly in CloudFormation with the template resulting from docker compose convert and it worked. If I use docker compose up instead if fails with: "NginxService TaskFailedToStart: ResourceInitializationError: failed to invoke EFS utils commands to set up EFS volumes: stderr: mount.nfs4: Connection reset by peer : unsuccessful EFS utils command execution; code: 32".

I can see in the CloudFormation template the EFS resources are declared only once (as expected).

@ndeloof
Copy link
Collaborator

ndeloof commented Dec 14, 2020

as compose up just applies the converted template using CloudFormation API I don't think this nfs command failure is related to this issue. If this error persist could you please open a dedicated issue?

@AndrchiamusI
Copy link
Author

AndrchiamusI commented Dec 14, 2020

Thank you both for responding.

I tried the compose up command in a new region and so on the default vpc and it worked. When I run it on abnother VPC which was created using terraform it failed with a fsmt error after timing out on delete (20 minutes)

terraform to make repeatable vpc

# https://github.com/cloudposse/terraform-aws-vpc
module "vpc" {
  source                                          = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.18.0"
  namespace                                       = var.namespace
  stage                                           = var.env
  name                                            = var.name
  cidr_block                                      = var.vpc_cidr_block
  enable_default_security_group_with_custom_rules = false
}

# https://github.com/cloudposse/terraform-aws-dynamic-subnets
module "dynamic_subnets" {
  source              = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.31.0"
  namespace           = var.namespace
  stage               = var.env
  name                = var.name
  availability_zones  = var.availability_zones
  vpc_id              = module.vpc.vpc_id
  igw_id              = module.vpc.igw_id
  cidr_block          = module.vpc.vpc_cidr_block
  nat_gateway_enabled = false
}

compose file with vpc specified

version: "3.8"

x-aws-vpc: "vpc-xxx"

services:
  nginx:
    image: nginx:latest
    ports:
      - 80:80
    networks:
      - ngnetwork
    volumes:
      - ngdata:/var/www/html
  nginx2:
    image: nginx:latest
    networks:
      - ngnetwork
    volumes:
      - ngdata:/var/www/html
volumes:
  ngdata:
networks:
  ngnetwork:

cloud formation from docker compose convert

AWSTemplateFormatVersion: 2010-09-09
Resources:
  CloudMap:
    Properties:
      Description: Service Map for Docker Compose project dc-github
      Name: dc-github.local
      Vpc: vpc-xxxx
    Type: AWS::ServiceDiscovery::PrivateDnsNamespace
  Cluster:
    Properties:
      ClusterName: dc-github
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
    Type: AWS::ECS::Cluster
  LoadBalancer:
    Properties:
      Scheme: internet-facing
      SecurityGroups:
      - Ref: NgnetworkNetwork
      Subnets:
      - subnet-046ba7ac726cdac84
      - subnet-01823730fddd7ab77
      - subnet-0babc7ef89eb58953
      - subnet-0158c0c2ba71e5ee4
      - subnet-0c46610dfb79debe3
      - subnet-0c10bc7011a7159b3
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      Type: application
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  LogGroup:
    Properties:
      LogGroupName: /docker-compose/dc-github
    Type: AWS::Logs::LogGroup
  NgdataAccessPoint:
    Properties:
      AccessPointTags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.volume
        Value: ngdata
      - Key: Name
        Value: dc-github_ngdata
      FileSystemId: fs-6fa4cede
    Type: AWS::EFS::AccessPoint
  NgdataNFSMountTargetOnSubnet046ba7ac726cdac84:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-046ba7ac726cdac84
    Type: AWS::EFS::MountTarget
  NgdataNFSMountTargetOnSubnet0158c0c2ba71e5ee4:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-0158c0c2ba71e5ee4
    Type: AWS::EFS::MountTarget
  NgdataNFSMountTargetOnSubnet01823730fddd7ab77:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-01823730fddd7ab77
    Type: AWS::EFS::MountTarget
  NgdataNFSMountTargetOnSubnet0babc7ef89eb58953:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-0babc7ef89eb58953
    Type: AWS::EFS::MountTarget
  NgdataNFSMountTargetOnSubnet0c10bc7011a7159b3:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-0c10bc7011a7159b3
    Type: AWS::EFS::MountTarget
  NgdataNFSMountTargetOnSubnet0c46610dfb79debe3:
    Properties:
      FileSystemId: fs-6fa4cede
      SecurityGroups:
      - Ref: NgnetworkNetwork
      SubnetId: subnet-0c46610dfb79debe3
    Type: AWS::EFS::MountTarget
  Nginx2Service:
    DependsOn:
    - NgdataNFSMountTargetOnSubnet046ba7ac726cdac84
    - NgdataNFSMountTargetOnSubnet01823730fddd7ab77
    - NgdataNFSMountTargetOnSubnet0babc7ef89eb58953
    - NgdataNFSMountTargetOnSubnet0158c0c2ba71e5ee4
    - NgdataNFSMountTargetOnSubnet0c46610dfb79debe3
    - NgdataNFSMountTargetOnSubnet0c10bc7011a7159b3
    Properties:
      Cluster:
        Fn::GetAtt:
        - Cluster
        - Arn
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DeploymentController:
        Type: ECS
      DesiredCount: 1
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
          - Ref: NgnetworkNetwork
          Subnets:
          - subnet-046ba7ac726cdac84
          - subnet-01823730fddd7ab77
          - subnet-0babc7ef89eb58953
          - subnet-0158c0c2ba71e5ee4
          - subnet-0c46610dfb79debe3
          - subnet-0c10bc7011a7159b3
      PlatformVersion: 1.4.0
      PropagateTags: SERVICE
      SchedulingStrategy: REPLICA
      ServiceRegistries:
      - RegistryArn:
          Fn::GetAtt:
          - Nginx2ServiceDiscoveryEntry
          - Arn
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx2
      TaskDefinition:
        Ref: Nginx2TaskDefinition
    Type: AWS::ECS::Service
  Nginx2ServiceDiscoveryEntry:
    Properties:
      Description: '"nginx2" service discovery entry in Cloud Map'
      DnsConfig:
        DnsRecords:
        - TTL: 60
          Type: A
        RoutingPolicy: MULTIVALUE
      HealthCheckCustomConfig:
        FailureThreshold: 1
      Name: nginx2
      NamespaceId:
        Ref: CloudMap
    Type: AWS::ServiceDiscovery::Service
  Nginx2TaskDefinition:
    Properties:
      ContainerDefinitions:
      - Command:
        - eu-west-3.compute.internal
        - dc-github.local
        Essential: false
        Image: docker/ecs-searchdomain-sidecar:1.0
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group:
              Ref: LogGroup
            awslogs-region:
              Ref: AWS::Region
            awslogs-stream-prefix: dc-github
        Name: Nginx2_ResolvConf_InitContainer
      - DependsOn:
        - Condition: SUCCESS
          ContainerName: Nginx2_ResolvConf_InitContainer
        Essential: true
        Image: nginx:latest
        LinuxParameters: {}
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group:
              Ref: LogGroup
            awslogs-region:
              Ref: AWS::Region
            awslogs-stream-prefix: dc-github
        MountPoints:
        - ContainerPath: /var/www/html
          SourceVolume: ngdata
        Name: nginx2
      Cpu: "256"
      ExecutionRoleArn:
        Ref: Nginx2TaskExecutionRole
      Family: dc-github-nginx2
      Memory: "512"
      NetworkMode: awsvpc
      RequiresCompatibilities:
      - FARGATE
      TaskRoleArn:
        Ref: Nginx2TaskRole
      Volumes:
      - EFSVolumeConfiguration:
          AuthorizationConfig:
            AccessPointId:
              Ref: NgdataAccessPoint
            IAM: ENABLED
          FilesystemId: fs-6fa4cede
          TransitEncryption: ENABLED
        Name: ngdata
    Type: AWS::ECS::TaskDefinition
  Nginx2TaskExecutionRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Condition: {}
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
        Version: 2012-10-17
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx2
    Type: AWS::IAM::Role
  Nginx2TaskRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Condition: {}
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
        Version: 2012-10-17
      Policies:
      - PolicyDocument:
          Statement:
          - Action:
            - elasticfilesystem:ClientMount
            - elasticfilesystem:ClientWrite
            - elasticfilesystem:ClientRootAccess
            Condition:
              StringEquals:
                elasticfilesystem:AccessPointArn:
                  Ref: NgdataAccessPoint
            Effect: Allow
            Principal: {}
            Resource:
            - arn:aws:elasticfilesystem:eu-west-3:xxxx:file-system/fs-6fa4cede
          Version: 2012-10-17
        PolicyName: Nginx2NgdataVolumeMountPolicy
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx2
    Type: AWS::IAM::Role
  NginxService:
    DependsOn:
    - NginxTCP80Listener
    - NgdataNFSMountTargetOnSubnet046ba7ac726cdac84
    - NgdataNFSMountTargetOnSubnet01823730fddd7ab77
    - NgdataNFSMountTargetOnSubnet0babc7ef89eb58953
    - NgdataNFSMountTargetOnSubnet0158c0c2ba71e5ee4
    - NgdataNFSMountTargetOnSubnet0c46610dfb79debe3
    - NgdataNFSMountTargetOnSubnet0c10bc7011a7159b3
    Properties:
      Cluster:
        Fn::GetAtt:
        - Cluster
        - Arn
      DeploymentConfiguration:
        MaximumPercent: 200
        MinimumHealthyPercent: 100
      DeploymentController:
        Type: ECS
      DesiredCount: 1
      LaunchType: FARGATE
      LoadBalancers:
      - ContainerName: nginx
        ContainerPort: 80
        TargetGroupArn:
          Ref: NginxTCP80TargetGroup
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: ENABLED
          SecurityGroups:
          - Ref: NgnetworkNetwork
          Subnets:
          - subnet-046ba7ac726cdac84
          - subnet-01823730fddd7ab77
          - subnet-0babc7ef89eb58953
          - subnet-0158c0c2ba71e5ee4
          - subnet-0c46610dfb79debe3
          - subnet-0c10bc7011a7159b3
      PlatformVersion: 1.4.0
      PropagateTags: SERVICE
      SchedulingStrategy: REPLICA
      ServiceRegistries:
      - RegistryArn:
          Fn::GetAtt:
          - NginxServiceDiscoveryEntry
          - Arn
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx
      TaskDefinition:
        Ref: NginxTaskDefinition
    Type: AWS::ECS::Service
  NginxServiceDiscoveryEntry:
    Properties:
      Description: '"nginx" service discovery entry in Cloud Map'
      DnsConfig:
        DnsRecords:
        - TTL: 60
          Type: A
        RoutingPolicy: MULTIVALUE
      HealthCheckCustomConfig:
        FailureThreshold: 1
      Name: nginx
      NamespaceId:
        Ref: CloudMap
    Type: AWS::ServiceDiscovery::Service
  NginxTCP80Listener:
    Properties:
      DefaultActions:
      - ForwardConfig:
          TargetGroups:
          - TargetGroupArn:
              Ref: NginxTCP80TargetGroup
        Type: forward
      LoadBalancerArn:
        Ref: LoadBalancer
      Port: 80
      Protocol: HTTP
    Type: AWS::ElasticLoadBalancingV2::Listener
  NginxTCP80TargetGroup:
    Properties:
      Port: 80
      Protocol: HTTP
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      TargetType: ip
      VpcId: vpc-xxxx
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
  NginxTaskDefinition:
    Properties:
      ContainerDefinitions:
      - Command:
        - eu-west-3.compute.internal
        - dc-github.local
        Essential: false
        Image: docker/ecs-searchdomain-sidecar:1.0
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group:
              Ref: LogGroup
            awslogs-region:
              Ref: AWS::Region
            awslogs-stream-prefix: dc-github
        Name: Nginx_ResolvConf_InitContainer
      - DependsOn:
        - Condition: SUCCESS
          ContainerName: Nginx_ResolvConf_InitContainer
        Essential: true
        Image: nginx:latest
        LinuxParameters: {}
        LogConfiguration:
          LogDriver: awslogs
          Options:
            awslogs-group:
              Ref: LogGroup
            awslogs-region:
              Ref: AWS::Region
            awslogs-stream-prefix: dc-github
        MountPoints:
        - ContainerPath: /var/www/html
          SourceVolume: ngdata
        Name: nginx
        PortMappings:
        - ContainerPort: 80
          HostPort: 80
          Protocol: tcp
      Cpu: "256"
      ExecutionRoleArn:
        Ref: NginxTaskExecutionRole
      Family: dc-github-nginx
      Memory: "512"
      NetworkMode: awsvpc
      RequiresCompatibilities:
      - FARGATE
      TaskRoleArn:
        Ref: NginxTaskRole
      Volumes:
      - EFSVolumeConfiguration:
          AuthorizationConfig:
            AccessPointId:
              Ref: NgdataAccessPoint
            IAM: ENABLED
          FilesystemId: fs-6fa4cede
          TransitEncryption: ENABLED
        Name: ngdata
    Type: AWS::ECS::TaskDefinition
  NginxTaskExecutionRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Condition: {}
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
        Version: 2012-10-17
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
      - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx
    Type: AWS::IAM::Role
  NginxTaskRole:
    Properties:
      AssumeRolePolicyDocument:
        Statement:
        - Action:
          - sts:AssumeRole
          Condition: {}
          Effect: Allow
          Principal:
            Service: ecs-tasks.amazonaws.com
        Version: 2012-10-17
      Policies:
      - PolicyDocument:
          Statement:
          - Action:
            - elasticfilesystem:ClientMount
            - elasticfilesystem:ClientWrite
            - elasticfilesystem:ClientRootAccess
            Condition:
              StringEquals:
                elasticfilesystem:AccessPointArn:
                  Ref: NgdataAccessPoint
            Effect: Allow
            Principal: {}
            Resource:
            - arn:aws:elasticfilesystem:eu-west-3:xxxx:file-system/fs-6fa4cede
          Version: 2012-10-17
        PolicyName: NginxNgdataVolumeMountPolicy
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.service
        Value: nginx
    Type: AWS::IAM::Role
  Ngnetwork80Ingress:
    Properties:
      CidrIp: 0.0.0.0/0
      Description: nginx:80/tcp on ngnetwork network
      FromPort: 80
      GroupId:
        Ref: NgnetworkNetwork
      IpProtocol: TCP
      ToPort: 80
    Type: AWS::EC2::SecurityGroupIngress
  NgnetworkNetwork:
    Properties:
      GroupDescription: dc-github Security Group for ngnetwork network
      Tags:
      - Key: com.docker.compose.project
        Value: dc-github
      - Key: com.docker.compose.network
        Value: ngnetwork
      VpcId: vpc-xxxx
    Type: AWS::EC2::SecurityGroup
  NgnetworkNetworkIngress:
    Properties:
      Description: Allow communication within network ngnetwork
      GroupId:
        Ref: NgnetworkNetwork
      IpProtocol: "-1"
      SourceSecurityGroupId:
        Ref: NgnetworkNetwork
    Type: AWS::EC2::SecurityGroupIngress

EDIT: The cloud formation seems to be targetting private subnets too.
EDIT: error from this one is due to load balancer (see below).

A load balancer cannot be attached to multiple subnets in the same Availability Zone (Service: AmazonElasticLoadBalancing; Status Code: 400; Error Code: InvalidConfigurationRequest; Request ID:

@ndeloof
Copy link
Collaborator

ndeloof commented Dec 14, 2020

ECS integration does not support (yet) multiple subnets per availability zone.
See #921 about this specific LoadBalancer error

@AndrchiamusI
Copy link
Author

So, is that the issue. When I create my own application load balancer ans specify it with the tag in the compose file the EFS also does not support public and private subnets?

@ndeloof
Copy link
Collaborator

ndeloof commented Dec 14, 2020

In the current implementation we collect all subnets from the configured VPC and this create such configuration issues. I'm looking into selecting only the public subnets, but AWS API doesn't make this trivial. Private subnets don't make much sense as this would prevent the service to pull required sidecar images from DockerHub.

@gtardif
Copy link
Contributor

gtardif commented Dec 18, 2020

This has been fixed by #1064 , along with #921. (Selecting only public subnets)

@gtardif gtardif closed this as completed Dec 18, 2020
@mreferre
Copy link
Contributor

mreferre commented Apr 3, 2021

I came across this error message in my tests and opened a dedicated issue: #1490

@j4ys0n
Copy link

j4ys0n commented Jul 16, 2021

I had this same issue and it was resolved by changing the volume name. I had used the same volume name in another region, i guess there was a conflict.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
bug 🐞 App is not working correctly. ecs
Projects
None yet
Development

No branches or pull requests

6 participants