본문 바로가기
AWS/EKS

[AEWS2] 8-2. Terraform으로 EKS 배포하기

by okms1017 2024. 4. 28.
728x90

✍ Posted by Immersive Builder  Seong

 

 

1. 시작하기 전에

 

이전 포스팅에서 Terraform의 기본 개념과 간단한 사용법에 대해 알아보았다면,

 

▶ 포스팅 보러가기 : https://okms1017.tistory.com/56

 

[AEWS2] 8-1. What is Terraform ?

✍ Posted by Immersive Builder  Seong  1. Terraform 기본 개념  Terraform 이란?HashiCorp에서 공개한 인프라스트럭처를 코드로 프로비저닝하고 관리할 수 있는 오픈소스 도구입니다.  HCL(HashiCorp Configuration

okms1017.tistory.com

 

오늘은 Terraform의 실전 활용 사례를 다루어볼 예정입니다. 

 

바로 Terraform으로 EKS 서비스 배포하기입니다! (두둥탁) 

 

사전에 미리 말씀드리면 Terraform은 인프라를 코드로 관리하기 위한 도구에 불과합니다. 

 

이말인 즉슨 Amazon EKS 서비스에 대한 개념과 원리를 모른다면

아무리 Terraform을 잘 알아도 Amazon EKS 서비스를 배포하고 관리할 수 없다는 얘기입니다. (고로 복습하자!)

 

바로 시작해보겠습니다. 

 


2. Terraform으로 EKS 배포하기 

 

EKS 서비스 배포를 위한 Terraform 코드를 처음부터 작성하지 않고,

Terraform 공식 레지스트리에 게시되어 있는 Amazon EKS 모듈을 내려받아 활용할 예정입니다. 

 

EKS 모듈 다운로드 

Terraform Registry- EKS Module

현재 최신 버전(v20.8.5)에서는 벌써 Pod Identity 기능을 지원한다고 합니다. (24.04.28 기준)

 

EKS 배포 

EKS 모듈을 내려받습니다. 그리고 Terraform 환경 변수로 키 페어를 설정해줍니다. 

 

$ export TF_VAR_KeyName='okms1017'
$ echo $TF_VAR_KeyName

okms1017

 

순차적으로 init - plan - apply하여 EKS를 배포합니다. 

 

$ cd aews-cicd/4

$ terraform init 

$ terraform plan

$ terraform apply -auto-apporve

 

VPC가 먼저 구성이 되고 

 

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~>5.7"

 

이후에 EKS 배포가 시작됩니다. 

 

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~>20.0"

 

쿠버네티스 버전은 v1.29 최신 버전으로 설치됩니다.  

 

variable "KubernetesVersion" {
  description = "Kubernetes version for the EKS cluster."
  type        = string
  default     = "1.29"
}

 

엔드포인트는 Public이며 add-on은 coredns, kube-proxy, vpc-cni 3개가 설치됩니다.(추가 가능) 

 

  cluster_endpoint_private_access = false
  cluster_endpoint_public_access  = true

  cluster_addons = {
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }

 

또한, vpc-cni 옵션으로 prefix delegation, network policy 등 추가 설정이 가능합니다. (아래 스크린샷 참고)

 

 

노드 그룹을 배포할 때 인스턴스 타입과 오토스케일링 그룹(desired/min/max)을 구성합니다. 

 

  eks_managed_node_groups = {
    default = {
      name             = "${var.ClusterBaseName}-node-group"
      use_name_prefix  = false
      instance_type    = var.WorkerNodeInstanceType
      desired_size     = var.WorkerNodeCount
      max_size         = var.WorkerNodeCount + 2
      min_size         = var.WorkerNodeCount - 1
      disk_size        = var.WorkerNodeVolumesize
      subnets          = module.vpc.public_subnets
      key_name         = var.KeyName
      vpc_security_group_ids = [aws_security_group.node_group_sg.id]
      iam_role_name    = "${var.ClusterBaseName}-node-group-eks-node-group"
      iam_role_use_name_prefix = false
      iam_role_additional_policies = {
        "${var.ClusterBaseName}ExternalDNSPolicy" = aws_iam_policy.external_dns_policy.arn
      }
   }

 

EKS 보안 구성(access entriy)으로 EKS API와 ConfigMap을 선택할 수 있습니다.  

 

  access_entries = {
    admin = {
      kubernetes_groups = []
      principal_arn     = "${data.aws_caller_identity.current.arn}"

      policy_associations = {
        myeks = {
          policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            namespaces = []
            type       = "cluster"
          }
        }
      }
    }
  }

 

IRSA 사용 여부는 'true'이며, 서비스별 IRSA 설정은 irsa.tf 구성파일에 구체적으로 명시할 수 있습니다. 

 

enable_irsa = true

 

약 10분 정도의 시간이 지나고 나서 배포가 완료됩니다. 

 

CloudFormation이 20분 정도의 시간이 소요되는 것에 비하면

무려 두 배나 빠른 속도입니다. 

 

EKS 배포 완료
EKS 클러스터 배포 확인

 

# 배포된 리소스 목록 확인 
$ terraform state list
data.aws_caller_identity.current
data.aws_eks_cluster.cluster
data.aws_eks_cluster_auth.cluster
aws_iam_policy.external_dns_policy
aws_iam_role_policy_attachment.external_dns_policy_attach
aws_security_group.node_group_sg
kubernetes_service_account.aws_lb_controller
module.aws_load_balancer_controller_irsa_role.data.aws_caller_identity.current
module.aws_load_balancer_controller_irsa_role.data.aws_iam_policy_document.load_balancer_controller[0]
module.aws_load_balancer_controller_irsa_role.data.aws_iam_policy_document.this[0]
module.aws_load_balancer_controller_irsa_role.data.aws_partition.current
module.aws_load_balancer_controller_irsa_role.aws_iam_policy.load_balancer_controller[0]
module.aws_load_balancer_controller_irsa_role.aws_iam_role.this[0]
module.aws_load_balancer_controller_irsa_role.aws_iam_role_policy_attachment.load_balancer_controller[0]
module.eks.data.aws_caller_identity.current
module.eks.data.aws_eks_addon_version.this["coredns"]
module.eks.data.aws_eks_addon_version.this["kube-proxy"]
module.eks.data.aws_eks_addon_version.this["vpc-cni"]
module.eks.data.aws_iam_policy_document.assume_role_policy[0]
module.eks.data.aws_iam_session_context.current
module.eks.data.aws_partition.current
module.eks.data.tls_certificate.this[0]
module.eks.aws_cloudwatch_log_group.this[0]
module.eks.aws_ec2_tag.cluster_primary_security_group["Environment"]
module.eks.aws_ec2_tag.cluster_primary_security_group["Terraform"]
module.eks.aws_eks_access_entry.this["admin"]
module.eks.aws_eks_access_policy_association.this["admin_myeks"]
module.eks.aws_eks_addon.this["coredns"]
module.eks.aws_eks_addon.this["kube-proxy"]
module.eks.aws_eks_addon.this["vpc-cni"]
module.eks.aws_eks_cluster.this[0]
module.eks.aws_iam_openid_connect_provider.oidc_provider[0]
module.eks.aws_iam_policy.cluster_encryption[0]
module.eks.aws_iam_role.this[0]
module.eks.aws_iam_role_policy_attachment.cluster_encryption[0]
module.eks.aws_iam_role_policy_attachment.this["AmazonEKSClusterPolicy"]
module.eks.aws_iam_role_policy_attachment.this["AmazonEKSVPCResourceController"]
module.eks.aws_security_group.cluster[0]
module.eks.aws_security_group.node[0]
module.eks.aws_security_group_rule.cluster["ingress_nodes_443"]
module.eks.aws_security_group_rule.node["egress_all"]
module.eks.aws_security_group_rule.node["ingress_cluster_443"]
module.eks.aws_security_group_rule.node["ingress_cluster_4443_webhook"]
module.eks.aws_security_group_rule.node["ingress_cluster_6443_webhook"]
module.eks.aws_security_group_rule.node["ingress_cluster_8443_webhook"]
module.eks.aws_security_group_rule.node["ingress_cluster_9443_webhook"]
module.eks.aws_security_group_rule.node["ingress_cluster_kubelet"]
module.eks.aws_security_group_rule.node["ingress_nodes_ephemeral"]
module.eks.aws_security_group_rule.node["ingress_self_coredns_tcp"]
module.eks.aws_security_group_rule.node["ingress_self_coredns_udp"]
module.eks.time_sleep.this[0]
module.eks-external-dns.data.aws_region.current
module.vpc.aws_default_network_acl.this[0]
module.vpc.aws_default_route_table.default[0]
module.vpc.aws_default_security_group.this[0]
module.vpc.aws_eip.nat[0]
module.vpc.aws_internet_gateway.this[0]
module.vpc.aws_nat_gateway.this[0]
module.vpc.aws_route.private_nat_gateway[0]
module.vpc.aws_route.public_internet_gateway[0]
module.vpc.aws_route_table.private[0]
module.vpc.aws_route_table.public[0]
module.vpc.aws_route_table_association.private[0]
module.vpc.aws_route_table_association.private[1]
module.vpc.aws_route_table_association.private[2]
module.vpc.aws_route_table_association.public[0]
module.vpc.aws_route_table_association.public[1]
module.vpc.aws_route_table_association.public[2]
module.vpc.aws_subnet.private[0]
module.vpc.aws_subnet.private[1]
module.vpc.aws_subnet.private[2]
module.vpc.aws_subnet.public[0]
module.vpc.aws_subnet.public[1]
module.vpc.aws_subnet.public[2]
module.vpc.aws_vpc.this[0]
module.eks.module.eks_managed_node_group["default"].data.aws_caller_identity.current
module.eks.module.eks_managed_node_group["default"].data.aws_iam_policy_document.assume_role_policy[0]
module.eks.module.eks_managed_node_group["default"].data.aws_partition.current
module.eks.module.eks_managed_node_group["default"].aws_eks_node_group.this[0]
module.eks.module.eks_managed_node_group["default"].aws_iam_role.this[0]
module.eks.module.eks_managed_node_group["default"].aws_iam_role_policy_attachment.additional["myeksExternalDNSPolicy"]
module.eks.module.eks_managed_node_group["default"].aws_iam_role_policy_attachment.this["AmazonEC2ContainerRegistryReadOnly"]
module.eks.module.eks_managed_node_group["default"].aws_iam_role_policy_attachment.this["AmazonEKSWorkerNodePolicy"]
module.eks.module.eks_managed_node_group["default"].aws_iam_role_policy_attachment.this["AmazonEKS_CNI_Policy"]
module.eks.module.eks_managed_node_group["default"].aws_launch_template.this[0]
module.eks.module.kms.data.aws_caller_identity.current[0]
module.eks.module.kms.data.aws_iam_policy_document.this[0]
module.eks.module.kms.data.aws_partition.current[0]
module.eks.module.kms.aws_kms_alias.this["cluster"]
module.eks.module.kms.aws_kms_key.this[0]
module.eks.module.eks_managed_node_group["default"].module.user_data.null_resource.validate_cluster_service_cidr

 

배포한 정보를 확인하기 위해 노드 정보를 조회해봅니다. 

뭔가 에러가 나고 있네요. 

 

$ kubectl get node -v=6

I0428 04:59:06.606880   26217 helpers.go:264] Connection error: Get http://localhost:8080/api?timeout=32s: dial tcp 127.0.0.1:8080: connect: connection refused

 

