hoonii2

[terraform] EKS 배포 본문

개념 공부/(DevOps) 01. IaC

[terraform] EKS 배포

hoonii2 2024. 7. 3. 01:27

1. 개요

aws document 와 terraform aws provider 를 참고하여 EKS 를 배포하고 구성요소 이해를 목적으로 합니다.

이해와 학습이 목적이므로 terraform module 을 사용하지 않고 직접 리소스를 작성하여 구성합니다.

 

배포 목적 아키텍처는 다음과 같습니다.

- 각 subnet 의 태그는 EKS 에서 올바른 서브넷을 검색하기 위해 필수 요구사항입니다.
( 관련 문서 링크는 아래 6.subnets.tf 에 기재하였습니다. )

- 추후 Ingress 동작 및 private subnet 의 외부 통신을 위해 public subnet 을 구성했습니다.

 

2. locals.tf

# locals.tf

locals {
  env         = "dev"
  region      = "ap-northeast-2"
  zone1       = "ap-northeast-2a"
  zone2       = "ap-northeast-2b"
  eks_name    = "hoonDemo"
  eks_version = "1.30"
}

- env 를 통해 "dev", "staging", "production" 등의 환경을 명시합니다.

 

- 서로 다른 AZ 로 고가용성 EKS 환경을 배포합니다.

 

- EKS 내 k8s 버전은 최신 버전으로 명시했습니다.

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/kubernetes-versions.html#available-versions

 

Amazon EKS Kubernetes 버전 - Amazon EKS

컨트롤 플레인을 업데이트하는 경우 Fargate 노드를 직접 업데이트해야 합니다. Fargate 노드를 업데이트하려면 노드가 나타내는 Fargate Pod를 삭제하고 Pod를 다시 배포합니다. 새 Pod는 클러스터와 동

docs.aws.amazon.com

 

3. providers.tf

# providers.tf

provider "aws" {
  region = local.region
}

terraform {
  required_version = ">=1.9.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.56.1"
    }
  }
}

- terraform 최신 stable 버전을 사용했습니다.

https://github.com/hashicorp/terraform/releases

 

Releases · hashicorp/terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared ...

github.com

 

- terraform aws provider 최신 버전을 사용했습니다.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

 

Terraform Registry

 

registry.terraform.io

 

4. vpc.tf

# vpc.tf

resource "aws_vpc" "hoon_vpc" {
  cidr_block = "10.0.0.0/16"

  enable_dns_support   = true
  enable_dns_hostnames = true

  tags = {
    Name = "${local.env}-vpc"
  }
}

- "Name" 태그를 통해 aws 리소스의 이름을 명시할 수 있습니다.

https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/Using_Tags.html ( 태그 지정 리소스 목록 )

 

Amazon EC2 리소스 태깅 - Amazon Elastic Compute Cloud

리소스를 삭제한 후에도 해당 태그가 콘솔, API 및 CLI 출력에 잠시 동안 표시될 수 있습니다. 이러한 태그는 리소스에서 서서히 연결이 해제되고 영구적으로 삭제됩니다.

docs.aws.amazon.com

 

5. igw.tf

# igw.tf

resource "aws_internet_gateway" "hoon_igw" {
  vpc_id = aws_vpc.hoon_vpc.id

  tags = {
    Name = "${local.env}-igw"
  }
}

- 외부 인터넷 통신을 위한 igw 를 생성합니다.

 

6. subnets.tf

# subnets.tf

resource "aws_subnet" "private_subnet1" {
  vpc_id            = aws_vpc.hoon_vpc.id
  cidr_block        = cidrsubnet(aws_vpc.hoon_vpc.cidr_block, 3, 1)
  availability_zone = local.zone1

  tags = {
    "Name"                            = "${local.env}-private-${local.zone1}"
    "kubernetes.io/role/internal-elb" = "1"
  }
}

resource "aws_subnet" "private_subnet2" {
  vpc_id            = aws_vpc.hoon_vpc.id
  cidr_block        = cidrsubnet(aws_vpc.hoon_vpc.cidr_block, 3, 2)
  availability_zone = local.zone2

  tags = {
    "Name"                            = "${local.env}-private-${local.zone2}"
    "kubernetes.io/role/internal-elb" = "1"
  }
}

