Single Instance ECS Setup

This article describes how you can set up Amazon’s EC2 Container Service (ECS) with only a single instance. ECS lets you run applications packaged in Docker containers on a managed cluster of EC2 instances.

Single Instance & Cluster?

The word “cluster” implies having multiple instances, so why would you want to have a single instance? Your application or service might not have high traffic load. In the world of microservices that can easily be the case. One instance is enough.

I strongly recommend using ECS if your application, or even parts of it, is running on Docker. Unlike an EC2 instance where you set up Docker yourself, ECS gives you an API and the ability to program your infrastructure. And since this is a single instance you do not have to pay for the AutoScaler or LoadBalancer.

People far smarter than me have said it many times: all regular tasks in the production environment must be automated. As with any other application code, you should also put it under version control.

Requirements

You require valid AWS account credentials and the AWS CLI before you can set up an ECS instance. If you haven’t installed it, you can easily run it with Docker by:

docker run -it --rm \
  -e AWS_ACCESS_KEY_ID=[ACCESS_KEY_ID] \
  -e AWS_SECRET_ACCESS_KEY=[SECRET_ACCESS_KEY] \
  -e AWS_DEFAULT_REGION=eu-central-1 \
  fstab/aws-cli

That’s quite handy and I advise you to put it as an alias in your ~/.bashrc.

Commands to set up and run

You should find yourself now within the aws cli and can boot up a Grafana instance using the following:

aws ecs create-cluster --cluster-name single-cluster

aws iam create-role --role-name ecsRole --assume-role-policy-document \
  '{"Version": "2012-10-17", 
    "Statement": {
      "Effect": "Allow", 
      "Principal": {"Service": "ec2.amazonaws.com"}, 
      "Action": "sts:AssumeRole"}}'
aws iam attach-role-policy --role-name ecsRole --policy-arn \
  "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
aws iam create-instance-profile --instance-profile-name ecsInstanceProfile
aws iam add-role-to-instance-profile --instance-profile-name ecsInstanceProfile \
  --role-name ecsRole
sleep 5 #https://github.com/hashicorp/terraform/issues/1885

taskDefinition=`aws ecs register-task-definition --family grafanaTasks \
  --query taskDefinition.taskDefinitionArn --output text --container-definitions \
  '[{
      "name": "grafana", 
      "image": "grafana/grafana", 
      "memoryReservation": 256, 
      "portMappings": [{"containerPort": 3000, "hostPort": 80}]}]'`
securityGroup=`aws ec2 create-security-group --group-name grafana \
  --description "Security Group for Grafana" --query GroupId --output text`
aws ec2 authorize-security-group-ingress --group-id $securityGroup \
  --protocol tcp --port 80 --cidr 0.0.0.0/0

instanceId=`aws ec2 run-instances --security-groups grafana \
  --image-id ami-ec2be583 \
  --iam-instance-profile "Name=ecsInstanceProfile" --user-data '
#!/bin/bash
echo ECS_CLUSTER=single-cluster >> /etc/ecs/ecs.config' \
  --query "Instances[0].InstanceId" --output text`
aws ec2 wait instance-status-ok --instance-ids $instanceId

aws ecs create-service --cluster single-cluster \
  --service-name grafanaService \
  --task-definition grafanaTasks --desired-count 1

Please note the “sleep 5” command. It is required since there seem to be some asynchronous processes in place.

Accessing the instance

By now Grafana should be up and running. You have created an ECS cluster called “single-cluster” along an IAM policy that allows EC2 instances to register themselves to the cluster. The Grafana container is registered as a task and the cluster has a service that runs that task.

You can request the public DNS of the instance by:

aws ec2 describe-instances --instance-ids $instanceId \
  --query Reservations[0].Instances[0].PublicDnsName --output text

Commands to clean up

To remove everything you’ve setup before, simply run the following commands within the AWS CLI:

containerInstanceId=`aws ecs list-container-instances \
  --cluster single-cluster --query containerInstanceArns[0] \
  --output text`
instanceId=`aws ecs describe-container-instances \
  --cluster single-cluster \
  --container-instances $containerInstanceId \
  --query containerInstances[0].ec2InstanceId --output text`
aws ec2 terminate-instances --instance-ids $instanceId
aws ec2 wait instance-terminated --instance-ids $instanceId
aws ec2 delete-security-group --group-name grafana
aws ecs update-service --cluster single-cluster --service grafanaService --desired-count 0
aws ecs delete-service --cluster single-cluster --service grafanaService
aws ecs delete-cluster --cluster single-cluster
aws iam remove-role-from-instance-profile --instance-profile ecsInstanceProfile \
  --role-name ecsRole
aws iam delete-instance-profile --instance-profile-name ecsInstanceProfile
aws iam detach-role-policy --role-name ecsRole \
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role
aws iam delete-role --role-name ecsRole

taskDefinitions=`aws ecs list-task-definitions --output text --query taskDefinitionArns[0]`
aws ecs deregister-task-definition --task-definition $taskDefinition

 

Leave a Reply