DevOps & CloudAWS 허브발행일 2025. 12. 29.원본 https://blog.naver.com/jword_/224126305905 ↗

AWS EKS 클러스터 구축 및 Gitops 파이프라인 최종안

AWS EKS 클러스터 구축 및 Gitops 파이프라인 최종안 — #개발자의도구들 #AWSEKS #쿠버네티스 #AWS쿠버네티스 #gitops #깃옵스 #깃허브액션 #githubActi...

#DevOps/cloudOps#Naver Blog

#개발자의도구들 #AWSEKS #쿠버네티스 #AWS쿠버네티스 #gitops #깃옵스 #깃허브액션 #githubActions

​

아키텍처

이미지

배포 파이프라인

  1. Dev Team이 Application Repository에 새로운 버전을 Push합니다.
  1. GitHub Actions가 트리거되어 빌드를 수행합니다. (자동/수동)
  1. 빌드된 이미지를 AWS ECR에 Push합니다.
  1. 빌드 완료 후 변경된 이미지 태그를 GitOps Repository에 업데이트합니다.
  1. ArgoCD가 GitOps Repository의 변경을 감지합니다.

-

  • ArgoCD가 변경된 매니페스트를 클러스터에 Apply합니다.

6.Public Node는 IGW를 통해, Private Node는 VPC Endpoint를 통해 이미지를 새로운 이미지를 PULL하여 Pod를 배포합니다.

​

​

AWS EKS 클러스터 구축

사용자는 AWS EKS 내에 배포된 프론트 서버와 통신이 가능해야 합니다.

​

  1. 사용자는 프론트 서버에 데이터를 요청합니다.
  • VPC 내의 모든 인터넷 통신은 Internet Gateway를 통합니다.

​

  1. VPC 내의 ALB는 사용자의 요청을 분석하여 Pod로 라우팅합니다.

-

  • 현재 프론트 서버는 3개의 Pod로 밸런싱됩니다. (실습용)

​

  1. 프론트 서버는 내부 MSA 서버들과 통신합니다.

-

  • 대부분의 서버는 Private Subnet에 배치되어 있습니다.

​

  1. 이미지 서버는 VPC Endpoint를 통해 AWS S3와 직접 통신합니다.

​

  1. Private Node Group의 Worker Node는 NAT Gateway → Internet Gateway를 통해 AWS EKS Control Plane과 통신합니다.

​

  1. VPC Endpoint를 직접 지원하지 않는 AWS 서비스(Cognito 등)는 NAT Gateway → Internet Gateway를 거쳐 VPC 외부 AWS 서비스와 통신합니다.

​

EKS 클러스터 구축 비용 분석

비용이 발생하는 구간

  1. Iternet GateWay
  • 인바운드 트래픽은 무료
  • 아웃바운드 트래픽은 유료: $0.09/GB
  1. ALB
  • 시간당 요금: $0.0225/hour
  • LCU(처리량)기반 요금
  • VPC 내부 트래픽은 무료
  1. EKS
  • 클러스터 시간당 요금: $0.10/hour
  • 워커노드: EC2 인스턴스(Fargate) 비용
  1. ECR

-

  • 이미지 저장 비용: $0.10/GB/월
  • 같은 리전내 ECR → EC2는 전송비용 무료

5.NAT Gateway

-

  • 시간당 요금: $0.045/hour
  • 데이터 처리: $0.045/GB
  1. RDS

-

  • 인스턴스 시간당 요금
  • 스토리지 비용: $0.115/GB/월
  • 데이터 번송비용: 같은 VPC내 무료
  1. S3

-

  • 스토리지: $0.023/GB/월
  • 요청 비용: PUT $0.005/1000건, GET $0.0004/1000건

​

​

무료리소스

  • VPC, Subnet, Route Table, Security Group
  • VPC Gateway Endpoint (S3, DynamoDB에 한정)
  • ClusterIP Service (Pod 간 내부 통신)

​

​

실습

모든 실습은 AWS CLI 명령어로 진행합니다. 차례대로 구성한다면 AWS 네트워크 및 보안 원리를 이해하며 AWS EKS 클러스터 구축을 하실 수 있도록 설계하였습니다.

​

