본문 바로가기
  • 1+1=3
개발삽질/잡다한 개발기록

[EKS 스터디-1] 클러스터 구조와 기본사용법

by 여스 2024. 3. 6.
반응형

 

EKS란

쿠버네티스를 쉽게 실행할 수 있는 관리형 aws 관리형 서비스이다.

순수한 쿠버네티스를 실행하면, 컨트롤플레인을 직접 설치하고 운영해야 하지만, EKS는 aws가 대신 해준다.

 

컨트롤플레인

여기서 컨트롤플레인이란 쿠버네티스 api서버, 컨트롤러, 스케쥴러, etcd를 말한다.

 컨트롤플레인이 어떤 역할을 하는지는 예시를 보면 이해하기 쉽다. 아래 상황을 순서대로 따라가보며 이해하자.

(출처:  https://www.youtube.com/watch?v=Iue9TC13vPQ)

1. 내가 팟을 생성하기 위해 kubectl 명령어를 날린다.

2. api서버가 이를 받는다.(이때 요청의 문법/권한이 합당한지 판단함)

3. 워커노드에 대한 정보를 가지고 있는 etcd를 확인하고, 이 정보를 스케쥴러에게 보냄.
     이때, etcd는 kubelet(워커노드마다 떠있는 데몬)안에 포함되어 있는 cAdvisor라는 컨테이너 모니터링 툴로부터 각 워커노드의 정보를 받아오는 것임.

4. 스케쥴러는 받은 etcd정보를 바탕으로 어떤 워커노드에다 팟을 만들지 결정해서 api서버에게 응답함.

5. api서버는 이 응답을 가지고 해당 워커노드의 kubelet에게 가서 팟  만들라고 요청보냄.

6. kubeletdocker한테 컨테이너 띄우라고 함.

7. docker는 이때 이미지저장소로부터 이미지 받아서 컨테이너 실행함.

 

만약, 내가 컨테이너를 2개를 띄우라고 명령했다면, 컨트롤러가 워커노드들이 잘 동작하는지 얘네를 바라보고 있다가, 이상이 있으면 api서버에게 만들라고 요청하고, 위 2~7번이 반복됨.

 

 

즉, EKS는 aws의 자체 vpc에서 컨트롤플레인을 실행해주고 고가용성을 보장한다.

그 외에도, 보안과 IAM인증, 그리고 다양한 aws 서비스 와 통합하여구성하기 용이하게 지원이 된다.

 

따라서 우리 개발자/데브옵스/클라우드 엔지니어는 데이터플레인(워커노드) 집중할 수 있다.

 

EKS 아키텍쳐

EKS owned ENI

위에서 컨트롤플레인은 aws 자체 vpc에서 실행된다고 했다. 반면 데이터플레인은 내 vpc에 설치가 된다.

api서버가 워커노드의 kubelet에 명령을 내리거나, cAdvisor의 정보를 etcd가 수집하거나 하는 등 각 플레인끼리 통신할 일이 매우 많은데, 이를 연결해주는 것이 EKS owned ENI이다. 

EKS Cluster Endpoint- 모두 Public인 경우

kubectl 명령어를 치는 서버(제어부라 부르겠다)와 컨트롤플레인(AWS의 vpc에 있는), 그리고 워커노드가 있는 내 vpc 간에는 네트워크가 통신되어야 한다.

이때, 각 통신이 public 네트워크로 가는지, private네트워크를 통하는지 알아보도록 하자.

 

먼저, 스터디에서 만든 EKS 클러스터는 public으로 컨트롤플레인의  api server endpoint access가 public으로 표시되었다. (아래 스샷의 오른쪽아래에 보임)

 

endpoint는 요롷게 표시되어있다.

실제로 저 endpoint를 브라우저에 검색해보면 간단한 정보가 나온다. 즉 Public 접근이 된다! (중요한 내용은 아니지만 보안에 좋지는 않아보인다.)

 

암튼, 위 엔드포인트로 연결되는 api 서버는 워커노드의 kubelet과 수시로 통신을 한다고 배웠다. 워커노드에 들어가서 직접 확인해보자.

제어부 서버에서 아래처럼 ssh로 워커노드에 들어가 ss -tnp를 해보자. (ss는 Socket Statistics를 보여주며, tnp는 각각 주소와 포트, 그리고 해당 연결을 한 프로세스를 보여줌)

$N1과 $N은 각각 워커노드 Ip임.
그리고 각 워커노드 SG에서 제어부서버 접속하도록 열어주도록 설정 필요함.

for i in $N1 $N2; do echo ">> node $i <<"; ssh ec2-user@$i sudo ss -tnp; echo; done

 

결과를 보면 두개의 워커노드에 kubelet과 kube-proxy모두

3.39.55.189:443과 3.37.178.179:443

이 연결되어있음을 보인다.

저 두 ip가 과연 Api server endpoint의 public ip일까?

저 eks 콘솔 스샷에서 봤던 api endpoint의 ip를 알아보기 위해 dig해보면,

dig +short 3459c2dc113173c2a7ae03c600c0f46c.sk1.ap-northeast-2.eks.amazonaws.com

워커노드에 kubelet과 kube-proxy이 연결되어 통신중인 ip와 같다!

즉, kubelet과 kube-proxy에서 api server로 이어지는 통신은 EKS의 Public endpoint로 향한다.

 

그럼, exec로 노드의 특정 팟에 접속한 경우에는 어떤 네트워크로 연결될까?

일단 제어부에서 하나의 노드 팟에 일단 접속해서 커넥션을 유지하고,

kubectl exec daemonsets/aws-node -it -n kube-system -c aws-eks-nodeagent -- bash

다른 제어부 터미널 창을 다시 켜서 소켓 상황을 보자.

잘 보면, exec로 접속한 노드에서는 kubelet의 소켓연결이 기존 endpoint public ip 이외에 private ip로 하나 더 추가되었다. (접속하지 않은 노드는 저 ip가 생성되지 않았음!)

 

즉, exec로 워커노드의 컨테이너에 접속할 때에는 public ip가 아니라, private으로 접속을 한다.

 

그럼 저 private ip의 정체는?

 

Network Interface에 가서 검색을 해보면, 해당 eni의 요청자와 소유자가 다르다!(eni 인스턴스의 소유자는 AWS이다!)

 

바로 아래그림에 보이는 EKS owned ENI가 바로 제어부가 api서버를 통해 워커노드의 컨테이너에 접속할 때 쓰이는 네트워크이다.

그러나, kubelet과 kubeproxy 팟이 api server와 통신 시에는 public ip를 통해 이루어짐을 확인했다.(3.39.55.189:443과 3.37.178.179:443)

 

위 단계에서, 한단계 더 보안을 높인게 아래 구성도이다. 이젠 클러스터 내부에서는 모두 EKS Owned ENI로만 통신한다.

 

위 보다 더 보안으로 하려면, 제어부가 API 서버 접근하는 것도 Private으로 하면 된다.

 

 

기본 사용법

멱등성이란 수학이나 컴퓨터 분야에서는 멱등성/멱등법칙(idempotence)을 얼마나 많이 실행하든 항상 같은 결과가 나오는 작업(operation)이라 설명한다.

 

kubectl은 간단한 명령어로 멱등성을 보장한다.

 

처음에 내가 pod을 총 3개만 띄우도록 앱을 아래처럼 띄운 상황에서, 

kubectl create deployment my-webs --image=gcr.io/google-samples/kubernetes-bootcamp:v1 --replicas=2

 

kubectl scale을 통해 팟의 개수를 조정할 수 있다.

kubectl scale deployment my-webs --replicas=3

 

자 여기서, 내가 갑자기 delete pod --all로 모두 삭제하더라도 팟은 그 즉시 replicas 개수를 맞추기 위해 즉시 생성된다.

위처럼 평화롭게 3개 팟이 running중인데, 

아래처럼 delete를 해보면

그 순간 아래처럼 기존건 Terminating되지만, 바로 새로운 팟 3개가 생성된다.

 

위와 같이 replicas 숫자 외에도 팟 생성시 어떠한 이미지를 쓰고, 팟 위에 서비스를 어떤 LoadBalancer를 달것인지도 정의할 수 있다.

아래는 예시로 다운받을 수 있는 마리오게임의 yaml인데, Deployment에서 replicas의 개수는 1개, image 다운로드 경로, Service의 포트번호와 타입도 정의하였다. 기본적으로그냥 LoadBalancer라고 하면 CLB라 한다.

(manager@myeks:N/A) [root@myeks-host ~]# cat 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

 

반응형

댓글