Home
home

1장 실습 - Amazon EKS Fully Private Cluster 구성하기

1. 기본 환경 배포

이번 실습은 IAM 사용자 계정을 통해 관리 콘솔에 접근하고 액세스 키를 활용해 awscli 도구를 사용합니다.
해당 작업을 수행하지 않았다면 아래 토글을 확장해 작업을 선행하고 본격적인 실습에 들어갑니다.
IAM 사용자 생성 및 액세스 키 생성

1.1. Terraform을 통한 기본 인프라 배포

Terraform을 통한 기본 인프라 배포에 앞서 SSH 키 페어, IAM User Access Key ID, IAM User Secret Access Key를 미리 확인하고 메모해 둡니다.
Terraform으로 기본 인프라 배포
cd cnaee_class_tf/ch1
Bash
복사
# 실습 디렉터리 경로 진입
export TF_VAR_KeyName=[각자 ssh keypair] export TF_VAR_MyIamUserAccessKeyID=[각자 iam 사용자의 access key id] export TF_VAR_MyIamUserSecretAccessKey=[각자 iam 사용자의 secret access key] export TF_VAR_SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32
Bash
복사
# Terraform 환경 변수 저장
terraform init terraform plan
Bash
복사
# Terraform 배포
nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
Bash
복사
Note:  nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 배포가 완료되면 정상적으로 자원 생성이 되었는지 확인을 합니다.(cat create.log)
Terraform을 통한 기본 인프라 배포가 완료되면 관리 콘솔에서 생성된 인프라들을 확인합니다.
Note: 
AWS 관리 콘솔에 로그인 할 땐 IAM 사용자 계정으로 진행합니다.

1.2. 기본 정보 확인 및 설정

Terraform 배포가 완료 후 출력되는 Output 정보에서 bastion_host_ip의 퍼블릭 IP를 확인합니다.
해당 IP로 EKS 관리용 인스턴스(myeks-bastion-EC2)에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
Note:
myeks-bastion-EC2의 OS 변경으로 SSH 접근에 대한 계정을 ubuntu로 지정합니다.
(ssh -i ~/.ssh/XXXX.pem ubuntu@X.X.X.X)
myeks-bastion에 EKS 클러스터 인증 정보 업데이트
cat ~/.kube/config | yh
Bash
복사
# kubeconfig 정보 확인
aws eks update-kubeconfig \ --region $AWS_DEFAULT_REGION \ --name $CLUSTER_NAME
Bash
복사
# EKS 클러스터 인증 정보 업데이트
kubens 설정
kubens default
Bash
복사
# kubectl 명령을 수행할 네임스페이스 지정
변수 호출 종합
echo $AWS_DEFAULT_REGION echo $CLUSTER_NAME echo $VPCID echo $PublicSubnet1,$PublicSubnet2,$PublicSubnet3 echo $PrivateSubnet1,$PrivateSubnet2,$PrivateSubnet3
Bash
복사
# 배포된 EC2에 선언된 변수 호출
Note:
변수 호출이 제대로 이루어지지 않을 경우 SSH 재 접속 후 다시 확인 합니다.
EKS 클러스터 정보 확인
kubectl cluster-info
Bash
복사
# kubectl을 통한 eks cluster 정보 확인
eksctl get cluster
Bash
복사
# eksctl을 통한 eks cluster 정보 확인
aws eks describe-cluster \ --name $CLUSTER_NAME | jq
Bash
복사
# awscli를 통한 eks cluster 정보 확인 (상세)
aws eks describe-cluster \ --name $CLUSTER_NAME | grep endpoint
Bash
복사
# awscli를 통한 eks cluster 정보 확인 (endpoint 주소와 endpoint access 확인)
API Server Endpoint 주소 확인 및 조회
APIDNS_PUBLIC=$(aws eks describe-cluster --name ${CLUSTER_NAME} | jq -r .cluster.endpoint | cut -d '/' -f 3) echo $APIDNS_PUBLIC echo "export APIDNS_PUBLIC=$APIDNS_PUBLIC" >> /etc/profile
Bash
복사
# API Server Endpoint 도메인 변수 선언
dig +short $APIDNS_PUBLIC
Bash
복사
# API Server Endpoint 도메인의 IP 주소 확인
EKS 노드 그룹 확인
eksctl get nodegroup \ --cluster $CLUSTER_NAME \ --name ${CLUSTER_NAME}-node-group
Bash
복사
# eksctl을 통한 노드 그룹 정보 확인
aws eks describe-nodegroup \ --cluster-name $CLUSTER_NAME \ --nodegroup-name ${CLUSTER_NAME}-node-group | jq
Bash
복사
# awscli를 통한 노드 그룹 정보 확인 (상세)
kubectl get node kubectl get node -owide kubectl get node -v=6
Bash
복사
# kubectl을 통한 노드 정보 확인
노드 IP 변수 선언 및 SSH 접근
PublicN1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address}) PublicN2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address}) PublicN3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address}) echo "export PublicN1=$PublicN1" >> /etc/profile echo "export PublicN2=$PublicN2" >> /etc/profile echo "export PublicN3=$PublicN3" >> /etc/profile echo $PublicN1, $PublicN2, $PublicN3
Bash
복사
# 노드 IP 변수 선언
for node in $PublicN1 $PublicN2 $PublicN3; \ do \ ssh -i ~/.ssh/kp_node.pem -o StrictHostKeyChecking=no ec2-user@$node hostname; \ done
Bash
복사
# 노드에 ssh 접근 확인

