EKS Anywhere 구축기

Jan.19.2023 신승엽

Infra

안녕하세요. 데이터플랫폼팀에서 전사 데이터 플랫폼을 구축, 운영하고 있는 신승엽입니다.

2022년에 데이터플랫폼팀에서는 AWS 이관으로 인해 사용성이 줄어든 온프레미스 Hadoop 클러스터 인프라를 재정비하여 MLOps 플랫폼으로 전환하는 프로젝트를 수행하였습니다.

MLOps 플랫폼 내 컨테이너를 관리하기 위한 도구로 EKS Anywhere를 채택하였습니다. 이 글에서는 EKS Anywhere의 소개와 함께 구축하면서 마주했던 문제들과 이를 해결한 과정에 대해 공유드리고자 합니다.

천상계로의 배달 그 이후…

지난 2021년 우아한테크콘스트(우아콘)에서 발표했던 데이터 분석 플랫폼, 지상계에서 천상계로 배달완료! AWS 이관기 이후 IDC 내에 있던 Hadoop 클러스터의 인프라의 사용성이 사라지면서 인프라 장비들을 다른 목적으로 사용할 수 있는 방안을 고민하기 시작했습니다.

때마침 허위 리뷰 방지, 가게 추천 모델링 등 GPU를 활용한 머신러닝, 딥러닝에 사내 수요가 증가하고 있었습니다. 증가하는 수요를 충족시킬만한 사내 온프레미스 환경의 GPU 인프라는 부족하였고, 대안으로 사용 가능한 AWS의 GPU 인스턴스 또한 품귀현상으로 할당받기 어려운 상황이 되었습니다.

점점 늘어가는 분석 자원에 대한 수요와 부족한 GPU 인프라의 활용도를 최대한으로 높이고자 기존 온프레미스 인프라를 재활용하여 Kubernetes 클러스터를 구축함으로써 유연하고 확장 가능한 분석 환경과 GPU 인프라를 제공하기로 하였습니다.

다양한 Kubernetes 배포판 중 아래의 세 가지의 이유로 AWS에서 배포하고 있는 EKS Anywhere(EKS-A)를 설치하기로 하였습니다.

  1. 전사 Data Lake가 구축되어 있는 AWS 환경과의 연계성
  2. 전사 MLOps의 기반 플랫폼으로 사용 중인 EKS 와의 유사한 사용자 경험
  3. Kubernetes 클러스터의 용이한 유지보수성

EKS Anywhere(EKS-A)

먼저 EKS-A(nywhere)에 대해서 설명드리겠습니다. EKS-A를 한 문장으로 표현하면 “AWS의 Managed Service인 EKS를 고객사 인프라에 직접 설치하여 사용 가능한 제품”이라고 할 수 있는데요.

EKS-A는 Kubernetes 배포판으로 온프레미스 환경에 간단하게 생성, 확장, 삭제 등 클러스터의 라이프 사이클을 관리하기 위한 오픈소스로 Ops Tool 과 Amazon EKS의 배포판인 EKS Distro로 구성되어 있습니다.

Amzon 은 2021 년 9월, AWS에서 Managed Service로 제공되고 있는 EKS(Elasitc Kubernetes Service)를 VMWare vSphere 환경에서만 배포할 수 있는 최초의 버전을 릴리스하였습니다.

그리고 첫 릴리스 이후 채 1년이 지나지 않은 지난 2022년 6월, 베어메탈 환경에서도 배포할 수 있는 버전을 릴리스하였습니다.

EKS-A의 전체 구조를 도식화해보면 아래와 같습니다.

EKS Distro(EKS-D)

EKS-A를 통해 배포되는 Kubernetes 배포판인 EKS-D(istro)에서도 간단히 소개해 드리겠습니다.

EKS-D는 2020년 12월 Amazon EKS에서 사용 중인 Kubernetes 배포판을 온프레미스(BM, VM) 환경에 설치할 수 있도록 공개한 오픈소스입니다.