목차

  1. 네트워크 설정: VPC, Internet Gateway, Iptable, VPC Endpoint, NAT Gateway
  2. IAM Role 설정: Cluster Policy, Node Policy

\[AWS EKS\] 1. 네트워크 설정

VPC, Internet Gateway, Iptable, VPC Endpoint, NAT Gateway

실습에 사용할 Worker Node는 총 4개입니다. Public Subnet과 Private Subnet에 각각 2개씩 배포합니다.

  • Public Subnet에는 Frontend 서버, ALB, NAT Gateway를 배치합니다.
  • Private Subnet에는 RDS와 Backend MSA 서버들(Auth, Image, Profile)을 배치합니다.

​

1,1 VPC 생성 명령어 (CLI)

  • Node를 배치할 VPC를 생성합니다.
javascript 코드 예제
                                    # VPC 생성
aws ec2 create-vpc \
    --cidr-block 172.31.0.0/16 \
    --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=marketing-vpc},{Key=Project,Value=marketing},{Key=Environment,Value=prod},{Key=ManagedBy,Value=terraform}]'

​

1.2 Internet Gateway 생성

  • VPC가 외부와 통신하기 위해 Internet Gateway를 사용합니다.사용할 게이트웨이를 생성하고 VPC와 연결합니다.
javascript 코드 예제
                                    # Internet Gateway 생성
aws ec2 create-internet-gateway \
     --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=marketing-igw},{Key=Project,Value=marketing},{Key=Environment,Value=prod}]

# VPC에 Internet Gateway 연결
aws ec2 attach-internet-gateway \
    --internet-gateway-id <IGW_ID> \
    --vpc-id <VPC_ID>

1.3 Public Subnet 구성 (2개)

  • HA를 고려하여 Public Subnet을 두개 구성합니다.
  • 이후 각 HA 영역에 하나씩 배포합니다.(ap-northeast-2a, ap-northeast-2c)
  • Public Subnet은 Front Pod, ALB, NAT Gateway를 이후에 배치합니다.
javascript 코드 예제
                                    # Public Subnet 1 (ap-northeast-2a)
aws ec2 create-subnet \
    --vpc-id <VPC_ID> \
    --cidr-block 172.31.0.0/20 \
    --availability-zone ap-northeast-2a \
     --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=marketing-public-ap-northeast-2a},{Key=kubernetes.io/role/elb,Value=1},{Key=kubernetes.io/cluster/marketing-eks,Value=shared},{Key=Project,Value=marketing}]'

# Public Subnet 2 (ap-northeast-2c)
aws ec2 create-subnet \
    --vpc-id <VPC_ID> \
    --cidr-block 172.31.16.0/20 \
    --availability-zone ap-northeast-2c \
    --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=marketing-public-ap-northeast-2c},{Key=kubernetes.io/role/elb,Value=1},{Key=kubernetes.io/cluster/marketing-eks,Value=shared},{Key=Project,Value=marketing}]'
  • 퍼블릭 자동 할당 활성
  • Public Subnet에 배포되는 리소스(EC2, EKS 노드 등)가 인터넷과 직접 통신하려면 퍼블릭 IP가 필요합니다. 이를 AWS가 자동으로 부여해줍니다.
javascript 코드 예제
                                    aws ec2 modify-subnet-attribute \
    --subnet-id <PUBLIC_SUBNET_1_ID> \
    --map-public-ip-on-launch

 aws ec2 modify-subnet-attribute \
    --subnet-id <PUBLIC_SUBNET_2_ID> \
    --map-public-ip-on-launch

1.4 Private Subnet 생성 (2개)

  • Public과 마찬가지로 HA를 고려하여 두 개의 Private Subnet을 구성합니다.
  • 이후 각 HA 영역에 하나씩 배포합니다.(ap-northeast-2a, ap-northeast-2c)
  • Private Subnet에 RDS 및 내부 MSA 서버들을 이후에 배치합니다.
javascript 코드 예제
                                    # Private Subnet 1 (ap-northeast-2a)
aws ec2 create-subnet \
  --vpc-id <VPC_ID> \
  --cidr-block 172.31.32.0/20 \
  --availability-zone ap-northeast-2a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=marketing-private-ap-northeast-2a},{Key=kubernetes.io/role/internal-elb,Value=1},{Key=kubernetes.io/cluster/marketing-eks,Value=shared},{Key=Project,Value=marketing}]'

