6주차 - EKS Fargate와 ECR

월간-CS | 쿠버네티스 비기너 클래스
이민석's avatar
Sep 05, 2024
6주차 - EKS Fargate와 ECR

지금까지

아래 과정을 수행하였습니다.

  1. 1주차 - Docker & EKS 기초

  2. 2주차 - 다양한 유형의 앱 배포하기

  3. 3주차 - Pod 그리고 RDS 연결

  4. 4주차 - CLB, ALB 그리고 aws-load-balancer-controller

  5. 5주차 - AWS Ingress 딥다이브

이번 주차에는

이번 주차에는 아래 3가지 내용들에 대해서 학습합니다.

  1. Fargate*와 사용하는 EKS

  2. aws-load-balancer-controller로 만드는 NLB

  3. ECR*과 함께 사용하는 EKS

Fargate* : AWS Fargate는 Amazon ECS, EKS와 연동되는 컨테이너용 서버리스 컴퓨팅 플랫폼입니다. — [Ref]
ECR* : AWS ECR은 Application 이미지 및 아티펙트를 안정적으로 배포할 수 있도록 뛰어난 성능 호스트를 제공해주는 완전관리형 컨테이너 레지스트리입니다. — [Ref]

AWS EKS with Fargate

  1. EKS, Fargate에 대한 기본적인 이해

  2. EKS Node Group 및 Fargate 사례

EKS, Fargate에 대한 기본적인 이해

Fargate는 Amazon ECS, EKS 등과 연동이되는 컨테이너용 서버리스 컴퓨팅 플랫폼입니다. 따라서 컨테이너에 적합한 크기의 온디멘드 컴퓨팅 용량을 제공합니다.

Fargate를 AWS EKS와 함께 사용하면
EKS Upstream Extensible Model을 사용한 Controller를 사용하여 EKS와 Fargate가 통합됩니다.

이 Controller는 EKS Managed Control Plane의 일부로 실행되어 기본 Kubernetes Pods를 Fargate로 스케줄링하는 역할을 담당합니다.

Fargate Controller는 여러 가지 변경 및 유효성 검사 Admission Controller 외에도 기본 kube-scheduler와 함께 실행되는 새로운 스케줄러가 포함되어 있습니다.

EKS Node Group 및 Fargate 사례

EKS에서는 3가지 Node를 지원하고 있습니다.

  1. Managed Node Group

  2. Unmanaged Node Group

  3. Fargate Node Gruop

그래서 EKS에서는 다음과 같은 조합 등 으로 Node를 사용합니다.

  1. EC2 Node Group만 사용하는 사례

    1. Managed EC2 Node Group

    2. Unmanaged EC2 Node Group

  2. EC2 Node Group과 Fargate를 혼합하여 사용하는 사례

    1. Managed EC2 Node Gruop

    2. Unmanaged EC2 Node Group

    3. Fargate Nodes

  3. Fargate만 사용하는 사례

    1. Fargate Nodes

여기에 각 항목별 특징을 비교하면 다음과 같습니다.

Options

Managed
Node Group

Unmanaged
Node Group

Fargate

작업 단위

Pod & EC2

Pod & EC2

Pod

비용 단위

EC2

EC2

Pod

호스트 Lifecycle

AWS
allowed ssh

Customer

Visible Host* 없음

호스트 AMI

AWS vetted
AMIs

Customer
BYO

Visible Host* 없음

호스트 : Pods

1:N

1:N

1:1

Visible Host* : 개발자 및 인프라 엔지니어가 SSH를 통해서 접속가능한 Host가 없다는 것을 표현하기 위해서 “Visible Host가 없다”라는 표현을 사용하였습니다.

Fargate Profile 생성하기

Fargate Profile은 EC2 Instance Profile과 유사한 개념입니다.
EC2 Instance Profile이 EC2가 타 AWS Resource에 엑세스하고 작업을 처리하기 위해서 사용되듯, Fargate Profile도 이와 같습니다.

Fargate Profile은 EKS가 Fargate와 관련해서 필요한 권한들을 정의하고 있습니다. 대표적으로 아래와 같은 권한들이 포함됩니다. [Ref]

  1. K8s Pods가 배포될 Subnet에 대한 권한

  2. K8s Agent가 컨테이너 이미지를 pods에 다운로드 하기 위한 권한

  3. 기타 작업을 자동화 하기 위해서 필요한 권한

