본 게시물은 CloudNet@에서 진행하는 AEWS (Amazon EKS Workshop Study) 스터디에 참여하며 정리한 내용입니다.
1. Amazon EKS 소개
Amazon EKS 사용자 가이드 공식 문서 (링크)에 따르면, Amazon Web Services (AWS)에서 제공하는 관리형 서비스로, Kubernetes (쿠버네티스) 컨트롤 플레인을 설치, 운영 및 유지 관리할 필요가 없는 "관리형 서비스"라고 설명되어 있다. 쿠버네티스 클러스터 아키텍처가 설명된 오픈 소스 쿠버네티스 문서 (링크)에 컨트롤 플레인에 대한 그림이 있다.
위 이미지에서 나온 컨트롤 플레인에 보면 cloud-controller-manager, etcd, kube-api-server, scheduler, Controller Manager 이렇게 5개 요소가 있는데, 해당 요소를 직접 설치하여 관리하는 대신 Amazon EKS라는 관리형 서비스를 생성하여 쿠버네티스 노드들을 활용하게 된다. 자세한 내용은 EKS 워크샵 설명(링크)에도 있으니 이를 참고하자.
쿠버네티스 오픈 소스는 https://github.com/kubernetes/kubernetes/releases 링크를 통해서도 새로 업데이트된 버전을 확인할 수가 있는데, 이 버전 번호에 대한 자세한 설명은 링크에서도 확인 가능하다.
x.y.z | x: 메이저 버전, y: 마이너 버전, z: 패치 버전
2. EKS 워크샵 실습 환경 소개 및 작업용 EC2 구성
본 스터디에서는 EKS 워크샵에 있는 "AWS 계정으로 시작"에 따라 스터디 시작 전 미리 AWS 계정을 준비하였으며, 실습 환경 구축에 보면 AWS Cloud9부터 kubectl 설치, eksctl 설치 등이 있는데 스터디장이신 가시다님께서 준비해 주신 AWS CloudFormation을 사용하여 편하게 스터디 참여를 할 수가 있었다. EKS 버전은 스터디를 진행하고 있는 2024년 3월을 기준으로 EKS 지원 add-on 및 K8s 생태계와 가장 잘 호환되고 검증된 애플리케이션이 많은 버전인 v1.28을 선택하여 진행하였다. 스터디 진행하는 AWS 환경을 이해해볼 겸 AWS 아키텍처 아이콘을 참고하여 아래와 같이 도식화해보았다.
아래와 같이 CloudFormation 템플릿을 다운로드 받은 다음에 AWS CLI (링크)를 사용해 실행해 보았다.
$ curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-1week.yaml
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 10373 100 10373 0 0 180k 0 --:--:-- --:--:-- --:--:-- 180k
$ aws cloudformation deploy --template-file myeks-1week.yaml --stack-name myeks --parameter-overrides KeyName=kp-ian SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - myeks
이후 다음 명령어를 실행하면 IP 주소를 알 수 있으며, 이 IP 주소로 SSH를 실행하여 Shell 로 접속하여 이후 작업을 진행한다. 접속할 SSH ID 및 Password는 위 CloudFormation 템플릿 파일에 있으니 참고하자.
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[*].OutputValue' --output text
작업용 EC2에 접속하였다면 IAM 사용자 자격 구성이 필요하다. 실습 편의를 위해 administrator 권한을 가진 IAM User의 자격 증명을 입력한다.
[root@myeks-host ~]# aws ec2 describe-instances
Unable to locate credentials. You can configure credentials by running "aws configure".
[root@myeks-host ~]# aws configure
AWS Access Key ID [None]: AKI..........
AWS Secret Access Key [None]: FQ.......................
Default region name [None]: ap-northeast-2
Default output format [None]: json
[root@myeks-host ~]# aws ec2 describe-instances
{
"Reservations": [
{
"Groups": [],
"Instances": [
{
"AmiLaunchIndex": 0,
"ImageId": "ami-025cebb6913219d99",...........
3. eksctl로 클러스터 생성하기
EKS 워크샵 내용 (링크)에서는 yaml 파일을 작성하여 eksctl 명령어로 클러스터를 생성하는데, 기본적인 옵션을 직접 eksctl 명령어에 적절한 파라미터 형태로 전달하는 방식 또한 가능하여 스터디에서는 이 방법을 사용해 보았다. 필요한 옵션 값을 환경 변수로 저장하여 활용하였다.
3.1. 필요한 환경 변수 준비하기
$AWS_DEFAULT_REGION 및 $CLUSTER_NAME은 작업용 EC2에서 이미 준비가 되어 있다. 이를 확인해보고 나머지 환경 변수에 대해 설정해보았다.
[root@myeks-host ~]# echo $AWS_DEFAULT_REGION
ap-northeast-2
[root@myeks-host ~]# echo $CLUSTER_NAME
myeks
[root@myeks-host ~]# export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId)
[root@myeks-host ~]# echo "export VPCID=$VPCID" >> /etc/profile
[root@myeks-host ~]# export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
rt PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
echo "export PubSubnet1=$PubSubnet1" >> /etc/profile
echo "export PubSubnet2=$PubSubnet2" >> /etc/profile
[root@myeks-host ~]# export PubSubnet2=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet2" --query "Subnets[0].[SubnetId]" --output text)
[root@myeks-host ~]# echo "export PubSubnet1=$PubSubnet1" >> /etc/profile
[root@myeks-host ~]# echo "export PubSubnet2=$PubSubnet2" >> /etc/profile
[root@myeks-host ~]# echo $VPCID
vpc-06019251cc08c519b
[root@myeks-host ~]# echo $PubSubnet1,$PubSubnet2
subnet-09c63523c434bcaec,subnet-0244ef5fa73c2f986
3.2. EKS 클러스터 생성하기
위 준비가 완료되었다면 아래 명령어를 통해 실행하면 된다.
eksctl create cluster --name $CLUSTER_NAME --region=$AWS_DEFAULT_REGION --nodegroup-name=$CLUSTER_NAME-nodegroup --node-type=t3.medium \
--node-volume-size=30 --vpc-public-subnets "$PubSubnet1,$PubSubnet2" --version 1.28 --ssh-access --external-dns-access --verbose 4
총 15-20분 정도 소요되니 잠시 기다려보자. 기다리는 동안에 다른 터미널을 1개 더 열어 아래 명령어를 실행하면 클러스터가 생성되었는지 여부를 확인하는 데 도움이 된다.
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,PrivateIPAdd:PrivateIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done
클러스터 생성이 완료되면 터미널 상태는 다음과 같이 변경되고
AWS 콘솔에서도 EKS가 배포된 내용을 확인할 수 있다 (혹 콘솔에서 갱신이 안되었다면 새로고침 버튼을 클릭해보자).
EKS 클러스터 생성이 완료가 된 이후부터는 kubectl 명령어를 통해 EKS 클러스터에 여러 명령을 실행할 수 있게 된다. 스터디 중 여러 가지를 실행해보면서 많은 것들을 확인을 하였는데, 그 중 한 가지만 블로그에 정리해 보고자 한다.
4. 생성된 EKS 클러스터 확인 - 엔드포인트 액세스 변경 (Public -> Public and private)
EKS 클러스터 정보를 확인하기 위해서는 "kubectl cluster-info" 라는 명령어를 사용하면 된다.
(awesian@myeks:N/A) [root@myeks-host ~]# eksctl get nodegroup --cluster $CLUSTER_NAME --name $CLUSTER_NAME-nodegroup
CLUSTER NODEGROUP STATUS CREATED MIN SIZE MAX SIZE DESIRED CAPACITY INSTANCE TYPE IMAGE ID ASG NAME TYPE
myeks myeks-nodegroup ACTIVE 2024-03-09T18:02:34Z 2 2 2 t3.medium AL2_x86_64 eks-myeks-nodegroup-eac71230-bb27-1b00-6c14-e2c96dfc5646 managed
(awesian@myeks:N/A) [root@myeks-host ~]# kubectl cluster-info
Kubernetes control plane is running at https://088CD22A78682CF5F017CFEE329E3C1A.gr7.ap-northeast-2.eks.amazonaws.com
CoreDNS is running at https://088CD22A78682CF5F017CFEE329E3C1A.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
뿐만 아니라 "eksctl get cluster" 명령어로도 확인이 가능하다. 한 가지 특이했던 점은 생성된 엔드포인트가 public이라는 것이다. Public이라는 의미는 해당 endpoint에 대한 네트워크 연결이 가능하다는 것을 의미하며, 해당 엔드포인트를 통해 Pod 생성 등을 진행하려면 추가 인증이 필요하나 간단한 version 확인은 public일 경우 별도의 인증을 거치지 않아도 위와 같이 생성한 EKS 클러스터에는 접근이 가능하였다.
콘솔에서 확인해 보더라도 API 서버 엔드포인트 액세스가 "Public"으로 나와있는 상황이다.
이를 "퍼블릭 및 프라이빗"으로 변경해보자. 변화 감지를 위해 총 3개의 터미널을 사용해보자. 2개 터미널은 모니터링 목적으로 사용한다.
# 터미널 A - 모니터링용 1
APIDNS=$(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint | cut -d '/' -f 3)
dig +short $APIDNS
while true; do dig +short $APIDNS ; echo "------------------------------" ; date; sleep 1; done
# 터미널 B - 모니터링용 2
N1=$(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})
N2=$(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})
while true; do ssh ec2-user@$N1 sudo ss -tnp | egrep 'kubelet|kube-proxy' ; echo ; ssh ec2-user@$N2 sudo ss -tnp | egrep 'kubelet|kube-proxy' ; echo "------------------------------" ; date; sleep 1; done
# 터미널 C - Public(본인 접속 IP만 제한)+Private 로 변경. 설정 후 약 8-10분 정도 이후 다른 터미널에 변화 감지 가능
aws eks update-cluster-config --region $AWS_DEFAULT_REGION --name $CLUSTER_NAME --resources-vpc-config endpointPublicAccess=true,publicAccessCidrs="$(curl -s ipinfo.io/ip)/32",endpointPrivateAccess=true
기다려보면 터미널 A에서 2개의 public IP 로 보이던 부분이 갑자기 내부 네트워크 서브넷으로 변경된 부분을 확인할 수 있었다.
그런데 오른쪽은 변화가 없었는데, 이는 Public 및 Private 모두 활성화되다보니 기존 kube-proxy 및 kubelet이 이미 연결을 맺고 있는 네트워크 연결을 굳이 종료할 필요가 없어서가 아닌가 생각된다.
이후 "kubectl" 명령어를 실행하면 동작하지 않는다. 다음과 같이 실행해보면 오류 메시지와 함께 보이는 IP 주소가 Public IP가 아니라는 것을 확인할 수 있다. 즉, 클러스터 설정이 변경되면서 이제는 Private IP로 Endpoint를 반환하는 것이다.
(awesian@myeks:N/A) [root@myeks-host ~]# kubectl get node -v=6
I0310 03:44:52.743735 18383 loader.go:395] Config loaded from file: /root/.kube/config
I0310 03:45:23.611890 18383 round_trippers.go:553] GET https://088CD22A78682CF5F017CFEE329E3C1A.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 in 30861 milliseconds
I0310 03:45:23.612005 18383 helpers.go:264] Connection error: Get https://088CD22A78682CF5F017CFEE329E3C1A.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500: dial tcp 192.168.1.51:443: i/o timeout
Unable to connect to the server: dial tcp 192.168.1.51:443: i/o timeout
(awesian@myeks:N/A) [root@myeks-host ~]# kubectl cluster-info
To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
Unable to connect to the server: dial tcp 192.168.2.122:443: i/o timeout
접속이 안된다는 것은 EKS Control plane 보안 그룹에서 서브넷에 접속 가능하도록 추가 설정을 해주어야 함을 의미한다. 다음 명령어를 통해 노드 보안 그룹에 myeks-host에서 노드(파드)에 접속 가능하도록 룰을 추가 설정하였다.
# EKS ControlPlane 보안그룹 ID 확인
aws ec2 describe-security-groups --filters Name=group-name,Values=*ControlPlaneSecurityGroup* --query "SecurityGroups[*].[GroupId]" --output text
CPSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*ControlPlaneSecurityGroup* --query "SecurityGroups[*].[GroupId]" --output text)
echo $CPSGID
# 노드 보안그룹에 myeks-host 에서 노드(파드)에 접속 가능하게 룰(Rule) 추가 설정
aws ec2 authorize-security-group-ingress --group-id $CPSGID --protocol '-1' --cidr 192.168.1.100/32
또한 kubelet과 kube-proxy도 private IP 주소로 접속하도록 설정을 변경해보자. 다음 명령어를 실행한다.
# kube-proxy rollout
kubectl rollout restart ds/kube-proxy -n kube-system
# kubelet 은 개별 노드에서 systemctl restart kubelet을 실행하는 형태로 적용. $N1과 $N2 환경 변수가 설정되어 있어야 함.
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo systemctl restart kubelet; echo; done
위 첫 번째 명령어를 실행한 다음에는 kube-proxy에 대한 연결이 private IP로 이루어지는 것을 볼 수 있으며,
두 번째 명령어가 잘 실행되면 kubelet 또한 연결이 private IP로 이루어지는 것을 볼 수 있다.
5. 리소스 정리
실습을 완료한 다음에는 반드시 리소스를 삭제하여 불필요한 비용 발생을 최소화하도록 하자.
- Amazon EKS 클러스터 삭제하기 (약 10분 정도 소요): eksctl delete cluster --name $CLUSTER_NAME
- 위 과정이 완료된 후 AWS CloudFormation 스택 삭제하기: aws cloudformation delete-stack --stack-name myeks
'Amazon EKS (Elastic Kubernetes Service)' 카테고리의 다른 글
[AEWS] 스터디 6주차 - EKS Security (0) | 2024.04.14 |
---|---|
[AEWS] 스터디 5주차 - EKS Autoscaling (0) | 2024.04.07 |
[AEWS] 스터디 4주차 - Observability (0) | 2024.03.31 |
[AEWS] 스터디 3주차 - EKS Storage & Nodegroup (0) | 2024.03.24 |
[AEWS] 스터디 2주차 - EKS Networking (0) | 2024.03.17 |