kubeadm 또는 kops 와 같은 Kubernetes 설치 도구를 통해 설치 가능하며 가장 최신 버전으로는 v1.24가 릴리스되어 있습니다.

EKS-A vs EKS

그럼 EKS-A는 관리형 서비스인 EKS 와는 어떤 차이점들이 있을까요?
아래 표는 EKS-A 와 EKS의 차이를 나타내고 있습니다. 가장 큰 차이는 Kubernetes 클러스터를 AWS에서 관리해 주는지 고객이 직접 관리하는지 일 것입니다.

EKS-A의 특징은 오픈소스 형태로 배포되고 있으며, 고객사의 인프라에 설치되고 고객이 직접 관리하지만 필요에 따라 유료 구독 서비스를 통해 기술 지원을 받을 수 있다는 점입니다. EKS-A를 사용해 보고 싶지만 직접 운영하는 것에 대한 부담을 느끼는 사용자에겐 좋은 옵션이 될 것 같습니다.

EKS-A EKS
Control plane
Control plane 관리 고객 AWS
Control plane 위치 고객의 IDC AWS 클라우드
업데이트 Control plane : CLI
Data plane : Flux
Control plane : Managed update
Data plane : Managed rolling update
Compute
Compute options VMWare vSphere
베어메탈
Amazon EC2
Amazon Fargate
지원 OS Bottlerocket
Ubuntu
Amazon Linux 2
Window Server
Bottlerocket
Ubuntu
인프라 고객이 관리 AWS
Management AWS
Serverless 지원 안 함 Amazon EKS on Amazon Fargate
CLI eksctl eksctl
웹 콘솔 Amazon EKS Console(Optional) Amazon EKS Console
IaC Cluster manifest(YAML)
Kubernetes controllers
3rd-party solution
AWS CloudFormation
3rd-party 솔루션
Logging and monitoring 3rd-party solution CloudWatch
CloudTrail
3rd-party 솔루션
GitOps Flux controller Flux controller
Functions and tooling
Networking and Security Cilium Amazon VPC CNI
Load balancer MetaLB(Optional) AWS App Mesh
Community
3rd-party solution
Community tools and Helm 지원 지원
Pricing and support
Control plane pricing 설치/사용은 무료
기술지원은 구독형 상품 필요
시간단위 클러스터 이용료 과금
AWS Support 연간 구독 기본 지원 포함
구독형 추가 지원 가능

EKS-A Architecture

EKS-A 와 EKS-D에 대해 알아보았습니다. 지금부터는 EKS-A의 내부 구조가 어떻게 되어 있고, 어떠한 설치 과정을 통해 온프레미스 환경에 Kubernetes 클러스터를 구축하는지 좀 더 구체적으로 살펴보겠습니다.

아래 그림은 온프레미스 환경에 EKS-A를 이용하여 Kubernetes 클러스터를 배포할 때 실행되는 컴포넌트들을 표현한 것입니다.

EKS-A를 설치하기 위해서는 목적에 따라 3가지 유형의 노드들이 필요합니다.

  • Bootstrap(또는 admin) 노드 : EKS-A의 CLI(Command Line Interface) 인 eksctl 명령어를 수행하기 위한 노드
  • Control Plane 노드 : Kubernetes 와 EKS-A의 System Component(etcd, Kubernetes API 서버 등)들이 배포될 노드
  • Data Plane 노드 : Kubernetes 클러스터에서 수행될 Workload 들이 배포될 노드

각 노드들에서 실행되는 컴포넌트들은 다음과 같은데요.

