Skip to content

Commit

Permalink
Adds Consul and Registrator agents to ECS Instances (#16)
Browse files Browse the repository at this point in the history
* Adds consul + registrator to ECS Clusters!

* Formating

* Setting enable_consul to false

* readme updates

* Some updates based on code review feedback

* Updated IAM Names so we don't have duplicates

* terraform fmt

* Updates README and adds an example consul template

* Updates based on feedback in #16

* Adding Build Status Badge to README

* READEME update about TF Version

* READEME update about TF Version
  • Loading branch information
tfhartmann authored Aug 22, 2017
1 parent dc9f643 commit b8779be
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 18 deletions.
4 changes: 2 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ version: 2
jobs:
build:
docker:
- image: hashicorp/terraform:0.9.11
- image: hashicorp/terraform:0.10.1
entrypoint: /bin/sh
steps:
- checkout
- run:
name: validate tf files (terraform validate)
command: find . -type f -name "*.tf" -exec dirname {} \;|sort -u | while read m; do (terraform validate "$m" && echo "√ $m") || exit 1 ; done
command: find . -type f -name "*.tf" -exec dirname {} \;|sort -u | while read m; do (terraform validate -check-variables=false "$m" && echo "√ $m") || exit 1 ; done
- run:
name: check if all tf files are formatted (terraform fmt)
command: if [ `terraform fmt | wc -c` -ne 0 ]; then echo "Some terraform files need be formatted, run 'terraform fmt' to fix"; exit 1; fi
Expand Down
1 change: 1 addition & 0 deletions .terraform-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
0.10.1
60 changes: 59 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ ecs terraform module

A terraform module to provide ECS clusters in AWS.

[![CircleCI](https://circleci.com/gh/terraform-community-modules/tf_aws_ecs.svg?style=svg)](https://circleci.com/gh/terraform-community-modules/tf_aws_ecs)


This Module currently supports Terraform 0.10.x, but does not require it. If you use tfenv, this module contains a `.terraform-version` file which matches the version of Terraform we currently use to test with.


Module Input Variables
----------------------
Expand All @@ -13,6 +18,9 @@ Module Input Variables
- `vpc_id` - The VPC ID to place the cluster in

#### Optional
note about `user_data` and - `additional_user_data_script`: The `user_data` parameter overwrites the user_data template used by this module, this will break some of the module features. (`docker_storage_size`, `dockerhub_token`, and `dockerhub_email`) `additional_user_data_script` however will concatenate additional data to the end of the current user_data script. It is recomended that you use `additional_user_data_script`. These two parameters are mutually exclusive - you can not pass both into this module and expect it to work.

- `additional_user_data_script` - Additional user_data scripts content
- `region` - AWS Region - defaults to us-east-1
- `servers` - Number of ECS Servers to start in the cluster - defaults to 2
- `instance_type` - AWS instance type - defaults to t2.micro
Expand All @@ -37,6 +45,10 @@ extra_tags = [
- `security_group_ids` - a list of security group IDs to apply to the launch configuration
- `user_data` - The instance user data (e.g. a `cloud-init` config) to use in the `aws_launch_configuration`

- `consul_image` - Image to use when deploying consul, defaults to the hashicorp consul image
- `registrator_image` - Image to use when deploying registrator agent, defaults to the gliderlabs registrator:latest
- `enable_agents` - Enable Consul Agent and Registrator tasks on each ECS Instance. Defaults to false

Usage
-----

Expand All @@ -47,11 +59,57 @@ module "ecs-cluster" {
servers = 1
subnet_id = ["subnet-6e101446"]
vpc_id = "vpc-99e73dfc"
key_name = "key.pem"
}
```

#### Example cluster with consul and Registrator

In order to start the Consul/Registrator task in ECS, you'll need to pass in a consul config into the `additional_user_data_script` script parameter. For example, you might pass something like this:

Please note, this module will try to mount `/etc/consul/` into `/consul/config` in the container and assumes that the consul config lives under `/etc/consul` on the docker host.

```Shell
/bin/mkdir -p /etc/consul
cat <<"CONSUL" > /etc/consul/config.json
{
"raft_protocol": 3,
"log_level": "INFO",
"enable_script_checks": true,
"datacenter": "${datacenter}",
"retry_join_ec2": {
"tag_key": "consul_server",
"tag_value": "true"
}
}
CONSUL
```


```hcl
data "template_file" "ecs_consul_agent_json" {
template = "${file("ecs_consul_agent.json.sh")}"
vars {
datacenter = "infra-services"
}
}
module "ecs-cluster" {
source = "github.com/terraform-community-modules/tf_aws_ecs"
name = "infra-services"
servers = 1
subnet_id = ["subnet-6e101446"]
vpc_id = "vpc-99e73dfc"
additional_user_data_script = "${data.template_file.ecs_consul_agent_json.rendered}"
enable_agents = true
}
```


Outputs
=======

Expand Down
54 changes: 54 additions & 0 deletions consul_agent.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
data "template_file" "consul" {
template = "${file("${path.module}/templates/consul.json")}"

vars {
env = "${aws_ecs_cluster.cluster.name}"
image = "${var.consul_image}"
registrator_image = "${var.registrator_image}"
awslogs_group = "consul-agent-${aws_ecs_cluster.cluster.name}"
awslogs_stream_prefix = "consul-agent-${aws_ecs_cluster.cluster.name}"
awslogs_region = "${var.region}"
}
}

# End Data block

resource "aws_ecs_task_definition" "consul" {
count = "${var.enable_agents ? 1 : 0}"
family = "consul-agent-${aws_ecs_cluster.cluster.name}"
container_definitions = "${data.template_file.consul.rendered}"
network_mode = "host"
task_role_arn = "${aws_iam_role.consul_task.arn}"

volume {
name = "consul-config-dir"
host_path = "/etc/consul"
}

volume {
name = "docker-sock"
host_path = "/var/run/docker.sock"
}
}

resource "aws_cloudwatch_log_group" "consul" {
count = "${var.enable_agents ? 1 : 0}"
name = "${aws_ecs_task_definition.consul.family}"

tags {
VPC = "${data.aws_vpc.vpc.tags["Name"]}"
Application = "${aws_ecs_task_definition.consul.family}"
}
}

resource "aws_ecs_service" "consul" {
count = "${var.enable_agents ? 1 : 0}"
name = "consul-agent-${aws_ecs_cluster.cluster.name}"
cluster = "${aws_ecs_cluster.cluster.id}"
task_definition = "${aws_ecs_task_definition.consul.arn}"
desired_count = "${var.servers}"

placement_constraints {
type = "distinctInstance"
}
}
38 changes: 38 additions & 0 deletions iam.tf
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,41 @@ resource "aws_iam_policy_attachment" "attach-ecs" {
roles = ["${aws_iam_role.ecs-role.name}"]
policy_arn = "${aws_iam_policy.ecs-policy.arn}"
}

# IAM Resources for Consul and Registrator Agents

data "aws_iam_policy_document" "consul_task_policy" {
statement {
actions = [
"ec2:Describe*",
"autoscaling:Describe*",
]

resources = ["*"]
}
}

data "aws_iam_policy_document" "assume_role_consul_task" {
statement {
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}

resource "aws_iam_role" "consul_task" {
count = "${var.enable_agents ? 1 : 0}"
name = "${replace(format("%.64s", replace("tf-consul-agentTaskRole-${var.name}-${data.aws_vpc.vpc.tags["Name"]}", "_", "-")), "/\\s/", "-")}"
path = "/"
assume_role_policy = "${data.aws_iam_policy_document.assume_role_consul_task.json}"
}

resource "aws_iam_role_policy" "consul_ecs_task" {
count = "${var.enable_agents ? 1 : 0}"
name = "${replace(format("%.64s", replace("tf-consul-agentTaskPolicy-${var.name}-${data.aws_vpc.vpc.tags["Name"]}", "_", "-")), "/\\s/", "-")}"
role = "${aws_iam_role.consul_task.id}"
policy = "${data.aws_iam_policy_document.consul_task_policy.json}"
}
15 changes: 10 additions & 5 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ data "template_file" "user_data" {
template = "${file("${path.module}/templates/user_data.tpl")}"

vars {
cluster_name = "${aws_ecs_cluster.cluster.name}"
docker_storage_size = "${var.docker_storage_size}"
dockerhub_token = "${var.dockerhub_token}"
dockerhub_email = "${var.dockerhub_email}"
additional_user_data_script = "${var.additional_user_data_script}"
cluster_name = "${aws_ecs_cluster.cluster.name}"
docker_storage_size = "${var.docker_storage_size}"
dockerhub_token = "${var.dockerhub_token}"
dockerhub_email = "${var.dockerhub_email}"
}
}

data "aws_vpc" "vpc" {
id = "${var.vpc_id}"
}

resource "aws_launch_configuration" "ecs" {
name_prefix = "${coalesce(var.name_prefix, "ecs-${var.name}-")}"
image_id = "${var.ami == "" ? format("%s", data.aws_ami.ecs_ami.id) : var.ami}" # Workaround until 0.9.6
Expand Down Expand Up @@ -71,7 +76,7 @@ resource "aws_autoscaling_group" "ecs" {
resource "aws_security_group" "ecs" {
name = "ecs-sg-${var.name}"
description = "Container Instance Allowed Ports"
vpc_id = "${var.vpc_id}"
vpc_id = "${data.aws_vpc.vpc.id}"

ingress {
from_port = 0
Expand Down
52 changes: 52 additions & 0 deletions templates/consul.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"name": "consul_agent-${env}",
"image": "${image}",
"memoryReservation": 512,
"environment": [
{
"name": "CONSUL_BIND_INTERFACE",
"value": "eth0"
}
],
"command": [
"agent", "-client=0.0.0.0"
],
"mountPoints": [
{
"sourceVolume": "consul-config-dir",
"containerPath": "/consul/config"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${awslogs_group}",
"awslogs-region": "${awslogs_region}",
"awslogs-stream-prefix": "${awslogs_stream_prefix}"
}
}
},
{
"name": "registrator-${env}",
"image": "${registrator_image}",
"memoryReservation": 256,
"command": [
"-retry-attempts=10", "-retry-interval=1000", "consul://localhost:8500"
],
"mountPoints": [
{
"sourceVolume": "docker-sock",
"containerPath": "/tmp/docker.sock"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${awslogs_group}",
"awslogs-region": "${awslogs_region}",
"awslogs-stream-prefix": "${awslogs_stream_prefix}"
}
}
}
]
13 changes: 13 additions & 0 deletions templates/ecs_consul_agent.json.sh-example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/bin/mkdir -p /etc/consul
cat <<"CONSUL" > /etc/consul/config.json
{
"raft_protocol": 3,
"log_level": "INFO",
"enable_script_checks": true,
"datacenter": "${datacenter}",
"retry_join_ec2": {
"tag_key": "consul_server",
"tag_value": "true"
}
}
CONSUL
3 changes: 3 additions & 0 deletions templates/user_data.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ echo 'OPTIONS="$${OPTIONS} --storage-opt dm.basesize=${docker_storage_size}G"' >
/etc/init.d/docker restart
echo ECS_ENGINE_AUTH_TYPE=dockercfg >> /etc/ecs/ecs.config
echo 'ECS_ENGINE_AUTH_DATA={"https://index.docker.io/v1/": { "auth": "${dockerhub_token}", "email": "${dockerhub_email}"}}' >> /etc/ecs/ecs.config

# Append addition user-data script
${additional_user_data_script}
39 changes: 29 additions & 10 deletions variables.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
variable "additional_user_data_script" {
default = ""
}

variable "allowed_cidr_blocks" {
default = ["0.0.0.0/0"]
type = "list"
description = "List of subnets to allow into the ECS Security Group. Defaults to ['0.0.0.0/0']"
}

variable "name_prefix" {
default = ""
}

variable "ami" {
default = ""
}
Expand All @@ -16,8 +16,13 @@ variable "ami_version" {
default = "*"
}

variable "user_data" {
default = ""
variable "associate_public_ip_address" {
default = false
}

variable "consul_image" {
description = "Image to use when deploying consul, defaults to the hashicorp consul image"
default = "consul:latest"
}

variable "docker_storage_size" {
Expand All @@ -35,6 +40,11 @@ variable "dockerhub_token" {
description = "Auth Token used for dockerhub. http://docs.aws.amazon.com/AmazonECS/latest/developerguide/private-auth.html"
}

variable "enable_agents" {
default = false
description = "Enable Consul Agent and Registrator tasks on each ECS Instance"
}

variable "extra_tags" {
default = []
}
Expand All @@ -57,11 +67,20 @@ variable "name" {
description = "AWS ECS Cluster Name"
}

variable "name_prefix" {
default = ""
}

variable "region" {
default = "us-east-1"
description = "The region of AWS, for AMI lookups."
}

variable "registrator_image" {
default = "gliderlabs/registrator:latest"
description = "Image to use when deploying registrator agent, defaults to the gliderlabs registrator:latest image"
}

variable "security_group_ids" {
type = "list"
description = "A list of Security group IDs to apply to the launch configuration"
Expand All @@ -83,10 +102,10 @@ variable "tagName" {
description = "Name tag for the servers"
}

variable "vpc_id" {
description = "The AWS VPC ID which you want to deploy your instances"
variable "user_data" {
default = ""
}

variable "associate_public_ip_address" {
default = false
variable "vpc_id" {
description = "The AWS VPC ID which you want to deploy your instances"
}

0 comments on commit b8779be

Please sign in to comment.