상세 컨텐츠

본문 제목

테라폼으로 eks 구축하기

Iac

by drogva 2024. 3. 31. 23:24

본문

목표 : eks 의 로드밸런서 콘트롤러와 ebs-csi addon 까지 자동화 구축하기

 

- root module - terraform registry 의 리소스를 참조하여 구성

provider.tf  
# Configure the AWS Provider
provider "aws" {
  region = "ap-northeast-2"
  alias  = "ap-northeast-2"
  profile = var.profile
}

provider "kubernetes" {
  host                   = module.eks.cluster_endpoint
  cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
  exec {
    api_version = "client.authentication.k8s.io/v1beta1"
    command     = "aws"
    # This requires the awscli to be installed locally where Terraform is executed
    args = ["eks", "get-token", "--cluster-name", module.eks.cluster_name]
  }
}

provider "helm" {
  kubernetes {
    host                   = module.eks.cluster_endpoint
    cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
    exec {
      api_version = "client.authentication.k8s.io/v1beta1"
      args        = ["eks", "get-token", "--cluster-name", var.cluster_name]
      command     = "aws"
    }
  }
}

 

- 출저 : https://github.com/terraform-aws-modules/terraform-aws-eks/issues/2009

 

프로바이더는 Terraform 코드 내에서 리소스를 생성하고 관리하기 위해 필요한 연결 및 설정 정보이다. 

command = "aws"는 Helm 및 Kubernetes 프로바이더가 AWS CLI를 사용하여 Kubernetes 클러스터와 상호작용하기에 필요한 것으로 자격증명과정이다. 이것이 왜 필요하나면 eks 내부에 aws load balancer 설치와 역할이 연결되어야 하기 때문에 필요하다.

 

vpc.tf - 처음 테라폼이 실행되면서 생성된 vpc 의 사이더, 서브넷을 지정해준다. 리소스를 사용하면 라우팅 테이블 구성은 알아서 생성된다.

 

 module "vpc" {
  source = "terraform-aws-modules/vpc/aws"

   providers = {
    aws = aws.ap-northeast-2
   }

  name = var.cluster_name
  cidr = "10.194.0.0/16"

  azs             = ["ap-northeast-2a", "ap-northeast-2c"]
  public_subnets  = ["10.194.0.0/24", "10.194.1.0/24"]
  private_subnets = ["10.194.100.0/24", "10.194.101.0/24"]

  enable_nat_gateway     = true

  enable_dns_hostnames = true

  public_subnet_tags = {
    "kubernetes.io/cluster/simon-test" = "owned"  # 클러스터 이름 통일
    "kubernetes.io/role/elb"           = "1"
  }

  private_subnet_tags = {
    "kubernetes.io/cluster/simon-test"     = "owned"  # 클러스터 이름 통일
    "kubernetes.io/role/internal-elb"      = "1"
  }

}

각 서브넷의 태그는 매우 중요하다. aws-load-balancer 컨트롤러가 설치되면 vpc 에 접근하여 서브넷에  대한 권한을 얻게 되는데 특히 ingress 를 생성시에는 퍼블릿 서브넷을 부여하는 vpc-cni 역할을 한다. 즉 vpc 에 있는 서브넷을 분배 하는 역할 을 하게 되는데 이 서브넷에 대한 태그를 통하여 외부로 노출할 로드밸런서를 생성할 수 있다. 클러스터가 소유하게 될 서브넷에 대한 태그를 모두 지정해야 로드밸런서 콘트롤러가 애먹지 않는다.  클러스터는 당연히 vpc 에 대한 역할을 소유하고 있다.

 

eks.tf

 

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

  cluster_endpoint_public_access  = true
  cluster_enabled_log_types       = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
  cluster_name                    = "simon-test"
  cluster_version                 = "1.29"
  vpc_id                          = module.vpc.vpc_id
  subnet_ids                      = module.vpc.private_subnets
  control_plane_subnet_ids        = module.vpc.private_subnets

  providers = {
    aws = aws.ap-northeast-2
  }

  eks_managed_node_group_defaults = {
    ami_type = "AL2_x86_64"
  }

  eks_managed_node_groups = {
    one = {
      name          = "node-group-1"
      instance_types = ["t3.small"]
      min_size      = 1
      max_size      = 3
      desired_size  = 2
    }
    two = {
      name          = "node-group-2"
      instance_types = ["t3.small"]
      min_size      = 1
      max_size      = 2
      desired_size  = 1
    }
  }

  enable_cluster_creator_admin_permissions = true

  cluster_addons = {
    coredns = {
      preserve    = true
      most_recent = true
      timeouts = {
        create = "25m"
        delete = "10m"
      }
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
    
  }
}

 

vpc_id                          = module.vpc.vpc_id                           

