※ AEWS는 '가시다'님이 속한 CloudNet@에서 진행하는 AWS EKS workshop에 대한 스터디 내용입니다.
0. 실습환경 구성
기본 인프라 배포 - 링크 ← AWS CloudFormation 페이지로 연결되며, 파라미터 입력 후 스택 실행
1. bastion 접속 후 기본정보확인
1) aws 자원확인
# 자격 구성 설정 없이 확인
aws ec2 describe-instances
# IAM User 자격 구성 : 실습 편리를 위해 administrator 권한을 가진 IAM User 의 자격 증명 입력
aws configure
AWS Access Key ID [None]: AKIA5...
AWS Secret Access Key [None]: CVNa2...
Default region name [None]: ap-northeast-2
Default output format [None]: json
# 자격 구성 적용 확인 : 노드 IP 확인
aws ec2 describe-instances
# 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에 속한 Subnet 정보 확인
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
## 퍼블릭 서브넷 ID 확인
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
2) Addon 정보 확인
# EKS Addon 정보 확인
aws eks describe-addon-versions --kubernetes-version 1.32 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output table
aws eks describe-addon-versions --kubernetes-version 1.31 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output table
aws eks describe-addon-versions --kubernetes-version 1.30 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output table
aws eks describe-addon-versions --kubernetes-version 1.29 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output table
## wc -l 로 갯수 비교
aws eks describe-addon-versions --kubernetes-version 1.32 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
aws eks describe-addon-versions --kubernetes-version 1.31 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
aws eks describe-addon-versions --kubernetes-version 1.30 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
aws eks describe-addon-versions --kubernetes-version 1.29 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
aws eks describe-addon-versions --kubernetes-version 1.28 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
aws eks describe-addon-versions --kubernetes-version 1.27 --query 'addons[].{MarketplaceProductUrl: marketplaceInformation.productUrl, Name: addonName, Owner: owner Publisher: publisher, Type: type}' --output text | wc -l
# EKS Add-on 별 전체 버전 정보 확인
ADDON=<add-on 이름>
ADDON=vpc-cni
# 아래는 vpc-cni 전체 버전 정보와 기본 설치 버전(True) 정보 확인
aws eks describe-addon-versions \
--addon-name $ADDON \
--kubernetes-version 1.31 \
--query "addons[].addonVersions[].[addonVersion, compatibilities[].defaultVersion]" \
--output text
# EKS 애드온의 버전별로 호환되는 EKS 버전을 확인하는 스크립트 https://malwareanalysis.tistory.com/760
ADDON_NAME=aws-ebs-csi-driver
aws eks describe-addon-versions --addon-name $ADDON_NAME | jq -r '
.addons[] |
.addonVersions[] |
select(.architecture[] | index("amd64")) |
[.addonVersion, (.compatibilities[] | .clusterVersion), (.compatibilities[] | .defaultVersion)] |
@tsv'
kubernetes 버전에 따른 Addon 기본 설치 버전 확인 (vpc-cni)
클러스터 버전 업그레이드 전 확인하면 좋을거 같다.
3) eksctl 사용연습
# eksctl help
eksctl
eksctl create
eksctl create cluster --help
eksctl create nodegroup --help
eksctl utils schema | jq
# 현재 지원 버전 정보 확인
eksctl create cluster -h | grep version
# eks 클러스터 생성 + 노드그룹없이
eksctl create cluster --name myeks --region=ap-northeast-2 --without-nodegroup --dry-run | yh
apiVersion: eksctl.io/v1alpha5
availabilityZones:
- ap-northeast-2c
- ap-northeast-2d
- ap-northeast-2a
...
# eks 클러스터 생성 + 노드그룹없이 & 사용 가용영역(2a,2c)
eksctl create cluster --name myeks --region=ap-northeast-2 --without-nodegroup --zones=ap-northeast-2a,ap-northeast-2c --dry-run | yh
apiVersion: eksctl.io/v1alpha5
availabilityZones:
- ap-northeast-2a
- ap-northeast-2c
...
# eks 클러스터 생성 + 관리형노드그룹생성(이름, 인스턴스 타입, EBS볼륨사이즈) & 사용 가용영역(2a,2c) + VPC 대역 지정
eksctl create cluster --name myeks --region=ap-northeast-2 --nodegroup-name=mynodegroup --node-type=t3.medium --node-volume-size=30 \
--zones=ap-northeast-2a,ap-northeast-2c --vpc-cidr=172.20.0.0/16 --dry-run | yh
...
managedNodeGroups:
- amiFamily: AmazonLinux2
desiredCapacity: 2
disableIMDSv1: true
disablePodIMDS: false
iam:
withAddonPolicies:
albIngress: false
appMesh: false
appMeshPreview: false
autoScaler: false
awsLoadBalancerController: false
certManager: false
cloudWatch: false
ebs: false
efs: false
externalDNS: false
fsx: false
imageBuilder: false
xRay: false
instanceSelector: {}
instanceType: t3.medium
labels:
alpha.eksctl.io/cluster-name: myeks
alpha.eksctl.io/nodegroup-name: mynodegroup
maxSize: 2
minSize: 2
name: mynodegroup
privateNetworking: false
releaseVersion: ""
securityGroups:
withLocal: null
withShared: null
ssh:
allow: false
publicKeyPath: ""
tags:
alpha.eksctl.io/nodegroup-name: mynodegroup
alpha.eksctl.io/nodegroup-type: managed
volumeIOPS: 3000
volumeSize: 30
volumeThroughput: 125
volumeType: gp3
metadata:
name: myeks
region: ap-northeast-2
version: "1.30"
privateCluster:
enabled: false
skipEndpointCreation: false
vpc:
autoAllocateIPv6: false
cidr: 172.20.0.0/16
clusterEndpoints:
privateAccess: false
publicAccess: true
manageSharedNodeSecurityGroupRules: true
nat:
gateway: Single
# eks 클러스터 생성 + 관리형노드그룹생성(AMI:Ubuntu 20.04, 이름, 인스턴스 타입, EBS볼륨사이즈, SSH접속허용) & 사용 가용영역(2a,2c) + VPC 대역 지정
eksctl create cluster --name myeks --region=ap-northeast-2 --nodegroup-name=mynodegroup --node-type=t3.medium --node-volume-size=30 \
--zones=ap-northeast-2a,ap-northeast-2c --vpc-cidr=172.20.0.0/16 --ssh-access --node-ami-family Ubuntu2004 --dry-run | yh
...
accessConfig:
authenticationMode: API_AND_CONFIG_MAP
addonsConfig: {}
apiVersion: eksctl.io/v1alpha5
availabilityZones:
- ap-northeast-2a
- ap-northeast-2c
cloudWatch:
clusterLogging: {}
iam:
vpcResourceControllerPolicy: true
withOIDC: false
kind: ClusterConfig
kubernetesNetworkConfig:
ipFamily: IPv4
managedNodeGroups:
- amiFamily: Ubuntu2004
desiredCapacity: 2
disableIMDSv1: true
disablePodIMDS: false
iam:
withAddonPolicies:
albIngress: false
appMesh: false
appMeshPreview: false
autoScaler: false
awsLoadBalancerController: false
certManager: false
cloudWatch: false
ebs: false
efs: false
externalDNS: false
fsx: false
imageBuilder: false
xRay: false
instanceSelector: {}
instanceType: t3.medium
labels:
alpha.eksctl.io/cluster-name: myeks
alpha.eksctl.io/nodegroup-name: mynodegroup
maxSize: 2
minSize: 2
name: mynodegroup
privateNetworking: false
releaseVersion: ""
securityGroups:
withLocal: null
withShared: null
ssh:
allow: true
publicKeyPath: ~/.ssh/id_rsa.pub
tags:
alpha.eksctl.io/nodegroup-name: mynodegroup
alpha.eksctl.io/nodegroup-type: managed
volumeIOPS: 3000
volumeSize: 30
volumeThroughput: 125
volumeType: gp3
metadata:
name: myeks
region: ap-northeast-2
version: "1.30"
privateCluster:
enabled: false
skipEndpointCreation: false
vpc:
autoAllocateIPv6: false
cidr: 172.20.0.0/16
clusterEndpoints:
privateAccess: false
publicAccess: true
manageSharedNodeSecurityGroupRules: true
nat:
gateway: Single
4) eks 배포
# 변수 확인***
echo $AWS_DEFAULT_REGION
echo $CLUSTER_NAME
echo $VPCID
echo $PubSubnet1,$PubSubnet2
# 옵션 [터미널1] EC2 생성 모니터링
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 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
# 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.31 --ssh-access --external-dns-access --dry-run | yh
...
vpc:
autoAllocateIPv6: false
cidr: 192.168.0.0/16
clusterEndpoints:
privateAccess: false
publicAccess: true
id: vpc-0505d154771a3dfdf
manageSharedNodeSecurityGroupRules: true
nat:
gateway: Disable
subnets:
public:
ap-northeast-2a:
az: ap-northeast-2a
cidr: 192.168.1.0/24
id: subnet-0d98bee5a7c0dfcc6
ap-northeast-2c:
az: ap-northeast-2c
cidr: 192.168.2.0/24
id: subnet-09dc49de8d899aeb7
# 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.31 --ssh-access --external-dns-access --verbose 4
...
023-04-23 01:32:22 [▶] setting current-context to admin@myeks.ap-northeast-2.eksctl.io
2023-04-23 01:32:22 [✔] saved kubeconfig as "/root/.kube/config"
...
eksctl 을 사용하면 cloudformation 스택이 생성된다.
5) eks 정보 확인
# krew 플러그인 확인
kubectl krew list
kubectl ctx
kubectl ns
kubectl ns default
kubectl get-all # 모든 네임스페이스에서 모든 리소스 확인
# eks 클러스터 정보 확인
kubectl cluster-info
Kubernetes control plane is running at https://50E14FE698DE0E5CA2055F72AB086163.gr7.ap-northeast-2.eks.amazonaws.com
...
eksctl get cluster
aws eks describe-cluster --name $CLUSTER_NAME | jq
aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint
https://50E14FE698DE0E5CA2055F72AB086163.gr7.ap-northeast-2.eks.amazonaws.com
## dig 조회 : 해당 IP 소유 리소스는 어떤것일까요? : 자신의 PC에서도 해당 도메인 질의 조회 해보자
APIDNS=$(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint | cut -d '/' -f 3)
dig +short $APIDNS
# eks API 접속 시도 : 도메인 or 출력되는 ip 주소로 https://<IP>/version 외부에서도 접속 가능!
curl -k -s $(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint)
curl -k -s $(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint)/version | jq
# 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
# 노드 정보 확인 : OS와 컨테이너런타임 확인
kubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zone
kubectl get node --label-columns=node.kubernetes.io/instance-type
kubectl get node
kubectl get node -owide
# 노드의 capacityType 확인
kubectl get node --label-columns=eks.amazonaws.com/capacityType
NAME STATUS ROLES AGE VERSION CAPACITYTYPE
ip-192-168-1-76.ap-northeast-2.compute.internal Ready <none> 19m v1.24.11-eks-a59e1f0 ON_DEMAND
ip-192-168-2-21.ap-northeast-2.compute.internal Ready <none> 19m v1.24.11-eks-a59e1f0 ON_DEMAND
# 인증 정보 확인 : 자세한 정보는 보안에서 다룸
kubectl get node -v=6
I0423 02:00:38.691443 5535 loader.go:374] Config loaded from file: /root/.kube/config
I0423 02:00:39.519097 5535 round_trippers.go:553] GET https://C813D20E6263FBDC356E60D2971FCBA7.gr7.ap-northeast-2.eks.amazonaws.com/api/v1/nodes?limit=500 200 OK in 818 milliseconds
...
cat /root/.kube/config
kubectl config view
kubectl ctx
## Get a token for authentication with an Amazon EKS cluster
aws eks get-token help
aws eks get-token --cluster-name $CLUSTER_NAME --region $AWS_DEFAULT_REGION
# 파드 정보 확인 : 온프레미스 쿠버네티스의 파드 배치와 다른점은? , 파드의 IP의 특징이 어떤가요? 자세한 네트워크는 2주차에서 다룸
kubectl get pod -n kube-system
kubectl get pod -n kube-system -o wide
kubectl get pod -A
kubectl top node
kubectl top pod -A
# kube-system 네임스페이스에 모든 리소스 확인
kubectl get-all -n kube-system
# 현재 네임스페이스에서 모든 리소스 확인
kubectl get-all
# 모든 파드의 컨테이너 이미지 정보 확인
kubectl get pods --all-namespaces -o jsonpath="{.items[*].spec.containers[*].image}" | tr -s '[[:space:]]' '\n' | sort | uniq -c
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon-k8s-cni:v1.19.0-eksbuild.1
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/amazon/aws-network-policy-agent:v1.1.5-eksbuild.1
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/coredns:v1.11.3-eksbuild.1
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/kube-proxy:v1.31.2-minimal-eksbuild.3
2 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/metrics-server:v0.7.2-eksbuild.1
# AWS ECR에서 컨테이너 이미지 가져오기 시도
docker pull 602401143452.dkr.ecr.ap-northeast-2.amazonaws.com/eks/coredns:v1.11.3-eksbuild.1
eks 가 public endpoint 으로 생성된 것을 확인
public 이기 때문에 외부에서 api endpoint address 를 입력하면 접근이 가능하다.
물론 토큰 인증을 받지 않았으니 403 error 가 발생한다.
하지만 버전 정보는 확인 가능하다.
bastion 에서 cli 을 통해서 eks 정보를 확인 할 수 있다.
api endpoint 를 도메인 질의 해보면 public ip 두개가 나오는데 이것은 재밌게도 control plane 에서 제일 앞단에 있는 NLB IP 이다.
curl 을 통해서도 api endpoint 에 접근이 가능한 것을 확인 할 수 있다.
디버그 레벨 정의를 통해서 node 목록을 조회할 때 .kube/config 를 읽어서 api endpoint 에 GET 요청을 보내는 것을 확인할 수 있다.
.kube/config file 에서 users 섹션에 aws eks get-token 명령을 통해서 임시 토큰을 발급받아 인증을 받는다.
-owide 옵션을 통해 자세한 정보를 확인 할 수 있다.
pod ip 정보를 보면 VPC 대역의 범위에 해당하는 것을 확인 할 수 있다.
2. 데이터플레인 실습
1) 노드 네트워크 정보 확인
# 노드 IP 확인 및 PrivateIP 변수 지정
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 에서 노드(파드)에 접속 가능하게 룰(Rule) 추가 설정
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 -o StrictHostKeyChecking=no ec2-user@$N1 hostname
ssh -i ~/.ssh/id_rsa -o StrictHostKeyChecking=no ec2-user@$N2 hostname
ssh ec2-user@$N1
exit
ssh ec2-user@$N2
exit
2) 노드 cgroup 정보 확인
Node cgroup version : v1(tmpfs), v2(cgroup2fs) - Link
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i stat -fc %T /sys/fs/cgroup/; echo; done
tmps 를 사용한다.
3) 노드 프로세스 및 스토리지 정보확인
## kubelet 상태 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo systemctl status kubelet; echo; done
## 노드 별 Process 구조확인
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
## EKS 내 manifest 및 kubelet-config 구성확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i ls /etc/kubernetes/manifests/; echo; done # EKS static pod X
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 | jq; echo; done
## 스토리지 정보 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i lsblk; echo; done
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i df -hT /; echo; done
노드에 접속해서 실행 중인 프로세스들의 계층 구조를 트리 형태로 확인한다.
containerd, containerd-shim 프로세스를 확인 할 수 있다.
쿠버네티스에서 동작하는 컨테이너 런타임 계층들은 다음과 같다.
- kubelet: 노드의 주요 에이전트로 컨테이너 런타임과 통신한다.
- containerd: 고수준 컨테이너 런타임으로, container life cycle 을 관리하고 container image 를 관리한다.
- runc: 저수준 컨테이너 런타임으로, 실제 컨테이너를 실행한다.
따라서 쿠버네티스는 kubelet을 통해 고수준의 컨테이너 런타임인 containerd에 명령을 내리고, containerd는 containerd-shim을 통해 저수준의 runc 컨테이너 런타임으로 파드를 생성하는 구조입니다.
kubelet-config.json 을 보면 인증 권한 있는 유저만 접근 허용하도록 설정했다.
4) EC2 메타데이터 확인 (IAM Role)
# 노드1 접속
ssh ec2-user@$N1
----------------
# IMDSv2 메타데이터 정보 확인
TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/ ;echo
eksctl-myeks-nodegroup-myeks-nodeg-NodeInstanceRole-4nyRq1rhLJLd
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/eksctl-myeks-nodegroup-myeks-nodeg-NodeInstanceRole-4nyRq1rhLJLd | jq
3. 관리 편의성을 위한 설정
1) kubectl 자동 완성 기능과 alias 사용하기
# 자동 완성 및 alias 축약 설정
source <(kubectl completion bash)
alias k=kubectl
complete -F __start_kubectl k'
2) kubectl cli 플러그인 매니저 쿠버네티스 크루(krew) 설치
# 설치
curl -fsSLO https://github.com/kubernetes-sigs/krew/releases/download/v0.4.4/krew-linux_amd64.tar.gz
tar zxvf krew-linux_amd64.tar.gz
./krew-linux_amd64 install krew
tree -L 3 /root/.krew/bin
# krew 확인
kubectl krew
kubectl krew update
kubectl krew search
kubectl krew list
3) krew 로 기타 플러그인 설치 및 사용 : df-pv get-all ktop neat oomd view-secret
# 설치
kubectl krew install df-pv get-all ktop neat oomd view-secret # mtail tree
# get-all 사용
kubectl get-all
kubectl get-all -n kube-system
# ktop 사용
kubectl ktop
# oomd 사용
kubectl oomd
# df-pv 사용
kubectl df-pv
# view-secret 사용 : 시크릿 복호화
kubectl view-secret
4. EKS 기본 사용 설정
1) 선언형 멱등성 알아보기
deployment replicas 를 3개로 지정했을 때, pod 3개를 전부 삭제해도 자동으로 pod 3개가 다시 생성된다.
이게 어떻게 가능한 것일까?
Control Plane 에는 kube controller manager 가 있다.
컨트롤러는 클러스터의 상태를 지속적으로 모니터링하고 현재 상태를 원하는 상태로 조정하는 역할을 수행한다.
Controller Manager 내에는 다양한 컨트롤러가 실행되며, 각 컨트롤러는 특정 리소스의 상태를 관리한다.
여기서 reconcile loop라는 개념이 존재하며, 이는 다음과 같은 순서로 동작한다:
- 주기적으로 리소스의 상태를 점검
- 현재 상태(current state)와 원하는 상태(desried state)의 차이를 감지
- 필요한 경우 리소스의 상태를 원하는 상태로 변경
이러한 지속적인 루프를 통해 클러스터는 항상 원하는 상태를 유지하려고 시도한다.
2) 서비스/디플로이먼트(mario 게임) 배포 테스트 with AWS CLB
# 터미널1 (모니터링)
watch -d 'kubectl get pod,svc'
# 수퍼마리오 디플로이먼트 배포
cat <<EOT > mario.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mario
labels:
app: mario
spec:
replicas: 1
selector:
matchLabels:
app: mario
template:
metadata:
labels:
app: mario
spec:
containers:
- name: mario
image: pengbai/docker-supermario
---
apiVersion: v1
kind: Service
metadata:
name: mario
spec:
selector:
app: mario
ports:
- port: 80
protocol: TCP
targetPort: 8080
type: LoadBalancer
EOT
kubectl apply -f mario.yaml
# 배포 확인 : CLB 배포 확인
kubectl get deploy,svc,ep mario
# 마리오 게임 접속 : CLB 주소로 웹 접속
kubectl get svc mario -o jsonpath={.status.loadBalancer.ingress[0].hostname} | awk '{ print "Maria URL = http://"$1 }'
pod 와 service type loadbalancer 가 생성됐다.
웹 접속을 확인할 수 있다.
AWS Console 을 보면 CLB 가 생성됐다.
[Q] AWS CLB는 어떻게 배포가 되었을 까요?
: Cloud Controller Manager 동작(아래 예시) - Docs → 하지만 부족한점? (동적 파드 IP 등)
- Node Controller : 클라우드 공급자가 응답을 멈춘 후 클라우드에서 노드가 삭제되었는지 확인하기 위해 클라우드 공급자를 확인합니다
- Route Controller : 기본 클라우드 인프라에서 경로를 설정하기 위한 것입니다.
- Service Contoller : 클라우드 공급자 로드 밸런서를 생성, 업데이트 및 삭제합니다 - Docs
서비스 컨트롤러는 서비스 오브젝트 생성, 업데이트 그리고 삭제 이벤트를 수신한 다음 해당 서비스에 대한 엔드포인트를 적절하게 구성한다(엔드포인트슬라이스(EndpointSlice)의 경우, kube-controller-manager가 필요에 따라 이들을 관리한다).
v1/Service : List , Get, Watch, Patch, Update
즉, cloud controller manager 는 service api 만 있고 endpoint slice 의 경우 kube controller manager 가 이들을 관리한다.
또한 CLB 의 경우 동적 IP 관리가 필요없지만 NLB, ALB 의 경우 동적 IP 관리가 필요하다. 이때는 aws load balancer controller 를 설치해야 한다.
2) 노드에 배포된 컨테이너 정보 확인 Containerd clients 3종 : ctr, nerdctl, crictl - 링크
# ctr 버전 확인
ssh ec2-user@$N1 ctr --version
# ctr help
ssh ec2-user@$N1 ctr
NAME:
ctr -
__
_____/ /______
/ ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/
containerd CLI
...
DESCRIPTION:
ctr is an unsupported debug and administrative client for interacting with the containerd daemon.
Because it is unsupported, the commands, options, and operations are not guaranteed to be backward compatible or stable from release to release of the containerd project.
COMMANDS:
plugins, plugin provides information about containerd plugins
version print the client and server versions
containers, c, container manage containers
content manage content
events, event display containerd events
images, image, i manage images
leases manage leases
namespaces, namespace, ns manage namespaces
pprof provide golang pprof outputs for containerd
run run a container
snapshots, snapshot manage snapshots
tasks, t, task manage tasks
install install a new package
oci OCI tools
shim interact with a shim directly
help, h Shows a list of commands or help for one command
# 네임스페이스 확인
ssh ec2-user@$N1 sudo ctr ns list
NAME LABELS
k8s.io
# 컨테이너 리스트 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ctr -n k8s.io container list; echo; done
CONTAINER IMAGE RUNTIME
28b6a15c475e32cd8777c1963ba684745573d0b6053f80d2d37add0ae841eb45 602401143452.dkr.ecr-fips.us-east-1.amazonaws.com/eks/pause:3.5 io.containerd.runc.v2
4f266ebcee45b133c527df96499e01ec0c020ea72785eb10ef63b20b5826cf7c 602401143452.dkr.ecr-fips.us-east-1.amazonaws.com/eks/pause:3.5 io.containerd.runc.v2
...
# 컨테이너 이미지 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ctr -n k8s.io image list --quiet; echo; done
...
# 태스크 리스트 확인
for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ctr -n k8s.io task list; echo; done
...
## 예시) 각 테스크의 PID(3706) 확인
ssh ec2-user@$N1 sudo ps -c 3706
PID CLS PRI TTY STAT TIME COMMAND
3099 TS 19 ? Ssl 0:01 kube-proxy --v=2 --config=/var/lib/kube-proxy-config/config --hostname-override=ip-192-168-1-229.ap-northeast-2.compute.internal
3) addon 실습
eks-node-monitoring-agent EKS 노드 상태 - Docs
# 기본 정보 확인
eksctl utils describe-addon-versions --kubernetes-version 1.31 | grep AddonName
eksctl utils describe-addon-versions --kubernetes-version 1.31 | grep AddonName | grep -i node
eksctl utils describe-addon-versions --kubernetes-version 1.31 --name eks-node-monitoring-agent | grep AddonVersion
"AddonVersion": "v1.0.1-eksbuild.2",
"AddonVersion": "v1.0.0-eksbuild.1",
# 설치 확인
watch -d kubectl get pod -n kube-system
kube-system eks-node-monitoring-agent-8lgdx 1/1 Running 0 110s
kube-system eks-node-monitoring-agent-zmpjm 1/1 Running 0 110s
# 노드 상태 정보 관찰 추가 : ContainerRuntimeReady,StorageReady,NetworkingReady,KernelReady
kubectl get nodes -o 'custom-columns=NAME:.metadata.name,CONDITIONS:.status.conditions[*].type,STATUS:.status.conditions[*].status'
kubecolor describe node
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
MemoryPressure False Sun, 02 Feb 2025 00:02:27 +0900 Sat, 01 Feb 2025 21:59:52 +0900 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Sun, 02 Feb 2025 00:02:27 +0900 Sat, 01 Feb 2025 21:59:52 +0900 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Sun, 02 Feb 2025 00:02:27 +0900 Sat, 01 Feb 2025 21:59:52 +0900 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Sun, 02 Feb 2025 00:02:27 +0900 Sat, 01 Feb 2025 22:00:07 +0900 KubeletReady kubelet is posting ready status
ContainerRuntimeReady True Sun, 02 Feb 2025 00:02:23 +0900 Sun, 02 Feb 2025 00:02:23 +0900 ContainerRuntimeIsReady Monitoring for the ContainerRuntime system is active
StorageReady True Sun, 02 Feb 2025 00:02:23 +0900 Sun, 02 Feb 2025 00:02:23 +0900 DiskIsReady Monitoring for the Disk system is active
NetworkingReady True Sun, 02 Feb 2025 00:02:23 +0900 Sun, 02 Feb 2025 00:02:23 +0900 NetworkingIsReady Monitoring for the Networking system is active
KernelReady True Sun, 02 Feb 2025 00:02:23 +0900 Sun, 02 Feb 2025 00:02:23 +0900 KernelIsReady Monitoring for the Kernel system is active
# 노드 상태 정보 확인
kubectl get nodes -o 'custom-columns=NAME:.metadata.name,CONDITIONS:.status.conditions[*].type,STATUS:.status.conditions[*].status'
NAME CONDITIONS STATUS
ip-192-168-1-164.ap-northeast-2.compute.internal MemoryPressure,DiskPressure,PIDPressure,Ready,ContainerRuntimeReady,StorageReady,NetworkingReady,KernelReady False,False,False,True,True,True,True,True
ip-192-168-2-20.ap-northeast-2.compute.internal MemoryPressure,DiskPressure,PIDPressure,Ready,ContainerRuntimeReady,StorageReady,NetworkingReady,KernelReady False,False,False,True,True,True,True,True
...>> 아래는 eks-node-monitoring-agent 미설치시 출력 정보
ip-192-168-1-164.ap-northeast-2.compute.internal MemoryPressure,DiskPressure,PIDPressure,Ready False,False,False,True
ip-192-168-2-20.ap-northeast-2.compute.internal MemoryPressure,DiskPressure,PIDPressure,Ready False,False,False,True
# 특정 노드 세부 정보
kubectl describe node <node-name>
kubecolor describe node <node-name>
# 노드 이벤트 정보
kubectl get events --field-selector involvedObject.kind=Node
kubectl get events -w --field-selector involvedObject.kind=Node
# 파드 로그 확인
kubectl krew install stern
kubectl stern -l app.kubernetes.io/instance=eks-node-monitoring-agent -n kube-system # EC2 재부팅 해두고 로그 확인
# 이벤트 확인 https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/node-health.html#node-health-issues
kubectl get events --field-selector=reportingComponent=eks-node-monitoring-agent # EC2 재부팅 해두고 로그 확인
LAST SEEN TYPE REASON OBJECT MESSAGE
60s Warning StorageReady node/ip-192-168-1-164.ap-northeast-2.compute.internal IODelays: Process (kworker/u4:1-xfs-cil/nvme0n1p1) (PID 22) incurred 14.6 seconds of I/O delay
Node auto repair : 문제 발생 시 자동으로 노드 교체 기능 - Docs
노드 자동 복구는 노드 상태를 지속적으로 모니터링하여 감지된 문제에 자동으로 대응하고 가능한 경우 노드를 교체하는 추가 기능입니다. 이렇게 하면 수동 개입을 최소화하면서 클러스터의 전반적인 가용성을 높일 수 있습니다. 상태 확인이 실패하면 노드에 새 포드가 예약되지 않도록 노드가 자동으로 차단됩니다.
노드 자동 복구는 자체적으로 kubelet 및 수동으로 삭제된 노드 객체의 Ready 조건에 대응할 수 있습니다. 노드 모니터링 에이전트와 페어링하면 노드 자동 복구가 감지되지 않는 더 많은 조건에 대응할 수 있습니다. 이러한 추가 조건에는 KernelReady, NetworkingReady, StorageReady가 포함됩니다.
이 자동 노드 복구는 클러스터 조인 실패, 응답하지 않는 kubelet, 액셀러레이터(디바이스) 오류 증가 등 간헐적인 노드 문제를 자동으로 해결합니다. 안정성이 향상되면 애플리케이션 가동 중지 시간을 줄이고 클러스터 작업을 개선할 수 있습니다. 노드 자동 복구는 DiskPressure, MemoryPressure, PIDPressure와 같이 보고되는 특정 문제를 처리할 수 없습니다. Amazon EKS는 AcceleratedHardwareReady NodeConditions에 대한 작업을 수행하기 전에 10분, 다른 모든 조건에 대해서는 30분을 기다립니다.
5. 자원 삭제
## - Amazon EKS 클러스터 ## 삭제(10분 정도 소요):
eksctl delete cluster --name $CLUSTER_NAME
## - (클러스터 삭제 완료 확인 후) AWS CloudFormation 스택 삭제 : **
aws cloudformation delete-stack --stack-name myeks
'AEWS' 카테고리의 다른 글
[AEWS 3주차] EKS Storage, Managed Node Groups (0) | 2025.02.23 |
---|---|
[AEWS 2주차] EKS Networking (0) | 2025.02.16 |
[AEWS 1주차] Amzaon EKS 설치 및 기본 사용 (0) | 2025.02.08 |