Powered by Zoomin Software. For more details please contactZoomin

Run on Amazon Web Services (AWS)

Resources declaration

  • Last Updated: April 14, 2026
  • 7 minute read
    • MarkLogic Server
    • Version 12.0
    • Documentation

The Resources portion of the template defines all of the AWS resources created for your stack by this template. Each resource is defined as a specific AWS type. The details of each resource type are described in AWS resource and property types reference.

These resources defined in this template include:

  • VpcStack — See VPC Stack for details.

  • ManagedEniStack — See Managed ENI Stack for details.

  • NodeMgrLambdaStack — See Node Manager Stack for details.

  • Elastic Block Store (EBS) volumes

  • DynamoDB Table (DynamoDB is the Amazon implementation of the Metadata Database)

  • AutoScaling Groups (ASG). For each ASG, there are the following resources:

  • Security Group

  • Instance Type

  • Identity and Access Management (IAM) Instance Profile

  • Launch Configuration

  • UserData

  • Load Balancer

  • Load Balancer ports

  • Health Check values

  • Security Group for each EC2 Instance

Because ENI is not managed by the CloudFormation stack directly, the Managed ENI Lambda function needs to identify the ENIs created in order to have the ability to update or clean them up. All ENIs created by the Lambda function are tagged with stack information.

The Availability Zones for VPC subnets. Accept either 1 zone or 3 zones. In the order of Subnet 1, Subnet 2 and Subnet 3 (if applicable). The Subnets in the VPC. You must provide values for all three public and private subnets for successful deployment. The order must be same as Availability Zone(s) selected. If you only select one Availability Zone, the second and third subnets will be ignored.

Upon launch of the ManagedEniStack stack, the AWS Lambda function creates an Elastic Network Interface based on the node count, subnets, and security group. The Network Interfaces created are tagged with a stack identifier.

ManagedEniStack:
    Type: AWS::CloudFormation::Stack
    DependsOn:
      - InstanceSecurityGroup
    Properties:
      NotificationARNs:
        - !If
          - UseLogSNS
          - !Ref LogSNS
          - !Ref 'AWS::NoValue'
      Parameters:
        S3Bucket: !Join [ "", [!FindInMap [Variable,"LambdaPackageBucket","base"], !Ref 'AWS::Region']]
        S3Directory: !FindInMap [Variable,"S3Directory","base"]
        NodesPerZone: !Ref NodesPerZone
        NumberOfZones: !Ref NumberOfZones
        Subnets: !If [MultiZone, !Join [',', [!Ref PrivateSubnet1, !Ref PrivateSubnet2, !Ref PrivateSubnet3]], !Ref PrivateSubnet1]
        ParentStackName: !Ref 'AWS::StackName'
        ParentStackId: !Ref 'AWS::StackId'
        SecurityGroup: !Ref InstanceSecurityGroup
      TemplateURL: !Join ['/', [!FindInMap [Variable,"TemplateUrl","base"],!FindInMap [Variable,"S3Directory","base"],'ml-managedeni.template']]
      TimeoutInMinutes: 5
  NodeMgrLambdaStack:
    Type: AWS::CloudFormation::Stack
    DependsOn: ManagedEniStack
    Properties:
      NotificationARNs:
        - !If
          - UseLogSNS
          - !Ref LogSNS
          - !Ref 'AWS::NoValue'
      Parameters:
        S3Bucket: !Join [ "", [!FindInMap [Variable,"LambdaPackageBucket","base"], !Ref 'AWS::Region']]
        S3Directory: !FindInMap [Variable,"S3Directory","base"]
      TemplateURL: !Join ['/', [!FindInMap [Variable,"TemplateUrl","base"],!FindInMap [Variable,"S3Directory","base"],'ml-nodemanager.template']]
      TimeoutInMinutes: 5

The NodeMgrLambdaStack portion of the template calls the ml-nodemanager.template sub-template to deploy a Lambda function that is hooked up with Auto Scaling Group's life cycle event and manages each cluster node. The resources created by the stack are described in Node Manager Stack.

  NodeMgrLambdaStack:
    Type: AWS::CloudFormation::Stack
    DependsOn: ManagedEniStack
    Properties:
      NotificationARNs:
        - !If
          - UseLogSNS
          - !Ref LogSNS
          - !Ref 'AWS::NoValue'
      Parameters:
        S3Bucket: !Join [ "", [!FindInMap [Variable,"LambdaPackageBucket","base"], !Ref 'AWS::Region']]
        S3Directory: !FindInMap [Variable,"S3Directory","base"]
      TemplateURL: !Join ['/', [!FindInMap [Variable,"TemplateUrl","base"],!FindInMap [Variable,"S3Directory","base"],'ml-nodemanager.template']]
      TimeoutInMinutes: 5  NodeMgrLambdaStack:

