본문 바로가기

DevOps

[AWS EKS] (1) EKS 스터디 1주차 ( EKS 설치 및 사용 )

CloudNet@팀의 EKS 스터디 AEWS 3기에 작성된 자료를 토대로 작성합니다.

 

이번 시간에 다뤄볼 내용은 EKS가 어떻게 보안과 고가용성 두마리의 토끼를 잡는지 입니다 !! 

 

  CloudFormation으로 EKS 설치

✔️ 사전 준비 : AWS 계정, EC2 접속을 위한 SSH 키 페어, IAM 계정 생성 후 액세스 키 발급

✔️ myeks-1week.yaml : VPC, Subnet4개, EC2 1대 + 보안그룹(자신의 집 IP만 허용)

# yaml 파일 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-1week.yaml

# 배포
# aws cloudformation deploy --template-file ~/Downloads/myeks-1week.yaml --stack-name mykops --parameter-overrides KeyName=<My SSH Keyname> SgIngressSshCidr=<My Home Public IP Address>/32 --region <리전>
예시) aws cloudformation deploy --template-file ~/Downloads/myeks-1week.yaml \
     --stack-name myeks --parameter-overrides KeyName=kp-gasida SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32 --region ap-northeast-2

# CloudFormation 스택 배포 완료 후 EC2 IP 출력
aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[*].OutputValue' --output text
예시) 3.35.137.31

# ec2 에 SSH 접속 : root / qwe123
예시) ssh root@3.35.137.31
ssh root@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)
root@@X.Y.Z.A's password: qwe123
  • CloudFormation 스택 실행 시 위에서 파라미터를 기입하면, 해당 정보가 반영되어 배포됩니다.
1. <<<<< **EKSCTL MY EC2** >>>>>
    1. ClusterBaseName: EKS 클러스터의 기본 이름 (생성되는 리소스들의 주석에 접두어로 활용), EKS 클러스터 이름에 **'_(밑줄)'** 사용 불가!
    2. **KeyName**: EC2 접속에 사용하는 SSH 키페어 지정
    3. **SgIngressSshCidr**: eksctl 작업을 수행할 EC2 인스턴스를 접속할 수 있는 IP 주소 입력 (**집 공인IP**/32 입력)
    4. MyInstanceType: eksctl 작업을 수행할 EC2 인스턴스의 타입 (기본 t3.medium)
2. <<<<< **Region AZ** >>>>> : 리전과 가용영역을 지정
3. <<<<< **VPC Subnet** >>>>> : VPC, 서브넷 정보 지정

 

  • myeks-1week.yaml : VPC, Subnet4개, EC2 1대 + 보안그룹(자신의 집 IP만 허용)
  •  전체 구성도 : 위 그림 참고
  • VPC 1개(퍼블릭 서브넷 3개, 프라이빗 서브넷 3개), EKS 클러스터(Control Plane), 관리형 노드 그룹(EC2 3대), Add-on

  Cloudformation 동작 20분  웨이팅 후 접속! 

# SSH 접속
ssh -i koo-seoul.pem ec2-user@$(aws cloudformation describe-stacks --stack-name myeks --query 'Stacks[*].Outputs[0].OutputValue' --output text)

 

✔️ 접속 후 잘 설치되었는지 확인 (cloud-init이 뻑날수 있음)

# (옵션) cloud-init 실행 과정 로그 확인
tail -f /var/log/cloud-init-output.log

# 사용자 확인
whoami

# 기본 툴 및 SSH 키 설치 등 확인
kubectl version --client=true -o yaml
eksctl version
aws --version
ls /root/.ssh/id_rsa*

# 도커 엔진 설치 확인
docker info

 

✔️ 접속 후 자격증명 확인

# 자격 구성 설정 없이 확인
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

✔️ 접속 후 Add-on 잘 설치되었는지 확인

# 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'

✔️ 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
...
managedNodeGroups:
- amiFamily: Ubuntu2004
  ...
  ssh:
    allow: true
    publicKeyPath: ~/.ssh/id_rsa.pub

✔️ 배포 방법

# 변수 확인***
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"
...

✔️ 삭제 방법

  • Amazon EKS 클러스터 삭제(10분 정도 소요):
  • (클러스터 삭제 완료 확인 후) AWS CloudFormation 스택 삭제 : 
# Amazon EKS 클러스터 삭제(10분 정도 소요):  
eksctl delete cluster --name $CLUSTER_NAME