Bootstrap

  • eksctl
    • eksctl은 Amazon EKS를 관리할 수 있는 명령어들을 실행시키기 위한 CLI(Command Line Interface)입니다.
    • eksctlanywhere 플러그인을 추가하여 Kubernetes 클러스터의 라이프 사이클을 관리할 수 있습니다.
    • 사용자들은 eksctl 명령어를 통해 Kubernetes 배포판인 EKS-D를 배포하고, 클러스터에 노드들을 추가하거나 제거(Scale in/out) 할 수 있으며 클러스터를 삭제할 수도 있습니다.
  • Tinkerbell

    • Tinkerbell은 데이터 센터 기업인 Equinix에서 개발한 베어메탈 용 프로비저닝 자동화 오픈소스입니다. EKS-A는 Tinkernell을 이용하여 베어메탈 장비에 EKS-D를 배포할 수 있습니다. Tinkerbell은 베어메탈 배포 시 에만 이용되며 vShpere 환경에서 배포하는 경우에는 vSphere의 스택들을 사용하여 배포가 이루어집니다.
    • eksctl을 통해 클러스터 배포를 시작하면 kind를 통해 Bootstrap 노드에 로컬 Kubernetes(Mgmt. cluster) 환경이 설치됩니다. 이 로컬 Kubernetes에 Tinkerbell의 컴포넌트들이 Pod로 생성되고, Kubernetes 클러스터의 Control/Data Plane 노드에 EKS-D 와 EKS-A 컴포넌트들을 설치합니다.
    • Tinkerbell의 컴포넌트들

      • Boots

        • 설치 대상 노드들이 네트워크 부팅을 할 수 있도록 지원하기 위한 DHCP 서버이자 설치 이미지를 제공하는 TFTP 서버이기도 합니다. 노드가 PXE 부팅이 되고 DHCP 요청을 하게 되면 Boots는 노드에 IP 주소를 할당하고, 설치에 필요한 iPXE 스크립트를 전달합니다.
        • iPXE 스크립트를 통해 각 노드는 Hook OS(Linux Kit)라는 운영체제를 메모리에 다운로드하고 부팅합니다. 이후 실제 운영체제(Bottlerocket 또는 Ubuntu) 와 EKS-A 관련된 컴포넌트들을 다운로드하고 설치하게 됩니다.
        • DHCP 서비스는 네트워크 2계층(데이터 계층)을 사용해야 하므로 Pod로 실행되는 다른 컴포넌트들과 달리 단독 컨테이너로 실행됩니다.
      • Hegel

        • Tinkerbell의 메타데이터 저장소입니다.
        • 프로비저닝 할 하드웨어의 스펙 정보를 가지고 있으며 HTTP 요청을 통해 메타 정보를 조회할 수 있습니다.(EC2 메타데이터 포맷과 유사)
        curl -s "192.168.1.1:50061/metadata" | jq .
        {
          "facility": {
            "facility_code": "onprem"
          },
          "instance": {},
          "state": ""
        }
      • Rufio

        • BMCs(Board Management Controller)를 통해 머신들의 시작/종료, 부트 오더 등을 제어하기 위한 서비스입니다.
      • Tink

        • Tink server, Tink controller, Tink worker로 구성
        • Tink Server
          • Tink worker 가 프로비저닝을 위한 워크플로를 검색하고 실행할 수 있도록 API를 통해 워크플로를 노출합니다.
        • Tink Worker
          • Tink Worker는 각 노드에 운영체제를 설치하기 위해 실행되는 에이전트입니다. 이 에이전트는 Tink Server 와 통신하기 위한 HookOS(Linux Kit) 내부의 작은 바이너리 형태로 제공됩니다.
          • Tink Worker는 노드의 MAC 주소를 Tink Server로 보내고 자신이 실행할 워크플로를 요청합니다. Tink Worker는 워크플로를 하나씩 실행하고 완료되면 이를 Tink Server에 보고합니다.
        • Tink Contoller
          • Tink Controller는 하드웨어 데이터, 실행하려는 템플릿, 각 노드에 배포하고자 하는 워크플로들을 관리합니다.
    • EKS-A는 Tinkerbell을 이용하여 모든 배포 과정을 자동화하였습니다. EKS-A의 모든 설치 과정이 완료되면 Tinkerbell 서비스들은 새로 설치된 Kubernetes 클러스터로 이동하여 Pod 형태로 실행됩니다.
    • Bootstrap 노드의 로컬 Kubrentes(관리용)에서 Tinkerbell 서비스들은 모두 삭제되고, 로컬 Kubernetes 또한 삭제됩니다.