The EBS volumes used by /var/opt/MarkLogic for the first node in Zone1, Zone2 and Zone3. For details on the AWS::EC2::Volume type, see AWS::EC2::Volume.

All EBS volume definitions are similar to MarklogicVolume1 for Zone1, shown below.

  MarklogicVolume1:
    Type: 'AWS::EC2::Volume'
    Properties:
      AvailabilityZone: !Select [0, !Ref AZ]
      Size: !Ref VolumeSize
      Tags:
        - Key: Name
          Value: MarkLogicData 1
      VolumeType: !Ref VolumeType
      Encrypted: !If [UseVolumeEncryption, 'true', 'false']
      KmsKeyId: !If [HasCustomEBSKey, !Ref VolumeEncryptionKey, !Ref 'AWS::NoValue']
    Metadata:
      'AWS::CloudFormation::Designer':
        id: c81032f7-b0ec-47ca-a236-e24d57b49ae3

MarkLogicDDBTable creates a DynamoDB database used as the Metadata Database, described in AWS Terminology, and returns the name of the DynamoDB Table.

Note: The read and write capacity are both set to 10 for a three-node template and 2 for a single-node template. It is critical to make sure you have enough capacity provisioned for peak periods, which occur when the instances in large cluster are restarted simultaneously. If you don’t have enough capacity, the cluster may not recouple correctly when nodes are replaced following termination. You can set a CloudWatch alarm on capacity, which can either alert you manually or trigger a script to modify the capacity.

For details on the AWS::DynamoDB::Table type, see AWS::DynamoDB::Table

  MarkLogicDDBTable:
    Type: 'AWS::DynamoDB::Table'
    Properties:
      AttributeDefinitions:
        - AttributeName: node
          AttributeType: S
      KeySchema:
        - KeyType: HASH
          AttributeName: node
      ProvisionedThroughput:
        WriteCapacityUnits: '10'
        ReadCapacityUnits: '10'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e7190602-c2de-47ab-81e7-1315f8c01e2d

MarkLogicServerGroup1, MarkLogicServerGroup2 and MarkLogicServerGroup3 are the AutoScaling Groups (ASGs) for Zone1, Zone2 and Zone3. For details on the AWS::AutoScaling::AutoScalingGroup type, see AWS::AutoScaling::AutoScalingGroup. All of them are similar to MarkLogicServerGroup1 for Zone1, shown below.

MarkLogicServerGroup1:
    Type: 'AWS::AutoScaling::AutoScalingGroup'
    DependsOn:
      - VpcStack
      - ManagedEniStack
      - NodeMgrLambdaStack
    Properties:
      VPCZoneIdentifier:
        - !GetAtt [VpcStack, Outputs.PrivateSubnet1Id]
      LaunchConfigurationName: !Ref LaunchConfig1
      MinSize: '0'
      MaxSize: !Ref NodesPerZone
      DesiredCapacity: !Ref NodesPerZone
      Cooldown: '300'
      HealthCheckType: EC2
      HealthCheckGracePeriod: '300'
      LoadBalancerNames:
        - !Ref ElasticLoadBalancer
      NotificationConfiguration: !If
        - UseLogSNS
        - TopicARN: !Ref LogSNS
          NotificationTypes:
            - 'autoscaling:EC2_INSTANCE_LAUNCH'
            - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR'
            - 'autoscaling:EC2_INSTANCE_TERMINATE'
            - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR'
        - !Ref 'AWS::NoValue'
      Tags:
        - Key: marklogic:stack:name
          Value: !Ref 'AWS::StackName'
          PropagateAtLaunch: 'true'
        - Key: marklogic:stack:id
          Value: !Ref 'AWS::StackId'
          PropagateAtLaunch: 'true'
      LifecycleHookSpecificationList:
        - LifecycleTransition: 'autoscaling:EC2_INSTANCE_LAUNCHING'
          LifecycleHookName: NodeManager
          HeartbeatTimeout: 4800
          NotificationTargetARN: !GetAtt [NodeMgrLambdaStack, Outputs.NodeMgrSnsArn]
          RoleARN: !GetAtt [NodeMgrLambdaStack, Outputs.NodeMgrIamArn]
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 31621dd0-4b18-4dcd-b443-db9cef64ebb1

NotificationTypes describes the notifications to be sent to the SNS Topic supplied to the cloud formation script to allow monitoring of AutoScaling group actions.

          NotificationTypes:
            - 'autoscaling:EC2_INSTANCE_LAUNCH'
            - 'autoscaling:EC2_INSTANCE_LAUNCH_ERROR'
            - 'autoscaling:EC2_INSTANCE_TERMINATE'
            - 'autoscaling:EC2_INSTANCE_TERMINATE_ERROR'
        - !Ref 'AWS::NoValue'

