Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ecr_ecs_deploy/ #13

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 25 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,43 @@

## What is this

This module contains reusable terraform modules to reduce boilerplate code. Mainly for M3 company but anyone can use this under [LICENSE](./LICENSE).
Reusable terraform modules. They are made for M3,Inc.'s internal use. But, anyone able to use them under [LICENSE](./LICENSE).

For example, you can setup ECS cluster + AutoScailing with [ecs_ec2_cluster_template](./ecs_ec2_cluster_template), no need to write many terraform for every applications.
## Modules

## Documents
**Setting up services**:

Look `README.md` and `variables.tf` of each module to know it's detail. For example, [ecs_ec2_cluster_template/README.md](./ecs_ec2_cluster_template/README.md) and [ecs_ec2_cluster_template/variables.tf](./ecs_ec2_cluster_template/variables.tf).
| Module | Description |
| -------------: | :------------- |
| [alb_template](./alb_template) | ALB + SSL certificate. |
| [ecr_repository_template](./ecr_repository_template) | ECR repository with Lifecycle policy. |
| [ecs_ec2_cluster_template](./ecs_ec2_cluster_template) | ECS nodes with EC2 + AutoScaling. |
| [ecs_web_service_template](./ecs_web_service_template) | ECS service + ALB target/listener + Route53 record.|

## How to use
**Monitoring**:

You can load this module from [GitHub registry](https://www.terraform.io/docs/modules/sources.html#github).
| Module | Description |
| -------------: | :------------- |
| [guardduty_slack](./guardduty_slack) | GuardDuty alerts in Slack. |
| [lambda_monitoring](./lambda_monitoring) | CloudWatch monitoring (alarm) for AWS lambda. |

Only what you need to do is to write following:
See `README.md` and `variables.tf` of each module for detail.

## Install

We can use modules with `module` blocks:

```
module "esc_ec2_cluster_template" {
source = "github.com/m3dev/m3-terraform-modules//ecs_ec2_cluster_template?ref=495ff58"

// ... set input variables, see `variables.tf` of the module.
// ... set input variables, see `variables.tf` of the mo.
}
```

Note that there are some key points in the `source` URL (see [official document for detail](https://www.terraform.io/docs/modules/sources.html)):
Note:

- You have to use double slash (`//`) to split repository URL and path from repository root.
- You should specify tag/branch/revision with `ref`, or your code might be broken when the `master` branch changed.

- Use double slash (`//`) to split repository URL and path from repository root
- Use `ref` to specify tag/branch/revision to use
See [the official document](https://www.terraform.io/docs/modules/sources.html)) for detail.
2 changes: 1 addition & 1 deletion alb_template/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AWS ALB template

Create ALB + SSL certificate.
ALB + SSL certificate.

This module also setup [DNS record](aws_route53_record.tf) and [aws_acm_certificate_validation](aws_acm_certificate_validation.tf) with DNS validation. So that this module requires Route53 hosted zone.

Expand Down
19 changes: 19 additions & 0 deletions ecr_ecs_deploy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# ecr_ecs_deploy

Updates ECS service to force a new deployment when new Docker image is pushed to ECR repository.

It must be useful for a case that ECS task definition refers docker image with ":latest" (or other fixed) tag.

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:-----:|
| docker\_image\_tags | Docker image tag to watch. | `string` | `"latest"` | no |
| ecr\_repository\_name | Name of ECR repository to watch. | `string` | n/a | yes |
| ecs\_cluster\_name | Name of ECS cluster which the ECS service belongs to | `string` | n/a | yes |
| ecs\_service\_name | Arn of ECS service to update | `string` | n/a | yes |
| name\_prefix | Prefix which is added for some resources. | `string` | `""` | no |

## Outputs

No output.
28 changes: 28 additions & 0 deletions ecr_ecs_deploy/aws_cloudwatch_event_rule.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
resource "aws_cloudwatch_event_rule" "ecr_deploy" {
name_prefix = "${var.name_prefix}ecr-put-image"
description = "ECR PutImage"

event_pattern = jsonencode({
source = [
"aws.ecr"
]
"detail" = {
eventName = [
"PutImage"
]
"requestParameters": {
"repositoryName": [
var.ecr_repository_name
],
"imageTag": [
var.docker_image_tags
]
}
}
})
}

resource "aws_cloudwatch_event_target" "slack" {
rule = aws_cloudwatch_event_rule.ecr_deploy.name
arn = aws_lambda_function.update_ecs_service.arn
}
50 changes: 50 additions & 0 deletions ecr_ecs_deploy/aws_iam_role.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
resource "aws_iam_role" "lambda_execution" {
name_prefix = "${var.name_prefix}lambda_execution"
assume_role_policy = data.aws_iam_policy_document.lambda_execution_assume_role_policy.json
}

data "aws_iam_policy_document" "lambda_execution_assume_role_policy" {
statement {
actions = [
"sts:AssumeRole"
]
principals {
type = "Service"
identifiers = [
"lambda.amazonaws.com"
]
}
}
}


resource "aws_iam_role_policy_attachment" "lambda_execution" {
role = aws_iam_role.lambda_execution.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "update_ecs_service" {
role = aws_iam_role.lambda_execution.name
policy_arn = aws_iam_policy.update_ecs_service.arn
}

resource "aws_iam_policy" "update_ecs_service" {
name = "${var.name_prefix}update_ecs_service"
policy = data.aws_iam_policy_document.update_ecs_service.json
}

resource "random_id" "sid" {
byte_length = 8
}

data "aws_iam_policy_document" "update_ecs_service" {
statement {
sid = random_id.sid.hex
actions = [
"ecs:UpdateService"
]
resources = [
var.ecs_service_arn
]
}
}
42 changes: 42 additions & 0 deletions ecr_ecs_deploy/aws_lambda_function.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
resource "random_id" "suffix" {
byte_length = 8
}

data "aws_ecs_cluster" "cluster" {
cluster_name = var.ecs_cluster_name
}

data "aws_ecs_service" "service" {
cluster_arn = data.aws_ecs_cluster.cluster.arn
service_name = var.ecs_service_name
}

resource "aws_lambda_function" "update_ecs_service" {
filename = data.archive_file.lambda.output_path
function_name = "${var.name_prefix}-update_ecs_service-${random_id.suffix.hex}"
role = aws_iam_role.lambda_execution.arn
handler = "main.lambda_handler"
source_code_hash = data.archive_file.lambda.output_base64sha256
runtime = "python3.8"
memory_size = 128
timeout = 30

environment {
variables = {
"EcsServiceArn" = data.aws_ecs_service.service.arn
"EcsClusterName" = var.ecs_cluster_name
}
}

lifecycle {
ignore_changes = [
filename,
]
}
}

data "archive_file" "lambda" {
type = "zip"
source_dir = "${abspath(path.module)}/lambda"
output_path = "${abspath(path.module)}/.upload/slack.zip"
}
6 changes: 6 additions & 0 deletions ecr_ecs_deploy/aws_lambda_permission.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
resource "aws_lambda_permission" "ecr_deploy" {
source_arn = aws_cloudwatch_event_rule.ecr_deploy.arn
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.update_ecs_service.function_name
principal = "events.amazonaws.com"
}
32 changes: 32 additions & 0 deletions ecr_ecs_deploy/lambda/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import json
import logging
import os

import boto3


class JsonFormatter:
def format(self, record):
return json.dumps(record.__dict__)


logging.basicConfig()
logging.getLogger().handlers[0].setFormatter(JsonFormatter())
logger = logging.getLogger(__name__)
logger.setLevel(os.environ.get('LOG_LEVEL', 'INFO'))


def lambda_handler(event, context):
try:
service = os.environ['EcsServiceArn']
cluster = os.environ['EcsClusterName']
except KeyError as e:
logger.exception(f'Environment variable not set: {e}')
raise

client = boto3.client("ecs")
response = client.update_service(
cluster=cluster,
service=service,
forceNewDeployment=True,
)
27 changes: 27 additions & 0 deletions ecr_ecs_deploy/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
variable "ecr_repository_name" {
type = string
description = "Name of ECR repository to watch."
}

variable "ecs_cluster_name" {
type = string
description = "Name of ECS cluster which the ECS service belongs to"
}

variable "ecs_service_name" {
type = string
description = "Arn of ECS service to update"
}

variable "docker_image_tags" {
type = string
description = "Docker image tag to watch."
default = "latest"
}

variable "name_prefix" {
type = string
description = "Prefix which is added for some resources."
default = ""
}

2 changes: 1 addition & 1 deletion ecr_repository_template/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ecr_repository_template

Create ECR repository with Lifecycle policy.
ECR repository with Lifecycle policy.

## Variables

Expand Down
2 changes: 1 addition & 1 deletion ecs_ec2_cluster_template/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ecs_ec2_cluster_template

Setup ECS nodes with EC2 + AutoScaling.
ECS nodes with EC2 + AutoScaling.

Also enable [SSM](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ec2-run-command.html) so that you can manage instance with it.

Expand Down
2 changes: 1 addition & 1 deletion ecs_web_service_template/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ecs_service_template

Create ECS service + ALB target/listener + Route53 record.
ECS service + ALB target/listener + Route53 record.

## Prerequisite

Expand Down
2 changes: 2 additions & 0 deletions guardduty_slack/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# guardduty_slack

Notification of GuardDuty for Slack.

This module setups:

- AWS GuardDuty
Expand Down