EKS Fargate를 생성하기 위해서는 eksctl 혹은 AWS-CLIv2를 사용할 수 있습니다.

  • eksctl을 사용하는 방법 — [Ref]

    eksctl get fargateprofile --cluster test-eks
    
    eksctl create fargateprofile --cluster test-eks \ 
                                 --name test-fargate \ 
                                 --namepsace test-fargate
  • AWS-CLIv2를 사용하는 방법 — [Ref]

    • fargate-profile.json 파일 준비하기

      {
          "fargateProfileName": "test-fargate",
          "clusterName": "test-eks",
          "podExecutionRoleArn": "arn:aws:iam::xxx:role/AmazonEKSFargatePodExecutionRole",
          "subnets": [
              "subnet-ID",
              "subnet-ID"
          ],
          "selectors": [
              {
                  "namespace": "test-fargate"
              }
          ]
      }
      

    • aws eks create-fargate-profile 사용하기

      aws eks create-fargate-profile --cli-input-json file://fargate-profile.json

Namespace 생성하기 (주의)

EKS Fargate Profile를 생성할 때, 지정한 namespace를 생성해줍니다.

  • test-fargate-namespace.yaml

    apiVersion: v1
    kind: Namespace
    metadata:
      name: test-fargate
  • K8s Manifest 배포하기

    kubectl apply -f test-fargate-namespace.yaml

Ingress Manifest

aws-load-balancer-controller에서 Ingress가 Service에 접속하는 방식을 반드시 ip방식으로 설정해주세요.

alb.ingress.kubernetes.io/target-type: ip

YAML을 이용해서 Fargate Profile 생성하기

K8s Object 중 ClusterConfig을 사용하면 Fargate Profile을 손쉽게 생성할 수 있습니다. 아래는 test-fargate-1, test-fargate-2 라는 k8s namespace에 Fargate Pod를 생성할 수 있도록 만들어주는 ClusterConfig입니다.

apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: test-fargate
  region: us-east-1

fargateProfiles:
  - name: test-fargate-2
    selectors:
     - namespace: test-fargate-1
  - name: test-fargate-2
    selectors:
     - namespace: test-fargate-2

EKS Fargate로의 마이그레이션

이미 가동 중인 어플리케이션을을 EKS Managed Node Group에서 EKS Fargate로 옮길려면 namespace가 달라지는 이슈가 생깁니다.

Stackoverflow에서는 K8s Manifest의 namespace를 변경하게 되면 K8s object가 그대로 복제되는 것에 불과 하다고 적혀있습니다. 아래 실습을 진행하면 실제로도 그런 것을 알 수 있습니다.

  1. 기존 Namespace로 배포하기

    1. Pod Manifest 파일 작성하기

      apiVersion: apps/v1
      kind: Pod
      metadata:
        name: prev-pod
        namespace: prev-namespace
      spec:
        containers:
        - name: nginx-container
          image: nginx:latest
          ports:
          - containerPort: 80
    2. Pod Manifest 배포하기

      kubectl apply -f pod-manifest.yaml
    3. Pod 확인하기

      kubectl get pods -A -o wide
  2. 신규 Namespace로 변경 후 배포하기

    1. Pod Manifest 파일 수정하기

      apiVersion: apps/v1
      kind: Pod
      metadata:
        name: now-app
        namespace: now-namespace # prev-namespace
      spec:
        containers:
        - name: nginx-container
          image: nginx:latest
          ports:
          - containerPort: 80

    2. Pod Manifest 배포하기

      kubectl apply -f pod-manifest.yaml
    3. Pod 확인하기

      kubectl get pods -A -o wide

실제로는 API 서버 배포를 위해서 Ingress, Service, Deployment, ReplicaSet, Pods 등을 사용하므로, 이 전체가 복제될 것입니다.

중요한 키 포인트는 Ingress Traffic을 다운타임 없이 스위칭 하는 것입니다. 기존에 있는 Service를 새로운 Service로 보내도록 하는 것이 좋습니다.