resource "aws_subnet" "public_subnet1" {
  vpc_id                  = aws_vpc.hoon_vpc.id
  cidr_block              = cidrsubnet(aws_vpc.hoon_vpc.cidr_block, 3, 3)
  availability_zone       = local.zone1
  map_public_ip_on_launch = true

  tags = {
    "Name"                   = "${local.env}-public-${local.zone1}"
    "kubernetes.io/role/elb" = "1"
  }
}

resource "aws_subnet" "public_subnet2" {
  vpc_id                  = aws_vpc.hoon_vpc.id
  cidr_block              = cidrsubnet(aws_vpc.hoon_vpc.cidr_block, 3, 4)
  availability_zone       = local.zone2
  map_public_ip_on_launch = true

  tags = {
    "Name"                   = "${local.env}-public-${local.zone2}"
    "kubernetes.io/role/elb" = "1"
  }
}

- 각 AZ 에 public / private subnet 을 생성합니다.

 

- EKS subnet 생성 시 private 은 "kubernetes.io/role/internal-elb" = "1", public 은 "kubernetes.io/role/elb" = "1" 를 필요로 합니다.

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/network-load-balancing.html

 

Amazon EKS의 네트워크 로드 밸런싱 - Amazon EKS

이전 버전과의 호환성을 위해 service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip" 주석이 여전히 지원됩니다. 그러나 service.beta.kubernetes.io/aws-load-balancer-type: "nlb-ip" 대신 새 로드 밸런서에 이전 주석을

docs.aws.amazon.com

 

- cidrsubnet 함수를 통해 자동으로 서브넷팅합니다.

https://developer.hashicorp.com/terraform/language/functions/cidrsubnet

 

cidrsubnet - Functions - Configuration Language | Terraform | HashiCorp Developer

The cidrsubnet function calculates a subnet address within a given IP network address prefix.

developer.hashicorp.com

 

7. nat.tf

# nat.tf

resource "aws_eip" "nat" {
  domain = "vpc"

  tags = {
    Name = "${local.env}-nat"
  }
}

resource "aws_nat_gateway" "nat" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public_subnet1.id

  tags = {
    Name = "${local.env}-nat"
  }

  depends_on = [aws_internet_gateway.hoon_igw]
}

- private subnet 의 외부 의존성 다운로드 등을 위한 외부 통신 용 nat gateway 를 생성합니다.

 

- nat gw 동작은 igw 에 의존하므로 igw 이후 생성하도록 depends_on 설정합니다. ( 테라폼 권장 사항 )

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway

 

Terraform Registry

 

registry.terraform.io

 

8. routes.tf

resource "aws_route_table" "hoon_private_rt" {
  vpc_id = aws_vpc.hoon_vpc.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat.id
  }

  tags = {
    Name = "${local.env}-hoon_private_rt"
  }
}

resource "aws_route_table" "hoon_public_rt" {
  vpc_id = aws_vpc.hoon_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.hoon_igw.id
  }

  tags = {
    Name = "${local.env}-hoon_public_rt"
  }
}

resource "aws_route_table_association" "private_subnet1" {
  subnet_id      = aws_subnet.private_subnet1.id
  route_table_id = aws_route_table.hoon_private_rt.id
}

resource "aws_route_table_association" "private_subnet2" {
  subnet_id      = aws_subnet.private_subnet2.id
  route_table_id = aws_route_table.hoon_private_rt.id
}

resource "aws_route_table_association" "public_subnet1" {
  subnet_id      = aws_subnet.public_subnet1.id
  route_table_id = aws_route_table.hoon_public_rt.id
}

resource "aws_route_table_association" "public_subnet2" {
  subnet_id      = aws_subnet.public_subnet2.id
  route_table_id = aws_route_table.hoon_public_rt.id
}

- public subnet 은 igw 를, private subnet 은 nat gw 로 외부 통신을 하도록 라우팅 테이블을 구성합니다.

 

- 이후 각 subnet 을 private / public 용도에 맞게 연결합니다.

 

9. eks.tf

# eks.tf