Control Plane

  • etcd
    • etcd는 키-값(key-value) 저장소입니다. Kubernetes는 etcd를 기본 저장소로 사용하고 있으며 클러스터의 모든 정보를 저장하고 있습니다.
  • kube-apiserver
    • kube-apiserver는 Kubernetes의 API를 노출하는 컴포넌트입니다. Kuberentes에 전달되는 모든 요청은 kube-apiserver를 통해 이루어집니다.
  • kube-scheduler
    • Pod 생성 요청이 발생하면 이를 감지하고 어느 노드에 배정할지 결정하는 역할을 수행하는 컴포넌트입니다.

이 외에도 Kubernetes의 필수 동작을 위해 다양한 컴포넌트들이 Control Plane 노드에 배치됩니다.

Data Plane

  • kubelet
    • 클러스터의 각 노드에서 실행되는 에이전트입니다. Kubelet으로 전달된 Pod 스펙대로 컨테이너가 잘 동작하도록 관리합니다.
  • kube-proxy
    • 클러스터의 각 노드에서 실행되는 네트워크 프록시입니다. 노드의 네트워크 규칙을 관리하며 Pod가 내/외부로 통신할 수 있도록 지원합니다.

설치과정

위에서 설명드린 EKS-A 클러스터의 상세 설치 과정을 토대로 실제 사용자 입장에서 설치하는 과정을 살펴보겠습니다. 내부 상세 구조는 굉장히 복잡해 보였지만 실제 설치 과정은 2가지의 설정 파일을 생성하고, 설치 명령어를 수행하기만 하면 되는 아주 간단한 과정입니다.

설정파일 작성

  • 하드웨어 정보 작성

    먼저 EKS-A 가 설치될 대상 서버들의 목록을 작성합니다. 파일은 CSV 포맷으로 헤더와 함께 EKS-A 가 설치될 각 노드의 시스템 정보(BMC 정보, IP 주소, 디스크 등)들이 포함됩니다.

# hardware.csv
hostname,bmc_ip,bmc_username,bmc_password,mac,ip_address,netmask,gateway,nameservers,labels,disk
cp01,,,,00:00:00:00:00:00,192.168.0.1,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=cp,/dev/sda
cp02,,,,11:11:11:11:11:11,192.168.0.2,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=cp,/dev/sda
cp03,,,,22:22:22:22:22:22,192.168.0.3,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=cp,/dev/sda
wk01,,,,33:33:33:33:33:33,192.168.0.4,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=wk/dev/sda
wk02,,,,44:44:44:44:44:44,192.168.0.5,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=wk,/dev/sda
  • 클러스터 배포 Manifest 작성(YAML)
    클러스터를 어떻게 구성할지 정의하기 위한 설정 파일입니다. 파일은 YAML 파일 포맷으로 작성하며 클러스터의 시스템 구성 정보(CNI, Pod/Service CIDR, 클러스터 크기 등)와 EKS-A에 기본적으로 설정할 컴포넌트(AWS IAM Authenticator, IAM for Pod 등) 설정들 그리고 각 노드에 설치할 OS 와 사용할 계정 등 클러스터 구성에 필요한 대부분의 작업들을 선언적 설정 파일을 통해 자동화할 수 있습니다.
# eksa-mgmt-cluster.yaml
apiVersion: anywhere.eks.amazonaws.com/v1alpha1
kind: Cluster
metadata:
  name: eksa-mgmt
spec:
  clusterNetwork:
    cniConfig:
      cilium: {}
    pods:
      cidrBlocks:
        - 192.168.0.0/16
    services:
      cidrBlocks:
        - 10.96.0.0/12
  controlPlaneConfiguration:
    count: 3
    endpoint:
      host: "10.255.32.51"
    machineGroupRef:
      kind: TinkerbellMachineConfig
      name: eksa-mgmt-cp
...
  • 클러스터 생성
    eksctl 명령어의 anywhere 플러그인을 사용하여 앞서 설명드린 설정 파일들과 함께 클러스터를 생성할 수 있습니다.
$ eksctl anywhere create cluster --hardware-csv hardware.csv -f eksa-mgmt-cluster.yaml