# Private Subnet 2 (ap-northeast-2c)
aws ec2 create-subnet \
  --vpc-id <VPC_ID> \
  --cidr-block 172.31.48.0/20 \
  --availability-zone ap-northeast-2c \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=marketing-private-ap-northeast-2c},{Key=kubernetes.io/role/internal-elb,Value=1},{Key=kubernetes.io/cluster/marketing-eks,Value=shared},{Key=Project,Value=marketing}]'

​

​

1.5 NAT Gateway

  • Private Subnet의 리소스가 외부 인터넷과 통신하기 위해 필요합니다. 본 프로젝트에서는 Private Subnet의 Backend 서버가 AWS Cognito와 통신할 때 사용됩니다.
javascript 코드 예제
                                    # Elastic IP 할당 (NAT Gateway용)
aws ec2 allocate-address \
  --domain vpc \
  --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=marketing-nat-eip},{Key=Project,Value=marketing}]'

# NAT Gateway 생성 (Public Subnet 1에 배치)
aws ec2 create-nat-gateway \
  --subnet-id <PUBLIC_SUBNET_1_ID> \
  --allocation-id <EIP_ALLOCATION_ID> \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=marketing-nat},{Key=Project,Value=marketing}]'

\* Elastic IP 할당 이유: NAT는 Pivate Subnet의 리소스들이 외부로 나갈 때 사용하는 고정된 출구 IP가 필요합니다.그래서 Elasitc IP를 사용하지 않으면 게이트웨이 생성이 불가능합니다.

​

​

1.6 Route Table 생성 및 연결

  • 프로젝트 성격에 맞게 Route Table을 구성합니다.
  • Public Route Table 생성 및 설정\]
  • Public VPC는 인터넷과 통신하기 위해 IGW를 사용합니다.
  • 이에 인터넷 라우트를 추가합니다.
javascript 코드 예제
                                    # Public Route Table 생성
aws ec2 create-route-table \
  --vpc-id <VPC_ID> \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=marketing-public-rt},{Key=Project,Value=marketing}]'

# Public Route Table에 인터넷 라우트(IGW) 추가
aws ec2 create-route \
  --route-table-id <PUBLIC_RT_ID> \
  --destination-cidr-block 0.0.0.0/0 \
  --gateway-id <IGW_ID>

# Public Subnet 1을 Public Route Table에 연결
aws ec2 associate-route-table \
  --route-table-id <PUBLIC_RT_ID> \
  --subnet-id <PUBLIC_SUBNET_1_ID>

# Public Subnet 2를 Public Route Table에 연결
aws ec2 associate-route-table \
  --route-table-id <PUBLIC_RT_ID> \
  --subnet-id <PUBLIC_SUBNET_2_ID>
  • Private Route Table 생성 및 설정
  • NAT Gateway에서 인터넷으로 Outbound 통신만 가능하도록 설계
javascript 코드 예제

# Private Route Table 생성
aws ec2 create-route-table \
  --vpc-id <VPC_ID> \
  --tag-specifications 'ResourceType=route-table,Tags=[{Key=Name,Value=marketing-private-rt},{Key=Project,Value=marketing}]'

# Private Route Table에 NAT Gateway 라우트 추가
aws ec2 create-route \
  --route-table-id <PRIVATE_RT_ID> \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id <NAT_GW_ID>

# Private Subnet 1을 Private Route Table에 연결
aws ec2 associate-route-table \
  --route-table-id <PRIVATE_RT_ID> \
  --subnet-id <PRIVATE_SUBNET_1_ID>

# Private Subnet 2를 Private Route Table에 연결
aws ec2 associate-route-table \
  --route-table-id <PRIVATE_RT_ID> \
  --subnet-id <PRIVATE_SUBNET_2_ID>

​

​

1.7 VPC Endpoint

Private Subnet에서 AWS 서비스에 직접 접근하기 위해 사용합니다. 본 프로젝트에서는 이미지 서버가 S3와 통신할 때 사용됩니다.

​

Security Group 생성

  • Interface VPC 타입의 VPC Endpoint는 ENI(네트워크 인터페이스)를 생성하기 때문에 ,ENI에 대한 제어가 필요합니다.
