EKS Study - w01

wdb·2024년 3월 9일

EKS

  • AWS EKS(Elastic Kubernetes Service)는 AWS에서 제공하는 관리형 kubernetes 서비스입니다.
  • Kubernetes의 컨트롤 플레인 or 노드를 직접 설치, 운영, 관리할 필요가 없습니다. -> 관리형 서비스
  • EKS는 컨트롤 플레인과 워커 노드로 구성되어 있습니다.
  • 복수 개의 가용영역에 Kubernetes의 컨트롤 플레인을 배치하고 자동으로 크기를 조정합니다.
  • EKS 컨트롤 플레인은 제어 영역 인스턴스의 크기를 조정하고, 상태를 감지하여 비정상일 경우 교체하며, 버전 업데이트 및 패치를 진행합니다. 이 모든 작업은 자동으로 이루어집니다.

Kubernetes 아키텍처

API

  • kuberctl 명령어, 권한, 문법을 확인하여 API 요청을 접수하고 클러스터 관리 작업을 실행합니다.

ETCD 저장소

  • 클러스터의 모든 구성 요소의 상태를 저장하는 분산 데이터베이스로, 워크노드의 상태가 Key-Value 값으로 저장됩니다.

컨트롤러 매니저

  • 클러스터에 여러 컨트롤러를 실행하여 시스템의 사태를 관리하고 조정합니다.

스케줄러

  • 새로운 파드에 적합한 노드를 할당합니다.

데이터 플레인

  • 클러스터에서 실행되는 실제 작업을 처리합니다.

kubelet

  • 각 노드에서 실행되며, 노드의 상태 정보를 수집하여 컨트롤 플레인에 전달합니다.
  • kubelet이 전달한 정보는 ETCD 저장소에 저장됩니다.

kube-proxy

  • 네트워크 프록시 서비스로 클러스터 내부 및 외부에서의 네트워크 트래픽을 관리합니다.

EKS 구성

  • EKS 컨트롤 플레인 노드는 AWS가 관리하고 있으며, 사용자는 워커노드를 구성해야 합니다.
  • 사용자는 kubectl 도구를 통해 EKS 컨트롤 플레인과 통신해야 합니다.
  • EKS의 엔드포인트는 퍼블릭 or 프라이빗 서브넷에 배치할 수 있습니다.

EKS의 퍼블릭 엔드포인트

  • 기본적으로 EKS 클러스터는 퍼블릭 서브넷에 엔드포인트를 배치합니다.
  • 클러스터 VPC 내부에서의 Kubernetes API 요청은 VPC 외부로 나가지만 AWS 네트워크 내부에서 벗어나지 않습니다.
  • 인터넷을 통해 클러스터 API 서버에 액세스할 있습니다. 소스 CIDR 블록을 제하는 방식으로 특정 네트워크 환경에 있는 노드만 엔드포인트에 접근하게 할 수 있습니다.

EKS의 퍼블릭 & 프라이빗 엔드포인트

  • 클러스터 VPC 내 Kubernetes API 요청에 대해서는 프라이빗 엔드포인트를 사용합니다.
  • 다른 네트워크 환경에는 퍼블릭 엔드포인트를 사용합니다.

EKS의 프라이빗 엔드포인트

  • 클러스터 API 호출은 클러스터 VPC 혹은 해당 VPC와 통신가능한 네트워크 내에서 발생해야 합니다.
  • 인터넷을 통해 API 서버와 통신할 수 없습니다.
  • 클러스터 API 서버의 엔드포인트는 퍼블릭 DNS 서버에 의해 VPC의 프라이빗 IP 주소로 확인됩니다.

EKS 배포

기본 환경 배포

  • CloudFormation에서 템플릿을 이용하여 기본 환경을 배포합니다.
  • KeyName에 인스턴스 접속 시 사용할 키 페어를 선택합니다.
  • SgIngressSSHCIDR에 인스턴스 접속 시 허용할 IP 대역을 입력합니다
  • 스택 생성이 출력 탭에서 인스턴스의 퍼블릭 IP 주소를 확인합니다.
  • 네트워크 인터페이스의 ControlPlaneSecurityGroup을 사용하는 ENI의 경우 ENI의 소유자, 요청자, 인스턴스 소유자가 다릅니다. EKS를 사용할 경우 AWS 관리 영역인 컨트롤 플레인과, 사용자 관리 영역인 워커 노드로 구분되기 때문에 해당 ENI의 소유는 사용자지만, 요청자와 인스턴스 소유자는 다른 계정의 ID로 확인됩니다.

EKS 클러스터 배포

  1. 인스턴스에 SSH 접속을 진행합니다.
ssh -i <키 페어 이름> ec2-user@<인스턴스 공인 IP>
  1. aws configure 명령을 이용해 AWS cmd 명령을 사용할 수 있게 합니다.
    편의를 위해 Administrator Access 권한을 부여받은 IAM 사용자의 액세스키를 이용합니다.
  2. 인스턴스에서 기본 정보를 확인합니다.
# 사용자 확인
whoami

