Created
June 19, 2018 16:41
-
-
Save damscott/9da8f2e623cac61423bb6a05839b10a9 to your computer and use it in GitHub Desktop.
Using CI/CD for deployment of ECS task definitions and images causes drift between the tfstate and AWS. Using a bash script in a Terraform External Data Source to pull the current task definition revision and container image tag from AWS keeps the state in sync with changes from CI. This does not currently support multiple containers in a single…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
resource "aws_ecs_service" "service" { | |
name = "${var.app}" | |
cluster = "${var.cluster}" | |
# Use task revision in AWS if it is greater than task revision in tfstate | |
# Prevents rolling back revision when it has been incremented by CI | |
task_definition = "${aws_ecs_task_definition.app.family}:${data.external.task_definition.result["task_definition_revision"] > aws_ecs_task_definition.app.revision ? data.external.task_definition.result["task_definition_revision"] : aws_ecs_task_definition.app.revision }" | |
desired_count = "${var.task_count}" | |
depends_on = [ | |
"aws_ecs_task_definition.app" | |
] | |
} | |
resource "aws_ecs_task_definition" "task" { | |
family = "${var.app}-${var.env}" | |
task_role_arn = "${aws_iam_role.app_role.arn}" | |
container_definitions = <<JSON | |
[ | |
{ | |
"name": "${var.app}", | |
"image": "${aws_ecr_repository.app_repo.repository_url}:${data.external.task_definition.result["image_tag"]}" | |
} | |
] | |
JSON | |
} | |
data "external" "task_definition" { | |
program = ["bash", "${path.module}/ecs-task-definition.sh"] | |
query = { | |
service = "${var.app}" | |
cluster = "${var.cluster}" | |
path_root = "${jsonencode(path.root)}" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# This script retrieves the container image and task definition revision | |
# for a given cluster+service. If it can't retrieve it, assume | |
# this is the initial deployment and default to "latest". | |
defaultImageTag='latest' | |
# Exit if any of the intermediate steps fail | |
set -e | |
# Get parameters from stdin | |
eval "$(jq -r '@sh "service=\(.service) cluster=\(.cluster) path_root=\(.path_root)"')" | |
# Remove extra quotes and backslashes from jsonencoding path_root in terraform | |
path_root="$(echo $path_root | sed -e 's/^"//' -e 's/"$//' -e 's/\\\\/\\/g')" | |
taskDefinitionID="$(aws ecs describe-services --service $service --cluster $cluster | jq -r .services[0].taskDefinition)" | |
# If a task definition is already running in AWS, use the revision and image tag from it | |
if [[ ! -z "$taskDefinitionID" && "$taskDefinitionID" != "null" ]]; then { | |
taskDefinitionRevision="$(echo "$taskDefinitionID" | sed 's/^.*://')" | |
taskDefinition="$(aws ecs describe-task-definition --task-definition $taskDefinitionID)" | |
containerImage="$(echo "$taskDefinition" | jq -r .taskDefinition.containerDefinitions[0].image)" | |
imageTag="$(echo "$containerImage" | awk -F':' '{print $2}')" | |
# Default to "latest" if taskDefinition doesn't exist | |
# Set revision to 0 so terraform logic uses task definition from terraform | |
} else { | |
imageTag=$defaultImageTag | |
taskDefinitionRevision='0' | |
} | |
fi | |
# Generate a JSON object containing the image tag. | |
jq -n --arg imageTag $imageTag --arg taskDefinitionRevision $taskDefinitionRevision '{image_tag: $imageTag, task_definition_revision: $taskDefinitionRevision}' | |
exit 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
that's great in order to use this what is the value of below
path_root = "${jsonencode(path.root)}"
I am not using the module to create ECS or ECS task definition I am using resources in this case what would be the value of path and path.root
@damscott