# (클러스터 삭제 완료 확인 후) AWS CloudFormation 스택 삭제 : 
aws cloudformation delete-stack --stack-name myeks

 

✅  EKS 아키텍처의 특징   

  • 컨트롤 플레인 ( 지휘자 )
    • ETCD
    • API server
    • 컨트롤러, 스케쥴러
  • 데이터 플레인 ( 연주자 )
    • EKS owned ENI
    • 노드 그룹
    • kubelet
    • kube-proxy

✅  컨트롤 플레인

  • 쿠버네티스를 제어 하기 위한 컴포넌트
  • AWS가 관리한다 
  • 고가용성을 고려한 설계가 되어있다. ( ELB, NLB, AZ, AutoScalingGroup )
  • API 서버, 컨트롤러, 스케쥴러, ETCD 등의 컴포넌트가 있다.
 
생성되는 VPC는 AWS에서 관리하는 Account가 관리하는 VPC 입니다.
  • 가용성 보장을 위해 가용영역을 나누고 etcd만 별개의 인스턴스로 분리하여 구성합니다.
  • 오토스케일링 그룹으로 각 컴포넌트들을 묶어 다수의 자원들이 안정적으로 유지됩니다.
  • 또한 각 가용영역 별로 트래픽 분산을 하는 환경을 구성하기 위해 Amazon CLB와 Amazon NLB를 사용합니다. 따라서 통칭 하여 ELB라고 표기된 자료들이 많습니다.

✅  데이터 플레인

  • 워커노드를 구성하기 위한 데이터 플레인 컴포넌트
  • 사용자 VPC에 생성됨 ( 사용자 어카운트에 배치 되기 때문에 사용자가 직접적으로 관리 및 운영)
  • POD, kubelet , Kube-proxy , Container-Runtime 등 
  • 노드 구성 방식들이 다양함 
    • 관리형
    • 자체형 : 사용자 정의 AMI를 사용해서 구성 , 유지관리 및 버전관리를 직접 수행
    • AWS Fargate : 컨테이너 형태의 구조가 아닌 마이크로 VM 형태의 가상머신으로 이루어짐
  • EKS Owned ENI 
    • 해당 네트워크 인터페이스는 소유자와 대상자가 서로 다른 어카운트로 이루어짐
    • == 크로스 어카운트 ENI
    • 해당 인터페이스를 통해 데이터 플레인과 컨트롤 플레인이 통신

 

 

  도전과제  1

[도전과제1] EKS Cluster Endpoint - Public Private : 직접 구성해보고 노드 → 제어부 연결 시 공인 도메인(IP)가 아닌, Private 도메인(EKS owned ENI) 연결 확인해보기

  • 먼저 현재 상태는 퍼블릭으로 지정되어 있음 ( IP가 퍼블릭 IP를 나타냄)
  • Public Private 상태의 Endpoint ? 
    • 노드는 프라이빗 서브넷에서 인스턴스화되고 (예: 로드 밸런서)는 퍼블릭 서브넷에서 인스턴스화 됩니다
(koo@myeks:default) [root@myeks-bastion ~]# kubectl get node -v=5

NAME                                               STATUS     ROLES    AGE   VERSION
ip-192-168-1-203.ap-northeast-2.compute.internal   NotReady   <none>   8d    v1.24.17-eks-5e0fdde
ip-192-168-2-42.ap-northeast-2.compute.internal    Ready      <none>   8d    v1.24.17-eks-5e0fdde
ip-192-168-3-125.ap-northeast-2.compute.internal   Ready      <none>   8d    v1.24.17-eks-5e0fdde
(koo@myeks:default) [root@myeks-bastion ~]# 
(koo@myeks:default) [root@myeks-bastion ~]# ss -tnp | grep kubectl
(koo@myeks:default) [root@myeks-bastion ~]# APIDNS=$(aws eks describe-cluster --name $CLUSTER_NAME | jq -r .cluster.endpoint | cut -d '/' -f 3)
(koo@myeks:default) [root@myeks-bastion ~]# dig +short $APIDNS
15.164.253.59
3.36.145.45
  • Private + Public (IP 주소제한) 으로 변경 
  • 변경 방법은 편한 방법을 사용하면 된다.
    • eks 명령어와 --resources-vpc-config 옵션을 통한 변경
    • UI 에서 Manage Endpoint access 클릭을 통한 변경
    • eksctl 의 설치 파일 config를 변경하여 변경
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
  • 이제 부터 동일한 DNS로 질의 할 시 Private IP를 리턴함
