--- AWSTemplateFormatVersion: "2010-09-09" Description: > This is container instance to run linkerd visual console in public network. Parameters: keyPairName: Description: Key pair name for ec2. Type: String ami: Description: Amazon image ID. Type: String baseVpc: Description: VPC to launch virtual server in. Type: AWS::EC2::VPC::Id # Default: !GetAtt networkStack.Outputs.baseVpcOutput s3cf: Description: S3 bucket name for storage cloudformation templates. Type: String publicSubnet1a: Description: subnet to launch virtual server in. Type: AWS::EC2::Subnet::Id publicSubnet1b: Description: subnet to launch virtual server in. Type: AWS::EC2::Subnet::Id instanceType: Description: instance tyep for ec2. Type: String Default: m5.large s3Dns: Description: DNS of S3 endpoint. Type: String ip4Ec2: Description: DNS of the identity provider for EC2 Type: String nodesRole: Description: Role for nodes in ECS cluster. Type: String volSize: Description: The size of root volume for ec2. Type: Number Default: 40 ecsCluster: Description: ECS Cluster for application running. Type: String Resources: LinkerdvizSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Allow http to shost VpcId: !Ref baseVpc SecurityGroupIngress: #ssh - IpProtocol: TCP FromPort: 22 ToPort: 22 CidrIp: '0.0.0.0/0' #linderd - IpProtocol: TCP FromPort: 4140 ToPort: 4140 CidrIp: '10.0.0.0/16' #linkerd-viz - IpProtocol: TCP FromPort: 3000 ToPort: 3000 CidrIp: '10.0.0.0/16' #linkerd-ui admin - IpProtocol: -1 CidrIp: '10.0.0.0/16' Tags: - Key: Name Value: !Sub '${AWS::StackName}-linkerdviz-sg' Ec2InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Path: "/" Roles: - !Ref nodesRole LinkerdvizEc2Instance: Type: AWS::EC2::Instance Metadata: AWS::CloudFormation::Init: config: files: /etc/ecs/ecs.config: content: !Sub | ECS_CLUSTER=${ecsCluster} ECS_INSTANCE_ATTRIBUTES={"stack":"linkerd-viz"} /home/ec2-user/first-run.sh: content: !Sub | #!/bin/bash mkdir -p /home/ec2-user/cloudwatch cd /home/ec2-user/cloudwatch curl https://${s3Dns}/amazoncloudwatch-agent-${AWS::Region}/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm -o amazon-cloudwatch-agent.rpm sudo rpm -U ./amazon-cloudwatch-agent.rpm aws s3 cp s3://${s3cf}/templates/cloudwatch4ecs/amazon-cloudwatch-agent-ecs.json amazon-cloudwatch-agent-ecs.json --endpoint-url https://${s3Dns}/ sudo cp ./amazon-cloudwatch-agent-ecs.json /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json cd /opt/aws/amazon-cloudwatch-agent/etc sudo sed -i -e "s/{aws_stack_name}/${AWS::StackName}/g" amazon-cloudwatch-agent.json EC2_INSTANCE_ID=$(curl -s http://169.254.169.254/1.0/meta-data/instance-id/) sudo sed -i -e "s/{instance_id}/$EC2_INSTANCE_ID/g" amazon-cloudwatch-agent.json sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s mkdir -p /home/ec2-user/awslogs cd /home/ec2-user/awslogs aws s3 cp s3://${s3cf}/templates/awslogs/daemon.json daemon.json --endpoint-url https://${s3Dns}/ sudo cp ./daemon.json /etc/docker/daemon.json cd /etc/docker/ sudo sed -i -e "s/{aws_stack_name}/${AWS::StackName}/g" daemon.json sudo sed -i -e "s/{cluster}/${ecsCluster}/g" daemon.json sudo sed -i -e "s/{container_instance_id}/$EC2_INSTANCE_ID/g" daemon.json #docker & ecs-agent (removed due to use ecs-optimiezed AMI) #sudo amazon-linux-extras disable docker #sudo amazon-linux-extras install -y ecs #sudo systemctl enable ecs #sudo systemctl restart docker #sudo systemctl restart --no-block ecs #sudo usermod -a -G docker ec2-user # Install ssm-agent (added due to use ecs-optimiezed AMI) sudo yum install -y https://${s3Dns}/amazon-ssm-${AWS::Region}/latest/linux_amd64/amazon-ssm-agent.rpm sudo systemctl enable amazon-ssm-agent sudo systemctl start amazon-ssm-agent # # This script generates config to be used by their respective Task Definitions: # 1. consul-registrator startup script # 2. Consul Agent config # 3. linkerd config # Gather metadata for linkerd and Consul Agent EC2_INSTANCE_IP_ADDRESS=$(curl -s http://169.254.169.254/latest/meta-data/local-ipv4) EC2_INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id) # # Generate consul-registrator startup file # mkdir -p /opt/consul-registrator/bin cat << EOF > /opt/consul-registrator/bin/start.sh #!/bin/sh exec /bin/registrator -ip $EC2_INSTANCE_IP_ADDRESS -retry-attempts -1 consul://$EC2_INSTANCE_IP_ADDRESS:8500 EOF chmod a+x /opt/consul-registrator/bin/start.sh # # Generate Consul Agent config file # mkdir -p /opt/consul/data mkdir -p /opt/consul/config cat << EOF > /opt/consul/config/consul-agent.json { "advertise_addr": "$EC2_INSTANCE_IP_ADDRESS", "client_addr": "0.0.0.0", "node_name": "$EC2_INSTANCE_ID", "retry_join": [ "provider=aws tag_key=Name tag_value=l5d-demo-consul-server" ] } EOF # # Generate linkerd config file # # The linkerd ECS task definition is configured to mount this config file into # its own Docker environment. mkdir -p /etc/linkerd cat << EOF > /etc/linkerd/linkerd.yaml admin: ip: 0.0.0.0 port: 9990 namers: - kind: io.l5d.consul host: $EC2_INSTANCE_IP_ADDRESS port: 8500 telemetry: - kind: io.l5d.prometheus - kind: io.l5d.recentRequests sampleRate: 0.25 usage: orgId: linkerd-examples-ecs routers: - protocol: http label: outgoing servers: - ip: 0.0.0.0 port: 4140 interpreter: kind: default transformers: # tranform all outgoing requests to deliver to incoming linkerd port 4141 - kind: io.l5d.port port: 4141 dtab: | /svc => /#/io.l5d.consul/dc1; - protocol: http label: incoming servers: - ip: 0.0.0.0 port: 4141 interpreter: kind: default transformers: # filter instances to only include those on this host - kind: io.l5d.specificHost host: $EC2_INSTANCE_IP_ADDRESS dtab: | /svc => /#/io.l5d.consul/dc1; EOF mode: "000755" owner: "ec2-user" group: "ec2-user" commands: agent1: command: "./first-run.sh >./run.log 2>./run.log" env: STACK_NAME: !Sub '${AWS::StackName}' AWS_DEFAULT_REGION: !Sub '${AWS::Region}' ECS_CLUSTER: !Ref ecsCluster cwd: "/home/ec2-user" ignoreErrors: false Properties: #AdditionalInfo: String # optional ImageId: !Ref ami InstanceType: !Ref instanceType IamInstanceProfile: !Ref Ec2InstanceProfile KeyName: !Ref keyPairName Monitoring: true DisableApiTermination: false NetworkInterfaces: - AssociatePublicIpAddress: true DeviceIndex: 0 GroupSet: - !Ref LinkerdvizSecurityGroup SubnetId: !Ref publicSubnet1a BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: VolumeSize: !Ref volSize DeleteOnTermination: true UserData: Fn::Base64: !Sub | #!/bin/bash -xe set -e sudo yum update -y sudo yum install -y aws-cfn-bootstrap awscli jq wget /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource LinkerdvizEc2Instance --region ${AWS::Region} /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource LinkerdvizEc2Instance --region ${AWS::Region} Tags: - Key: Name Value: !Sub '${AWS::StackName}-linkerdviz-node' - Key: Purpose Value: linkerdviz CreationPolicy: ResourceSignal: Count: 1 Timeout: PT5M