Performing setup and validations
✅ Tinkerbell Provider setup is valid
✅ Validate certificate for registry mirror
✅ Create preflight validations pass
Creating new bootstrap cluster
Provider specific pre-capi-install-setup on bootstrap cluster
Installing cluster-api providers on bootstrap cluster
Provider specific post-setup
Creating new workload cluster
Installing networking on workload cluster
Installing cluster-api providers on workload cluster
Installing EKS-A secrets on workload cluster
Installing resources on management cluster
Moving cluster management from bootstrap to workload cluster
Installing EKS-A custom components (CRD and controller) on workload cluster
Installing EKS-D components on workload cluster
Creating EKS-A CRDs instances on workload cluster
Installing AddonManager and GitOps Toolkit on workload cluster
GitOps field not specified, bootstrap flux skipped
Writing cluster config file
Deleting bootstrap cluster
🎉 Cluster created!
  • 클러스터 생성 확인
    • kube-system : Kubernetes의 필수 컴포넌트들이 설치되어 있음을 확인할 수 있습니다.
      NAME                                       READY   STATUS    RESTARTS      AGE
      aws-iam-authenticator-4fqzn                1/1     Running   0             1d
      cilium-2h79w                               1/1     Running   0             1d
      cilium-operator-54c84c9987-5wfcl           1/1     Running   0             1d
      coredns-57ffd8bf69-4bv6x                   1/1     Running   0             1d
      etcd-david3-eksa-cp01                      1/1     Running   0             1d
      kube-apiserver-david3-eksa-cp01            1/1     Running   0             1d
      kube-controller-manager-david3-eksa-cp01   1/1     Running   0             1d
      kube-proxy-2dqtz                           1/1     Running   0             1d
      kube-scheduler-david3-eksa-cp01            1/1     Running   0             1d
      kube-vip-david3-eksa-cp01                  1/1     Running   0             1d
    • eksa-system : EKS-A의 필수 컴포넌트들이 설치된 것을 확인할 수 있습니다. 앞에서 설명드렸던 것처럼 Tinkerbell 관련 컴포넌트들이 로컬 Kubernetes에서 신규 Kubernetes로 이동하였습니다. 이 컴포넌트들은 추후 EKS-A의 구성을 변경할 때 사용됩니다.
      NAME                                        READY   STATUS    RESTARTS       AGE
      boots-58f898555d-2vvhx                      1/1     Running   0              1d
      eksa-controller-manager-c5dd46548-x87mc     1/1     Running   0              1d
      envoy-5495f95f6c-g59b8                      1/1     Running   0              1d
      hegel-6b68799fd4-srf29                      1/1     Running   0              1d
      kube-vip-2bgtj                              1/1     Running   0              1d
      rufio-controller-manager-77dc96dff4-7tc5s   1/1     Running   0              1d
      tink-controller-manager-5f8cf55cd7-thjj7    1/1     Running   0              1d
      tink-server-599c786bb8-774v8                1/1     Running   0              1d

클러스터 스케일링

이미 구성이 완료된 클러스터에 노드를 추가하는 방법 또한 설치와 마찬가지로 굉장히 간단합니다.

먼저 신규 노드의 정보가 포함된 하드웨어 목록 파일을 신규 설치 때와 동일하게 CSV 포맷으로 작성합니다.

  • 하드웨어 정보 작성
# hardware_2.csv
hostname,bmc_ip,bmc_username,bmc_password,mac,ip_address,netmask,gateway,nameservers,labels,disk
wk03,,,,55:55:55:55:55:55,192.168.0.6,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=wk/dev/sda
wk04,,,,66:66:66:66:66:66,192.168.0.7,255.255.255.0,192.168.0.254,1.1.1.1|8.8.8.8,type=wk,/dev/sda
  • 클러스터 스케일링 명령어 수행
    이미 클러스터 배포가 완료된 상태이므로 이번에는 클러스터 구성을 위한 설정 파일은 필요하지 않습니다. 하드웨어 정보 파일과 함께 노드 추가 명령어를 eksctl을 이용하여 수행합니다.