1.3. API Server - Endpoint Public Access 통신 흐름

Terraform 배포로 생성된 Amazon EKS Cluster는 Endpoint Public Access 환경으로 구성됩니다.
이러한 환경에서 3가지 측면으로 통신 흐름을 확인합니다.
[통신 확인] api-server → kubelet
kubectl exec -it deploy/external-dns -n kube-system -- bash
Bash
복사
# external-dns deployments의 파드에 bash 실행
for i in $PublicN1 $PublicN2 $PublicN3; \ do echo ">> node $i <<"; \ ssh -i ~/.ssh/kp_node.pem ec2-user@$i sudo ss -tnp; echo; \ done
Bash
복사
# [신규 터미널] tcp 세션 확인 (Peer Address)
kubelet에 연결된 Peer Address는 어떤 대상의 IP 주소일까요?
[통신 확인] bastion-host → api-server
tcpdump -n -i ens5 tcp port 443 -c 3
Bash
복사
# tcpdump: tcp 443 (3Way Handshake)
kubectl get node
Bash
복사
# [신규 터미널] kubectl 명령 수행
dig +short $APIDNS_PUBLIC
Bash
복사
# [신규 터미널] dig 명령으로 api-server endpoint 주소 확인
[통신 확인] kubelet & kube-proxy → api-server
for i in $PublicN1 $PublicN2 $PublicN3; \ do echo ">> node $i <<"; \ ssh -i ~/.ssh/kp_node.pem ec2-user@$i sudo ss -tnp| grep -E "State|kube"; echo; \ done
Bash
복사
# 노드마다 tcp 세션 정보 확인

2. EKS Fully Private Cluster 배포 및 확인

Amazon EKS Fully Private Cluster를 배포하고 통신을 확인합니다.

2.1. EKS Fully Private Cluster 배포