(koo@myeks:default) [root@myeks-bastion ~]# dig +short $APIDNS
192.168.1.233
192.168.3.82

# 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

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



(koo@myeks:default) [root@myeks-bastion ~]# kubectl get node -v=5

NAME                                               STATUS   ROLES    AGE   VERSION
ip-192-168-1-203.ap-northeast-2.compute.internal   Ready    <none>   8d    v1.24.17-eks-5e0fdde
ip-192-168-2-42.ap-northeast-2.compute.internal    Ready    <none>   8d    v1.24.17-eks-5e0fdde
ip-192-168-3-125.ap-northeast-2.compute.internal   Ready    <none>   8d    v1.24.17-eks-5e0fdde

 

  도전과제  2,3

[도전과제 2 3] EKS Cluster를 YAML 파일로 만들어서  Spot instance를 배포해보기

  • 먼저 우리 bastion 서버에 spot-instance.yaml이라는 파일을 만들것이다. 
  • eksctl로 dry-run 옵션을 통해 다음과 같이 생성 예정인 yaml을 먼저 확인한다.
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 > eksctl-instance.yaml
  • 기존에 설치한 eks cluster을 삭제하고 다시 배포할 것
# eks 클러스터 삭제 
eksctl delete cluster --name $CLUSTER_NAME
  • 파일을 통해서 노드그룹을 Spot instance로 새로 배포해보자.
# 위에 --dry-run으로 작성된 yaml에 다음과 같이 spot instance을 Custom nodeGroups으로 마지막 줄에 추가한다.
# node group 추가는 https://eksctl.io/usage/nodegroups/

# spot-cluster.yaml

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: spot-cluster
  region: us-west-2

managedNodeGroups:
- name: spot
  instanceTypes: ["c3.large","c4.large","c5.large","c5d.large","c5n.large","c5a.large"]
  spot: true


# `instanceTypes` defaults to [`m5.large`]
- name: spot-2
  spot: true

# On-Demand instances
- name: on-demand
  instanceTypes: ["c3.large", "c4.large", "c5.large"]
  • 스팟 인스턴스는 온디맨드 가격보다 저렴한 가격으로 제공되는 예비 EC2 용량을 사용합니다.
  •  스팟 인스턴스를 사용하면 사용하지 않는 EC2 인스턴스를 대폭 할인된 가격으로 요청할 수 있으므로 Amazon EC2 비용을 크게 낮출 수 있습니다.
  • 중단 허용 워크로드에만 사용할것을 권장
  • 배치 및 기계 학습 교육 워크로드, Apache Spark와 같은 빅 데이터 ETL, 대기열 처리 애플리케이션, 상태 비저장 API 엔드포인트가 포함