$ eksctl anywhere generate hardware -z hardware_2.csv | kubectl apply -f -
  • 설치 과정과 동일하게 Tinkerbell 이 프로비저닝을 수행

아직은 갈 길이 먼

지금까지의 설명만 보면 EKS-A는 너무나도 편리하고 완벽한 도구처럼 보입니다. 아직 1.0 버전이 릴리스되지 않아서일까요?

실제 베어메탈 환경에서 EKS-A를 설치해 보면서 많은 문제들을 마주할 수 있었습니다. 지금부터는 EKS-A를 실제 운영 환경에 설치하면서 발생하였던 문제들을 해결해나갔던 과정들을 공유드리고자 합니다.

먼저 클러스터 배포 설정을 위한 Manifest 파일에서 지원하는 구성이 베어메탈 환경에서는 아직까지 많이 부족합니다. 아래는 EKS-A의 공식 사이트에서 vSphere 환경에서 배포했을 때와 베어메탈 환경에서 배포했을 때 Manifest 파일을 통하여 최초 배포 시 설정할 수 있는 기능들에 대한 설명입니다.

vSphere

  • 클러스터 배포 설정

베어메탈

  • 클러스터 배포 설정
    • v0.11.0 부터 IAM Authenticator는 지원

위 캡처화면에서 볼 수 있듯이 vSphere는 모든 구성들을 최초 배포 시 Manifest 파일 설정을 통해 자동화할 수 있습니다. 그러나 베어메탈 은 공식적으로 네트워크 플로그인인 CNI만 지원하고 있습니다.(문서에는 나와있지는 않지만 일부 기능은 현재도 Manifest 설정을 통해 구성 가능하며, 배포 후 수동으로도 설정 가능한 경우도 있습니다).

이 부분은 앞으로 신규 버전들이 계속 릴리스 됨에 따라 추가될 것이라고 생각되지만 아직까지는 EKS-A를 통해 얻을 수 있는 장점들을 베어메탈 환경에서는 온전히 누릴 수 없습니다.

이 외에도 EKS-A에서 제공하는 클러스터 관리 기능들 중 베어메탈에서 지원하지 않는 기능들도 존재합니다.

  • 아직 지원하지 않는 주요 관리 기능
    • Etcd Backup and Restore
    • Upgrade Cluster
    • Manage cluster with GitOps
    • Manage cluster with Terrafom
    • 수동으로 삽질하면 설치가 되는 것들도 있음

위 기능들은 vShpere 환경에서는 역시 지원하는 것들입니다. vSphere 기반의 EKS-A 먼저 출시되었기 때문에 당연하지만 베어메탈도 빨리 동일한 기능들이 지원되길 바라봅니다.

삽질을 통해 해결된 문제들

AWS IAM Authenticator

AWS IAM Authenticator는 Kubernetes 클러스터의 인증을 AWS 계정을 통해 수행할 수 있도록 지원하는 도구입니다.

  • 문제 원인
    • 처음 EKS-A를 설치할 당시 버전인 v0.10.0에서는 클러스터 배포 시 Manifest 파일에 AWS IAM Authenticator 관련된 옵션을 추가하고도 정상적으로 수행되지 않았습니다. EKS-A의 Github Issue 목록에도 관련된 스레드가 게시되어 있었습니다.
    • 결국 수동 설정을 통해 해당 문제를 해결할 수밖에 없었습니다. AWS IAM Authenticator 가 정상 동작하지 않는 데에는 2가지 이유가 있었습니다. 1) Kube API 서버 Pod에 AWS IAM Aunthenticator의 인증서가 정상 배포되지 않았고, 2) API 서버의 Pod Manifest 파일에 추가로 필요한 설정들이 선언되어 있지 않았습니다.
  • 해결 방법

    • 이를 해결하기 위해 먼저 aws-iam-authenticator의 CLI를 통해 설정에 필요한 인증서들을 생성하였고, 인증서 파일들을 API 서버의 Pod 가 마운트 하고 있는 Host의 디렉터리에 복사하였습니다.
    • 그리고 Kube API 서버 인증을 위한 Webhook 설정을 API 서버 Manifest 추가하였습니다.
     - --authentication-token-webhook-config-file=/etc/kubernetes/aws-iam-authenticator/kubeconfig.yaml
    • Kubernetes ConfigMap(aws-auth)에 aws account 별로 권한 작성
  • v0.11.0부터 해당 이슈는 fix 되어 최초 클러스터 배포 시 Manifest에 관련 설정을 추가하여 배포할 수 있습니다.