Amazon EKS Fully Private Cluster를 생성하기 위해 eksctl 명령을 활용해 배포합니다.
eksctl로 EKS Fully Private Cluster 생성
cat > eks-private-cluster.yaml <<EOF --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: ${CLUSTER_NAME}-Private region: ${AWS_DEFAULT_REGION} version: "1.32" privateCluster: enabled: true vpc: id: "${VPCID}" subnets: private: private-ap-northeast-2a: id: "${PrivateSubnet1}" private-ap-northeast-2b: id: "${PrivateSubnet2}" private-ap-northeast-2c: id: "${PrivateSubnet3}" managedNodeGroups: - name: ${CLUSTER_NAME}-Private-ng instanceType: t3.medium minSize: 3 desiredCapacity: 3 maxSize: 3 privateNetworking: true volumeSize: 50 volumeType: gp3 iam: withAddonPolicies: autoScaler: false albIngress: true cloudWatch: false externalDNS: true ssh: allow: true publicKeyPath: ~/.ssh/id_rsa.pub subnets: - private-ap-northeast-2a - private-ap-northeast-2b - private-ap-northeast-2c addons: - name: vpc-cni attachPolicyARNs: - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy - name: coredns version: latest - name: kube-proxy version: latest iam: withOIDC: true serviceAccounts: - metadata: name: aws-load-balancer-controller namespace: kube-system wellKnownPolicies: awsLoadBalancerController: true EOF cat eks-private-cluster.yaml | yh
Bash
복사
# eks-private-cluster.yaml 파일 생성
eksctl create cluster -f eks-private-cluster.yaml
Bash
복사
# [eksctl] EKS Fully Private Cluster 배포
Note:
참고로 eksctl로 Endpoint Private Access를 구성하면, EKS 환경이 바로 프라이빗 환경으로 구성되지 않고 퍼블릭 & 프라이빗 환경으로 구성 후 자동으로 퍼블릭 접근을 제거하는 업데이트를 수행합니다.
Warning:
EKS Fully Cluster 구성을 할 때 보안 그룹 설정이 필요합니다.
클러스터 배포가 진행 중일 때 빠른 시점에 아래 보안 그룹 생성 작업을 진행해 주세요.
참고로 너무 늦게 설정하면 클러스터 배포가 실패될 것입니다!!
보안 그룹 인바운드 규칙 확인 및 추가
aws ec2 describe-security-groups \ --filters Name=group-name,Values=*myeks-Private-cluster-Cluster* \ --query "SecurityGroups[*].[GroupId]" \ --output text aws ec2 describe-security-groups \ --filters Name=group-name,Values=*myeks-Private-cluster-Control* \ --query "SecurityGroups[*].[GroupId]" \ --output text CSN_SGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*myeks-Private-cluster-Cluster* --query "SecurityGroups[*].[GroupId]" --output text); echo $CSN_SGID CP_SGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*myeks-Private-cluster-Control* --query "SecurityGroups[*].[GroupId]" --output text); echo $CP_SGID
Bash
복사
# Cluster Shared Node SG와 Control Plane SG의 보안 그룹 ID 확인 및 변수 선언
aws ec2 describe-security-groups \ --group-ids $CP_SGID \ --output yaml | yh aws ec2 describe-security-groups \ --group-ids $CSN_SGID \ --output yaml | yh
Bash
복사
# Cluster Shared Node SG와 Control Plane SG의 보안 그룹 규칙 확인
aws ec2 authorize-security-group-ingress \ --group-id $CSN_SGID \ --protocol tcp \ --port 443 \ --cidr 192.168.1.100/32
Bash
복사
# Cluster Shared Node SG의 인바운드 규칙에 Bastion-Host, TCP 443 추가
aws ec2 authorize-security-group-ingress \ --group-id $CP_SGID \ --protocol tcp \ --port 443 \ --cidr 192.168.1.100/32
Bash
복사
# Control Plane SG의 인바운드 규칙에 Bastion-Host, TCP 443 추가
Note:
Amazon EKS 관리 콘솔에 접근해서 정보를 확인합니다.

2.2. EKS Fully Private Cluster 정보 확인 및 설정