apiVersion: v1
kind: Service
metadata:
  name: prev-svc
  namespace: prev-namespace

spec:
  type: ExternalName
  externalName: now-svc.now-namespace.svc.cluster.local

이후 CoreDNS에 TTL 설정을 일부 손보고 나머지 마이그레이션 작업을 진행할 수 있습니다.

app-old.example.com, TTL 300, type A, <namespace-new ingress IP>

가격 비교

다양한 제품군에서 EC2 Instance에 비해서 Fargate가 훨씬 비싼 가격대를 보여줍니다.

Specification

EC2
(t3.small)

Fargate

vCPU

2

0.0208

0.09312

RAM

2

0.01022

NLB Ingress

4주차에 aws-load-balancer-controller를 통해서 ALB를 만들었습니다.
이 때는 IngressClass + Ingress + Service .spec.type: NodePort 옵션으로 생성했습니다.

NLB

NLB with HTTPs

NLB는 Service .spec.type: LoadBalancer 옵션으로 생성할 수 있습니다.
이때 .metadata.annotations.service\.beta\.kubernetes\.io/aws-load-balancer-typenlb-ip 아니면 external 중 하나를 선택합니다.

apiVersion: v1
kind: Service
metadata:
  name: <Service-Name>
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-name: <lb-name>
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-target-type: instance

    # TLS
    service.beta.kubernetes.io/aws-load-balancer-cert: <acm-arn>
    service.beta.kubernetes.io/aws-load-balancer-ports: 443
    service.beta.kubernetes.io/aws-load-balancer-negotiation-policy: ELBSecurityPolicy-TLS13-1-2-2021-06
    service.beta.kubernetes.io/aws-load-balancer-backend-policy: tcp

    # Access Control
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"

    # AWS Resources Tags
    service.beta.kubernetes.io/load-balancer-source-ranges: 0.0.0.0/0

spec:
  type: LoadBalancer
  selector:
    app: <deployment-name>
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 80

NLB with IP Mode, Instance Mode

NLB를 생성하면 IP 혹은 Instance Mode 중 하나를 선택해서 생성할 수 있었습니다.

apiVersion: v1
kind: Service
metadata:
  name: <Service-Name>
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-type: external
    service.beta.kubernetes.io/aws-load-balancer-target-type: ip 

    service.beta.kubernetes.io/aws-load-balancer-target-type: instance

NLB with ExternalDNS

ExternalDNS를 사용해서 Route53에서 NLB로 레코드를 생성할 수 있습니다.

# ...

metadata:
  annotations:
    # NLB with HTTPS와 동일
    external-dns.alpha.kubernetes.io/hostname: <Domain>
    service.beta.kubernetes.io/aws-load-balancer-eip-allocations: <eip1>, <eip2>

EKS & ECR

EKS에서 App을 배포하기 위해서 Container Image를 사용합니다.
이 경우에 적합한 Instance Profile을 설정해야 해야 사용이 가능합니다.

EKS NodeGroup Instance Profile

Amazon EKS에서는 NodeGroup, Fargate 중 하나에서 파드를 실행합니다.
해당 NodeGroupo, Fargate에서 ECR Private Repository를 사용하기 위해서는 적합한 IAM Policy가 필요합니다. [Ref]

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:BatchCheckLayerAvailability",
                "ecr:BatchGetImage",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetAuthorizationToken"
            ],
            "Resource": "*"
        }
    ]
}

EKS Deployment with ECR Image

ECR Private Repository에 올라간 컨테이너 이미지는
.spec.template.spec.containers[*].image에 명시하여 사용이 가능합니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <app-name>
  labels:
    app: <app-name>

spec:
  replicas: 2
  selector:
    matchLabels:
      app: <app-name>
  template:
    metadata:
      labels:
        app: <app-name>
    spec:
      containers:
        - name: <container-name>
          image: <account-id>.dkr.ecr.<region>.amazonaws.com/<ecr-name>:<tags>
          # 123456789101.dkr.ecr.ap-northeast-2.amazonaws.com/app:latest

          resources:
            requests:
              memory: "128Mi"
              cpu: "500m"
            limits:
              memory: "256Mi"
              cpu: "1000m"
          ports:
            - containerPort: 80

참고 자료

Share article

Unchaptered