IAM for Pod

IAM for Pod는 흔히 IRSA(IAM Roles for Service Account)라고도 하는데요. 이미 EKS에서 제공하고 있는 기능으로 AWS IAM의 Role 과 Kubernetes의 Service Account를 매핑하여 Service Account에 IAM Role 이 가지는 권한을 그대로 사용할 수 있게 해주는 기능입니다.

AWS 외부 시스템에서 AWS 서비스에 접근하기 위해서는 Access/Secret Key를 발급하여 권한을 획득할 수 있었는데요. Access/Secret Key는 처음 발급할 때 이외에는 다시 확인할 방법이 없기 때문에 분실의 위험이 있고, 타인에게 유출되면 모든 권한을 탈취당할 수 있는 취약점을 가지고 있습니다. 그러나 IAM for Pod 기능을 사용하면 더 이상 키 발급 없이 IAM 권한을 Kubernetes 클러스터에서도 사용할 수 있으므로 키 관리에 대한 번거로움과 취약점을 해결할 수 있습니다.

Kubernetes 클러스터에서 AWS S3의 데이터에 접근하는 Workload 가 많은 곳에서는 굉장히 유용한 기능일 것입니다.

  • 문제 원인
    • Manifest 파일에 IAM for Pod 관련 설정을 추가하였음에도 1) Kube API 서버에 관련 설정이 선언되어 있지 않았습니다. 그리고 2) Service Account를 인지하여 Pod에 권한을 부여해 주는 역할을 수행하는 amazon-eks-pod-identity-webhook Pod 역시 배포되지 않았습니다.
  • 해결 방안

    • 이 문제 또한 앞선 AWS IAM Authenticator 와 마찬가지로 몇 가지 수작업을 통해 정상적으로 기능을 추가할 수 있었습니다.

    • amazon-eks-pod-identity-webhook 프로젝트에서 제공하는 키 생성기를 통해 OIDC Provider에 제공할 공개키를 발급합니다.

    • AWS의 S3(Kubernetes 클러스터의 Key 저장소) 와 Cloudfront를 이용하여 Service Issuer를 구축하고 이를 이용하여 AW IAM의 OIDC(Open ID Connect) Provider 구축하였습니다. OIDC Provider를 통해 IAM의 임시 토큰을 발급받을 수 있도록 [sts.amazonaws.com](http://sts.amazonaws.com)을 Audience로 추가합니다. 최종적으로 토큰을 통해 IAM Role이 가지는 권한을 획득할 수 있도록 OIDC Provider 와 IAM Role 간의 신뢰관계(Trust Relationship)를 설정 하였습니다.

    • 여기까지 하면 IAM Role의 권한을 Kubernetes에서 사용할 수 있는 준비는 끝났습니다. 이제 Kube API 서버의 Manifest 파일에 위에서 구축한 내용들을 연동할 수 있도록 설정을 추가합니다.

      - --api-audiences=sts.amazonaws.com
      - --service-account-issuer=https://{SERVICE_ISSUER_HOST}
    • 마지막으로 Service Account에서 등록한 IAM Role의 정보를 가지고 Pod에 권한을 부여하는 역할을 수행하는 webhook 서비스인 amazon-eks-pod-identity-webhook (https://github.com/aws/amazon-eks-pod-identity-webhook) 프로젝트를 빌드 하여 Kubernetes 클러스터에 배포합니다.

    • 위 과정을 모두 수행하고 나면, 이제 Service Account에 Annotation으로 IAM Role을 설정하면 이 Service Account를 사용하는 Pod들은 해당 Role 권한을 획득할 수 있게 됩니다.

      apiVersion: v1
      kind: ServiceAccount
      metadata:
        annotations:
          eks.amazonaws.com/role-arn: {ROLE_ARN}
        name: iam
        namespace: default
      secrets:
      - name: iam-token-s2f49

Ubuntu 이미지 미제공

EKS-A는 각 노드에 설치할 운영체제로 Amazon에서 배포하는 컨테이너 환경을 위한 경량화 리눅스인 Bottlerocket 과 Ubuntu를 지원하고 있으며 해당 운영체제들의 배포판을 제공하고 있었습니다.

  • 문제 원인
    • v0.11.0부터 EKS-A 용 Ubuntu 이미지를 더 이상 제공하지 않고 있습니다. Ubuntu를 설치하기 위해서는 Amazon에서 제공하는 [image-builder](https://anywhere-assets.eks.amazonaws.com/releases/bundles/24/artifacts/image-builder/0.1.2/image-builder-linux-amd64.tar.gz)를 사용하여 직접 이미지를 빌드하고 자체 이미지 저장소를 구축하여 제공해야 했습니다.
  • 해결 방안

    • 다행히도 EKS-A는 Ubuntu 이미지를 빌드 하기 위한 가이드를 상세히 제공하고 있어 가이드 대로 이미지를 생성할 수 있었습니다.
    • KVM(가상머신)을 지원하는 베어메탈 서버에서만 빌드가 가능하므로 스펙을 만족하는 서버가 필요합니다. 가이드대로 이미지를 빌드하고 Apache 웹서버를 활용하여 해당 이미지를 HTTP를 통해 다운로드할 수 있는 환경을 구축합니다.
    • Kubernetes 클러스터 구성을 위한 Manifest 파일에 운영체제 이미지를 다운로드할 수 있는 경로를 명시해 줍니다.

      spec:
        osImageURL: "http://my-web-server/ubuntu-v1.23.7-eks-a-12-amd64.gz" 

지금까지 설치 과정에서 마주했던 여러 문제들 중 일부의 해결 방안에 대해 공유하였습니다. 예상치 못한 문제들을 마주했지만 다행히도 EKS-A의 Github 저장소 내 이슈 게시판에서는 버그 리포팅이나 설치 중 발생하는 예외 상황에 대한 문의에 기술 지원 구독을 하고 있지 않음에도 신속하게 대응해 주고 있어 많은 도움을 받을 수 있었습니다.

마치며

MLOps 환경을 Baremetal 환경에 구축하기 위해 여러 Kubernetes 배포판 중 저희 상황에서 가장 쓰기 적합하다고 생각한 EKS-A를 선택하고 실제 운영환경에 구축을 해보았습니다. 생각보다는 많은 우여곡절 끝에 원하는 수준의 구성 상태로 설치를 완료할 수 있었습니다.

팀에서 이미 AWS에 EKS를 배포하고 운영하고 있었던 터라 비록 베어메탈 환경이지만 EKS를 모태로 하는 EKS-A에 대해 설치 및 운영 편의성면에서 많은 기대를 했었습니다.

하지만 출시된 지 얼마 되지 않았고, 아직 버전도 v0.x.x에 머무르고 있어서인지 기대했던 만큼의 만족도를 주지는 못하였습니다. 특히 Managed Kubernetes처럼 한 번의 CLI 수행을 통해 Kubernetes 버전을 업그레이드할 수 있는 기능이 아직 베어메탈 환경에서 제공되지 않는 점이 특히 아쉬웠습니다.

그럼에도 불구하고 AWS 와 연동하여 사용할 수 있는 기능들을 제공하고, 설치 과정이 매우 간단하며 Tinkerbell을 통해 운영체제 설치부터 모두 자동화되어 있는 부분은 인상 깊었습니다.

vSphere 환경에서 제공하고 있는 EKS-A의 모든 기능들이 하루빨리 베어메탈에도 추가되길 기대합니다.

참고자료