# 기본 도구 버전 확인 
kubectl version --client=ture -o yaml | yj
eksctl version
aws --version

# SSH 키 설치 확인
ls /root.ssh/id_rsa*

# 도커 엔진 설치 확인
docker info


4. eksctl 명령을 사용하기 위해 VPC 정보를 조회하여 서브넷 등의 항목을 환경변수로 지정합니다.

# EKS를 배포할 VPC 정보를 환경변수로 설정
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq Vpcs[]
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq Vpcs[].VpcId
aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId
export VPCID=$(aws ec2 describe-vpcs --filters "Name=tag:Name,Values=$CLUSTER_NAME-VPC" | jq -r .Vpcs[].VpcId)
echo "export VPCID=$VPCID" >> /etc/profile
echo $VPCID
# EKS를 배포할 VPC의 서브넷 정보를 환경변수로 설정
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --output json | jq
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$VPCID" --output yaml
# VPC 퍼블릭 서브넷 정보를 환경변수로 설정
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" | jq
aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text
export PubSubnet1=$(aws ec2 describe-subnets --filters Name=tag:Name,Values="$CLUSTER_NAME-PublicSubnet1" --query "Subnets[0].[SubnetId]" --output text)
export 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
echo $PubSubnet1
echo $PubSubnet2


5. EKS 클러스터 생성 (15분 정도 소요)

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


6. EKS 정보 확인

# eks 클러스터 정보 확인
kubectl cluster-info
Kubernetes control plane is running at https://{###}.gr7.ap-northeast-2.eks.amazonaws.com

# eks 노드 그룹 정보 확인
eksctl get nodegroup --cluster $CLUSTER_NAME --name $CLUSTER_NAME-nodegroup
aws eks describe-nodegroup --cluster-name $CLUSTER_NAME --nodegroup-name $CLUSTER_NAME-nodegroup | jq

# 노드의 capacityType 확인
kubectl get node --label-columns=eks.amazonaws.com/capacityType

# 파드 정보 확인 
kubectl get pod -n kube-system

# 모든 파드의 컨테이너 이미지 정보 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
  1. 워커노드 정보 확인
# 노드 IP 확인 및 프라이빗 IP 환경변수 지정
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 table
kubectl get node --label-columns=topology.kubernetes.io/zone
kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2a
kubectl get node --label-columns=topology.kubernetes.io/zone --selector=topology.kubernetes.io/zone=ap-northeast-2c
**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})
****echo $N1, $N2
echo "export N1=$N1" >> /etc/profile
echo "export N2=$N2" >> /etc/profile

# eksctl-host 에서 노드의IP나 coredns 파드IP로 ping 테스트
ping <IP>
ping -c 1 $N1
ping -c 1 $N2

# 노드 보안그룹 ID 확인
aws ec2 describe-security-groups --filters Name=group-name,Values=*nodegroup* --query "SecurityGroups[*].[GroupId]" --output text
NGSGID=$(aws ec2 describe-security-groups --filters Name=group-name,Values=*nodegroup* --query "SecurityGroups[*].[GroupId]" --output text)
echo $NGSGID
echo "export NGSGID=$NGSGID" >> /etc/profile

# 노드 보안그룹에 eksctl-host 에서 노드 혹은 파드에 접속 가능하게 룰 추가 설정
aws ec2 authorize-security-group-ingress --group-id $NGSGID --protocol '-1' --cidr **192.168.1.100/32**

# eksctl-host 에서 노드의IP나 coredns 파드IP로 ping 테스트
ping -c 2 $N1
ping -c 2 $N2

# 워커 노드 SSH 접속
**ssh -i ~/.ssh/id_rsa ec2-user@$N1 hostname
ssh -i ~/.ssh/id_rsa ec2-user@$N2 hostname**
**ssh ec2-user@$N1 
exit**
**ssh ec2-user@$N2
exit**
  1. 노드의 네트워크 정보 확인
# AWS VPC CNI 사용 확인
kubectl -n kube-system get ds aws-node
kubectl describe daemonset aws-node

# 파드 IP 확인
kubectl get pod -n kube-system -o wide


# 노드 정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i hostname; echo; done
  1. 노드의 cgroup version 확인
or i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i stat -fc %T /sys/fs/cgroup/; echo; done
  1. 노드의 process 정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo systemctl status kubelet; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo pstree; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ps afxuwww; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ps axf |grep /usr/bin/containerd; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ls /etc/kubernetes/manifests/; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ls /etc/kubernetes/kubelet/; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i cat /etc/kubernetes/kubelet/kubelet-config.json; echo; done
  1. 노드의 스토리지 정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i lsblk; echo; done

애플리케이션 배포

# 배포를 위한 yaml 다운로드
curl -s -O https://raw.githubusercontent.com/gasida/PKOS/main/1/mario.yaml
kubectl apply -f mario.yaml
cat mario.yaml | yh

# 배포 확인
kubectl get deploy,svc,ep mario

# 접속 URL 조회
kubectl get svc mario -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Mario URL = http://"$1 }'

0개의 댓글