mirror of
https://github.com/farcasclaudiu/terraform-course.git
synced 2026-06-22 09:01:59 +03:00
@@ -0,0 +1,10 @@
|
|||||||
|
version: 0.0
|
||||||
|
Resources:
|
||||||
|
- TargetService:
|
||||||
|
Type: AWS::ECS::Service
|
||||||
|
Properties:
|
||||||
|
# <TASK_DEFINITION> will be replaced by codedeploy when the pipeline runs
|
||||||
|
TaskDefinition: "<TASK_DEFINITION>"
|
||||||
|
LoadBalancerInfo:
|
||||||
|
ContainerName: demo
|
||||||
|
ContainerPort: 3000
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
version: 0.2
|
||||||
|
|
||||||
|
phases:
|
||||||
|
pre_build:
|
||||||
|
commands:
|
||||||
|
- $(aws ecr get-login --no-include-email)
|
||||||
|
build:
|
||||||
|
commands:
|
||||||
|
- docker build -t $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION .
|
||||||
|
post_build:
|
||||||
|
commands:
|
||||||
|
# push
|
||||||
|
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION
|
||||||
|
# create new task definition
|
||||||
|
- ./create-new-task-def.sh $IMAGE_REPO_NAME
|
||||||
|
- ./set-network-configuration.sh $IMAGE_REPO_NAME
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
files:
|
||||||
|
- 'appspec.yaml'
|
||||||
|
- 'taskdef.json'
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -ex
|
||||||
|
SERVICE_NAME=$1
|
||||||
|
IMAGE_URI="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$CODEBUILD_RESOLVED_SOURCE_VERSION"
|
||||||
|
TASKDEF_NAME=$(aws ecs list-task-definitions |jq --raw-output '.taskDefinitionArns[] | select(contains("'${SERVICE_NAME}'"))' | tail -n1)
|
||||||
|
CURRENT_TASKDEF=`aws ecs describe-task-definition --task-definition $TASKDEF_NAME`
|
||||||
|
CURRENT_TASKDEF_CONTAINERDEF=`echo $CURRENT_TASKDEF| jq --raw-output ".taskDefinition.containerDefinitions"`
|
||||||
|
TASKDEF_ROLE_ARN=`echo $CURRENT_TASKDEF| jq --raw-output ".taskDefinition.taskRoleArn"`
|
||||||
|
EXECUTION_ROLE_ARN=`echo $CURRENT_TASKDEF| jq --raw-output ".taskDefinition.executionRoleArn"`
|
||||||
|
TASKDEF=`echo $CURRENT_TASKDEF_CONTAINERDEF | jq ' [ .[] | .image = "'${IMAGE_URI}'" ]'`
|
||||||
|
CPU=$(echo $CURRENT_TASKDEF |jq -r '.taskDefinition.cpu')
|
||||||
|
MEMORY=$(echo $CURRENT_TASKDEF |jq -r '.taskDefinition.memory')
|
||||||
|
NETWORK_MODE=$(echo $CURRENT_TASKDEF |jq -r '.taskDefinition.networkMode')
|
||||||
|
REQUIRES_COMPATIBILITIES=$(echo $CURRENT_TASKDEF |jq '.taskDefinition.requiresCompatibilities[]' | tr '\n' ',' | sed 's/.$//')
|
||||||
|
echo '{"family": "'${SERVICE_NAME}'", "taskRoleArn": "'${TASKDEF_ROLE_ARN}'", "executionRoleArn": "'${EXECUTION_ROLE_ARN}'", "containerDefinitions": '$TASKDEF', "cpu": "'$CPU'", "memory": "'$MEMORY'", "requiresCompatibilities": ['$REQUIRES_COMPATIBILITIES'], "networkMode": "'${NETWORK_MODE}'" }' > taskdef.json
|
||||||
|
#aws ecs register-task-definition --cli-input-json file://task-def-template.json.new > task-def-template.json.out
|
||||||
|
#NEW_TASKDEF_ARN=`cat task-def-template.json.out |jq -r '.taskDefinition.taskDefinitionArn'`
|
||||||
|
sed -i 's#$TASKDEF#'$NEW_TASKDEF_ARN'#' appspec.yaml
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# set subnet, security groups, public ip
|
||||||
|
SERVICE_NAME=$1
|
||||||
|
CLUSTER_NAME=$1
|
||||||
|
NETWORK_CONFIGURATION=$(aws ecs describe-services --services $SERVICE_NAME --cluster $CLUSTER_NAME |jq -r '.services[].networkConfiguration')
|
||||||
|
SUBNETS=$(echo $NETWORK_CONFIGURATION |jq '.awsvpcConfiguration.subnets[]' | tr '\n' ',' | sed 's/.$//')
|
||||||
|
SECURITY_GROUPS=$(echo $NETWORK_CONFIGURATION |jq '.awsvpcConfiguration.securityGroups[]' | tr '\n' ',' | sed 's/.$//')
|
||||||
|
PUBLIC_IP=$(echo $NETWORK_CONFIGURATION |jq '.awsvpcConfiguration.assignPublicIp')
|
||||||
|
sed -i 's/$SUBNETS/'$SUBNETS'/' appspec.yaml
|
||||||
|
sed -i 's/$SECURITY_GROUPS/'$SECURITY_GROUPS'/' appspec.yaml
|
||||||
|
sed -i 's/$PUBLIC_IP/'$PUBLIC_IP'/' appspec.yaml
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
resource "aws_codedeploy_app" "demo" {
|
||||||
|
compute_platform = "ECS"
|
||||||
|
name = "demo"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_codedeploy_deployment_group" "demo" {
|
||||||
|
app_name = aws_codedeploy_app.demo.name
|
||||||
|
deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
|
||||||
|
deployment_group_name = "demo"
|
||||||
|
service_role_arn = aws_iam_role.demo-codedeploy.arn
|
||||||
|
|
||||||
|
auto_rollback_configuration {
|
||||||
|
enabled = true
|
||||||
|
events = ["DEPLOYMENT_FAILURE"]
|
||||||
|
}
|
||||||
|
|
||||||
|
blue_green_deployment_config {
|
||||||
|
deployment_ready_option {
|
||||||
|
action_on_timeout = "CONTINUE_DEPLOYMENT"
|
||||||
|
}
|
||||||
|
|
||||||
|
terminate_blue_instances_on_deployment_success {
|
||||||
|
action = "TERMINATE"
|
||||||
|
termination_wait_time_in_minutes = 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deployment_style {
|
||||||
|
deployment_option = "WITH_TRAFFIC_CONTROL"
|
||||||
|
deployment_type = "BLUE_GREEN"
|
||||||
|
}
|
||||||
|
|
||||||
|
ecs_service {
|
||||||
|
cluster_name = aws_ecs_cluster.demo.name
|
||||||
|
service_name = aws_ecs_service.demo.name
|
||||||
|
}
|
||||||
|
|
||||||
|
load_balancer_info {
|
||||||
|
target_group_pair_info {
|
||||||
|
prod_traffic_route {
|
||||||
|
listener_arns = [aws_lb_listener.demo.arn]
|
||||||
|
}
|
||||||
|
|
||||||
|
target_group {
|
||||||
|
name = aws_lb_target_group.demo-blue.name
|
||||||
|
}
|
||||||
|
|
||||||
|
target_group {
|
||||||
|
name = aws_lb_target_group.demo-green.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,8 +26,8 @@ resource "aws_codepipeline" "demo" {
|
|||||||
output_artifacts = ["demo-docker-source"]
|
output_artifacts = ["demo-docker-source"]
|
||||||
|
|
||||||
configuration = {
|
configuration = {
|
||||||
RepositoryName = aws_codecommit_repository.demo.repository_name
|
RepositoryName = aws_codecommit_repository.demo.repository_name
|
||||||
BranchName = "master"
|
BranchName = "master"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,19 +54,19 @@ resource "aws_codepipeline" "demo" {
|
|||||||
name = "Deploy"
|
name = "Deploy"
|
||||||
|
|
||||||
action {
|
action {
|
||||||
name = "Deploy"
|
name = "DeployToECS"
|
||||||
category = "Deploy"
|
category = "Deploy"
|
||||||
owner = "AWS"
|
owner = "AWS"
|
||||||
provider = "ECS"
|
provider = "CodeDeployToECS"
|
||||||
input_artifacts = ["demo-docker-build"]
|
input_artifacts = ["demo-docker-build"]
|
||||||
version = "1"
|
version = "1"
|
||||||
|
|
||||||
configuration = {
|
configuration = {
|
||||||
ClusterName = "demo" # name of cluster
|
ApplicationName = aws_codedeploy_app.demo.name
|
||||||
ServiceName = "demo" # name of service
|
DeploymentGroupName = aws_codedeploy_deployment_group.demo.deployment_group_name
|
||||||
|
TaskDefinitionTemplateArtifact = "demo-docker-build"
|
||||||
|
AppSpecTemplateArtifact = "demo-docker-build"
|
||||||
}
|
}
|
||||||
|
|
||||||
role_arn = aws_iam_role.demo-codepipeline.arn
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
resource "aws_ecs_task_definition" "demo" {
|
resource "aws_ecs_task_definition" "demo" {
|
||||||
family = "demo"
|
family = "demo"
|
||||||
execution_role_arn = aws_iam_role.ecs-task-execution-role.arn
|
execution_role_arn = aws_iam_role.ecs-task-execution-role.arn
|
||||||
task_role_arn = aws_iam_role.ecs-demo-task-role.arn
|
task_role_arn = aws_iam_role.ecs-demo-task-role.arn
|
||||||
cpu = 256
|
cpu = 256
|
||||||
memory = 512
|
memory = 512
|
||||||
network_mode = "awsvpc"
|
network_mode = "awsvpc"
|
||||||
requires_compatibilities = [
|
requires_compatibilities = [
|
||||||
"FARGATE"
|
"FARGATE"
|
||||||
]
|
]
|
||||||
@@ -39,42 +39,60 @@ DEFINITION
|
|||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_ecs_service" "demo" {
|
resource "aws_ecs_service" "demo" {
|
||||||
name = "demo"
|
name = "demo"
|
||||||
cluster = aws_ecs_cluster.demo.id
|
cluster = aws_ecs_cluster.demo.id
|
||||||
desired_count = 1
|
desired_count = 1
|
||||||
task_definition = aws_ecs_task_definition.demo.arn
|
task_definition = aws_ecs_task_definition.demo.arn
|
||||||
launch_type = "FARGATE"
|
launch_type = "FARGATE"
|
||||||
|
depends_on = [aws_lb_listener.demo]
|
||||||
|
|
||||||
|
deployment_controller {
|
||||||
|
type = "CODE_DEPLOY"
|
||||||
|
}
|
||||||
|
|
||||||
network_configuration {
|
network_configuration {
|
||||||
subnets = slice(module.vpc.public_subnets, 1, 2)
|
subnets = slice(module.vpc.public_subnets, 1, 2)
|
||||||
security_groups = [aws_security_group.ecs-demo.id]
|
security_groups = [aws_security_group.ecs-demo.id]
|
||||||
assign_public_ip = true
|
assign_public_ip = true
|
||||||
}
|
}
|
||||||
|
|
||||||
load_balancer {
|
load_balancer {
|
||||||
target_group_arn = aws_lb_target_group.demo.id
|
target_group_arn = aws_lb_target_group.demo-blue.id
|
||||||
container_name = "demo"
|
container_name = "demo"
|
||||||
container_port = "3000"
|
container_port = "3000"
|
||||||
}
|
}
|
||||||
lifecycle {
|
lifecycle {
|
||||||
ignore_changes = [
|
ignore_changes = [
|
||||||
task_definition
|
task_definition,
|
||||||
|
load_balancer
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# security group
|
# security group
|
||||||
resource "aws_security_group" "ecs-demo" {
|
resource "aws_security_group" "ecs-demo" {
|
||||||
name = "ECS demo"
|
name = "ECS demo"
|
||||||
vpc_id = module.vpc.vpc_id
|
vpc_id = module.vpc.vpc_id
|
||||||
description = "ECS demo"
|
description = "ECS demo"
|
||||||
|
|
||||||
|
ingress {
|
||||||
|
from_port = 3000
|
||||||
|
to_port = 3000
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
}
|
||||||
|
|
||||||
egress {
|
egress {
|
||||||
from_port = 0
|
from_port = 0
|
||||||
to_port = 0
|
to_port = 0
|
||||||
protocol = "-1"
|
protocol = "-1"
|
||||||
cidr_blocks = [
|
cidr_blocks = [
|
||||||
"0.0.0.0/0"
|
"0.0.0.0/0"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# logs
|
||||||
|
resource "aws_cloudwatch_log_group" "demo" {
|
||||||
|
name = "demo"
|
||||||
|
}
|
||||||
|
|||||||
@@ -114,6 +114,17 @@ resource "aws_iam_role_policy" "demo-codebuild" {
|
|||||||
"*"
|
"*"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Sid": "ECS",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Action": [
|
||||||
|
"ecs:List*",
|
||||||
|
"ecs:Describe*"
|
||||||
|
],
|
||||||
|
"Resource": [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Effect": "Allow",
|
"Effect": "Allow",
|
||||||
"Action": [
|
"Action": [
|
||||||
|
|||||||
@@ -0,0 +1,86 @@
|
|||||||
|
resource "aws_iam_role" "demo-codedeploy" {
|
||||||
|
name = "demo-codedeploy"
|
||||||
|
|
||||||
|
assume_role_policy = <<EOF
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {
|
||||||
|
"Service": "codedeploy.amazonaws.com"
|
||||||
|
},
|
||||||
|
"Action": "sts:AssumeRole"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "demo-codedeploy-role-policy" {
|
||||||
|
statement {
|
||||||
|
effect = "Allow"
|
||||||
|
actions = [
|
||||||
|
"ecs:DescribeServices",
|
||||||
|
"ecs:CreateTaskSet",
|
||||||
|
"ecs:UpdateServicePrimaryTaskSet",
|
||||||
|
"ecs:DeleteTaskSet",
|
||||||
|
"elasticloadbalancing:DescribeTargetGroups",
|
||||||
|
"elasticloadbalancing:DescribeListeners",
|
||||||
|
"elasticloadbalancing:ModifyListener",
|
||||||
|
"elasticloadbalancing:DescribeRules",
|
||||||
|
"elasticloadbalancing:ModifyRule",
|
||||||
|
"lambda:InvokeFunction",
|
||||||
|
"cloudwatch:DescribeAlarms",
|
||||||
|
"sns:Publish",
|
||||||
|
"s3:GetObject",
|
||||||
|
"s3:GetObjectVersion"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"*",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
effect = "Allow"
|
||||||
|
actions = [
|
||||||
|
"s3:Get*",
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"${aws_s3_bucket.demo-artifacts.arn}/*",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
effect = "Allow"
|
||||||
|
actions = [
|
||||||
|
"kms:DescribeKey",
|
||||||
|
"kms:Decrypt",
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
aws_kms_key.demo-artifacts.arn
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
effect = "Allow"
|
||||||
|
actions = [
|
||||||
|
"iam:PassRole"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
aws_iam_role.ecs-task-execution-role.arn,
|
||||||
|
aws_iam_role.ecs-demo-task-role.arn,
|
||||||
|
]
|
||||||
|
condition {
|
||||||
|
test = "StringLike"
|
||||||
|
variable = "iam:PassedToService"
|
||||||
|
values = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy" "demo-codedeploy" {
|
||||||
|
name = "codedeploy-policy"
|
||||||
|
role = aws_iam_role.demo-codedeploy.id
|
||||||
|
policy = data.aws_iam_policy_document.demo-codedeploy-role-policy.json
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -78,6 +78,7 @@ data "aws_iam_policy_document" "demo-codepipeline-role-policy" {
|
|||||||
statement {
|
statement {
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
actions = [
|
actions = [
|
||||||
|
"codedeploy:*",
|
||||||
"ecs:*",
|
"ecs:*",
|
||||||
]
|
]
|
||||||
resources = [
|
resources = [
|
||||||
@@ -87,19 +88,23 @@ data "aws_iam_policy_document" "demo-codepipeline-role-policy" {
|
|||||||
statement {
|
statement {
|
||||||
effect = "Allow"
|
effect = "Allow"
|
||||||
actions = [
|
actions = [
|
||||||
"iam:PassRole",
|
"iam:PassRole"
|
||||||
]
|
]
|
||||||
resources = [
|
resources = [
|
||||||
aws_iam_role.ecs-task-execution-role.arn,
|
aws_iam_role.ecs-task-execution-role.arn,
|
||||||
aws_iam_role.ecs-demo-task-role.arn,
|
aws_iam_role.ecs-demo-task-role.arn,
|
||||||
]
|
]
|
||||||
|
condition {
|
||||||
|
test = "StringLike"
|
||||||
|
variable = "iam:PassedToService"
|
||||||
|
values = ["ecs-tasks.amazonaws.com"]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_iam_role_policy" "demo-codepipeline" {
|
resource "aws_iam_role_policy" "demo-codepipeline" {
|
||||||
name = "codepipeline-policy"
|
name = "codepipeline-policy"
|
||||||
role = aws_iam_role.demo-codepipeline.id
|
role = aws_iam_role.demo-codepipeline.id
|
||||||
policy = data.aws_iam_policy_document.demo-codepipeline-role-policy.json
|
policy = data.aws_iam_policy_document.demo-codepipeline-role-policy.json
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-6
@@ -1,7 +1,8 @@
|
|||||||
resource "aws_lb" "demo" {
|
resource "aws_lb" "demo" {
|
||||||
name = "demo"
|
name = "demo"
|
||||||
subnets = module.vpc.public_subnets
|
subnets = module.vpc.public_subnets
|
||||||
load_balancer_type = "network"
|
load_balancer_type = "network"
|
||||||
|
enable_cross_zone_load_balancing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_lb_listener" "demo" {
|
resource "aws_lb_listener" "demo" {
|
||||||
@@ -10,13 +11,33 @@ resource "aws_lb_listener" "demo" {
|
|||||||
protocol = "TCP"
|
protocol = "TCP"
|
||||||
|
|
||||||
default_action {
|
default_action {
|
||||||
target_group_arn = aws_lb_target_group.demo.id
|
target_group_arn = aws_lb_target_group.demo-blue.id
|
||||||
type = "forward"
|
type = "forward"
|
||||||
}
|
}
|
||||||
|
lifecycle {
|
||||||
|
ignore_changes = [
|
||||||
|
default_action,
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resource "aws_lb_target_group" "demo" {
|
resource "aws_lb_target_group" "demo-blue" {
|
||||||
name = "demo-http"
|
name = "demo-http-blue"
|
||||||
|
port = "3000"
|
||||||
|
protocol = "TCP"
|
||||||
|
target_type = "ip"
|
||||||
|
vpc_id = module.vpc.vpc_id
|
||||||
|
deregistration_delay = "30"
|
||||||
|
|
||||||
|
health_check {
|
||||||
|
healthy_threshold = 2
|
||||||
|
unhealthy_threshold = 2
|
||||||
|
protocol = "TCP"
|
||||||
|
interval = 30
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resource "aws_lb_target_group" "demo-green" {
|
||||||
|
name = "demo-http-green"
|
||||||
port = "3000"
|
port = "3000"
|
||||||
protocol = "TCP"
|
protocol = "TCP"
|
||||||
target_type = "ip"
|
target_type = "ip"
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ module "vpc" {
|
|||||||
enable_vpn_gateway = false
|
enable_vpn_gateway = false
|
||||||
|
|
||||||
tags = {
|
tags = {
|
||||||
"Name" = "terraform-cloudpipeline-demo"
|
"Name" = "terraform-cloudpipeline-demo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user