[Private Cluster] kubectx와 kubens 확인 및 설정
kubectx
Bash
복사
# kubectx 확인 및 설정
kubectx [Context 이름]
Bash
복사
kubectx -
Bash
복사
kubens default
Bash
복사
# kubens default 설정
[Private Cluster] EKS Private Cluster 정보 확인
kubectl cluster-info
Bash
복사
# kubectl을 통한 eks private cluster 정보 확인
eksctl get cluster
Bash
복사
# eksctl을 통한 eks private cluster 정보 확인
aws eks describe-cluster \ --name ${CLUSTER_NAME}-Private | grep endpoint
Bash
복사
# awscli를 통한 eks private cluster 정보 확인 (endpoint 주소와 endpoint access 확인)
[Private Cluster] API Server Endpoint 주소 확인 및 조회
APIDNS_PRIVATE=$(aws eks describe-cluster --name ${CLUSTER_NAME}-Private | jq -r .cluster.endpoint | cut -d '/' -f 3) echo $APIDNS_PRIVATE echo "export APIDNS_PRIVATE=$APIDNS_PRIVATE" >> /etc/profile
Bash
복사
# API Server Endpoint 도메인 변수 선언
dig +short $APIDNS_PRIVATE
Bash
복사
# API Server Endpoint 도메인의 IP 주소 확인
[Private Cluster] EKS 노드 그룹 확인
eksctl get nodegroup \ --cluster ${CLUSTER_NAME}-Private \ --name ${CLUSTER_NAME}-Private-ng
Bash
복사
# eksctl을 통한 노드 그룹 정보 확인
kubectl get node -owide
Bash
복사
# kubectl을 통한 노드 정보 확인
[Private Cluster] 노드 IP 변수 선언 및 SSH 접근
PrivateN1=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a -o jsonpath={.items[0].status.addresses[0].address}) PrivateN2=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2b -o jsonpath={.items[0].status.addresses[0].address}) PrivateN3=$(kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c -o jsonpath={.items[0].status.addresses[0].address}) echo "export PrivateN1=$PrivateN1" >> /etc/profile echo "export PrivateN2=$PrivateN2" >> /etc/profile echo "export PrivateN3=$PrivateN3" >> /etc/profile echo $PrivateN1, $PrivateN2, $PrivateN3
Bash
복사
# 노드 IP 변수 저장
for node in $PrivateN1 $PrivateN2 $PrivateN3; \ do \ ssh -o StrictHostKeyChecking=no ec2-user@$node hostname; \ done
Bash
복사
# 노드에 ssh 접근 확인
[Private Cluster] 실습에 활용할 도구 설치
helm repo add eks https://aws.github.io/eks-charts helm repo update helm install aws-load-balancer-controller eks/aws-load-balancer-controller -n kube-system --set clusterName=${CLUSTER_NAME}-Private \ --set serviceAccount.create=false \ --set serviceAccount.name=aws-load-balancer-controller
Bash
복사
# AWS Load Balancer Controller 설치
MyDomain=<자신의 도메인>
Bash
복사
# ExternalDNS 설치
MyDnsHostedZoneId=$(aws route53 list-hosted-zones-by-name --dns-name "${MyDomain}." --query "HostedZones[0].Id" --output text) echo $MyDomain, $MyDnsHostedZoneId curl -s -O https://raw.githubusercontent.com/cloudneta/cnaeblab/master/_data/externaldns.yaml MyDomain=$MyDomain MyDnsHostedZoneId=$MyDnsHostedZoneId envsubst < externaldns.yaml | kubectl apply -f -
Bash
복사
helm repo add geek-cookbook https://geek-cookbook.github.io/charts/ helm install kube-ops-view geek-cookbook/kube-ops-view --version 1.2.2 --set env.TZ="Asia/Seoul" --namespace kube-system kubectl patch svc -n kube-system kube-ops-view -p '{"spec":{"type":"LoadBalancer"}}' kubectl annotate service kube-ops-view -n kube-system "external-dns.alpha.kubernetes.io/hostname=kubeopsview.$MyDomain" echo -e "Kube Ops View URL = http://kubeopsview.$MyDomain:8080/#scale=1.5"
Bash
복사
# kube-ops-view 설치

2.3. API Server - Endpoint Private Access 통신 흐름

eksctl 배포로 생성된 Amazon EKS Cluster는 Endpoint Private Access 환경으로 구성됩니다.
이러한 환경에서 3가지 측면으로 통신 흐름을 확인합니다.
aws eks delete-addon \ --cluster-name ${CLUSTER_NAME}-Private \ --addon-name metrics-server
Bash
복사
# 메트릭 서버 Add-On 삭제
Note:
eksctl 0.201.0 부터 Metrics Server가 클러스터 생성 시 기본 Add-On으로 포함됐습니다.
이번 실습에 필요한 대상이 아니고 세션 정보 확인에 혼선을 줄 수 있어 Add-On을 삭제합니다.
[Private Cluster - 통신 확인] api-server → kubelet
kubectl exec -it deploy/kube-ops-view -n kube-system -- bash
Bash
복사
# kube-ops-view deployments의 파드에 bash 실행
for i in $PrivateN1 $PrivateN2 $PrivateN3; \ do echo ">> node $i <<"; \ ssh ec2-user@$i sudo ss -tnp; echo; \ done
Bash
복사
# [신규 터미널] tcp 세션 확인 (Peer Address)
[Private Cluster - 통신 확인] bastion-host → api-server
tcpdump -n -i ens5 tcp port 443 -c 3
Bash
복사
# tcpdump: tcp 443 (3Way Handshake)
kubectl get node
Bash
복사
# [신규 터미널] kubectl 명령 수행
dig +short $APIDNS_PRIVATE
Bash
복사
# [신규 터미널] dig 명령으로 api-server endpoint 주소 확인
[Private Cluster - 통신 확인] kubelet & kube-proxy → api-server
for i in $PrivateN1 $PrivateN2 $PrivateN3; \ do echo ">> node $i <<"; \ ssh ec2-user@$i sudo ss -tnp | grep -E "State|kube"; echo; \ done
Bash
복사
# 노드마다 tcp 세션 정보 확인

2.4. Private Cluster에 파드 구성 및 통신 확인

