Terraform을 사용하여 AWS ECS 클러스터 만들기
49859 단어 awsterraforminfrastructurecontainers
리소스
내가 배치해야 할 응용 프로그램은 단일 NodeJS 응용 프로그램이기 때문에, 배치하고 신축성을 가지기 위해, 나는 자동 축소 도구가 있는 용기를 사용하여 CPU와 메모리 사용 상황에 따라 응용 프로그램을 축소하기로 결정했다.AWS에서 이 환경을 구축하기 위해 아래 나열된 서비스를 사용했습니다.
지형 초기 배치
내가 사용하는 지형 배치는 매우 간단하다.첫 번째 단계는 지형 상태를 저장하기 위해 AWS S3에 저장통을 만드는 것입니다.이것은 필수적인 것이 아니지만, 만약 누군가가 이 인프라 시설을 유지해야 한다면, 우리의 생활은 더욱 수월해질 것이다.이 구성의 파일
main.tf
입니다.# main.tf | Main Configuration
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "2.70.0"
}
}
backend "s3" {
bucket = "terraform-state-bucket"
key = "state/terraform_state.tfstate"
region = "us-east-1"
}
}
provider "aws" {
region = var.aws_region
access_key = var.aws_access_key
secret_key = var.aws_secret_key
}
provider
부분에 변수를 사용했다.우리는 atfvars
에서 변수를 정의할 수 있다.잠시 후에 나는 이 문장에서 해석할 것이다.업데이트: 이 초기 설정을 사용하면 실행
terraform init
만 가능합니다.독점 네트워크 및 네트워크
VPC를 만들고 네트워크 리소스를 구성해 보겠습니다.다음 예제 코드는 VPC를 생성합니다.
# vpc.tf | VPC Configuration
resource "aws_vpc" "aws-vpc" {
cidr_block = "10.10.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.app_name}-vpc"
Environment = var.app_environment
}
}
네트워크를 연결하기 위해서는 전유 네트워크 안에서 공공과 사유 서브네트워크, 그리고 공공 서브네트워크의 인터넷 스위치와 루트표를 만들 필요가 있다.다음 예시에서 이 자원을 만들 것입니다# networking.tf | Network Configuration
resource "aws_internet_gateway" "aws-igw" {
vpc_id = aws_vpc.aws-vpc.id
tags = {
Name = "${var.app_name}-igw"
Environment = var.app_environment
}
}
resource "aws_subnet" "private" {
vpc_id = aws_vpc.aws-vpc.id
count = length(var.private_subnets)
cidr_block = element(var.private_subnets, count.index)
availability_zone = element(var.availability_zones, count.index)
tags = {
Name = "${var.app_name}-private-subnet-${count.index + 1}"
Environment = var.app_environment
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.aws-vpc.id
cidr_block = element(var.public_subnets, count.index)
availability_zone = element(var.availability_zones, count.index)
count = length(var.public_subnets)
map_public_ip_on_launch = true
tags = {
Name = "${var.app_name}-public-subnet-${count.index + 1}"
Environment = var.app_environment
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.aws-vpc.id
tags = {
Name = "${var.app_name}-routing-table-public"
Environment = var.app_environment
}
}
resource "aws_route" "public" {
route_table_id = aws_route_table.public.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.aws-igw.id
}
resource "aws_route_table_association" "public" {
count = length(var.public_subnets)
subnet_id = element(aws_subnet.public.*.id, count.index)
route_table_id = aws_route_table.public.id
}
컨테이너 등록 및 ECS 클러스터
이제 컨테이너 레지스트리와 ECS 클러스터를 만들 때가 되었습니다.먼저 다음 코드로 컨테이너 레지스트리를 만듭니다.
# ecr.tf | Elastic Container Repository
resource "aws_ecr_repository" "aws-ecr" {
name = "${var.app_name}-${var.app_environment}-ecr"
tags = {
Name = "${var.app_name}-ecr"
Environment = var.app_environment
}
}
ECR은 배포할 응용 프로그램의 Docker 이미지를 저장하는 저장소입니다.Docker에 익숙하면 Docker Hub처럼 작동합니다.로컬에서 Docker 이미지를 구축하여 ECR로 전송하거나 CI/CD 플랫폼을 사용하여 구현할 수 있습니다.이제 ECS 클러스터, 서비스 및 작업 정의를 작성합니다.
서비스는 우리가 집단에서 여러 작업을 동시에 실행하고 유지할 수 있도록 설정하는 것이다.컨테이너는 서비스에서 작업을 실행하는 데 사용되는 작업에 의해 정의됩니다.
ECS 클러스터를 생성하기 전에 서비스가 ECR에서 이미지를 추출할 수 있도록 IAM 정책을 작성해야 합니다.
# iam.tf | IAM Role Policies
resource "aws_iam_role" "ecsTaskExecutionRole" {
name = "${var.app_name}-execution-task-role"
assume_role_policy = data.aws_iam_policy_document.assume_role_policy.json
tags = {
Name = "${var.app_name}-iam-role"
Environment = var.app_environment
}
}
data "aws_iam_policy_document" "assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
resource "aws_iam_role_policy_attachment" "ecsTaskExecutionRole_policy" {
role = aws_iam_role.ecsTaskExecutionRole.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}
이제 ECS를 위해 필요한 것을 만듭니다.먼저 ECS 클러스터를 만듭니다.resource "aws_ecs_cluster" "aws-ecs-cluster" {
name = "${var.app_name}-${var.app_environment}-cluster"
tags = {
Name = "${var.app_name}-ecs"
Environment = var.app_environment
}
}
컨테이너 로그를 가져오려면 CloudWatch에 로그 그룹을 만들었습니다.resource "aws_cloudwatch_log_group" "log-group" {
name = "${var.app_name}-${var.app_environment}-logs"
tags = {
Application = var.app_name
Environment = var.app_environment
}
}
AWS FARGATE와 호환되는 작업 정의를 만들었습니다. 인프라를 더욱 잘 활용하기 위해 이렇게 하고 싶습니다.data "template_file" "env_vars" {
template = file("env_vars.json")
}
resource "aws_ecs_task_definition" "aws-ecs-task" {
family = "${var.app_name}-task"
container_definitions = <<DEFINITION
[
{
"name": "${var.app_name}-${var.app_environment}-container",
"image": "${aws_ecr_repository.aws-ecr.repository_url}:latest",
"entryPoint": [],
"environment": ${data.template_file.env_vars.rendered},
"essential": true,
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "${aws_cloudwatch_log_group.log-group.id}",
"awslogs-region": "${var.aws_region}",
"awslogs-stream-prefix": "${var.app_name}-${var.app_environment}"
}
},
"portMappings": [
{
"containerPort": 8080,
"hostPort": 8080
}
],
"cpu": 256,
"memory": 512,
"networkMode": "awsvpc"
}
]
DEFINITION
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
memory = "512"
cpu = "256"
execution_role_arn = aws_iam_role.ecsTaskExecutionRole.arn
task_role_arn = aws_iam_role.ecsTaskExecutionRole.arn
tags = {
Name = "${var.app_name}-ecs-td"
Environment = var.app_environment
}
}
data "aws_ecs_task_definition" "main" {
task_definition = aws_ecs_task_definition.aws-ecs-task.family
}
작업 정의에 대한 관찰 결과, 나는 Terraformdata
함수를 사용하여 JSON 파일에서 정의한 환경 변수를 설정하고 있다. (AWS EKS 또는 다른 방식으로 기밀을 저장하는 것은 개선이 필요하다.)자, 이제 ECS 서비스를 만들겠습니다.
resource "aws_ecs_service" "aws-ecs-service" {
name = "${var.app_name}-${var.app_environment}-ecs-service"
cluster = aws_ecs_cluster.aws-ecs-cluster.id
task_definition = "${aws_ecs_task_definition.aws-ecs-task.family}:${max(aws_ecs_task_definition.aws-ecs-task.revision, data.aws_ecs_task_definition.main.revision)}"
launch_type = "FARGATE"
scheduling_strategy = "REPLICA"
desired_count = 1
force_new_deployment = true
network_configuration {
subnets = aws_subnet.private.*.id
assign_public_ip = false
security_groups = [
aws_security_group.service_security_group.id,
aws_security_group.load_balancer_security_group.id
]
}
load_balancer {
target_group_arn = aws_lb_target_group.target_group.arn
container_name = "${var.app_name}-${var.app_environment}-container"
container_port = 8080
}
depends_on = [aws_lb_listener.listener]
}
용기와의 외부 연결을 피하기 위해 보안 그룹도 정의했다.resource "aws_security_group" "service_security_group" {
vpc_id = aws_vpc.aws-vpc.id
ingress {
from_port = 0
to_port = 0
protocol = "-1"
security_groups = [aws_security_group.load_balancer_security_group.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "${var.app_name}-service-sg"
Environment = var.app_environment
}
}
어플리케이션 로드 밸런서
다음 단계는 부하 균형기를 설정하는 것입니다.ECS 구성에서 알 수 있듯이 이 구성에는 a
load_balancer
에 대한 참조가 있습니다.resource "aws_alb" "application_load_balancer" {
name = "${var.app_name}-${var.app_environment}-alb"
internal = false
load_balancer_type = "application"
subnets = aws_subnet.public.*.id
security_groups = [aws_security_group.load_balancer_security_group.id]
tags = {
Name = "${var.app_name}-alb"
Environment = var.app_environment
}
}
이제 부하 균형기에 안전 그룹을 추가합니다resource "aws_security_group" "load_balancer_security_group" {
vpc_id = aws_vpc.aws-vpc.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
ipv6_cidr_blocks = ["::/0"]
}
tags = {
Name = "${var.app_name}-sg"
Environment = var.app_environment
}
}
부하 균형기 목표 그룹을 만들어야 합니다. 부하 균형기와 용기를 연결합니다.resource "aws_lb_target_group" "target_group" {
name = "${var.app_name}-${var.app_environment}-tg"
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = aws_vpc.aws-vpc.id
health_check {
healthy_threshold = "3"
interval = "300"
protocol = "HTTP"
matcher = "200"
timeout = "3"
path = "/v1/status"
unhealthy_threshold = "2"
}
tags = {
Name = "${var.app_name}-lb-tg"
Environment = var.app_environment
}
}
여기서 매우 중요한 점은 path
중의 속성health_check
이다.이것은 응용 프로그램의 루트입니다. 부하 균형기는 이 루트를 사용하여 응용 프로그램의 상태를 검사합니다.마지막으로 out 부하 밸런서에 HTTP 탐지기를 만듭니다.
resource "aws_lb_listener" "listener" {
load_balancer_arn = aws_alb.application_load_balancer.id
port = "80"
protocol = "HTTP"
default_action {
type = "forward"
target_group_arn = aws_lb_target_group.target_group.id
}
}
자동 배율 조정
그래서 자동 축소는 내가 개발하고 있는 응용 프로그램에 있어서 없어서는 안 될 것이다.AWS에서 그것을 설정하려면, 나는 자동 축소 목표와 두 개의 간단한 자동 축소 정책을 만들어야 한다.하나는 CPU 사용량에 따라 확장하고, 다른 하나는 메모리 사용량에 사용됩니다.
# autoscaling.tf | Auto Scaling Group
resource "aws_appautoscaling_target" "ecs_target" {
max_capacity = 2
min_capacity = 1
resource_id = "service/${aws_ecs_cluster.aws-ecs-cluster.name}/${aws_ecs_service.aws-ecs-service.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
resource "aws_appautoscaling_policy" "ecs_policy_memory" {
name = "${var.app_name}-${var.app_environment}-memory-autoscaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs_target.resource_id
scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
service_namespace = aws_appautoscaling_target.ecs_target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageMemoryUtilization"
}
target_value = 80
}
}
resource "aws_appautoscaling_policy" "ecs_policy_cpu" {
name = "${var.app_name}-${var.app_environment}-cpu-autoscaling"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.ecs_target.resource_id
scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
service_namespace = aws_appautoscaling_target.ecs_target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
target_value = 80
}
}
따라서 메모리나 cpu의 사용률이 사용률의 80%에 이르면 응용 프로그램이 확대될 것이다.이 값보다 낮을 때 프로그램은 비례에 따라 축소됩니다.변량
나는 네가 우리가 지형 설정 파일에 많은 변수를 사용했다는 것을 이미 알아차렸다고 믿는다.변수를 사용하기 위해
variables.tf
라는 파일을 만들었습니다.이 파일은 변수 정의만 있습니다.# variables.tf | Auth and Application variables
variable "aws_access_key" {
type = string
description = "AWS Access Key"
}
variable "aws_secret_key" {
type = string
description = "AWS Secret Key"
}
variable "aws_region" {
type = string
description = "AWS Region"
}
variable "aws_cloudwatch_retention_in_days" {
type = number
description = "AWS CloudWatch Logs Retention in Days"
default = 1
}
variable "app_name" {
type = string
description = "Application Name"
}
variable "app_environment" {
type = string
description = "Application Environment"
}
variable "cidr" {
description = "The CIDR block for the VPC."
default = "10.0.0.0/16"
}
variable "public_subnets" {
description = "List of public subnets"
}
variable "private_subnets" {
description = "List of private subnets"
}
variable "availability_zones" {
description = "List of availability zones"
}
각 변수의 값은 terraform.tfvars
라는 파일에 정의됩니다.aws_region = "us-east-1"
aws_access_key = "your aws access key"
aws_secret_key = "your aws secret key"
# these are zones and subnets examples
availability_zones = ["us-east-1a", "us-east-1b"]
public_subnets = ["10.10.100.0/24", "10.10.101.0/24"]
private_subnets = ["10.10.0.0/24", "10.10.1.0/24"]
# these are used for tags
app_name = "node-js-app"
app_environment = "production"
이 파일은 내 저장소에 제출되지 않았습니다.나는 로컬에서 그것을 만들고 S3를 사용하여 접근을 관리하고 버전을 제어했다.그것은 아직 약간의 개선이 필요하다. 나는 더욱 개선할 것이다.업데이트: 현재 모든 프로필을 정확하게 작성한 후 명령
terraform plan
을 실행하여 변경 사항을 검사하고 terraform apply
변경 사항을 검사하고 적용합니다.너도 데이터베이스의 상황을 물어볼 수 있다.이 프로젝트에서, 나는 MongoCloud에 그룹을 만들고, 증거를 환경에 두었다.
온전한 코드는 나의 [Github]에서 찾을 수 있다.( https://github.com/thnery/terraform-aws-template )
고마워요 고마워요
이 글을 읽어 주셔서 감사합니다.나는 그것이 쓸모가 있기를 바란다.만약 당신에게 어떤 피드백이 있다면 저에게 알려 주세요.
Reference
이 문제에 관하여(Terraform을 사용하여 AWS ECS 클러스터 만들기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/thnery/create-an-aws-ecs-cluster-using-terraform-g80텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)