Amazon EKS란?
date: 2026-03-15
Kubernetes를 직접 운영하려면 컨트롤 플레인 서버 구성, 고가용성(HA) 설정 등을 모두 직접 관리해야 한다.
Amazon EKS는 이 컨트롤 플레인 인프라 운영을 AWS가 대신 맡아주는 완전관리형 Kubernetes 서비스다.
사용자는 Kubernetes API를 그대로 사용하면서, 컨트롤 플레인 서버 관리 부담을 AWS에 위임할 수 있다.
한줄요약: Kubernetes Cluster를 사용자가 수동으로 하나하나 직접 클러스터를 구축하는것은 쉽지 않음.
EKS는 AWS의 서비스들을 이용하여 자동으로 Kubernetes 클러스터를 구축하는 복잡성을 크게 줄여줌.
Kubernetes 란 무엇인가?
아주 간단하게 설명하면 잘 만들어진 Container Images 들을 오케스트레이션 하는 도구이다.
컨테이너 하나를 로컬에서 띄우는 건 docker run 한 줄로 충분하다.
하지만 수백 개의 컨테이너를 여러 서버에 걸쳐 배포하고, 장애가 나면 자동으로 재시작하고, 트래픽에 따라 수를 늘리고 줄이는 일을 수동으로 하기엔 한계가 있다.
Kubernetes는 이런 컨테이너 운영의 복잡성을 자동화해주는 도구다.
간략한 역사
Google은 내부적으로 Borg라는 컨테이너 오케스트레이션 시스템을 수년간 운영해왔다.
이 경험을 바탕으로 2014년 오픈소스 프로젝트로 Kubernetes를 공개했다.
2016년에는 벤더 중립성을 위해 CNCF(Cloud Native Computing Foundation)에 기증되었고, 현재는 사실상 컨테이너 오케스트레이션의 표준으로 자리잡았다.
EKS 란?
AWS가 Kubernetes 컨트롤 플레인을 대신 운영해주는 관리형 서비스로, 사용자는 클러스터 인프라 관리를 조금이나마 쉽게 하여 Kubernetes를 사용할 수 있다.
Control Plane and Data Plane
Kubernetes 클러스터는 크게 두 영역으로 나뉜다.
컨트롤 플레인: 클러스터 상태 관리, 워크로드 스케줄링 등 클러스터 전체를 제어하는 두뇌 역할을 한다. EKS에서는 이 영역을 AWS가 관리한다.
데이터 플레인: 컨테이너(워크로드)가 실행되는 노드들의 집합이다. EKS에서는 이 영역을 어떻게 운영할지 사용자가 직접 선택한다.
Control Plane Components
공식 문서를 기준으로 정리해보았다 - Kubernetes 컨트롤 플레인
컨트롤 플레인은 다음 핵심 컴포넌트들로 구성된다.
- API 서버 (
kube-apiserver): Kubernetes HTTP API를 외부에 노출하는 핵심 서버다.kubectl명령을 포함해 클러스터에 대한 모든 요청이 이 API 서버를 통해 처리된다.
ex)
kubectl apply를 실행하면 가장 먼저 API 서버가 요청을 받고 처리하도록 함
- etcd: 모든 API 서버 데이터를 저장하는 일관성 있는 고가용성 key-value 저장소다. 클러스터의 현재 상태 전체가 여기에 기록된다. etcd가 죽으면 클러스터 상태를 읽거나 변경할 수 없게 된다.
ex) "현재 포드가 3개 실행 중"이라는 정보가 etcd에 저장된다.
- 스케줄러 (
kube-scheduler): 아직 노드에 배정되지 않은 포드를 감지하고, 각 포드를 실행하기에 적합한 노드를 선택해 할당한다. 노드의 가용 리소스, 제약 조건, 어피니티 설정 등을 고려해 결정한다.
ex) 새 포드를 띄울 때 CPU가 남는 노드를 골라서 배정한다.
- 컨트롤러 관리자 (
kube-controller-manager): Kubernetes API의 동작을 구현하는 다양한 컨트롤러를 실행한다. 실제 상태가 원하는 상태와 일치하는지 지속적으로 감시하고 조정한다.
ex) Deployment에 복제본 3개를 설정했는데 포드 1개가 죽으면, 자동으로 새 포드를 1개 더 생성한다.
- 클라우드 컨트롤러 관리자 (
cloud-controller-manager, 선택): 클러스터를 클라우드 공급자(AWS, GCP 등)와 통합하는 컴포넌트다. 로드 밸런서 프로비저닝, 노드 상태 동기화 등 클라우드 플랫폼 고유의 기능을 처리한다. EKS에서는 AWS가 이 역할을 담당한다.
예:
LoadBalancer타입의 Service를 생성하면 AWS 로드밸런서를 자동으로 프로비저닝한다.
EKS에서는 위 컴포넌트 모두를 AWS가 관리하므로, 직접 건드릴 일이 없다.
Data Plane Components
데이터 플레인, 좀더 자세한 내용은 공식문서 참조 - Kubernetes 노드 컴포넌트
각 노드에는 다음 컴포넌트들이 실행된다.
- kubelet: 포드와 그 안의 컨테이너가 정상적으로 실행되고 있는지 보장하는 에이전트다. API 서버로부터 포드 스펙을 받아 컨테이너 런타임에 실행을 지시하고, 상태를 지속적으로 보고한다.
ex) 포드가 비정상 종료되면 kubelet이 이를 감지하고 API 서버에 상태를 보고한다. 컨트롤러 관리자는 API 서버를 감시(watch)하다가 이 변화를 인지하고 새 포드를 생성한다.
- kube-proxy: 각 노드에서 네트워크 규칙을 관리하여 Service가 동작하도록 한다. 클러스터 내부 또는 외부에서 포드로 향하는 트래픽을 적절한 포드로 전달하는 역할을 한다.
ex)
ClusterIPService로 요청이 오면, kube-proxy가 실제로 실행 중인 포드 중 하나로 트래픽을 라우팅한다.
- 컨테이너 런타임: 컨테이너를 실제로 실행하는 소프트웨어다. Kubernetes는 특정 런타임에 종속되지 않으며, CRI(Container Runtime Interface)를 구현한 런타임이라면 사용할 수 있다. EKS에서는 기본적으로
containerd를 사용한다.
ex) kubelet이 "이 이미지로 컨테이너를 실행해"라고 지시하면, 컨테이너 런타임이 실제로 이미지를 내려받고 컨테이너를 띄운다.
EKS에서는 노드 운영 방식에 따라 이 컴포넌트들의 관리 주체가 달라진다.
EKS Auto Mode
컨트롤 플레인을 넘어 데이터 플레인까지 AWS가 완전히 관리하는 방식이다.
Karpenter 기반으로 애플리케이션 수요에 맞게 노드의 오토스케일링을 지원하고, Kubernetes 버전 업그레이드와 OS 패치도 자동으로 처리된다.
노드에는 변경 불가 AMI가 사용되며, SELinux와 읽기 전용 루트 파일시스템이 적용되는 등 보안이 강화되어 있다.
또한 노드에 SSH/SSM으로 직접 접속하거나 커스텀 AMI를 사용하는 것은 불가능하다.
사실상 노드의 관리 권한까지도 AWS에 위임하는 형태.
For more:
Managed Node Group
EC2 인스턴스를 노드로 사용하되, 노드의 수명 주기 관리를 AWS가 보조해주는 방식이다.
내부적으로는 EC2 Auto Scaling 그룹으로 구성되지만, 이를 EKS가 직접 생성하고 관리한다. 노드 업그레이드 시 EKS가 순서를 제어하며 기존 노드의 포드를 안전하게 drain한 뒤 새 노드로 교체하는 과정을 자동화해준다. 콘솔에서 원클릭으로 AMI를 업데이트할 수 있고, 커스텀 AMI나 Launch Template 적용도 가능하다.
다만 OS 패치와 보안 유지는 여전히 사용자 책임이다. AMI 업데이트 타이밍을 사용자가 결정해야 하고, 업데이트를 트리거하지 않으면 노드는 그대로 방치된다.
Self Managed Nodes
EC2 인스턴스를 사용자가 직접 생성하고 EKS 클러스터에 수동으로 등록하는 방식이다. Managed Node Group과 마찬가지로 EC2 Auto Scaling 그룹을 사용하지만, 이를 사용자가 직접 구성하고 관리한다.
Managed Node Group과 가장 큰 차이는 노드 업그레이드와 교체를 완전히 직접 처리해야 한다는 점이다. 새 AMI가 나와도 EKS가 알아서 교체해주지 않는다. 노드를 새로 띄우고, 기존 노드의 포드를 drain하고, 구 노드를 제거하는 모든 과정을 수동으로 진행해야 한다.
대신 OS 선택(Amazon Linux, Bottlerocket, Windows, Ubuntu 등), 커널 파라미터 튜닝, 특수 소프트웨어 설치 등 노드 구성에 대한 완전한 제어권을 가진다. 일반 EC2 인스턴스를 직접 운영하는 것과 거의 동일한 수준의 자유도다.
AWS Fargate
EC2 인스턴스를 직접 관리하지 않고 Pods 에 대해 각각 컴퓨팅 리소스를 할당받는 서버리스 방식이다. 즉 노드에 대해서 내가 관리를 할 수 없고 그냥 Pod 를 배포하면 AWS의 어딘가의 Node에 배포되는 방식.
다만 제약이 매우 많다. (공식 문서 참고)
- GPU사용불가
- DaemonSets 사용불가
- Amazon EBS 사용불가
- 등등등...
Pods and Container
컨테이너는 애플리케이션을 실행하기 위한 격리된 환경이다.
포드(Pod) 는 Kubernetes에서 배포 가능한 가장 작은 단위로, 하나 이상의 컨테이너를 묶은 것이다.
포드를 어떻게 배포하느냐는 애플리케이션 성격에 따라 달라진다.
| 배포 방식 | 언제? |
|---|---|
| Deployment | 웹 서버처럼 상태가 없는(stateless) 애플리케이션 |
| StatefulSet | DB처럼 상태와 고유 식별이 필요한 애플리케이션 |
| DaemonSet | 모든 노드에서 반드시 실행되어야 하는 에이전트 |
| Job / CronJob | 특정 작업을 완료하면 종료되는 배치성 작업 |
Namespace
Namespace는 하나의 클러스터 안에서 리소스를 논리적으로 격리하는 단위다. 환경(dev/staging/prod), 서비스 단위로 구분할 때 사용한다.
같은 클러스터를 쓰더라도 Namespace가 다르면 리소스 이름이 겹쳐도 충돌하지 않는다.
EKS 클러스터를 처음 생성하면 기본으로 아래 Namespace들이 존재한다.
default: Namespace를 지정하지 않으면 여기에 리소스가 생성된다.kube-system: Kubernetes 시스템 컴포넌트(kube-proxy, CoreDNS 등)가 실행되는 곳.kube-public: 클러스터 전체에서 읽기 가능한 공개 리소스용. 거의 사용하지 않는다.
참고: Namespace는 리소스를 논리적으로 분리할 뿐, 네트워크 격리는 별도로 NetworkPolicy를 설정해야 한다.
Networking
포드는 IP가 동적으로 바뀌기 때문에, 다른 포드가 직접 IP를 추적하기 어렵다. 이를 해결하기 위해 두 가지 개념이 존재한다.
-
Service: 포드 앞에 고정된 이름과 IP를 제공하는 추상화 레이어다. 포드는 언제든 재시작되거나 교체되어 IP가 바뀔 수 있는데, Service는 이 변화와 무관하게 항상 같은 주소로 접근할 수 있게 해준다. 내부적으로는 라벨 셀렉터(label selector)로 대상 포드를 선택하고, 요청을 해당 포드들에 분산한다.
-
ClusterIP(기본값): 클러스터 내부에서만 접근 가능한 가상 IP를 부여한다. 외부에서는 접근할 수 없다. 포드 간 내부 통신에 사용한다. NodePort: 모든 노드의 특정 포트를 열어 외부에서 접근할 수 있게 한다. 간단하지만 포트 관리가 불편해 운영 환경보다는 테스트용으로 쓰인다.LoadBalancer: 클라우드 공급자의 로드 밸런서를 자동으로 프로비저닝한다.-
ExternalName: 클러스터 내부에서 외부 DNS 이름을 별칭으로 참조할 때 사용한다. -
Ingress: 클러스터 외부에서 내부 Service로 HTTP/HTTPS 트래픽을 라우팅하는 리소스다. 단순한 로드 밸런서와 달리, 하나의 진입점에서 호스트명이나 URL 경로를 기준으로 여러 Service로 트래픽을 분기할 수 있다. Ingress 리소스 자체는 라우팅 규칙을 정의하는 설정일 뿐이고, 실제로 트래픽을 처리하는 것은 클러스터에 설치된 Ingress Controller다. Ingress Controller가 없으면 Ingress 리소스를 만들어도 동작하지 않는다. AWS EKS에서는 주로 AWS Load Balancer Controller를 사용하며, Ingress를 생성하면 자동으로 ALB(Application Load Balancer)가 프로비저닝된다.
클러스터 엔드포인트 접근 모드
EKS 클러스터의 API 서버 엔드포인트에 어디서 접근할 수 있는지를 결정하는 설정이다. 퍼블릭, 퍼블릭+프라이빗, 프라이빗 세 가지 모드를 선택할 수 있다.
퍼블릭 (기본값)
인터넷에서 API 서버에 직접 접근할 수 있는 모드다. kubectl 명령을 로컬 PC에서 바로 실행할 수 있어 초기 설정이 간편하다.
VPC 내부 노드에서 API 서버로 향하는 트래픽도 VPC 밖으로 나갔다가 돌아오는 경로를 거친다.
다만 인터넷을 경유하더라도 AWS 네트워크 내부에서 처리된다. IAM과 Kubernetes RBAC으로 인증·인가를 제어하며, CIDR 제한을 설정해 특정 IP에서만 접근하도록 좁힐 수 있다.
퍼블릭 + 프라이빗
퍼블릭과 프라이빗 접근을 동시에 허용하는 모드다.
VPC 내부 노드와 포드는 프라이빗 VPC 엔드포인트를 통해 API 서버와 통신하고, 외부 클라이언트는 퍼블릭 엔드포인트로 접근한다. 내부 트래픽의 네트워크 경로가 최적화되면서 외부 접근도 유지된다.
두 가지 접근 경로를 함께 관리해야 하므로 보안 설정이 다소 복잡해진다.
프라이빗
API 서버를 인터넷에 노출하지 않는 모드다. 모든 API 트래픽은 VPC 내부 또는 Transit Gateway 등으로 연결된 네트워크에서만 가능하다. 보안 수준이 가장 높다.
kubectl 명령을 실행하려면 반드시 VPC 내부 또는 연결된 네트워크에서 접근해야 한다. 일반적으로 아래 방법 중 하나를 사용한다.
- VPC 내부에 EC2 Bastion Host를 두고 SSH 터널링으로 접근
- Transit Gateway로 온프레미스 네트워크와 연결
- VPC 내부에서 실행되는 AWS Cloud9 IDE 사용
주의: 퍼블릭 접근을 비활성화하기 전에 필요한 IAM principal을 미리 RBAC에 등록해두어야 한다. 그렇지 않으면 클러스터에 접근할 방법이 없어진다.
내부적으로는 AWS가 프라이빗 Route 53 호스티드 존을 자동으로 생성하여 VPC와 연결한다. 이 때문에 VPC에서 enableDnsHostnames와 enableDnsSupport가 활성화되어 있어야 한다.
Common Deployment Flow
- 애플리케이션을 컨테이너 이미지로 빌드
- Amazon ECR(컨테이너 레지스트리)에 이미지 푸시
- YAML 파일로 포드/Deployment 정의
- kubectl apply로 클러스터에 배포
- Service / Ingress로 외부에 노출
참고: EKS에서는
eksctl, Terraform, AWS 콘솔 등 다양한 방법으로 클러스터를 생성할 수 있다. 이 스터디에서는 Terraform(OpenTofu)을 주로 사용할 예정이다.