vpc endpoint - elasticloadbalancing 생성
CSN_SGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*myeks-Private-cluster-Cluster* --query "SecurityGroups[*].[GroupId]" --output text); echo $CSN_SGID aws ec2 create-vpc-endpoint \ --vpc-id $VPCID \ --service-name com.amazonaws.ap-northeast-2.elasticloadbalancing \ --vpc-endpoint-type Interface \ --subnet-ids $PrivateSubnet1 $PrivateSubnet2 $PrivateSubnet3 \ --security-group-ids $CSN_SGID
Bash
복사
# vpc endpoint - elasticloadbalancing 생성
watch -d "aws ec2 describe-vpc-endpoints --query 'VpcEndpoints[*].[VpcEndpointId, ServiceName, State]' --output text"
Bash
복사
# [신규 터미널] vpc endpoint의 SericeName과 State 모니터링
파드와 Ingress ALB 생성
curl -s -O https://raw.githubusercontent.com/cloudneta/cnaeblab/master/_data/ingress1.yaml cat ingress1.yaml | yh
Bash
복사
# 파드와 Ingress ALB 생성
kubectl apply -f ingress1.yaml
Bash
복사
while true; do \ aws elbv2 describe-load-balancers \ --query 'LoadBalancers[*].[LoadBalancerName,State.Code]' \ --output table; \ done
Bash
복사
# elb 생성 확인 (Ctrl + Z로 중지)
kubectl annotate ingress ingress-2048 -n game-2048 "external-dns.alpha.kubernetes.io/hostname=ingress.$MyDomain" echo -e "2048 Game URL = http://ingress.$MyDomain"
Bash
복사
# externalDNS 연결

3. 실습 환경 삭제

1장 “Amazon EKS Fully Private Cluster 구성하기” 실습 환경 삭제와 Terraform 삭제 작업을 진행합니다.

3.1. 실습 자원 삭제

실습 애플리케이션 삭제
kubectl delete -f ingress1.yaml
Bash
복사
# 파드와 Ingress ALB 삭제
vpc endpoint - elasticloadbalancing 삭제
ELB_EPID=$(aws ec2 describe-vpc-endpoints | jq -r '.VpcEndpoints[] | select(.ServiceName=="com.amazonaws.ap-northeast-2.elasticloadbalancing") | .VpcEndpointId'); echo $ELB_EPID aws ec2 delete-vpc-endpoints --vpc-endpoint-ids $ELB_EPID
Bash
복사
# vpc endpoint - elasticloadbalancing 삭제
watch -d "aws ec2 describe-vpc-endpoints --query 'VpcEndpoints[*].[VpcEndpointId, ServiceName, State]' --output text"
Bash
복사
# [신규 터미널] vpc endpoint의 SericeName과 State 모니터링
[Private Cluster] kube-ops-view 삭제
helm uninstall kube-ops-view -n kube-system
Bash
복사
# kube-ops-view 삭제
eksctl로 EKS Fully Private Cluster 삭제
eksctl delete cluster --name $CLUSTER_NAME-Private
Bash
복사
# myeks-Private Cluster 삭제

3.2. Terraform 삭제

1장 두 번째 실습을 이어서 진행하려면 현재 생성 자원을 유지합니다.
만약 이어서 진행하지 않을 경우 아래 Terraform 삭제 작업을 진행합니다.
Terraform 자원 삭제
nohup sh -c "terraform destroy -auto-approve" > delete.log 2>&1 &
Bash
복사
# terraform 자원 삭제
Warning:
nohup으로 백그라운드로 실행하도록 변경했습니다. Terraform 삭제가 완료되면 정상적으로 자원 삭제 되었는지 확인을 합니다.(cat delete.log)

[번외] Terraform으로 Amazon EKS Fully Private Cluster 구성

번외로 앞서 실습 자원을 삭제하고 Terraform을 통해 Amazon EKS Fully Private Cluster를 구성합니다.
eks2.tf 파일
기존 eks.tf 파일을 eks.tf.old로 변경하고 eks2.tf 파일을 사용합니다.
mv eks.tf eks.tf.old
Bash
복사
다음 실습은 EKS - Endpoint Public Access 환경으로 eks.tf 파일을 사용합니다.
mv eks2.tf eks2.tf.old mv eks.tf.old eks.tf
Bash
복사
여기까지 1장의 첫 번째 실습인 Amazon EKS Fully Private Cluster 실습을 마칩니다.
수고하셨습니다 :)