resource "aws_iam_role" "hoon_eks_role" {
  name = "${local.env}-${local.eks_name}-eks_cluster"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Alllow"
        Principal = {
          Service = "eks.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "hoon_eks_attach" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role       = aws_iam_role.hoon_eks_role.name
}

resource "aws_eks_cluster" "hoon_eks_cluster" {
  name     = "${local.env}-${local.eks_name}"
  version  = local.eks_version
  role_arn = aws_iam_role.hoon_eks_role.arn

  vpc_config {
    endpoint_private_access = false
    endpoint_public_access  = true

    subnet_ids = [
      aws_subnet.private_subnet1.id,
      aws_subnet.private_subnet2.id
    ]
  }

  access_config {
    authentication_mode                         = "API"
    bootstrap_cluster_creator_admin_permissions = true
  }

  depends_on = [aws_iam_role_policy_attachment.hoon_eks_attach]
}

- terraform aws provider 를 참고했습니다.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_cluster

 

Terraform Registry

 

registry.terraform.io

 

- aws 문서를 참고하여 eks cluster iam role 을 부여합니다.

( 혹은 최소 권한 원칙을 원하는 경우 아래 문서를 참고해 Custom Policy 를 만들어 사용할 수 있습니다 )

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/service_IAM_role.html

 

Amazon EKS 클러스터 IAM 역할 - Amazon EKS

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

- jsonencode 를 사용하여 iam role 을 선언합니다.

https://developer.hashicorp.com/terraform/language/functions/jsonencode

 

jsonencode - Functions - Configuration Language | Terraform | HashiCorp Developer

The jsonencode function encodes a given value as a JSON string.

developer.hashicorp.com

 

 

10. nodes.tf

# nodes.tf

resource "aws_iam_role" "hoon_nodes_role" {
  name = "${local.env}-${local.eks_name}-hoon_nodes"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      }
    ]
  })
}

resource "aws_iam_role_policy_attachment" "hoon_nodes_worker_attach" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
  role       = aws_iam_role.hoon_nodes_role.name
}

resource "aws_iam_role_policy_attachment" "hoon_nodes_cni_attach" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role       = aws_iam_role.hoon_nodes_role.name
}

resource "aws_iam_role_policy_attachment" "hoon_nodes_ecr_attach" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role       = aws_iam_role.hoon_nodes_role.name
}

resource "aws_eks_node_group" "hoon_node_group" {
  cluster_name    = aws_eks_cluster.hoon_eks_cluster.name
  version         = local.eks_version
  node_group_name = "hoon_node_group"
  node_role_arn   = aws_iam_role.hoon_nodes_role.arn

  subnet_ids = [
    aws_subnet.private_subnet1.id,
    aws_subnet.private_subnet2.id
  ]

  capacity_type  = "ON_DEMAND"
  instance_types = ["t3.large"]

  scaling_config {
    desired_size = 1
    max_size     = 10
    min_size     = 0
  }

  update_config {
    max_unavailable = 1
  }

  labels = {
    role = "hoon_node_group"
  }

  depends_on = [
    aws_iam_role_policy_attachment.hoon_nodes_cni_attach,
    aws_iam_role_policy_attachment.hoon_nodes_ecr_attach,
    aws_iam_role_policy_attachment.hoon_nodes_worker_attach
  ]

  lifecycle {
    ignore_changes = [scaling_config[0].desired_size]
  }
}

- terraform aws provider 를 참고했습니다.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group

 

Terraform Registry

 

registry.terraform.io

 

- aws 문서를 참고하여 node iam role 을 부여합니다.

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/create-node-role.html

 

Amazon EKS 노드 IAM 역할 - Amazon EKS

이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.

docs.aws.amazon.com

 

- EKS 3가지 노드 타입 중 관리형 노드그룹을 사용합니다.

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/create-managed-node-group.html

 

관리형 노드 그룹 생성 - Amazon EKS

관리형 노드 그룹을 처음 생성할 때 사용자 정의 시작 템플릿을 사용하지 않는 경우 나중에 노드 그룹에 대해 시작 템플릿을 사용하지 마세요. 사용자 정의 시작 템플릿을 지정하지 않은 경우

docs.aws.amazon.com

 

- 온디맨드 인스턴스로 서비스 중단을 방지하고 auto-scaling 을 구성합니다.

 

- ignore-change 를 통해 auto-scaling 시 terraform 의 desire 값이 mismatch 충돌되는 것을 방지합니다.

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eks_node_group#ignoring-changes-to-desired-size

 

Terraform Registry

 

registry.terraform.io

 

11. 확인 및 배포

terraform init > plan > apply 를 통해 상태를 확인하고 배포합니다.

 

'개념 공부 > (DevOps) 01. IaC' 카테고리의 다른 글

[terraform] EC2 EBS 증설  (0) 2024.06.27
[terraform] EC2 최신 AMI ID 연결  (0) 2024.06.26
Comments