javascript 코드 예제
                                    # VPC Endpoints Security Group 생성
aws ec2 create-security-group \
  --group-name marketing-vpc-endpoints-sg \
  --description "Security group for VPC endpoints" \
  --vpc-id <VPC_ID> \
  --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=marketing-vpc-endpoints-sg},{Key=Project,Value=marketing}]'

# Ingress 규칙 추가 (HTTPS 443 from VPC CIDR)
aws ec2 authorize-security-group-ingress \
  --group-id <VPC_ENDPOINTS_SG_ID> \
  --protocol tcp \
  --port 443 \
  --cidr 172.31.0.0/16

​

1.8 VPC Endpoints 생성

  • S3 Gateway Endpoint를 생성합니다.
javascript 코드 예제
                                    # S3 Gateway Endpoint 생성
  aws ec2 create-vpc-endpoint \
    --vpc-id <VPC_ID> \
    --service-name com.amazonaws.ap-northeast-2.s3 \
    --vpc-endpoint-type Gateway \
    --route-table-ids <PRIVATE_RT_ID> <PUBLIC_RT_ID> \
    --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=marketing-s3-endpoint},{Key=Project,Value=marketing}]'
  • ECR Interface Endpoint를 생성합니다.
  • AWS ECR에서 이미지를 Pull하는 과정이 여러 단계로 나뉘며,각 단계가 서로 다른 AWS 서비스를 호출합니다.
  1. 인증(STS): EKS Node가 ECR에 접근 권한이 있는지 확인(토큰 발급)
  2. ECR API: 이미지 메타데이터 조회
  3. ECR DKR: 실제 이미지 다운로드 (blob 파일들을 다운로드)
javascript 코드 예제
                                    # STS Interface Endpoint 생성
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --service-name com.amazonaws.ap-northeast-2.sts \
  --vpc-endpoint-type Interface \
  --subnet-ids <PRIVATE_SUBNET_1_ID> <PRIVATE_SUBNET_2_ID> \
  --security-group-ids <VPC_ENDPOINTS_SG_ID> \
  --private-dns-enabled \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=marketing-sts-endpoint},{Key=Project,Value=marketing}]'

# ECR DKR Interface Endpoint 생성
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --service-name com.amazonaws.ap-northeast-2.ecr.dkr \
  --vpc-endpoint-type Interface \
  --subnet-ids <PRIVATE_SUBNET_1_ID> <PRIVATE_SUBNET_2_ID> \
  --security-group-ids <VPC_ENDPOINTS_SG_ID> \
  --private-dns-enabled \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=marketing-ecr-dkr-endpoint},{Key=Project,Value=marketing}]'

# ECR API Interface Endpoint 생성
aws ec2 create-vpc-endpoint \
  --vpc-id <VPC_ID> \
  --service-name com.amazonaws.ap-northeast-2.ecr.api \
  --vpc-endpoint-type Interface \
  --subnet-ids <PRIVATE_SUBNET_1_ID> <PRIVATE_SUBNET_2_ID> \
  --security-group-ids <VPC_ENDPOINTS_SG_ID> \
  --private-dns-enabled \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=marketing-ecr-api-endpoint},{Key=Project,Value=marketing}]'

\[AWS EKS\] 2. IAM Role 설정

Cluster Policy, Node Policy

AWS EKS 및 AWS EKS에 등록된 워커 노드가 사용할 IAM Role을 생성해야합니다.

​

2.1 Cluster Policy: AWS EKS의 Control Plane이 사용할 IAM Role

javascript 코드 예제
                                    # Trust Policy Json 파일 준비
{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {
          "Service": "eks.amazonaws.com"
        },
        "Action": "sts:AssumeRole"
      }
    ]
}

aws iam create-role \
  --role-name marketing-eks-cluster-role \
  --assume-role-policy-document file://eks-cluster-trust-policy.json \
  --tags Key=Name,Value=marketing-eks-cluster-role Key=Project,Value=marketing

# AWS EKS Cluster Policy 연결 (Control Plane 용) = 클러스터 기본 권한
aws iam attach-role-policy \
  --role-name marketing-eks-cluster-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy

