✍ Posted by Immersive Builder Seong
1. 시작하기 전에
이전 포스팅에서 Terraform의 기본 개념과 간단한 사용법에 대해 알아보았다면,
▶ 포스팅 보러가기 : https://okms1017.tistory.com/56
오늘은 Terraform의 실전 활용 사례를 다루어볼 예정입니다.
바로 Terraform으로 EKS 서비스 배포하기입니다! (두둥탁)
사전에 미리 말씀드리면 Terraform은 인프라를 코드로 관리하기 위한 도구에 불과합니다.
이말인 즉슨 Amazon EKS 서비스에 대한 개념과 원리를 모른다면
아무리 Terraform을 잘 알아도 Amazon EKS 서비스를 배포하고 관리할 수 없다는 얘기입니다. (고로 복습하자!)
바로 시작해보겠습니다.
2. Terraform으로 EKS 배포하기
EKS 서비스 배포를 위한 Terraform 코드를 처음부터 작성하지 않고,
Terraform 공식 레지스트리에 게시되어 있는 Amazon EKS 모듈을 내려받아 활용할 예정입니다.
현재 최신 버전(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가 먼저 구성이 되고
이후에 EKS 배포가 시작됩니다.
쿠버네티스 버전은 v1.29 최신 버전으로 설치됩니다.
엔드포인트는 Public이며 add-on은 coredns, kube-proxy, vpc-cni 3개가 설치됩니다.(추가 가능)
또한, vpc-cni 옵션으로 prefix delegation, network policy 등 추가 설정이 가능합니다. (아래 스크린샷 참고)
노드 그룹을 배포할 때 인스턴스 타입과 오토스케일링 그룹(desired/min/max)을 구성합니다.
EKS 보안 구성(access entriy)으로 EKS API와 ConfigMap을 선택할 수 있습니다.
IRSA 사용 여부는 'true'이며, 서비스별 IRSA 설정은 irsa.tf 구성파일에 구체적으로 명시할 수 있습니다.
enable_irsa = true
약 10분 정도의 시간이 지나고 나서 배포가 완료됩니다.
CloudFormation이 20분 정도의 시간이 소요되는 것에 비하면
무려 두 배나 빠른 속도입니다.
# 배포된 리소스 목록 확인
$ 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
3) https://www.eksworkshop.com/docs/introduction/setup/your-account/using-terraform
'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 |