subnet_ids                      = module.vpc.private_subnets
  control_plane_subnet_ids        = module.vpc.private_subnets       ---> vpc.tf 의 모듈에 eks 를 구축한다는 뜻이다.                                                                                                                                    module.vpc 는        vpc를 뜻한다

 

 

 

variables.tf

variable "profile" {
  type    = string
  default = "default"
}

variable "main-region" {
  type    = string
  default = "ap-northeast-2"
}


variable "cluster_name" {
  type    = string
  default = "simon-test"
}

variable "rolearn" {
  description = "Add admin role to the aws-auth configmap"
}

variable "CREDENTIAL_FILES" {
  description = "This is a path of credentials file"
  default = "/.aws/credentials"
}

각 모듈에 참조할 변수이다.

 

alb.tf
module "aws_load_balancer_controller_irsa_role" {
  source    = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
  role_name = "aws-load-balancer-controller"
  attach_load_balancer_controller_policy = true

  oidc_providers = {
    main = {
      provider_arn               = module.eks.oidc_provider_arn
      namespace_service_accounts = ["kube-system:aws-load-balancer-controller"]
    }
  }
}

 

main.tf 에서 eks 가 생성되면 oidc 는 자동 발급된다. 로드밸런서컨트롤러 같은 경우는 aws 에서 서비스 해 주지 않아 꾸버네티스가 aws 에 들어와 RBAC 형태로 서비스해준다. 따라서 AWS 에서는 OIDC 라는 웹자격증명을 통해 로드밸런서 컨트롤러에 대한 역할에 기반한 제어권만을 부여해 주게 된다.  

https://registry.terraform.io/modules/terraform-aws-modules/iam/aws/latest/submodules/iam-role-for-service-accounts-eks   --출저

-I-AM-ASSUMABLE-OIDC 로 생성해 봤는데

유효한 ARN 을 사용해서 형식에 맞는 정책과 역할에 대한 신뢰관계가 작성되야 한다고 하는 거 같다. 
공식문서에 따라서 IRSA 리소스에 맞는 모듈을 사용하면 된다.

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/aws-load-balancer-controller.html- 출저

cat >load-balancer-role-trust-policy.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
            },
            "Action": "sts:AssumeRoleWithWebIdentity",
            "Condition": {
                "StringEquals": {
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
                    "oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
                }
            }
        }
    ]
}
EOF

IRSA 정책과 역할의 신뢰관계 예시

 

 

-생성한 역할을 기반으로 이제 KUBE-SYSTEM 에 꾸버네띠스 SA 를 생성해 준다.

resource "kubernetes_service_account" "aws_load_balancer_controller" {
  metadata {
    name      = "aws-load-balancer-controller"
    namespace = "kube-system"

    labels = {
      "app.kubernetes.io/name"      = "aws-load-balancer-controller"
      "app.kubernetes.io/component" = "controller"
    }
    annotations = {
      "eks.amazonaws.com/role-arn" = module.aws_load_balancer_controller_irsa_role.iam_role_arn
      "eks.amazonaws.com/sts-regional-endpoints" = "true"
    }
  }
  depends_on = [module.eks]
}

중요한 것은 여기 주석이다. 

 "eks.amazonaws.com/role-arn" = module.aws_load_balancer_controller_irsa_role.iam_role_arn


https://github.com/kubernetes-sigs/aws-load-balancer-controller/issues/1138 - 출저
꾸버네티스에 irsa 를 통해 생성된 역할을 부여해줘야 콘트롤러를 실행할 수 있는 권한을 갖는다. 위에서 생성한 모듈의 i am role arn 을 뜻한다. 이 arn 을 통해 자격증명을 얻고 일을 하게 된다.

 


그 다음은 helm 으로 설치하는 것인데 선수 조건 꾸버네티스 계정이 생성되고 난 이후이다. - helm 최신 버전이 깔렷는데 정책은 구버전 그대로면 애러가 난다. irsa 모듈을 참조해 롤과 정책을 부착하는 것이 가용성이 좋다고 본다.

resource "helm_release" "lb_controller" {
  name       = "aws-load-balancer-controller"
  repository = "https://aws.github.io/eks-charts"
  chart      = "aws-load-balancer-controller"
  namespace  = "kube-system"

  depends_on = [
    kubernetes_service_account.aws_load_balancer_controller
  ]

  set {
    name  = "clusterName"
    value = var.cluster_name
  }

  set {
    name  = "serviceAccount.create"
    value = "false"
  }

  set {
    name  = "serviceAccount.name"
    value = kubernetes_service_account.aws_load_balancer_controller.metadata[0].name
  }

  set {
    name  = "region"
    value = var.main-region
  }

  set {
  name  = "vpcId"
  value = module.vpc.vpc_id
}
}

 

 

 

관련글 더보기