# VPC/ENI 관리
aws iam attach-role-policy \
  --role-name marketing-eks-cluster-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEKSVPCResourceController

2.2 Node Policy: EKS Node Role 생성

javascript 코드 예제
                                    # Trust Policy Json 파일 준비
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

aws iam create-role \
  --role-name marketing-eks-node-role \
  --assume-role-policy-document file://eks-node-trust-policy.json \
  --tags Key=Name,Value=marketing-eks-node-role Key=Project,Value=marketing

# AWS EKS용 Worker Node Policy 연결
aws iam attach-role-policy \
  --role-name marketing-eks-node-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy

# CNI Policy (Pod IP 할당)
aws iam attach-role-policy \
  --role-name marketing-eks-node-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy

# ECR 읽기 권한
aws iam attach-role-policy \
  --role-name marketing-eks-node-role \
  --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly

\[AWS EKS\] 3. EKS 클러스터 생성 및 OIDC

이제 본격적으로 EKS 클러스터를 구축합니다.

​

3.1 AWS EKS 생성

javascript 코드 예제
                                    # EKS Cluster Security Group 생성
aws ec2 create-security-group \
  --group-name marketing-eks-cluster-sg \
  --description "Security group for EKS cluster" \
  --vpc-id <VPC_ID> \
  --tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=marketing-eks-cluster-sg},{Key=Project,Value=marketing}]'

# EKS 클러스터 생성 (10~15분 소요)
aws eks create-cluster \
  --name marketing-eks \
  --role-arn arn:aws:iam::<ACCOUNT_ID>:role/marketing-eks-cluster-role \
  --resources-vpc-config subnetIds=<PUBLIC_SUBNET_1>,<PUBLIC_SUBNET_2>,<PRIVATE_SUBNET_1>,<PRIVATE_SUBNET_2>,securityGroupIds=<EKS_CLUSTER_SG>,endpointPublicAccess=true,endpointPrivateAccess=true \
  --kubernetes-version 1.31 \
  --logging '{"clusterLogging":[{"types":["api","audit","authenticator","controllerManager","scheduler"],"enabled":true}]}' \
  --tags Project=marketing,Environment=prod

# 클러스터 상태 확인
aws eks describe-cluster \
  --name marketing-eks \
  --query "cluster.status"

# ACTIVE 상태까지 대기
aws eks wait cluster-active \
  --name marketing-eks

# 클러스터 정보 최종 확인
aws eks describe-cluster \
  --name marketing-eks

3.2 OIDC Provider 설정 (IRSA)

특정 Pod가 AWS 서비스에 접근하려면 IAM 권한이 필요합니다.

IRSA(IAM Roles for Service Accounts)는 Pod 단위로 IAM 권한을 부여하는 방식입니다.

​

OIDC(OpenID Connect)는 신원 인증 프로토콜로 OAuth2.0 기반의 인증 프로토콜입니다. "이 사람이 누구인지 증명"해주는 표준 프로토콜입니다.

​

  1. Pod가 OIDC로 JWR 토큰을 보냅니다.
  2. OIDC는 JWT 토큰을 검증하고 이를 바탕으로 임시 자격증명을 발급해줍니다.
  3. Pod는 임시 자격증명을 통해 AWS 리소스에 접근할 수 있습니다.

​

왜 필요한가?

예전 방식은 Node에 모든 권한을 부여했습니다.

이 경우 해당 Node의 모든 Pod가 동일한 권한을 갖게 되어 보안에 취약합니다.

IRSA를 사용하면 필요한 Pod에만 필요한 권한을 부여할 수 있습니다.

javascript 코드 예제
                                    # OIDC Provider URL 가져오기 (https 제거)
OIDC_PROVIDER=$(aws eks describe-cluster \
  --name marketing-eks \
  --query "cluster.identity.oidc.issuer" \
  --output text | sed 's|https://||')

echo "OIDC_PROVIDER=${OIDC_PROVIDER}"
# 예: oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLE1234567890

# AWS 계정 ID 가져오기
ACCOUNT_ID=$(aws sts get-caller-identity \
  --query Account \
  --output text)

echo "ACCOUNT_ID=${ACCOUNT_ID}"
javascript 코드 예제
                                    # ALB Controller IAM Role Trust Policy 생성 (환경변수 치환)
