[AWES 3기] 1주차 스터디 내용 정리

ajufresh·2025년 2월 8일
0

[사전과제] Awazon EKS Overview

링크: https://www.youtube.com/watch?v=E49Q3y9wsUo

Kubernetes 기본 개념

  • 도커에서 컨테이너를 실행한다는 것 = 단일 머신에서 실행하는 것
    • 애플리케이션을 운영하다보면 사용량이 늘어남에 따라 서버 증설이 필요
    • 컨테이너가 아주 많아진 상태에서, 컨테이너 하나만 장애가 난다면?
      • 관리자가 서버에 들어가서 다시 되살리거나, 특정 노드를 한 대 더 증설하거나 하는 조치를 취해야 함 (운영부담이 커짐)
    • 컨테이너 관리가 필요 ⇒ 관리해주는걸 “컨테이너 오케스트레이터”라고 함
  • AWS에서는 대표적으로 EKS, ECS라는 관리형 Control plane을 제공해줌
    • 둘 다 컨테이너 오케스트레이션이지만, 차이가 있음
      • ECS: AWS에서 제작한 컨테이너 서비스. “쉽다” “단순하다”
        - EKS: 관리형 쿠버네티스 서비스. “유연하다” “자유롭다”
  • 쿠버네티스의 클러스터 구조
    • 마스터 노드
      • API 서버: kubectl로 명령어를 받으면 내부적으로는 API 호출
      • 컨트롤러 매니저: 각각의 컨트롤러가 독립적으로 실행
      • 스케줄러: 어느 노드에 파드가 배포될 것인가? (우선순위에 따라 결정)
      • etcd: 쿠버네티스 클러스터에 생성되는 모든 데이터가 여기에 저장
      • 이중화가 되어 있음. 여러 대의 마스터 노드가 있으며 이런것들을 묶은게 컨트롤 플레인
    • 워커 노드
      • kubelet: API 서버에서 수신을 받아서 컨테이너를 띄우는 역할
      • kube-proxy: 네트워크에 대한 설정 역할
      • pod: 배포 최소 단위. 컨테이너가 하나 이상 실행될 수도 있음
    • 컨트롤 플레인의 아키텍처
      • API 서버는 2대 이상, etcd는 3대 이상
      • API 서버는 오토스케일링 그룹이 묶여 있음
      • API 서버는 AWS에서 관리하는 VPC에, 데이터 플레인은 사용자 VPC에 있음
      • VPC가 다르면 네트워크가 단절될텐데 어떻게 통신함?
        => Cross Account ENI가 있음. 내부적으로 인터페이스를 통해 private하게 통신

Kubernetes 통신 방법

  1. public
  • 인터넷을 통해 API에 접근함
  • 개발과정에서 편리하게 사용할 수 있으나, 보안상 좋지 않음
  • API 서버와 데이터 플레인간 통신을 할때도 인터넷을 통해 통신하기 때문에 비효율적임
  1. public + private
  • API 서버가 인터넷 망으로 연결되는건 동일하나, 데이터 플레인간 통신은 private하게 통신
  • Route 53에 private hosted zone이라는게 있어서 같은 도메인으로 요청하면 private으로 통신
  1. private
  • 보안상 가장 좋으나, 번거로움. 노트북에서는 연결이 안됨. bastion host같은걸 두고 kubectl을 설치해서 사용해야 함
  • 인터넷으로 나갈 수 없으니 vpc endpoint를 만들어야 함

Kubernetes Configuration

  • 현재 클러스터의 상태(current state)와 원하는 상태(desired state)를 YAML에 저장
  • 비교를 해서 변경점이 생기면 sync를 맞춰줌
  • 선언형 vs 명령형

Kubernetes Object


Pod를 중심으로 많은 Object가 모여있음

  • Pod: 배포의 가장 최소 단위
  • Replica Set: Seloector를 기반으로 하여 Pod의 스케줄, 스케일링, 삭제를 담당
  • Deployment: 배포 전략. 롤링 업데이트를 한다거나, 카나리배포를 한다거나~ 이런 전략을 세움
    • Deployment를 생성하면 ReplicaSet을 생성하고, 이게 Pod를 생성하는 식으로 하기 때문에 보통 Deployment를 생성함
    • Deployment - Replication set(version=1, count=3) - 3개의 Pod
      • 이미지가 갱신되면?
      • Deployment - Replication set(version=2, count=3) - 새로운 Pod 생성 후 정상실행되면 기존에 있는 파드 삭제 (롤링업데이트 방식으로)

Workload 생성을 위한 기본 컨셉

  • Sidecar: 보조석. 애플리케이션이 있으면 fluentbit 같이 로그를 수집하는게 따라 담을 . 수있는 경량의 컨테이너 같은걸 실행하게 하는 것
  • DaemonSet: 워커노드가 10대 있다. 하면 하나의 파드에 동일하게 실행해야 된다. 한대씩 실행하는걸 보장. kubeproxy가 이거임 모든 노드에 1개씩 다 들어감
  • Addon: 플러그인

