dcim.yaml
---

dcim ECS Task

This CloudFormation template will deploy the OpenDCIM application as a task on an existing ECS cluster.

AWSTemplateFormatVersion: '2010-09-09' Description: OpenDCIM Application

Parameters

These are the input parameters for this template. All of these parameters must be supplied for this template to be deployed.

Parameters: TaskName: MinLength: '3' Type: String Description: Short application slug, ie 'dcim'. Lowercase letters, numbers and dashes only Default: dcim AllowedPattern: "[a-z0-9-]*" EnvSlug: MinLength: '2' Type: String Description: Short environment slug, ie 'dev', or 'markdev'. Lowercase letters, numbers and dashes only AllowedPattern: "[a-z0-9]*"

Name of the ECS Base CloudFormation Stack.

BaseStackName: Type: String Description: "ECS Base Stack Name" Default: "toolshed-ecs" DockerImage: Description: 'Docker Image, i.e.: ecs/sftphub:latest' Type: String DockerHostName: Description: Hostname to use for the docker container Type: String HostedZoneName: Description: Name of the Route53 HostedZone to use Type: String Default: "uits-nonprod-aws.arizona.edu" EFSStackName: Description: Name of the DCIM EFS Stack Type: String Default: "dcim-toolshed-efs" DatabaseHost: Description: IP or DNS of the database host Type: String DatabaseUser: Description: Database Username Type: String NoEcho: 'true' DatabasePassword: Description: Database Password Type: String NoEcho: 'true' DatabaseSchema: Description: Database Schema Name Type: String ServiceTag: Description: Refers to the application (Uaccess Learning, Uaccess Employee, Uaccess Student) Type: String Default: "Toolshed" EnvironmentTag: Description: Type of environment that is using this resource, such as 'dev', 'tst', 'prd'. Type: String ContactNetidTag: Description: NetID of person most familiar with resource Type: String Default: "fischerm" AccountNumberTag: Description: Identifies the financial system account number Type: String SubAccountTag: Description: Identifies the financial system subaccount number Type: String TicketNumberTag: Description: Jira Ticket Number Type: String

Metadata

Metadata is mostly for organizing and presenting Parameters in a better way when using CloudFormation in the AWS Web UI.

Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: Application Information Parameters: - TaskName - EnvSlug - DockerImage - BaseStackName - HostedZoneName - Label: default: Tags Parameters: - ServiceTag - EnvironmentTag - ContactNetidTag - AccountNumberTag - SubAccountTag - TicketNumberTag

Resources

These are all of the actual AWS resources created for this application.

Resources:

Route53 DNS Record

Create a DNS entry in Route53 for this environment. This creates a CNAME pointing at the DNS name of the Load Balancer.

AppDnsRecord: Type: AWS::Route53::RecordSet Properties:

Append a period after the hosted zone DNS name

HostedZoneName: !Sub "${HostedZoneName}." Name: !Sub "dcim.${HostedZoneName}." Type: CNAME TTL: '900' ResourceRecords: - Fn::ImportValue: !Sub "${BaseStackName}-alb-dns" #ECS Task Definition EcsTask: Type: "AWS::ECS::TaskDefinition" Properties: Family: !Sub "${TaskName}-${EnvSlug}" NetworkMode: "bridge" ContainerDefinitions: - Name: !Sub "${TaskName}-${EnvSlug}" Essential: "true" Image: !Ref DockerImage PortMappings: - ContainerPort: "80" Hostname: !Ref DockerHostName Cpu: "200" MemoryReservation: "256" Privileged: "true" Environment: - Name: NFS_MOUNT Value: Fn::Sub: - "${EFSID}.efs.${AWS::Region}.amazonaws.com:/" - EFSID: Fn::ImportValue: !Sub "${EFSStackName}-fs-id" - Name: DCIM_DB_HOST Value: !Ref DatabaseHost - Name: DCIM_DB_NAME Value: !Ref DatabaseSchema - Name: DCIM_DB_USER Value: !Ref DatabaseUser - Name: DCIM_DB_PASS Value: !Ref DatabasePassword LogConfiguration: LogDriver: "awslogs" Options: awslogs-group: !Ref EcsLogGroup awslogs-region: !Ref "AWS::Region" awslogs-stream-prefix: dcim

ECS Service

EcsService: Type: "AWS::ECS::Service" #Waiting for the DNS record to be created beause we know the LB has been #created if the DNS record is created, and the LB needs to be created #before the ECS service is created DependsOn: - AppDnsRecord - EcsLogGroup Properties: ServiceName: !Sub "${TaskName}-${EnvSlug}" Cluster: Fn::ImportValue: !Sub "${BaseStackName}-ecs" TaskDefinition: !Ref EcsTask DesiredCount: 1 Role: !Ref EcsServiceRole LoadBalancers: - ContainerName: !Sub "${TaskName}-${EnvSlug}" ContainerPort: "80" TargetGroupArn: !Ref AlbTargetGroup #For now we will spread across AZs PlacementStrategies: - Field: "attribute:ecs.availability-zone" Type: "spread" DeploymentConfiguration: MaximumPercent: "200" #Need to create a LogGroup in order for the ECS service to log details of the build #If this does not exist the ECS Service will not come up EcsLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub "${TaskName}-${EnvSlug}-ecs-lg" RetentionInDays: 30

ECS Service Role

EcsServiceRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ecs.amazonaws.com Action: - sts:AssumeRole Path: "/" ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role - arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceRole

Add to Load Balancer

Target Group

Define the Target Group for adding Instances to the ALB as well as the health checks for those Instances

AlbTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: HealthCheckIntervalSeconds: 60 UnhealthyThresholdCount: 10 HealthCheckPath: / Matcher: HttpCode: "200-399" Port: 80 Protocol: HTTP VpcId: Fn::ImportValue: !Sub "${BaseStackName}-vpcid" Tags: - Key: service Value: !Ref ServiceTag - Key: environment Value: !Ref EnvironmentTag - Key: contactnetid Value: !Ref ContactNetidTag - Key: accountnumber Value: !Ref AccountNumberTag - Key: ticketnumber Value: !Ref TicketNumberTag

ALB Listener Rule

ListenerRuleA: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - Type: forward TargetGroupArn: !Ref AlbTargetGroup Conditions: - Field: host-header Values: - !Sub "dcim.${HostedZoneName}" ListenerArn: Fn::ImportValue: !Sub "${BaseStackName}-alb-listener" Priority: 50 ListenerRuleB: Type: AWS::ElasticLoadBalancingV2::ListenerRule Properties: Actions: - Type: forward TargetGroupArn: !Ref AlbTargetGroup Conditions: - Field: host-header Values: - dcim.uits.arizona.edu ListenerArn: Fn::ImportValue: !Sub "${BaseStackName}-alb-listener" Priority: 60

Add Ingress Rule to the EFS security group to allow in traffic from the ECS hosts

EFSIngress: Type: AWS::EC2::SecurityGroupIngress Properties: GroupId: Fn::ImportValue: !Sub "${EFSStackName}-sg" IpProtocol: tcp FromPort: '2049' ToPort: '2049' SourceSecurityGroupId: Fn::ImportValue: !Sub "${BaseStackName}-instance-sg"

Outputs

Output values that can be viewed from the AWS CloudFormation console.

Outputs: AppURL: Description: Application URL Value: !Sub "http://dcim.${HostedZoneName}"