본문 바로가기

DevOps/Terraform

(15) 테라폼 모듈 (3) VPC & EKS

cloudNet@ 팀의 가시다 님이 진행하는 테라폼 102 스터디 4주차 정리입니다.

1. vpc 모듈 실습 

  • 모듈을 통해 코드 재사용성을 확보할수 있다
  • 모듈은 테라폼 구성의 집합 
  • 로컬 디렉토리의 테라폼 구성을 모듈화 할수도 있지만 다음과 같이 github 같은 퍼블릭 레포지토리도 모듈화 가능하다.

✔️ 실습 1. (vpc )

#
git clone https://github.com/terraform-aws-modules/terraform-aws-vpc/
tree terraform-aws-vpc/examples -L 1
tree terraform-aws-vpc/examples -L 2
cd terraform-aws-vpc/examples/simple
ls *.tf
cat main.tf
✅ 코드를 사용자 환경에 맞게 수정합니다.
# 서울 리전 변경
grep 'eu-west-1' main.tf
sed -i -e 's/eu-west-1/ap-northeast-2/g' main.tf

# VPC CIDR 변경
grep '10.0.0.0' main.tf
sed -i -e 's/10.0.0.0/10.10.0.0/g' main.tf

# main.tf 파일 내용 확인
cat main.tf
...
module "vpc" {
  source = "../../"

  name = local.name
  cidr = local.vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]

  tags = local.tags
}

# 모듈 확인
tree ../../modules
# ✅ 테라폼 실행 및 결과 확인
terraform init
cat .terraform/modules/modules.json| jq

# 생성된 리소스들 확인해보자!
terraform apply -auto-approve
terraform output
terraform state list

# 실습 완료 후 리소스 삭제
terraform destroy -auto-approve
  • 잘 생성되는것을 확인 할수 있다.

2. EKS 모듈 실습 

 

✔️ 실습 2. ( eks 모듈 )

  • 먼저 Terraform registry에서 eks module을 검색합니다.

source code 부분에 git repository를 들어갑니다.
초록색 버튼을 눌러서 Code Clone 부분을 복사합니다.

# ✅ aws-eks 모듈 다운로드 
git clone https://github.com/terraform-aws-modules/terraform-aws-eks.git
# ✅ example 모듈 확인
cd terraform-aws-eks/examples/complete/


# ✅ 테라폼 실행 / 확인
terraform init && terraform plan && terraform apply -auto-approve

3. EKS 모듈  뜯어보기

 

 

사실 500줄이나 되서 전체를 다 뜯어보진 못하겠고, 궁금한거 위주로 뜯어보겠다.

 

✔️ 프로바이더 

  • aws 프로바이더
  • kubernetes 프로바이더
provider "aws" {
  region = local.region
}

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]
  }
}

 

 

✔️ 데이터 블록

  • 데이터 블록은 aws의 리소스를 조회해서 가져오는데 사용된다.
  • state 파일을 조회하면 eu-west-1에 대한 AZ들이 조회되는데, 아래 local 변수에서 기록한 region명에 의해 state 값이 결정되는것 같다

✔️ 로컬 변수

data "aws_availability_zones" "available" {}
data "aws_caller_identity" "current" {}

locals {
  name   = "ex-${replace(basename(path.cwd), "_", "-")}"
  region = "eu-west-1"

  vpc_cidr = "10.0.0.0/16"
  azs      = slice(data.aws_availability_zones.available.names, 0, 3)

  tags = {
    Example    = local.name
    GithubRepo = "terraform-aws-eks"
    GithubOrg  = "terraform-aws-modules"
  }
}

 

✔️ EKS 모듈

  • 모듈은 최상위 디렉토리에 존재하기 때문에 ../ ..
  • cluster_name은 local 변수에서 입력값을 받는다. 
    • local 변수는 위에 있었다. replace 함수를 통해 현재 디렉토리 path를 활용하여 ex-complete 라는 클러스터 네임을 가진다.
    • cluster의 endpoint는 public access를 허용한다.
    • cluster_addons은 추가기능 ( Coredns, kube-proxy, vpc-cni ) 3가지를 enabled 시킨다.

module "eks" {
  source = "../.."

  cluster_name                   = local.name
  cluster_endpoint_public_access = true