The InstanceSecurityGroup defines the ingress rules for the SecurityGroup.

InstanceSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    DependsOn:
      - VpcStack
    Properties:
      GroupDescription: Enable SSH access and HTTP access on the inbound port
      VpcId: !GetAtt [VpcStack, Outputs.VpcId]
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '7998'
          ToPort: '7998'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '8000'
          ToPort: '8010'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '7997'
          ToPort: '7997'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '7999'
          ToPort: '7999'
          CidrIp: 0.0.0.0/0
  InstanceSecurityGroupIngress:
    Type: 'AWS::EC2::SecurityGroupIngress'
    DependsOn:
      - InstanceSecurityGroup
    Properties:
      IpProtocol: tcp
      FromPort: '0'
      ToPort: '65355'
      GroupId: !Ref InstanceSecurityGroup
      SourceSecurityGroupId: !Ref InstanceSecurityGroup
  ElbSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    DependsOn: VpcStack
    Properties:
      GroupDescription: Enable SSH access and HTTP access on the inbound port
      VpcId: !GetAtt [VpcStack, Outputs.VpcId]
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: '22'
          ToPort: '22'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '7998'
          ToPort: '7998'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '8000'
          ToPort: '8010'
          CidrIp: 0.0.0.0/0
        - IpProtocol: tcp
          FromPort: '7997'
          ToPort: '7997'
          CidrIp: 0.0.0.0/0

LaunchConfig1, LaunchConfig2 and LaunchConfig3 are the Launch Configurations for ASG 1, ASG 2 and ASG 3. These describe how to look up the AMI id associated with the region, instance type, and architecture (PVM vs. HVM). All are similar to that below for ASG 1. For details on the AWS::AutoScaling::LaunchConfiguration type, see AWS::AutoScaling::LaunchConfiguration.

  LaunchTemp1:
    Type: 'AWS::EC2::LaunchTemplate'
    DependsOn:
      - InstanceSecurityGroup
    Properties:
      LaunchTemplateData:
        BlockDeviceMappings:
          - DeviceName: /dev/xvda
            Ebs:
              VolumeSize: 40
          - DeviceName: /dev/sdf
            NoDevice: true
            Ebs: {}
        KeyName: !Ref KeyName
        ImageId: !If [PAYG, !FindInMap [LicenseRegion2AMI,!Ref 'AWS::Region',"PAYGAl2023"], !FindInMap [LicenseRegion2AMI, !Ref 'AWS::Region', "BYOLAl2023"]]
    

Each Launch Configuration has a UserData and a SecurityGroups property, as shown below.

The UserData property that is populated with the data assigned to the variables described in AWS Configuration Variables. Below is the UserData property for ASG 1.

Note:

In VolumeSize, the ,* defines the volume size for the 2nd and any additional nodes in each ASG. The # indicates that the nodes are dynamically named and a numeric suffix is added from 1 - MaxNodesPerZone.

UserData: !Base64
        'Fn::Join':
          - ''
          - - MARKLOGIC_CLUSTER_NAME=
            - !Ref MarkLogicDDBTable
            - |+
            - MARKLOGIC_EBS_VOLUME=
            - !Ref MarklogicVolume1
            - ',:'
            - !Ref VolumeSize
            - '::'
            - !Ref VolumeType
            - |
              ::,*
            - |
              MARKLOGIC_NODE_NAME=NodeA#
            - MARKLOGIC_ADMIN_USERNAME=
            - !Ref AdminUser
            - |+
            - MARKLOGIC_ADMIN_PASSWORD=
            - !Ref AdminPass
            - |+
            - |
              MARKLOGIC_CLUSTER_MASTER=1
            - MARKLOGIC_LICENSEE=
            - !Ref Licensee
            - |+
            - MARKLOGIC_LICENSE_KEY=
            - !Ref LicenseKey
            - |+
            - MARKLOGIC_LOG_SNS=
            - !Ref LogSNS
            - |+
            - !If
              - UseVolumeEncryption
              - !Join
                - ''
                - - 'MARKLOGIC_EBS_KEY='
                  - !If
                    - HasCustomEBSKey
                    - !Ref VolumeEncryptionKey
                    - 'default'
              - ''

Each Launch Configuration has a SecurityGroups property that assigns the security group defined by InstanceSecurityGroup to the Amazon EC2 instances in the Auto Scaling group. Each property is like the following.

      SecurityGroups:
        - !Ref InstanceSecurityGroup
      InstanceType: !Ref InstanceType
      IamInstanceProfile: !Ref IAMRole
      SpotPrice: !If 
        - UseSpot
        - !Ref SpotPrice
        - !Ref 'AWS::NoValue'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: 2efb8cfb-df53-401d-8ff2-34af0dd25993