kube config를 업데이트하여 자격증명을 진행해보겠습니다. 

 

$ CLUSTER_NAME=myeks
$ aws eks update-kubeconfig --region ap-northeast-2 --name $CLUSTER_NAME

 

다시 노드 정보를 조회해보니 확인이 되는 모습입니다. 

 

$ kubectl get node -v=6

NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-1-49.ap-northeast-2.compute.internal    Ready    <none>   34m   v1.29.0-eks-5e0fdde
ip-192-168-2-247.ap-northeast-2.compute.internal   Ready    <none>   34m   v1.29.0-eks-5e0fdde
ip-192-168-3-190.ap-northeast-2.compute.internal   Ready    <none>   34m   v1.29.0-eks-5e0fdde

 

파드 정보도 조회가 잘 되고 있네요. 

 

$ kubectl get pod -A
NAMESPACE     NAME                      READY   STATUS    RESTARTS   AGE
kube-system   aws-node-49k4c            2/2     Running   0          34m
kube-system   aws-node-6ksj7            2/2     Running   0          35m
kube-system   aws-node-p5rmd            2/2     Running   0          34m
kube-system   coredns-6bddb7676-q7r8r   1/1     Running   0          35m
kube-system   coredns-6bddb7676-x4x9g   1/1     Running   0          35m
kube-system   kube-proxy-lj2lc          1/1     Running   0          35m
kube-system   kube-proxy-vwbmq          1/1     Running   0          35m
kube-system   kube-proxy-xwcsh          1/1     Running   0          35m

 

