Attach ephemeral storage to Fargate service with CloudFormation - expected type: JSONArray, found: JSONObject

24.4k views Asked by At

I'm trying to attach an ephemeral volume to a service that we run on Fargate, so it can generate some files before copying them into S3. When I launch the service without the volume information, the CloudFormation template is created successfully, and the service runs.

However, when putting the volume parameters, it fails with this error:

Model validation failed (#/Volumes: expected type: JSONArray, found: JSONObject #/ContainerDefinitions/0/MountPoints: expected type: JSONArray, found: JSONObject #/ContainerDefinitions/0/PortMappings/0/ContainerPort: expected type: Number, found: String)

And this is the template:

  Cluster:
    Type: AWS::ECS::Cluster
    Properties:
      ClusterName: !Join ['-', [!Ref Env, !Ref ShortServiceName, cluster]]
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    DependsOn: LogGroup
    Properties:
      Family: !Join ['-', [!Ref Env, !Ref ShortServiceName, 'taskdefinition']]
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      Cpu: !Ref Cpu
      Memory: !Ref Memory
      Volumes:
        Name: !Ref VolumeName
        DockerVolumeConfiguration:
          Autoprovision: True
          Scope: Task
      ExecutionRoleArn: !Ref ExecutionRole
      TaskRoleArn: !Ref TaskRole
      ContainerDefinitions:
        - Name: !Join ['-', [!Ref Env, !Ref ShortServiceName]]
          Image: !Ref Image
          RepositoryCredentials:
            CredentialsParameter: !Ref RepositoryCredentials
          PortMappings:
            - ContainerPort: !Ref ContainerPort
          MountPoints:
            ContainerPath: "/app"
            SourceVolume: !Ref VolumeName
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-region: !Ref AWS::Region
              awslogs-group: !Ref LogGroup
              awslogs-stream-prefix: ecs

  ContainerSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      Tags:
        -
          Key: Name
          Value: !Join ['-', [!Ref ShortServiceName, 'app-sg']]
      GroupDescription: !Join ['-', [!Ref ShortServiceName, ContainerSecurityGroup]]
      VpcId: !Ref VPC
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: !Ref ContainerPort
          ToPort: !Ref ContainerPort
          SourceSecurityGroupId: !Ref ManagementSecurityGroup

  Service:
    Type: AWS::ECS::Service
    Properties:
      ServiceName: !Ref ServiceName
      Cluster: !Ref Cluster
      TaskDefinition: !Ref TaskDefinition
      DeploymentConfiguration:
        MinimumHealthyPercent: 50
        MaximumPercent: 200
      DesiredCount: !Ref DesiredCount
      LaunchType: FARGATE
      NetworkConfiguration:
        AwsvpcConfiguration:
          AssignPublicIp: DISABLED
          Subnets:
            - !Ref AppSubnetA
            - !Ref AppSubnetB
          SecurityGroups:
            - !Ref ManagementSecurityGroup
            - !Ref ContainerSecurityGroup

  LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join ['/', [/ecs, !Ref Env, !Ref ServiceName]]

Outputs:
  ContainerSecurityGroup:
    Description: ContainerSecurityGroup
    Value: !Ref ContainerSecurityGroup

I have searched high and low for the issue, yet haven't found anything related to the problem. Also, the ContainerPort parameter works fine as a string when not attaching the volume. I have also tried changing the type from String to Number but keep getting the same found JsonObject, whilst it was expecting JsonArray.

Could someone throw me in the right direction, please?

Cheers!

4

There are 4 answers

3
Marcin On BEST ANSWER

MountPoints should be a list of MountPoint. Thus in you case it should be (note -):

          MountPoints:
            - ContainerPath: "/app"
              SourceVolume: !Ref VolumeName
0
ARITRA CHAKRABORTY On

Please use this:

ContainerDefinitions:
  - Name: !Join ['-', [!Ref Env, !Ref ShortServiceName]]
    Image: !Ref Image

This should solve your problem. I think that you entered the Name and Image as key value pairs, but you forgot to maintain the indentation here. It seems to be the case to me.

1
pooja ganvir On
VpcEndponit:
    Type: AWS::EC2::VPCEndpoint
    Properties:
      ServiceName: com.amazonaws.ap-south-1.s3
      VpcEndpointType: Gateway
      VpcId:
        Ref: MyVpc
      RouteTableIds:
        Ref: PrivateRouteTable
      SubnetIds:
        - !Ref MySubnet
        - !Ref PrivateSub
0
Jackstine On

put it as an entire JSON Object, no quotes!. Example

MyRepo:
  Type: AWS::ECR::Repository
  Properties:
    RepositoryName: my/repo
    EncryptionConfiguration: {"encryptionType": "AES256"}
  DeletionPolicy: Retain