cat <<EOF > alb-controller-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:aud": "sts.amazonaws.com",
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
        }
      }
    }
  ]
}
EOF

# IAM Role 생성 (AWS Load Balancer Controller용)
aws iam create-role \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --assume-role-policy-document file://alb-controller-trust-policy.json \
  --tags Key=Name,Value=AmazonEKSLoadBalancerControllerRole Key=Project,Value=marketing

# ALB Controller 정책 연결 (사전 생성된 커스텀 정책)
aws iam attach-role-policy \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy

Kubernetes Service Account 생성

javascript 코드 예제
                                    # .yaml 파일 준비
apiVersion: v1
  kind: ServiceAccount
  metadata:
    name: aws-load-balancer-controller
    namespace: kube-system
    annotations:
      eks.amazonaws.com/role-arn: arn:aws:iam::${ACCOUNT_ID}:role/AmazonEKSLoadBalancerControllerRole
    labels:
      app.kubernetes.io/component: controller
      app.kubernetes.io/name: aws-load-balancer-controller

# 적용
kubectl apply -f alb-controller-sa.yaml

​

​

​

\[AWS EKS\] 4. 노드 그룹 생성

노드 그룹은 노드가 배치되는 서브넷에 따라 나눠집니다. 퍼블릭 서브넷에 배치 퍼블릭 노드 그룹, 프라이빗 서브넷 배치 프라이빗 노드 그룹이라고 부릅니다.

​

​

​

​

4.1 Public Node Group 생성

javascript 코드 예제
                                     # Public Node Group 생성
  aws eks create-nodegroup \
    --cluster-name marketing-eks \
    --nodegroup-name marketing-public-nodes \
    --node-role arn:aws:iam::<ACCOUNT_ID>:role/marketing-eks-node-role \
    --subnets <PUBLIC_SUBNET_1> <PUBLIC_SUBNET_2> \
    --instance-types t3.medium \
    --capacity-type ON_DEMAND \
    --scaling-config minSize=1,maxSize=4,desiredSize=2 \
    --update-config maxUnavailable=1 \
    --labels purpose=public \
    --tags Project=marketing,Environment=prod

​

4.2 Private Node Group 생성

Private Node Group 생성에 유의점이 있습니다. BootStrap과정에서 온전히 노드가 등록되지 않고 무한 대기 상태로 빠질 수 있습니다.

​

BootStrap은 Worker Node가 EKS 클러스터에 등록되는 과정입니다. Node가 시작되면 bootstrap.sh 스크립트가 실행되어 kubelet을 설정하고, EKS Control Plane에 자신을 등록합니다.

​

Node가 정상적으로 등록되려면 다음 AWS 서비스들과 통신해야 합니다.

  • EKS API Server: Node 등록 요청
  • ECR: 컨테이너 이미지 Pull (kube-proxy, aws-node 등)
  • S3: 이미지 레이어 다운로드
  • STS: IAM 인증 토큰 발급

​

즉 VPC 외부와 소통이 가능해야 한다는 것입니다. Private Subnet과 VPC외부 통신을 하기 위해선 NAT Gateway가 필요합니다. 우리는 1장의 네트워크 설정에서 이미 다뤘기에 바로 생성이 가능합니다.

​

javascript 코드 예제
                                      aws eks create-nodegroup \
    --cluster-name marketing-eks \
    --nodegroup-name marketing-private-nodes \
    --node-role arn:aws:iam::<ACCOUNT_ID>:role/marketing-eks-node-role \
    --subnets <PRIVATE_SUBNET_1> <PRIVATE_SUBNET_2> \
    --instance-types t3.medium \
    --capacity-type ON_DEMAND \
    --scaling-config minSize=1,maxSize=4,desiredSize=2 \
    --update-config maxUnavailable=1 \
    --labels purpose=private \
    --tags Project=marketing,Environment=prod

​

\[AWS EKS\] 5. ALB 설정

5.1. ALB Controller IAM Policy 생성 및 IRSA 적용

javascript 코드 예제
                                    # AWS Load Balancer Controller IAM Policy 다운로드
curl -o alb-controller-policy.json \
  https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.7.0/docs/install/iam_policy.json