Amazon EKS Networking

  • 물리적인 서버에 물리적인 IP가 있고, 도커를 설치하면 가상의 Bridge Network가 만들어짐 (172.~)
    • Host: 설정하면 컨테이너가 호스트의 IP를 그대로 사용 (포트 충돌 할수도)
    • Container: 특정 Container의 네트워크를 다른 Container에서 공유해서 사용
      • 파드가 중간에 Pause라는걸 놓고 통신하게 함
    • None: 네트워크 인터페이스 설정 X
  • Kubernetes 네트워킹
    • 컨테이너들은 각각 IP가 있음 (가상의 IP)
    • 컨테이너 1 ↔ 통신을 위해 Overlay 네트워크 모드를 사용
    • CNI를 지원하기 위해 VPC CNI라는걸 사용
    • Pod도 VPC IP를 사용하게 됨 (Overlay가 아닌 일반 VPC 네트워킹)
      => 여기에 Warm IP Pool이 있음. 여기에서 IP 꺼내서 할당하는거 (인스턴스만큼 네트워크 인터페이스 수 제한이 있음)

Kubernetes Service

  • 파드는 언제든 IP가 바뀔 수 있고, 변경할 수 있음 (가변적임)
  • 로드밸런서처럼 파드 앞단에 대표 IP를 만드는걸 하는데, 이걸 서비스라고 함
  • 유형
    • Cluster IP: 클러스터 내부에서 서비스에 접속하는 용도 (파드간 통신)
      • iptables -t nat -nL PREROUTING
      • iptables -t nat -nL KUBE-SERVICES
      • iptables -t nat -nL KUBE-SVC-3PEDVOHU4LLKSHDI (파드 찾음 여기서)
      • iptables -t nat -nL KUBE-SEP-LDFTIGB
    • Node Port: 인스턴스에서 포트를 open해서 pod와 통신
      • 3000~32767 사이에서 사용.
      • 위랑 마찬가지로 iptables 사용
    • Load Balancer: LB를 두고 노드와 통신하는거
      • 앞에 로드밸런서를 두고 뒷단에 서버를 분배해주는 역할을 함
      • CLB말고 ALB 사용을 권장

k8s 서비스 타입별 트래픽 흐름(Ingress)

  • 여기서부터는 L7 (애플리케이션 계층)

  • annotaions 방식을 사용하면 aws에서 참조해서 사용

  • aws load balancer addon을 설치하면 얘가 인스턴스모드, ip 모드 선택 가능.

    • ip 모드로 하면 node port가 아니라 pod ip로 다이렉트로 보낼 수 있음(직접 통신)
    • iptables 때문에 복잡해진 네트워크를 간소화할 수 있음

eks 스토리지

  • PV Provisioning: 온프렘환경에서는 미리 스토리지가 있기 때문에 바인딩
  • Dynamic PV Provisioning: 정의만 해두고 필요할때 생성해서 사용
  • 사용 가능한 스토리지
    • EBS (특정 파드에 마운트할때)
    • EFS (공유해서 쓸때)
    • FSx for Lustre (윈도우)
  • 사용 방법

[스터디] Awazon EKS 설치 및 기본 사용 실습

기본 인프라는 CloudNet@에서 AWS CloudFromation 템플릿으로 준비해주셨다.

  • 사용하는 템플릿
# CloudFormataion 템플릿 다운로드
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/K8S/myeks-1week.yaml

템플릿을 사용해 CloudFormation에서 리소스를 생성한다.
KeyName: KeyPair (없으면 생성한다)
SgIngressSshCidr: 본인 집의 IP로 (작업용 EC2 접근을 집에서만 할 수 있게)

내용을 확인하고 배포한다.
사용하면 가상 네트워크 VPC, PublicSubent1, PublicSubent2, 작업용 EC2를 배포하게 된다 (사진에 있는 아키텍처 그대로)

생성이 완료되면 CREATE_COMPLETE가 된다.

기본 정보 확인

kubectl version --client=true -o yaml
eksctl version
aws --version

docker info

IAM User 자격 증명 설정 및 VPC 확인 및 변수 지정

실습을 하기 위해 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

그 이후에는 EKS 배포할 VPC 정보와 서브넷 ID를 환경변수에 저장합니다.

# 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

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

echo 결과가 잘 나오면 성공한 것이다.

eksctl로 배포

이미 eksctl가 서버에 깔려있기 때문에 바로 사용하면 된다. --dry-run을 사용하면 실제 배포 없이 내용 확인이 가능하다.

사용 전 연습

# eks 클러스터 생성 + 노드그룹 없이
eksctl create cluster --name myeks --region=ap-northeast-2 --without-nodegroup --dry-run | yh

기본 값으로 나오는 것들을 argument로 줄 수 있다.

# 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

이제 실제로 배포해본다. 터미널을 새로 띄운 뒤 아래 명령어를 사용한다.

# 옵션 [터미널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