(Ted@spot-cluster:N/A) [root@myeks-host ~]# kubectl get nodes
NAME                                           STATUS   ROLES    AGE     VERSION
ip-192-168-42-87.us-west-2.compute.internal    Ready    <none>   3m39s   v1.30.8-eks-aeac579
ip-192-168-5-66.us-west-2.compute.internal     Ready    <none>   3m10s   v1.30.8-eks-aeac579
ip-192-168-53-200.us-west-2.compute.internal   Ready    <none>   3m16s   v1.30.8-eks-aeac579
ip-192-168-69-5.us-west-2.compute.internal     Ready    <none>   3m40s   v1.30.8-eks-aeac579
ip-192-168-79-233.us-west-2.compute.internal   Ready    <none>   3m15s   v1.30.8-eks-aeac579
ip-192-168-79-37.us-west-2.compute.internal    Ready    <none>   3m11s   v1.30.8-eks-aeac579
(Ted@spot-cluster:N/A) [root@myeks-host ~]# kubectl get nodes --show-labels
NAME                                           STATUS   ROLES    AGE     VERSION               LABELS
ip-192-168-42-87.us-west-2.compute.internal    Ready    <none>   3m56s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=spot-2,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=spot-2,eks.amazonaws.com/sourceLaunchTemplateId=lt-03748be385f0a04ce,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2a,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-42-87.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=m5.large,topology.k8s.aws/zone-id=usw2-az1,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2a
ip-192-168-5-66.us-west-2.compute.internal     Ready    <none>   3m27s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=spot,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c5a.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=spot,eks.amazonaws.com/sourceLaunchTemplateId=lt-07fb91f485fa24ffb,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2b,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-5-66.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c5a.large,topology.k8s.aws/zone-id=usw2-az2,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2b
ip-192-168-53-200.us-west-2.compute.internal   Ready    <none>   3m33s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=on-demand,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c3.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=on-demand,eks.amazonaws.com/sourceLaunchTemplateId=lt-019689480a66bd719,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2a,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-53-200.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c3.large,topology.k8s.aws/zone-id=usw2-az1,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2a
ip-192-168-69-5.us-west-2.compute.internal     Ready    <none>   3m57s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=spot-2,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=m5.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=spot-2,eks.amazonaws.com/sourceLaunchTemplateId=lt-03748be385f0a04ce,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-69-5.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=m5.large,topology.k8s.aws/zone-id=usw2-az3,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2c
ip-192-168-79-233.us-west-2.compute.internal   Ready    <none>   3m32s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=on-demand,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c3.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=ON_DEMAND,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=on-demand,eks.amazonaws.com/sourceLaunchTemplateId=lt-019689480a66bd719,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-79-233.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c3.large,topology.k8s.aws/zone-id=usw2-az3,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2c
ip-192-168-79-37.us-west-2.compute.internal    Ready    <none>   3m28s   v1.30.8-eks-aeac579   alpha.eksctl.io/cluster-name=spot-cluster,alpha.eksctl.io/nodegroup-name=spot,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=c5a.large,beta.kubernetes.io/os=linux,eks.amazonaws.com/capacityType=SPOT,eks.amazonaws.com/nodegroup-image=ami-0ddee5cc7ce7c43b9,eks.amazonaws.com/nodegroup=spot,eks.amazonaws.com/sourceLaunchTemplateId=lt-07fb91f485fa24ffb,eks.amazonaws.com/sourceLaunchTemplateVersion=1,failure-domain.beta.kubernetes.io/region=us-west-2,failure-domain.beta.kubernetes.io/zone=us-west-2c,k8s.io/cloud-provider-aws=e852366363eb923c947c162543d3ca1e,kubernetes.io/arch=amd64,kubernetes.io/hostname=ip-192-168-79-37.us-west-2.compute.internal,kubernetes.io/os=linux,node.kubernetes.io/instance-type=c5a.large,topology.k8s.aws/zone-id=usw2-az3,topology.kubernetes.io/region=us-west-2,topology.kubernetes.io/zone=us-west-2c
  • spot cluster을 삭제
# 기존에 설치한 eks cluster을 삭제하고 다시 배포할 것
eksctl delete cluster -f spot-cluster.yaml

 

  도전과제  4

[도전과제 4 ]

Nitro 시스템

x86 vs ARM ? 
# 요즘이라고 하기엔 시간이 많이 흘렀지만 화두가 되고 있는 x86이냐? 

# 위 논제에 대한 선택 기준에 대해서..

  • 사용하려는 아키텍처 (ARM) 에 대한 준비가 되어 있는가? 애초에 준비가 되어 있지 않다면 의미가 없습니다. ( 물론 사용하기로 하고 준비할수도 있죠 )
  • 단일코어의 성능이 중요한가? 보편적으로 x86 계열이 ARM 계열보다 단일 코어의 성능이 좋습니다. 만약 특정한 작업을 빠르게 수행하고 응답하길 원한다면 x86을 선택하는것이 좋습니다 (db와 같은 )
  • 단일 코어 성능은 낮지만 물리 CPU가 많은것이 중요하다면 ARM이 보편적으로 좋습니다. ( WEB , WAS 등 )
  • 비용 압박이 심하다면? 무조건 ARM이 유리합니다. 
# 먼저 클러스터를 배포한다.
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

# 이후에 노드그룹을 추가한다.
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: myeks
  region: ap-northeast-2

managedNodeGroups:
  - name: graviton
    instanceTypes:
    - t4g.medium
    minSize: 1
    maxSize: 3
    desiredCapacity: 1
    privateNetworking: true
    subnets:
    - subnet-0db86b686270585fd
  • 이와 같이 config.yaml 을 만든후에 다음과 같이 노드그룹 추가 가능.
# 아까 만들어둔 config-gravition.yaml
eksctl create nodegroup --config-file=config-gravition.yaml
  • nodegroup 추가됨 
  • T4g 인스턴스는 대규모 마이크로서비스, 중소형 데이터베이스, 가상 데스크톱 및 비즈니스 크리티컬 애플리케이션에 주로 사용됨

 

  내가만든 도전과제  