EKS 모듈 재사용 검증

그럼 이번에는 EKS 모듈에 입력 변수만 달리하여 신규 클러스터를 배포해보겠습니다. 

 

$ cp aews-cicd/4/*.tf aews-cicd/5/

$ cd aews-cicd/5/

 

$ terraform init
$ terraform apply -auto-approve -var=ClusterBaseName=myeks2 -var=KubernetesVersion="1.28"

 

쿠버네티스 v1.28 버전의 신규 클러스터(myeks2)가 정상적으로 배포되고 있습니다.  

 

신규 클러스터 배포 확인

 

배포가 완료되면 동일하게 자격증명을 업데이트한 후

노드와 파드의 정보를 조회해봅니다. 

 

$ CLUSTER_NAME2=myeks2
$ aws eks update-kubeconfig --region ap-northeast-2 --name $CLUSTER_NAME2 --kubeconfig ./myeks2config

Added new context arn:aws:eks:ap-northeast-2:732659419746:cluster/myeks2 to /home/okms1017/aews-cicd/5/myeks2config

 

$ kubectl --kubeconfig ./myeks2config get node

NAME                                               STATUS   ROLES    AGE     VERSION
ip-192-168-1-75.ap-northeast-2.compute.internal    Ready    <none>   5m22s   v1.28.5-eks-5e0fdde
ip-192-168-2-168.ap-northeast-2.compute.internal   Ready    <none>   5m26s   v1.28.5-eks-5e0fdde
ip-192-168-3-155.ap-northeast-2.compute.internal   Ready    <none>   5m24s   v1.28.5-eks-5e0fdde

$ kubectl --kubeconfig ./myeks2config get pod -A

NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE
kube-system   aws-node-7xh66             2/2     Running   0          4m55s
kube-system   aws-node-jznth             2/2     Running   0          4m45s
kube-system   aws-node-v8lkz             2/2     Running   0          4m37s
kube-system   coredns-55474bf7b9-lhhhw   1/1     Running   0          4m53s
kube-system   coredns-55474bf7b9-rn6jb   1/1     Running   0          4m54s
kube-system   kube-proxy-958fb           1/1     Running   0          4m55s
kube-system   kube-proxy-d62xp           1/1     Running   0          4m53s
kube-system   kube-proxy-p4sfs           1/1     Running   0          4m49s

 

EKS 삭제 

 

실습을 마치고 각 디렉토리에 진입하여 리소스를 삭제합니다. 

혹시 중간에 수동으로 배포한 리소스가 있다면 삭제가 진행이 안될 수 있는 점 주의하시기 바랍니다. 

 

$ terraform destroy -auto-approve

$ terraform destroy -auto-approve -var=ClusterBaseName=myeks2 -var=KubernetesVersion="1.28"

 

 


[출처] 

1) CloudNet@, AEWS 실습 스터디 

2) https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/20.8.5

 

Terraform Registry

 

registry.terraform.io

3) https://www.eksworkshop.com/docs/introduction/setup/your-account/using-terraform

 

Using Terraform | EKS Workshop

Creating the workshop cluster with Terraform is currently in preview. Please raise any issues encountered in the GitHub repository.

www.eksworkshop.com

 

 

728x90

'AWS > EKS' 카테고리의 다른 글

AEWS2 스터디 완주 후기 🎉  (2) 2024.05.07
[AEWS2] 8-1. What is Terraform ?  (2) 2024.04.28
[AEWS2] 7-2. EKS CI/CD - ArgoCD  (0) 2024.04.21
[AEWS2] 7-1. EKS CI/CD - Jenkins  (2) 2024.04.21
[AEWS2] 6-5. Kyverno  (0) 2024.04.13