AWSTemplateFormatVersion: '2010-09-09' Parameters: Namespace: Description: A string of 4-20 lowercase letters and digits, starting with a letter. Included in resource names, allowing multiple deployments. Default: monai Type: String AllowedPattern: "^[a-z]{1}[a-z0-9]{3,19}$" ConstraintDescription: Between 4-20 letters and digits, starting with a letter VPCID: Description: ID of the VPC Type: AWS::EC2::VPC::Id PublicSubnet1Id: Description: SubnetId, for Availability Zone 1 in the region in your VPC. The only one OMERO Server instance is deployed in this subnet. Type: AWS::EC2::Subnet::Id PublicSubnet2Id: Description: SubnetId, for Availability Zone 2 in the region in your VPC. None of OMERO Server instance is deployed in this subnet. Type: AWS::EC2::Subnet::Id PrivateSubnet1Id: Description: SubnetId, for Availability Zone 1 in the region in your VPC Type: AWS::EC2::Subnet::Id PrivateSubnet2Id: Description: SubnetId, for Availability Zone 2 in the region in your VPC Type: AWS::EC2::Subnet::Id LBSecurityGroup: Description: Security group for Application Load Balancer Type: AWS::EC2::SecurityGroup::Id OmeroSecurityGroup: Description: Security group for OMERO web and service containers Type: AWS::EC2::SecurityGroup::Id EFSSecurityGroup: Description: Security group for EFS Type: AWS::EC2::SecurityGroup::Id EFSFileSystem: Description: The ID of the EFS volume Type: String LBAccessLogBucketName: Type: String Default: lb-accesslog RDSEndpointAddress: Type: String Description: The RDS database endpoinst address NumberofWebInstances: Type: Number Default: 2 OMEROWebContainerCPU: Description: The number of cpu units the Amazon ECS container agent will reserve for the container. Type: Number Default: 2048 AllowedValues: [256, 512, 1024, 2048, 4096] OMEROWebContainerMemory: Description: The amount (in MiB) of memory to present to the container. . Memory should be at least two times of vCPU unit according to documentation. Type: Number Default: 4096 AllowedValues: [512, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 30720] OMEROServerContainerImage: Type: String Default: openmicroscopy/omero-server:latest OMEROWebContainerImage: Type: String Default: openmicroscopy/omero-web-standalone:latest LatestAmiId: Type: 'AWS::SSM::Parameter::Value' Default: '/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id' KeyName: Type: String Description: Name of an existing EC2 KeyPair to enable SSH access to the EC2 instances. OPTIONAL only for EC2 launch type. InstanceType: Description: EC2 instance type. OPTIONAL only for EC2 launch type. Type: String Default: c5.xlarge AllowedValues: [t2.large, m3.large, m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge, c5.large, c5.xlarge, c5.2xlarge, c5.4xlarge, c5.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge, r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge] ConstraintDescription: Please choose a valid instance type. NumberofEC2Instances: Description: Number of EC2 instance to run container in ECS cluster. OPTIONAL only for EC2 lanuch type. Type: Number Default: 1 OMEROServerContainerCPU: Description: The number of cpu units the Amazon ECS container agent will reserve for the container. Type: Number Default: 2048 AllowedValues: [256, 512, 1024, 2048, 4096] OMEROServerContainerMemory: Description: The amount (in MiB) of memory to present to the container. . Memory should be at least two times of vCPU unit according to documentation. Type: Number Default: 4096 AllowedValues: [512, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384] S3FileGatewayIp: Type: String Description: The public IP address of the EC2 instance for S3 file gateway S3BucketName: Type: String Description: The S3 bucket name for s3 file gateway MountPoint: Type: String Default: S3FileGateway DBUser: Type: String Default: omero Description: OMERO Database User NoEcho: true RDSDatabaseSecret: Type: String Description: OMERO Database Password Default: RDSDatabaseSecret ExistingHostedZoneId: Description: Existing HostedZone for Registered Domain used for ACM Certificate Type: AWS::Route53::HostedZone::Id FullDomainName: Description: Enter the Fully Qualified Domain Nanme for ACM Certificate Type: String Mappings: RegionELBAccountIdMap: us-east-1: AccountId: '127311923021' us-west-1: AccountId: '027434742980' us-west-2: AccountId: '797873946194' eu-west-1: AccountId: '156460612806' ap-northeast-1: AccountId: '582318560864' ap-northeast-2: AccountId: '600734575887' ap-southeast-1: AccountId: '114774131450' ap-southeast-2: AccountId: '783225319266' ap-south-1: AccountId: '718504428378' us-east-2: AccountId: '033677994240' sa-east-1: AccountId: '507241528517' cn-north-1: AccountId: '638102146993' eu-central-1: AccountId: '054676820928' Resources: CloudMap: Type: AWS::ServiceDiscovery::PrivateDnsNamespace Properties: Description: Service Map for OMERO ECS deployment Name: !Sub ${AWS::StackName}.ecscloudmap.org Vpc: !Ref VPCID OmerowebServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Description: '"omeroweb" service discovery entry in Cloud Map' DnsConfig: DnsRecords: - TTL: 60 Type: A RoutingPolicy: MULTIVALUE HealthCheckCustomConfig: FailureThreshold: 1 Name: omeroweb NamespaceId: !Ref 'CloudMap' OmeroserverServiceDiscoveryEntry: Type: AWS::ServiceDiscovery::Service Properties: Description: '"omeroserver" service discovery entry in Cloud Map' DnsConfig: DnsRecords: - TTL: 60 Type: A RoutingPolicy: MULTIVALUE HealthCheckCustomConfig: FailureThreshold: 1 Name: omeroserver NamespaceId: !Ref 'CloudMap' OMEROECSCluster: Type: AWS::ECS::Cluster Properties: ClusterName: !Sub ${AWS::StackName}-OMEROECSCluster ClusterSettings: - Name: containerInsights Value: enabled Tags: - Key: project Value: omero-on-aws OMEROLoadBalancer: DependsOn: - LBAccessLogBucket - LBAccessLogBucketPolicy Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: LoadBalancerAttributes: - Key: load_balancing.cross_zone.enabled Value: "true" Scheme: internet-facing Subnets: - !Ref 'PublicSubnet1Id' - !Ref 'PublicSubnet2Id' SecurityGroups: - !Ref LBSecurityGroup Tags: - Key: project Value: omero-on-aws Type: application LoadBalancerAttributes: - Key: access_logs.s3.enabled Value: true - Key: access_logs.s3.bucket Value: !Join - '-' - - !Ref LBAccessLogBucketName - !Ref Namespace - !Ref AWS::AccountId OMERONetworkLoadBalancer: DependsOn: - LBAccessLogBucket - LBAccessLogBucketPolicy Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Scheme: internet-facing Subnets: - !Ref 'PublicSubnet1Id' - !Ref 'PublicSubnet2Id' Tags: - Key: project Value: omero-on-aws Type: network LoadBalancerAttributes: - Key: access_logs.s3.enabled Value: true - Key: access_logs.s3.bucket Value: !Join - '-' - - !Ref LBAccessLogBucketName - !Ref Namespace - !Ref AWS::AccountId LBAccessLogBucket: Type: AWS::S3::Bucket Properties: BucketName: !Join - '-' - - !Ref LBAccessLogBucketName - !Ref Namespace - !Ref AWS::AccountId BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 VersioningConfiguration: Status: Enabled LBAccessLogBucketPolicy: Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref LBAccessLogBucket PolicyDocument: Statement: - Action: - 's3:PutObject' Effect: Allow Resource: - !Sub '${LBAccessLogBucket.Arn}/*' Principal: AWS: !FindInMap [RegionELBAccountIdMap, !Ref 'AWS::Region', AccountId] - Action: - 's3:PutObject' Effect: Allow Resource: - !Sub '${LBAccessLogBucket.Arn}/*' Principal: Service: delivery.logs.amazonaws.com Condition: StringEquals: s3:x-amz-acl: bucket-owner-full-control - Action: - 's3:GetBucketAcl' Effect: Allow Resource: - !Sub ${LBAccessLogBucket.Arn} Principal: Service: delivery.logs.amazonaws.com LogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /ecs/omero/${AWS::StackName} MountTarget: Type: AWS::EFS::MountTarget Properties: FileSystemId: !Ref EFSFileSystem SubnetId: !Ref PrivateSubnet1Id SecurityGroups: - !Ref EFSSecurityGroup NFSAccessPoint: Type: AWS::EFS::AccessPoint Properties: FileSystemId: !Ref EFSFileSystem PosixUser: Gid: "0" Uid: "0" RootDirectory: Path: "/" OmeroserverService: Type: AWS::ECS::Service DependsOn: - OMERONetworkLoadBalancer - OmeroserverTaskDefinition - OmeroserverTCP4064Listener - OmeroserverTCP4063Listener Properties: Cluster: !Ref 'OMEROECSCluster' DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DeploymentController: Type: ECS DesiredCount: 1 LaunchType: 'EC2' LoadBalancers: - ContainerName: omeroserver ContainerPort: 4064 TargetGroupArn: !Ref 'OmeroserverTCP4064TargetGroup' - ContainerName: omeroserver ContainerPort: 4063 TargetGroupArn: !Ref 'OmeroserverTCP4063TargetGroup' EnableExecuteCommand: true NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref OmeroSecurityGroup Subnets: - !Ref 'PrivateSubnet1Id' PropagateTags: SERVICE SchedulingStrategy: REPLICA ServiceRegistries: - RegistryArn: !GetAtt 'OmeroserverServiceDiscoveryEntry.Arn' Tags: - Key: project Value: omero-on-aws - Key: service Value: omeroserver TaskDefinition: !Ref 'OmeroserverTaskDefinition' OmeroserverTCP4064Listener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - ForwardConfig: TargetGroups: - TargetGroupArn: !Ref OmeroserverTCP4064TargetGroup Type: forward LoadBalancerArn: !Ref OMERONetworkLoadBalancer Port: 4064 Protocol: TCP OmeroserverTCP4064TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup DependsOn: - OMERONetworkLoadBalancer Properties: Port: 4064 Protocol: TCP TargetType: ip VpcId: !Ref VPCID Tags: - Key: project Value: omero-on-aws OmeroserverTCP4063Listener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - ForwardConfig: TargetGroups: - TargetGroupArn: !Ref OmeroserverTCP4063TargetGroup Type: forward LoadBalancerArn: !Ref OMERONetworkLoadBalancer Port: 4063 Protocol: TCP OmeroserverTCP4063TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup DependsOn: - OMERONetworkLoadBalancer Properties: Port: 4063 Protocol: TCP TargetType: ip VpcId: !Ref VPCID Tags: - Key: project Value: omero-on-aws OmeroserverTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: ContainerDefinitions: - Environment: - Name: CONFIG_omero_db_host Value: !GetAtt 'RDSInstance.Endpoint.Address' - Name: CONFIG_omero_db_user Value: !Ref DBUser - Name: CONFIG_omero_db_pass Value: !Join ['', ['{{resolve:secretsmanager:', !Ref RDSDatabaseSecret, ':SecretString:password}}' ]] - Name: CONFIG_omero_db_name Value: omero - Name: LOCALDOMAIN Value: !Join - '' - - !Ref 'AWS::Region' - .compute.internal - 'omero.local' - Name: ROOTPASS Value: omero Essential: true Image: !Ref OMEROServerContainerImage LinuxParameters: { InitProcessEnabled: true } LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'LogGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: omeroserver Name: omeroserver MountPoints: - ContainerPath: /OMERO SourceVolume: my-fg PortMappings: - ContainerPort: 4063 HostPort: 4063 Protocol: tcp - ContainerPort: 4064 HostPort: 4064 Protocol: tcp Volumes: - Name: my-fg Host: SourcePath: !Sub /${MountPoint} Cpu: !Ref OMEROServerContainerCPU Memory: !Ref OMEROServerContainerMemory ExecutionRoleArn: !Ref 'OmeroserverTaskExecutionRole' TaskRoleArn: !Ref 'OmeroserverTaskRole' Family: omero-server NetworkMode: awsvpc RequiresCompatibilities: - 'EC2' OmeroserverTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole 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: project Value: omero-on-aws - Key: service Value: omeroserver OmeroserverTaskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Version: '2012-10-17' Policies: - PolicyName: OmeroserverOmeroVolumeMountPolicy PolicyDocument: Statement: - Action: - elasticfilesystem:ClientMount - elasticfilesystem:ClientWrite - elasticfilesystem:ClientRootAccess Condition: StringEquals: elasticfilesystem:AccessPointArn: !Ref NFSAccessPoint Effect: Allow Principal: {} Resource: - !Join - '' - - 'arn:aws:elasticfilesystem:' - !Ref 'AWS::Region' - ':' - !Ref 'AWS::AccountId' - ':file-system/' - !Ref EFSFileSystem - PolicyName: OmeroserverSSMPolicy PolicyDocument: Statement: - Action: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel Effect: Allow Resource: "*" Tags: - Key: project Value: omero-on-aws - Key: service Value: omeroserver ECSAutoScalingGroup: Type: AWS::AutoScaling::AutoScalingGroup DependsOn: - MountTarget Properties: VPCZoneIdentifier: - !Ref PrivateSubnet1Id LaunchConfigurationName: !Ref 'ContainerInstances' MinSize: '1' MaxSize: '4' DesiredCapacity: !Ref NumberofEC2Instances CreationPolicy: ResourceSignal: Timeout: PT15M UpdatePolicy: AutoScalingReplacingUpdate: WillReplace: 'true' ContainerInstances: Type: AWS::AutoScaling::LaunchConfiguration Metadata: AWS::CloudFormation::Init: configSets: MountConfig: - mount mount: commands: 01_newfolder: command: !Sub "mkdir /${MountPoint}" 02_mount: command: !Sub > mount -t nfs -o nolock,hard ${S3FileGatewayIp}:/${S3BucketName} /${MountPoint} 03_echo: command: !Sub > echo "${S3FileGatewayIp}:/${S3BucketName} /${MountPoint} nfs defaults,_netdev,tls 0 0" >> /etc/fstab Properties: ImageId: !Ref LatestAmiId SecurityGroups: - !Ref OmeroSecurityGroup InstanceType: !Ref 'InstanceType' IamInstanceProfile: !Ref 'EC2InstanceProfile' KeyName: !Ref 'KeyName' UserData: Fn::Base64: !Sub | #!/bin/bash -xe echo ECS_CLUSTER=${OMEROECSCluster} >> /etc/ecs/ecs.config yum install -y aws-cfn-bootstrap bzip2 unzip /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource ContainerInstances --configsets MountConfig --region ${AWS::Region} /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource ECSAutoScalingGroup --region ${AWS::Region} || echo "failed to notify stack" curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" unzip awscliv2.zip ./aws/install yum install java-11-amazon-corretto-headless -y curl -LO https://anaconda.org/anaconda-adam/adam-installer/4.4.0/download/adam-installer-4.4.0-Linux-x86_64.sh bash adam-installer-4.4.0-Linux-x86_64.sh -b -p /opt/adam echo -e '\n# Anaconda Adam\nexport PATH=/opt/adam/bin:$PATH' >> /etc/bashrc source /etc/bashrc conda install -c anaconda libstdcxx-ng -y conda install -c anaconda libgcc-ng -y EC2Role: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Effect: Allow Principal: Service: - ec2.amazonaws.com Action: - sts:AssumeRole Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/AmazonS3FullAccess Tags: - Key: project Value: omero-on-aws - Key: service Value: omeroserver EC2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: / Roles: [!Ref 'EC2Role'] OmerowebService: Type: AWS::ECS::Service DependsOn: - OMEROLoadBalancer - OmerowebHTTPSListener - OmerowebHTTPListener Properties: Cluster: !Ref 'OMEROECSCluster' DeploymentConfiguration: MaximumPercent: 200 MinimumHealthyPercent: 100 DeploymentController: Type: ECS DesiredCount: !Ref NumberofWebInstances LaunchType: 'FARGATE' EnableExecuteCommand: true LoadBalancers: - ContainerName: omeroweb ContainerPort: 4080 TargetGroupArn: !Ref 'OmerowebTCP4080TargetGroup' NetworkConfiguration: AwsvpcConfiguration: AssignPublicIp: DISABLED SecurityGroups: - !Ref OmeroSecurityGroup Subnets: - !Ref 'PrivateSubnet1Id' - !Ref 'PrivateSubnet2Id' PropagateTags: SERVICE SchedulingStrategy: REPLICA ServiceRegistries: - RegistryArn: !GetAtt 'OmerowebServiceDiscoveryEntry.Arn' Tags: - Key: project Value: omero-on-aws - Key: service Value: omeroweb TaskDefinition: !Ref 'OmerowebTaskDefinition' HostedZoneRecord: DependsOn: - LoadBalancerSSLCert Type: AWS::Route53::RecordSet Properties: HostedZoneId: !Ref ExistingHostedZoneId Type: A Name: !Ref FullDomainName AliasTarget: DNSName: !GetAtt 'OMEROLoadBalancer.DNSName' HostedZoneId: !GetAtt 'OMEROLoadBalancer.CanonicalHostedZoneID' LoadBalancerSSLCert: Type: AWS::CertificateManager::Certificate Properties: DomainName: !Ref FullDomainName DomainValidationOptions: - DomainName: !Ref FullDomainName HostedZoneId: !Ref ExistingHostedZoneId ValidationMethod: DNS CertificateTransparencyLoggingPreference: ENABLED OmerowebHTTPSListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: Certificates: - CertificateArn: !Ref LoadBalancerSSLCert DefaultActions: - Type: forward TargetGroupArn: !Ref 'OmerowebTCP4080TargetGroup' LoadBalancerArn: !Ref 'OMEROLoadBalancer' Port: 443 Protocol: HTTPS OmerowebHTTPListener: Type: AWS::ElasticLoadBalancingV2::Listener Properties: DefaultActions: - Type: redirect RedirectConfig: Protocol: HTTPS Port: '443' Host: '#{host}' Path: /#{path} Query: '#{query}' StatusCode: HTTP_301 LoadBalancerArn: !Ref 'OMEROLoadBalancer' Port: 80 Protocol: HTTP OmerowebTCP4080TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Port: 4080 Protocol: HTTP TargetType: ip VpcId: !Ref VPCID HealthCheckEnabled: true HealthCheckProtocol: HTTP HealthCheckPort: 4080 HealthCheckPath: /index/ Matcher: HttpCode: 200-302 TargetGroupAttributes: - Key: stickiness.enabled Value: true - Key: stickiness.type Value: lb_cookie - Key: stickiness.lb_cookie.duration_seconds Value: 86500 Tags: - Key: project Value: omero-on-aws OmerowebTaskDefinition: Type: AWS::ECS::TaskDefinition Properties: ContainerDefinitions: - Environment: - Name: OMEROHOST Value: !Sub omeroserver.${AWS::StackName}.ecscloudmap.org - Name: LOCALDOMAIN Value: !Join - '' - - !Ref 'AWS::Region' - .compute.internal - 'omero.local' Essential: true Image: !Ref OMEROWebContainerImage LinuxParameters: { InitProcessEnabled: true } LogConfiguration: LogDriver: awslogs Options: awslogs-group: !Ref 'LogGroup' awslogs-region: !Ref 'AWS::Region' awslogs-stream-prefix: omeroweb Name: omeroweb PortMappings: - ContainerPort: 4080 HostPort: 4080 Protocol: tcp Cpu: !Ref OMEROWebContainerCPU Memory: !Ref OMEROWebContainerMemory ExecutionRoleArn: !Ref 'OmerowebTaskExecutionRole' TaskRoleArn: !Ref 'OmerowebTaskRole' Family: omero-web NetworkMode: awsvpc RequiresCompatibilities: - 'FARGATE' OmerowebTaskExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole 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: project Value: omero-on-aws - Key: service Value: omeroweb OmerowebTaskRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: ecs-tasks.amazonaws.com Version: '2012-10-17' Policies: - PolicyName: OmerowebSSMPolicy PolicyDocument: Statement: - Action: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - ssmmessages:OpenDataChannel Effect: Allow Resource: "*" Outputs: OMEROLoadBalancerHTTPEnpoint: Description: The HTTP endpoint of the OMEROLoadBalancer Value: !Join - '' - - 'https://' - !GetAtt OMEROLoadBalancer.DNSName OMERONetworkLoadBalancerHTTPEnpoint4063: Description: The HTTP endpoint of the OMERONetworkLoadBalancer Value: !Join - '' - - 'http://' - !GetAtt OMERONetworkLoadBalancer.DNSName - ':4063' OMERONetworkLoadBalancerHTTPEnpoint4064: Description: The HTTP endpoint of the OMERONetworkLoadBalancer Value: !Join - '' - - 'http://' - !GetAtt OMERONetworkLoadBalancer.DNSName - ':4064'