# IAM Policy 생성
aws iam create-policy \
  --policy-name AWSLoadBalancerControllerIAMPolicy \
  --policy-document file://alb-controller-policy.json \
  --tags Key=Name,Value=AWSLoadBalancerControllerIAMPolicy Key=Project,Value=marketing

# 변수 설정
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
OIDC_PROVIDER=$(aws eks describe-cluster \
  --name marketing-eks \
  --query "cluster.identity.oidc.issuer" \
  --output text | sed 's|https://||')

echo "ACCOUNT_ID=${ACCOUNT_ID}"
echo "OIDC_PROVIDER=${OIDC_PROVIDER}"

# Trust Policy 생성 (IRSA)
cat <<EOF > alb-controller-trust-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "${OIDC_PROVIDER}:aud": "sts.amazonaws.com",
          "${OIDC_PROVIDER}:sub": "system:serviceaccount:kube-system:aws-load-balancer-controller"
        }
      }
    }
  ]
}
EOF

# IAM Role 생성 (AWS Load Balancer Controller용)
aws iam create-role \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --assume-role-policy-document file://alb-controller-trust-policy.json \
  --tags Key=Name,Value=AmazonEKSLoadBalancerControllerRole Key=Project,Value=marketing

# Policy 연결
aws iam attach-role-policy \
  --role-name AmazonEKSLoadBalancerControllerRole \
  --policy-arn arn:aws:iam::${ACCOUNT_ID}:policy/AWSLoadBalancerControllerIAMPolicy

​

5.2. ALB Controller 등록

ALB Controller는 워커노드 내 kube-system namespace에 Pod로 배포됩니다.

​

ALB Controller가 Ingress 리소스를 감지하면, AWS API를 호출하여 ALB(로드밸런서)를 VPC Public Subnet에 생성합니다.

javascript 코드 예제
                                    # 변수 설정
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# ServiceAccount 생성 (IRSA)
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: aws-load-balancer-controller
  namespace: kube-system
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::${ACCOUNT_ID}:role/AmazonEKSLoadBalancerControllerRole
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
EOF

# Helm repo 추가 및 업데이트
helm repo add eks https://aws.github.io/eks-charts
helm repo update

# AWS Load Balancer Controller 설치
helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
  -n kube-system \
  --set clusterName=marketing-eks \
  --set serviceAccount.create=false \
  --set serviceAccount.name=aws-load-balancer-controller \
  --set region=ap-northeast-2 \
  --set vpcId=<VPC_ID>

Target Group 설정 시 직접 Pod IP를 사용하여 통신하거나, Pod를 띄운 Node IP를 설정합니다.

Node IP를 사용하는 경우, 내부 Pod와 통신하기 위해 NodePort를 등록합니다.

​

\[AWS EKS\] 6. Ingress 설정

6.1. Ingress예시

Ingress로 생성된 ALB는 AWS가 관리합니다. ALB에 Target Group을 설정하여 트래픽을 분배합니다.

javascript 코드 예제

  # ingress.yaml
  apiVersion: networking.k8s.io/v1
  kind: Ingress
  metadata:
    name: marketing-ingress
    namespace: default
    annotations:
      # ALB 생성 지정
      kubernetes.io/ingress.class: alb

      # 인터넷 facing (Public)
      alb.ingress.kubernetes.io/scheme: internet-facing

      # Public Subnet에 ALB 생성
      alb.ingress.kubernetes.io/subnets: <PUBLIC_SUBNET_1>, <PUBLIC_SUBNET_2>

      # Target Type (IP 모드 권장)
      alb.ingress.kubernetes.io/target-type: ip

      # Health Check 설정
      alb.ingress.kubernetes.io/healthcheck-path: /health
      alb.ingress.kubernetes.io/healthcheck-interval-seconds: '15'

      # 태그
      alb.ingress.kubernetes.io/tags: Project=marketing,Environment=prod

  spec:
    rules:
      - http:
          paths:
            - path: /
              pathType: Prefix
              backend:
                service:
                  name: marketing-service
                  port:
                    number: 80

​

​

​

​

\[GitOps\] 1. Github Actions

\[GitOps\] 2. AWS ECR

\[GitOps\] 3. Helm

\[GitOps\] 4. ArgoCD

​