  cluster_addons = {
    coredns = {
      preserve    = true
      most_recent = true

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

 

✔️ KMS  ( 키 매니지먼트 서비스 )

  • KMS_KEY
    • 데이터를 보호하는 암호화 키를 안전하게 관리하는데 목적을 둔 서비스
    • AWS 관리형 키 :  AWS managed key 는 AWS 서비스들이 KMS 를 통해 Key를 서비스 받는 것으로, 내부적으로 자동으로 일어나게 되며 사용자가 직접적으로 제어가 불가능하다.
    • 고객 관리형 키 : Customer managed key (CMK) 는 사용자가 직접 key를 생성하고 관리하는 것으로 해당 포스팅에서 주로 다룰 방식이 바로 CMK 이다. CMK 에 대한 제어는 IAM 을 통해 권한을 부여 받아 제어가 가능하다.
  • KMS_동작방식
    • KMS에서 고객 관리형 키를 생성한다. 이 마스터 키는 데이터를 암호화 하기 위해 사용되는 Data Key를 생성하는 데 사용
    • Data key는 CMK 로부터 GenerateDataKey 라는 작업을 통해 생성되는데, 이때 생성되는 Data key 는 크게 두가지 종류로 Plaintext data key 와 Encrypted data key 가 있다.
    • Plain 데이터 키는 데이터를 암호화 하는데 사용
    • Encrypted data key는 데이터를 복호화 하는데 사용

bluese05.tistory.com 에서 퍼왔습니다

module "kms" {
  source  = "terraform-aws-modules/kms/aws"
  version = "~> 1.5"

  aliases               = ["eks/${local.name}"]
  description           = "${local.name} cluster encryption key"
  enable_default_policy = true
  key_owners            = [data.aws_caller_identity.current.arn]

  tags = local.tags
}

 

✔️ VPC 와 서브넷  

  • module "vpc" 
  • azs 는 총 3개 (a,b,c)
  • for k, v in local.azs (각 az 마다public,intra 서브넷을 24 비트로 생성 / private은 20 비트로 생성 )
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 4.0"

  name = local.name
  cidr = local.vpc_cidr

  azs             = local.azs
  private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)]
  public_subnets  = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)]
  intra_subnets   = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)]

  enable_nat_gateway = true
  single_nat_gateway = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }

  tags = local.tags
}
# ✅ vpc, private_subnet, intra_subnet
 
  vpc_id                   = module.vpc.vpc_id
  subnet_ids               = module.vpc.private_subnets
  control_plane_subnet_ids = module.vpc.intra_subnets

이렇게 많이 만들어질 필요가 있을까 싶기도 하다 ㅋㅋ

✔️ EKS Managed Node Groups

  • 모든 관리형 노드는 Amazon EKS에서 관리하는 Amazon EC2 Auto Scaling 그룹의 일부로 프로비저닝됩니다.
  • 원래 쿠버네티스 처럼 워커노드를 배포하고 조인 시키는 형태처럼 번거로운 작업을 안해도 된다. 노드 업데이트 및 종료는 자동으로 노드를 드레이닝 이게 가장 큰 장점이다.
  • 다만 AMI 유형과 용량 유형 쯤 선택해주면 된다. 근데 일괄 적용된다는게 또 좀 단점이다.
  • Bottlerocket은 Linux 기반 오픈 소스 운영 체제로, AWS에서 가상 머신 또는 베어 메탈 호스트에서 컨테이너를 실행하기 위해 특별히 개발했습니다. 안전하며 컨테이너를 실행하는 데 필요한 최소한의 패키지만 포함합니다. 이는 취약성의 공격 표면과 영향을 줄입니다. 

✔️ Self Managed Node Groups

  • EKS의 "Node"는 쿠버네티스 Pod 를 스케줄링할 수 있는 Amazon EC2 인스턴스입니다. Pod 는 EKS 클러스터의 API 엔드포인트에 연결됩니다. Node 는 Node Group 으로 구성됩니다. Node Group 에 있는 모든 EC2 인스턴스는 동일해야 합니다
  • Kubernetes 데이터 플레인 노드를 완벽하게 제어할 수 있으며 노드 그룹 내에서 실행할 EC2 인스턴스 유형을 선택할 수 있습니다. Auto Scaling 그룹을 생성하고 원하는 메트릭을 기반으로 확장할 수 있습니다
  • ❌ New 버전의 AWS EKS 최적화 AMI가 출시되면 노드 그룹 내부의 노드를 수동으로 업데이트하여 먼저 실행 중인 포드의 노드를 수동으로 draining 해야 합니다. 다른 옵션은 새로 업데이트된 AMI로 완전히 새로운 노드 그룹을 생성하여 기존 노드 그룹을 이전 버전의 AMI로 교체한 다음 워크로드를 새 노드 그룹으로 마이그레이션하는 것입니다.

  • EKS는 컨트롤 플레인과 컨트롤 플레인 역할을 하는 노드를 AWS에서 관리함
  • 사용자가 직접 관리하는 노드 그룹도 있다. ( self_managed_node_group )
  • Fargate 라는 서버리스 컨테이너 컴퓨팅 리소스를 이용하는 경우도 있다.

 