[도전과제 9 ] EKS Cluster privatelink-access 패턴을 이용하여 접속해보기 

- 먼저 다음 블로그는 트래픽을 인터넷에 노출하지 않고 VPC와 Cross Account에 걸쳐 연결을 제공하는 다양한 서비스중 

- 엔드포인트 서비스인 PrivateLink을 사용한 연결방식을 소개합니다.

- PrivateLink 서비스는 인터페이스 VPC 엔드포인트의 인터페이스 역할  VPC 내부에 직접 생성됩니다.

- A service powered by PrivateLink is created directly inside your VPC as an interface VPC endpoint.

 

Amazon VPC 연결 옵션

트래픽을 공용 인터넷에 노출하지 않고 VPC와 계정 전반에 걸쳐 연결을 제공하는 다양한 AWS 기본 네트워킹 서비스가 여럿 있습니다. 

  • VPC Peering – which creates a connection between two or more VPCs that allow endpoints to communicate as if they were on the same network. It can connect VPCs that are in different accounts and in different regions.
  • AWS Transit Gateway – which acts as a highly scalable cloud router connecting multiple VPCs in a region with a hub-and spoke architecture. Transit Gateway works across accounts using AWS Resource Access Manager (AWS RAM).
  • AWS PrivateLink – which provides private connectivity to a service in one VPC that can be consumed from a VPC in the same account or from another account. PrivateLink supports private access to customer application services, AWS Marketplace partner services, and to certain AWS services.

 

git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd terraform-aws-eks-blueprints/patterns/privatelink-access
  • 테라폼을 통해 private-link 배포 (엔드포인트 서비스, 엔드포인트 15종 )
terraform init
terraform apply -target=module.eventbridge -target=module.nlb --auto-approve
terraform apply --auto-approve
  • eks 명령 을 이용한 엔드포인트 private access로 전환
aws eks update-cluster-config \
--region us-west-2 \
--name privatelink-access \
--resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true

 

EKS API 서버 엔드포인트의 프라이빗 호스팅 영역이 작동했습니다.

    • PrivateLink 액세스는 NLB를 통해 서비스 제공업체 VPC에서 프라이빗인 EKS 클러스터의 프라이빗 API 엔드포인트까지 작동했습니다.
    • EKS Kubernetes API 서버 엔드포인트가 준비되어 작동합니다.
    • AWS Session Manager을 통한 접속 
# private Endpoint
COMMAND="curl -ks https://91FDCFCB79B48A9D00D839F56B74F911.gr7.us-west-2.eks.amazonaws.com/readyz"

# AWS의 노드관리 - 명령실행에서 RunShellScript라는 Document을 찾아서 적용
COMMAND_ID=$(aws ssm send-command --region us-west-2 \
   --document-name "AWS-RunShellScript" \
   --parameters "commands=[$COMMAND]" \
   --targets "Key=instanceids,Values=i-0a77c835dd82d125c" \
   --query 'Command.CommandId' \
   --output text)


aws ssm get-command-invocation --region us-west-2 \
   --command-id $COMMAND_ID \
   --instance-id i-0a77c835dd82d125c \
   --query 'StandardOutputContent' \
   --output text

 

# 세션관리자 접속 후
aws eks update-kubeconfig --region us-west-2 --name privatelink-access

# kubectl 명령어 적용
kubectl get pods -A
NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE
kube-system   aws-node-4f8g8             1/1     Running   0          1m
kube-system   coredns-6ff9c46cd8-59sqp   1/1     Running   0          1m
kube-system   coredns-6ff9c46cd8-svnpb   1/1     Running   0          2m
kube-system   kube-proxy-mm2zc           1/1     Running   0          1m

이와 같이 세션 관리자를 통해 ssh 접근에 대한 보안성을 약화를 방지 할수 있다.

 

 

시스템 매니저로 SSH가 아닌 원격접속 - 선택이 아닌 필수일수도...!!

  • AWS System Manager - Session Manager
  • 시스템 매니저를 통한 원격 접속은 SSH가 아님 따라서 보안에 유리함
  • AWS 리소스 운영에 도움이 되는 기능을 제공.
  • 5 종류의 범주로 분류 되며 각 범주 내에 다양한 기능이 존재합니다