루프를 돌며 EC2 정보를 계속 보여주는 것을 볼 수 있다. 이제 실제로 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 --verbose 4
  • eksctl create cluster: eksctl 도구를 사용하여 EKS 클러스터를 생성
  • --name $CLUSTER_NAME: 클러스터의 이름을 $CLUSTER_NAME 환경 변수로 지정
  • --region=$AWS_DEFAULT_REGION: 클러스터가 생성될 AWS 리전을 $AWS_DEFAULT_REGION 환경 변수로 지정
  • --nodegroup-name=$CLUSTER_NAME-nodegroup: 노드 그룹의 이름을 $CLUSTER_NAME 변수에 -nodegroup을 추가하여 지정
  • --node-type=t3.medium: 노드의 인스턴스 유형을 t3.medium으로 지정합니다. 이는 EC2 인스턴스의 크기를 결정
  • --node-volume-size=30: 각 노드에 할당할 EBS 볼륨의 크기를 30GB로 지정
  • --vpc-public-subnets "PubSubnet1,PubSubnet1,PubSubnet2": EKS 클러스터가 사용할 공용 서브넷을 $PubSubnet1과 $PubSubnet2 환경 변수에 지정된 값으로 설정
  • --version 1.31: EKS 클러스터의 Kubernetes 버전을 1.31로 설정
  • --ssh-access: SSH 액세스를 활성화하여 클러스터 노드에 SSH로 접속할 수 있도록 설정
  • --external-dns-access: 외부 DNS 액세스를 활성화하여 외부에서 DNS 요청을 처리할 수 있도록 설정
  • --verbose 4: 명령어 실행 시 세부적인 로그를 verbose 모드로 4단계까지 출력하도록 설정

dry-run을 했을 때와는 다르게 로그가 찍히는 것을 확인할 수 있다.

eksctl로 CloudFormatin Stack을 생성하여 리소스를 생성하기 때문에 CloudFormation콘솔에서 생성되는 과정을 확인할 수 있다.

생성이 완료되면 CREATE_COMPLETE 상태가 된다.

또한 노드 모니터링용 인스턴스에도 Node Group이 생기는 것을 확인할 수 있다.

eksctl 정보 확인

# 클러스터 정보 확인
eksctl get cluster

# 노드 그룹 정보 확인
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 pod -n kube-system -o wide

kubectl get pod -A
kubectl top node
kubectl top pod -A


기본 사용

선언형(멱등성) 알아보기 실습

터미널 2개를 띄우고 하나는 모니터링을, 하나는 Deployment를 배포한다.

# 터미널1 (모니터링)
watch -d 'kubectl get pod'

# 터미널2
# Deployment 배포(Pod 3개)
kubectl create deployment my-webs --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --replicas=3
kubectl get pod -w

kubectl scale deployment my-webs --replicas=6 && kubectl get pod -w
kubectl scale deployment my-webs --replicas=3
kubectl get pod

강제로 파드를 삭제해본다

kubectl delete pod --all && kubectl get pod -w

<- 명령어 / 모니터링 ->

파드가 모두 삭제되었지만, 곧바로 새로운 3개의 파드가 뜨는 것을 확인할 수 있다.

kubectl get deploy -o yaml | kubectl neat | yh

replica: 3으로 구성이 되어있기 때문에 파드가 삭제해도 일관성을 보장하기 위해 다시 파드를 띄우기 때문이다.

실습 완료 후에는 Deployment를 삭제한다.

kubectl delete deploy my-webs

노드에 배포된 컨테이너 정보 확인 Containerd clients 3종 : ctr, nerdctl, crictl

  • ctr: containerd의 기본 CLI 도구
  • nerdctl: Docker와 유사한 명령어를 제공하는 containerd 클라이언트
  • crictl: Kubernetes 환경에서 containerd와 상호작용하는 데 사용되는 CLI 도구

EKS Cluster Endpoint 를 Public(IP제한)+Private 로 변경 및 확인

  • EKS API 서버는 AWS 관리 VPC에 위치

  • API 서버 <> 워커 노드 연결 시 EKS Owned ENI를 사용

  • kubectl -> API 서버의 endpoint -> API 서버 -> EKS owned ENI -> kubelet

  • kubelet, kube-proxy -> EKS owned ENI -> API 서버

현재는 pulic 하게 열려있기 때문에 보안 강화를 목적으로 외부에서 접근이 가능했던 API Server의 End Point를 AWS VPC내에서만 접근이 가능하도록 변경해본다.

이후에 kubectl cluster-info 명령어를 입력하면 결과가 제대로 나오지 않는 것을 확인할 수 있다.

또한 콘솔에서 확인해도 API server endpoint access가 public에서 public and private로 변경되었다.

이제 설정을 허용해주기 위해 보안 그룹 설정을 해준다.

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을 설정한다.

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

보안 그룹 수정 후에 ping 테스트가 성공하는 것을 확인할 수 있다.

ping -c 2 $N1
ping -c 2 $N2

아까는 실행이 되지 않던 cluster-info도 잘 나오는 것을 확인할 수 있다.

kubectl cluster-info

실습 완료 후 자원 삭제

- eksctl delete cluster --name $CLUSTER_NAME
- aws cloudformation delete-stack --stack-name myeks
profile
공블로그

0개의 댓글

관련 채용 정보