✔️   eks가 관리하는 노드 그룹과 self 관리하는 노드그룹도 모듈을 통해 각각 배포해본다.

  • Bottle rocket 이라는 이미지 생소하다. 궁금
  • module 코드들을 분석해봐야 하지만, 너무 deep하게 들어가진 않겠다. 테라폼과 관련된 부분만 이번 포스팅에서 다룬다.
module "eks_managed_node_group" {
  source = "../../modules/eks-managed-node-group"

  name            = "separate-eks-mng"
  cluster_name    = module.eks.cluster_name
  cluster_version = module.eks.cluster_version

  subnet_ids                        = module.vpc.private_subnets
  cluster_primary_security_group_id = module.eks.cluster_primary_security_group_id
  vpc_security_group_ids = [
    module.eks.cluster_security_group_id,
  ]

  ami_type = "BOTTLEROCKET_x86_64"
  platform = "bottlerocket"

  # this will get added to what AWS provides
  bootstrap_extra_args = <<-EOT
    # extra args added
    [settings.kernel]
    lockdown = "integrity"

    [settings.kubernetes.node-labels]
    "label1" = "foo"
    "label2" = "bar"
  EOT

  tags = merge(local.tags, { Separate = "eks-managed-node-group" })
}

module "self_managed_node_group" {
  source = "../../modules/self-managed-node-group"

  name                = "separate-self-mng"
  cluster_name        = module.eks.cluster_name
  cluster_version     = module.eks.cluster_version
  cluster_endpoint    = module.eks.cluster_endpoint
  cluster_auth_base64 = module.eks.cluster_certificate_authority_data

  instance_type = "m5.large"

  subnet_ids = module.vpc.private_subnets
  vpc_security_group_ids = [
    module.eks.cluster_primary_security_group_id,
    module.eks.cluster_security_group_id,
  ]

  tags = merge(local.tags, { Separate = "self-managed-node-group" })
}

 

✔️  Self 관리하는 노드  ( seperate-self-mng * )

✔️  Eks 관리하는 노드  ( seperate-eks-mng * )

 

 

✔️ Fargate 

  • 서버리스 컨테이너 서비스인 Amazon Fargate를 사용하면 기본 서버 인프라를 관리하지 않고도 worker node를 실행할 수 있습니다.
  • Fargate는 사용된 실제 vCPU와 메모리에 대해서만 비용을 청구합니다.
  • 실제로 생성하거나 관리할 노드 그룹이 없으며 Kubernetes 데이터 평면은 AWS Fargate에서 완전히 관리합니다.
  • Kubernetes 데이터 평면을 실행하기 위한 특정 노드 유형 선택에 대한 세밀한 제어가 없습니다.
  • 서비스의 노드 포트 유형과 같은 모든 업스트림 Kubernetes 특정 기능을 지원하지 않습니다.
  • EKS 데이터 플레인을 생성 및 관리하고 싶지 않고 관리 오버헤드를 줄이는 대가로 데이터 플레인 EC2 인스턴스 선택 및 자동 조정에 대한 제어를 포기할 의향이 있는 경우 이 옵션을 선택 하기도 합니다.


 

우워 ㅠㅠ 모듈 연습해보려다 eks 공부하게 되어버림.

 

 

✅ EKS 접근 ? 

 

# EKS 클러스터 이름만 알면 eks 명령어로 가볍게
# kubeconfig 파일로 저장
aws eks --region eu-west-1 update-kubeconfig --name ex-complete --kubeconfig ~/.kube/config

 

✅ EKS 확인 ? 

# KUBECTL 명령어 확인

kubectl get nodes

mzc01-kook@MZC01-KOOK .kube % kubectl get nodes
NAME                                        STATUS   ROLES    AGE   VERSION
ip-10-0-16-137.eu-west-1.compute.internal   Ready    <none>   46m   v1.27.3-eks-6f07bbc
ip-10-0-19-59.eu-west-1.compute.internal    Ready    <none>   45m   v1.27.3-eks-a5565ad
ip-10-0-28-120.eu-west-1.compute.internal   Ready    <none>   44m   v1.27.3-eks-a5565ad
ip-10-0-3-200.eu-west-1.compute.internal    Ready    <none>   42m   v1.27.3-eks-a5565ad
ip-10-0-35-162.eu-west-1.compute.internal   Ready    <none>   42m   v1.27.3-eks-a5565ad
mzc01-kook@MZC01-KOOK .kube %

✅ pod배포 후 통신 테스트

cat <<EOF | kubectl create -f -
apiVersion: apps/v1
kind: Deployment
metadata:
  name: netshoot-pod
spec:
  replicas: 3
  selector:
    matchLabels:
      app: netshoot-pod
  template:
    metadata:
      labels:
        app: netshoot-pod
    spec:
      containers:
      - name: netshoot-pod
        image: nicolaka/netshoot
        command: ["tail"]
        args: ["-f", "/dev/null"]
      terminationGracePeriodSeconds: 0
EOF