ElasticLoadBalancer is the Load Balancer for all of the ASGs. For details on the AWS::ElasticLoadBalancing::LoadBalancertype, see AWS::ElasticLoadBalancing::LoadBalancer.

ElasticLoadBalancer:
    Type: 'AWS::ElasticLoadBalancing::LoadBalancer'
    DependsOn:
      - VpcStack
      - ElbSecurityGroup
    Properties:
      AppCookieStickinessPolicy:
        - CookieName: SessionID
          PolicyName: MLSession
      SecurityGroups:
        - !Ref ElbSecurityGroup
      Subnets:
        - !GetAtt [VpcStack, Outputs.PublicSubnet1Id]
        - !If [MultiZone, !GetAtt [VpcStack, Outputs.PublicSubnet2Id], !Ref 'AWS::NoValue']
        - !If [MultiZone, !GetAtt [VpcStack, Outputs.PublicSubnet3Id], !Ref 'AWS::NoValue']
      ConnectionDrainingPolicy:
        Enabled: 'true'
        Timeout: '60'
      CrossZone: 'true'

Listeners defines all of the ports the Elastic Load Balancer (ELB) opens to the public.

      Listeners:
        - LoadBalancerPort: '8000'
          InstancePort: '8000'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8001'
          InstancePort: '8001'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8002'
          InstancePort: '8002'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8003'
          InstancePort: '8003'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8004'
          InstancePort: '8004'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8005'
          InstancePort: '8005'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8006'
          InstancePort: '8006'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8007'
          InstancePort: '8007'
          Protocol: HTTP
          PolicyNames:
            - MLSession
        - LoadBalancerPort: '8008'
          InstancePort: '8008'
          Protocol: HTTP
          PolicyNames:
            - MLSession

HealthCheck checks the health of each MarkLogic instance by contacting its HealthCheck App Server on port 7997 every number of seconds specified by Interval. Any answer other than "200 OK" within the Timeout period (in seconds) is considered unhealthy and that instance is removed from the ELB. For details on the HealthCheck parameters, see HealthCheck.

      HealthCheck:
        Target: 'HTTP:7997/'
        HealthyThreshold: '3'
        UnhealthyThreshold: '5'
        Interval: '10'
        Timeout: '5'
    Metadata:
      'AWS::CloudFormation::Designer':
        id: e188e71e-5f01-4816-896e-9bd30b9a96c1

The ALB declaration

Alb:
  Condition: MultiZone
  Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  DependsOn:
    - VpcStack
    - ElbSecurityGroup
  Properties: 
    SecurityGroups: 
    - !Ref ElbSecurityGroup
    Subnets: 
    - !GetAtt [VpcStack, Outputs.PublicSubnet1Id]
    - !If [MultiZone, !GetAtt [VpcStack, Outputs.PublicSubnet2Id], !Ref 'AWS::NoValue']
    - !If [MultiZone, !GetAtt [VpcStack, Outputs.PublicSubnet3Id], !Ref 'AWS::NoValue']
  Metadata:
    'AWS::CloudFormation::Designer':
    id: e188e71e-5f01-4816-896e-9bd30b9a96c1

ALB Target group section after the ALB declaration

Description: #Descriptions of the 9 TargetGroups for MultiZone deployments (3 zones). TargetGroups route requests to registered targets.
#Health checks are performed on each TargetGroup.
AlbTargetGroup1:
Condition: MultiZone
Type: "AWS::ElasticLoadBalancingV2::TargetGroup"
DependsOn:
  - VpcStack
Properties:
  HealthCheckIntervalSeconds: 10
  HealthCheckTimeoutSeconds: 5
  HealthyThresholdCount: 3
  HealthCheckPort: 7997
  UnhealthyThresholdCount: 5
  Port: 8000
  Protocol: HTTP
  TargetGroupAttributes:
    - Key: stickiness.enabled
      Value: true
    - Key: stickiness.type
      Value: lb_cookie
    - Key: stickiness.lb_cookie.duration_seconds
      Value: 3600
    - Key: deregistration_delay.timeout_seconds
      Value: 60
VpcId: !GetAtt [VpcStack, Outputs.VpcId]

ALB Listener groups section after the ALB target groups

Description:   #Descriptions of the 9 Listeners for MultiZone deployments (3 zones). Each Listener connects Application Load Balancer to a TargetGroup with a particular port.
AlbListener1:
  Condition: MultiZone
  Type: "AWS::ElasticLoadBalancingV2::Listener"
  DependsOn:
    - Alb
    - AlbTargetGroup1
  Properties:
    DefaultActions:
      - TargetGroupArn: !Ref AlbTargetGroup1
        Type: forward
    LoadBalancerArn: !Ref Alb
    Port: 8000
    Protocol: HTTP
TitleResults for “How to create a CRG?”Also Available inAlert