BACKEND/AWS

AWS EKS - Web Application (1)

gngsn 2022. 7. 17. 23:53

본 포스팅은 AWS EKS의 실습 과정을 기록한 내용입니다.

 

 

좋은 기회를 얻어 AWS EKS를 학습하고 실습하는 시간을 가졌습니다.

AWS ECR로 Docker image를 올려 관리하고, EKS를 직접 실습하는 시간을 가졌습니다.

좋은 기회를 그대로 끝내기는 아쉬워서, 따로 기록한 내용을 정리했습니다.

참고 영상은 링크를 통해 확인할 수 있습니다.

 

 

기술의 기초 지식인 Docker와 관련된 이전 포스팅을 참고하셔도 좋을 듯 합니다.

📌  Docker Series

Docker Engine, 제대로 이해하기 (1) - docker engine deep dive

Docker Engine, 제대로 이해하기 (2) - namespace, cgroup

Docker Network, 제대로 이해하기 (1) - libnetwork

Docker Network, 제대로 이해하기 (2) - bridge, host, none drivers

 

📌  AWS EKS - Web Application

AWS EKS - Web Application(1) 

AWS EKS - Web Application(2)

AWS EKS - Web Application(3)

 

Amazon EKS

Amazon EKS 는 Kubernetes를 쉽게 실행할 수 있는 관리형 서비스입니다. Amazon EKS를 사용하시면 AWS 환경에서 Kubernetes 컨트롤 플레인 또는 노드를 직접 설치, 운영 및 유지할 필요가 없습니다.

 

 

Amazon EKS는 여러 가용 영역에서 Kubernetes 컨트롤 플레인 인스턴스를 실행하여 고가용성을 보장합니다. 또한, 비정상 컨트롤 플레인 인스턴스를 자동으로 감지하고 교체하며 자동화된 버전 업그레이드 및 패치를 제공합니다.

Amazon EKS는 다양한 AWS 서비스들과 연동하여 애플리케이션에 대한 확장성 및 보안을 제공하는 서비스를 제공합니다.

 

✔️ 컨테이너 이미지 저장소인 Amazon ECR(Elastic Container Registry)

✔️ 로드 분산을 위한 AWS ELB(Elastic Load Balancing)

✔️ 인증을 위한 AWS IAM

✔️ 격리된 Amazon VPC

 

Amazon EKS는 오픈 소스 Kubernetes 소프트웨어의 최신 버전을 실행하므로 Kubernetes 커뮤니티에서 사용되는 플러그인과 툴을 모두 사용할 수 있습니다. 온프레미스 데이터 센터에서 실행 중인지 퍼블릭 클라우드에서 실행 중인지에 상관없이, Amazon EKS에서 실행 중인 애플리케이션은 표준 Kubernetes 환경에서 실행 중인 애플리케이션과 완벽하게 호환됩니다. 즉, 코드를 수정하지 않고 표준 Kubernetes 애플리케이션을 Amazon EKS로 손쉽게 마이그레이션할 수 있습니다.

 

 

Kubernetes Structure

쿠버네티스는 Contorl Plan과 Data Plan으로 구분할 수 있습니다.

사용자가 원하는 상태로 동작하도록 관리하는 것입니다.

 

✔️ Control plane : Master Node. 명령을 받고, 어떤 Data plane에 전달할지를 선택합니다. EKS이나 ECS를 사용할 수 있습니다.

✔️ Data plane : Worker Node. 실제 올려지는 곳으로, EC2나 Fagate 등이 존재합니다.

 

 

 

Kubernetes Objects

쿠버네티스의 오브젝트는 바라는 상태(desired state)를 담은 레코드입니다. 오브젝트를 생성하면 쿠버네티스의 컨트롤 플레인에서 오브젝트의 현재 상태(current state) 와 바라는 상태를 일치시키기 위해 끊임없이 관리합니다.

쿠버네티스의 오브젝트에는 파드(pod), 서비스(service), 디플로이먼트(Deployment) 등이 존재합니다.

 

 

 

Environment Setting

AWS CLI

command-line shell의 명령을 사용하여 AWS 서비스와 상호 작용할 수 있는 오픈 소스 툴

 

참고 링크에 따라 아래와 같이 AWS CLI를 설치합니다.

 

# download
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install

# or update
$ sudo pip install --upgrade awscli
 
 
 

현재 실행할 EKS를 사용할 때에는 1.18.124 >= version 혹은 2.0.42 >= version을 만족해야합니다.

 
$ aws --version​
 
 
 
 

kubectl

쿠버네티스 클러스터에 명령을 내리는 CLI
 

 

쿠버네티스는 오브젝트 생성, 수정 혹은 삭제와 관련한 동작을 수행하기 위해 쿠버네티스 API를 사용하는데,

kubectl CLI를 사용하면 해당 명령어가 쿠버네티스 API를 호출해 관련 동작을 수행합니다.

 

 

Amazon EKS에서 사용하는 Kubernetes 버전에 상응하는 kubectl 버전을 설치합니다.

 

$ sudo curl -o /usr/local/bin/kubectl  \
   https://amazon-eks.s3.us-west-2.amazonaws.com/1.21.2/2021-07-05/bin/linux/amd64/kubectl
$ sudo chmod +x /usr/local/bin/kubectl
$ kubectl version --client=true --short=true
# Client Version: v1.21.2-13+d2965f0db10712

 

kubectl 자동 완성 기능은 kubectl cheatsheet 링크를 참조할 수 있습니다.

 

 

 

Other Tools

jq

JSON 형식의 데이터를 다루는 커맨드라인 유틸리티

sudo yum install -y jq

 

 

bash-completion

kubectl completion script 생성 명령어

 

kubectl completion script는 kubectl 명령어의 자동 완성을 지원합니다.

해당 기능은 bash-completion에 의존하기 때문에 아래의 명령어를 통해 bash-completion을 설치합니다.

 

sudo yum install -y bash-completion

 

Origin 쉘에 completion script를 소싱하면 kubectl 명령어의 자동 완성을 가능하게 만들 수 있습니다.

하지만 이런 completion script는 bash-completion에 의존하기 때문에 위의 명령어를 통해, bash-completion 을 설치해야 합니다.

 

Bash 쉘에서 kubectl completion script는 kubectl completion bash 명령어를 통해 생성할 수 있습니다.

 

 

 

eksctl

(🔗 Link) EKS 클러스터를 쉽게 생성 및 관리하는 CLI 툴

 

Amazon EKS 클러스터를 배포하는 방식은 다양합니다.

e.g. AWS 콘솔, CloudFormation, CDK, eksctl 및 Terraform 등

Go 언어로 쓰여 있으며 CloudFormation 형태로 배포됩니다.

아래의 명령어를 통해, 최신의 eksctl 바이너리를 다운로드 합니다.

 

curl --silent --location "<https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$>(uname -s)_amd64.tar.gz" | tar xz -C /tmp

 

바이너리를 /usr/local/bin으로 옮깁니다.

 

sudo mv -v /tmp/eksctl /usr/local/bin

 

아래의 명령어를 통해 설치 여부를 확인합니다.

eksctl version
# 0.105.0

 

 

AWS ECR

컨테이너 이미지를 저장, 공유 및 배포할 수 있는 완전관리형 Docker 컨테이너 레지스트리

 

ECR을 통해 이미지를 가용성과 확장성이 뛰어난 아키텍처에 호스팅하여 컨테이너를 안정적으로 배포할 수 있습니다. AWS IAM을 사용하여 컨테이너 이미지에 액세스할 수 있는 사용자 및 리소스에 대한 권한을 제어하고 모니터링할 수 있고, 이미지 취약점 스캔 기능도 활성화할 수 있습니다. 또한, 리포지토리를 프라이빗 혹은 퍼블릭으로 설정할 수 있습니다.

 

 

Docker

docker는 예전에 정리한 내용이 있는데, 참고차 링크합니다.

아래의 명령어를 통해, 컨테이너라이징할 소스 코드를 다운 받습니다.

 

$ git clone https://github.com/joozero/amazon-eks-flask.git

 

 AWS CLI를 통해, 이미지 리포지토리를 생성합니다.

리포지토리 이름은 demo-flask-backend라고 설정했습니다.

또한, 리전 값에는 EKS 클러스터를 배포할 리전 코드(e.g. ap-northeast-2)를 명시합니다.

 

$ aws ecr create-repository \
--repository-name demo-flask-backend \
--image-scanning-configuration scanOnPush=true \
--region ${AWS_REGION}

위의 명령어를 입력하면 아래와 같이 ECR 콘솔창에서 확인할 수 있습니다.

 

 

이제 만들어진 레포지토리에 도커를 push 해서 내용을 채워야 합니다.

'푸시명령 보기'를 선택해서 push 하려는 도커를  AWS CLI를 통해 올릴 수 있습니다.

 

 

위의 명령을 통해 아래와 같이 최신 버전(latest)의 컨테이너가 생성된 것을 확인할 수 있습니다.

 

 

 

 

 

eksctl: create cluster

 

eksctl을 사용해 EKS 클러스터를 생성할 수 있습니다.

실습한 내용으로 아래와 같은 구조를 생성했습니다.

 

 

이때, eksctl을 사용하여 아무 설정 값을 주지 않고 eksctl create cluster 명령어를 실행하면 default parameter로 클러스터가 배포됩니다.

예시로 제시된 클러스터 배포 설정 파일을 통해 배포를 진행해 보겠습니다.

 

cat << EOF > eks-demo-cluster.yaml
---
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: eks-demo # 생성할 EKS 클러스터명
  region: ${AWS_REGION} # 클러스터를 생성할 리전
  version: "1.21"

vpc:
  cidr: "192.168.0.0/16" # 클러스터에서 사용할 VPC의 CIDR

managedNodeGroups:
  - name: node-group # 클러스터의 노드 그룹명
    instanceType: m5.large # 클러스터 워커 노드의 인스턴스 타입
    desiredCapacity: 3 # 클러스터 워커 노드의 갯수
    volumeSize: 10  # 클러스터 워커 노드의 EBS 용량 (단위: GiB)
    iam:
      withAddonPolicies:
        imageBuilder: true # Amazon ECR에 대한 권한 추가
        # albIngress: true  # albIngress에 대한 권한 추가
        cloudWatch: true # cloudWatch에 대한 권한 추가
        autoScaler: true # auto scaling에 대한 권한 추가

cloudWatch:
  clusterLogging:
    enableTypes: ["*"]
EOF

 

아래와 같이 클러스터를 배포한 다음, 생성된 worker node를 확인해볼 수 있습니다.

$ eksctl create cluster -f eks-demo-cluster.yaml
$ kubectl get nodes 
NAME                STATUS   AGE
default             Active   33h
kube-public         Active   33h
kube-system         Active   33h
...

 

 

 

Ingress Controller

본 실습에서는 AWS Load Balancer Controller 를 사용하여 진행합니다.

 

 

인그레스 Ingress

주로 클러스터 외부에서 쿠버네티스 내부로 접근할 때, 요청들을 어떻게 처리할지 정의해놓은 규칙이자 리소스 오브젝트입니다. 한마디로 외부의 요청이 내부로 접근하기 위한 관문의 역할을 하는 것이죠. 외부 요청에 대한 로드 밸런싱, TLS/SSL 인증서 처리, HTTP 경로에 대한 라우팅 등을 설정할 수 있습니다. 인그레스는 L7 영역의 요청을 처리합니다.

쿠버네티스에서 서비스 타입 중, NodePort 혹은 LoadBalancer로도 외부로 노출할 수 있지만 인그레스 없이 서비스를 사용할 경우, 모든 서비스에게 라우팅 규칙 및 TLS/SSL 등의 상세한 옵션들을 적용해야 되죠. 그래서 인그레스가 필요합니다.

 

 

 

인그레스는 외부 요청 처리에 대한 규칙들을 설정해놓은 것을 의미하며, 이런 설정이 동작하기 위해서 필요한 것이 인그레스 컨트롤러입니다. kube-controller-manager의 일부로 실행되는 다른 컨트롤러와 달리 인그레스 컨트롤러는 클러스터와 함께 생성되진 않습니다. 따라서 직접 구현해야 합니다.

 

 

AWS Load Balancer Controller

Amazon EKS의 Application Load Balancing 이란 클러스터에 인그레스 자원이 생성될 때에 ALB(Application Load Balancer) 및 필요한 자원이 생성되도록 트리거하는 컨트롤러입니다. 인그레스 자원들은 ALB를 구성하여 HTTP 또는 HTTPS 트래픽을 클러스터 내 파드로 라우팅합니다.

 

✔️ 쿠버네티스 Ingress: Application Load Balancers으로 프로비저닝

✔️ 쿠버네티스 Service: Network Load Balancers으로 프로비저닝

 

 

AWS Load Balancer 컨트롤러에서 지원하는 트래픽 모드는 아래의 두 가지입니다.

 

✔️ Instance(default)

클러스터 내 노드를 ALB의 대상으로 등록합니다. ALB에 도달하는 트래픽은 NodePort로 라우팅된 다음 파드로 프록시됩니다.

 

✔️ IP

: 파드를 ALB 대상으로 등록합니다. ALB에 도달하는 트래픽은 파드로 직접 라우팅됩니다. 해당 트래픽 모드를 사용하기 위해선 ingress.yaml 파일에 주석을 사용하여 명시적으로 지정해야 합니다.

 

 

먼저, 앞으로의 매니페스트를 관리하기 위해 루트 폴더(e.g. /home/ec2-user/environment/)에서 manifests라는 이름을 가진 폴더를 생성합니다. 그 후, manifests 폴더 안에서, ALB 인그레스 컨트롤러 관련 매니페스트를 관리하기 위한 폴더 alb-ingress-controller를 만듭니다.

$ mkdir -p manifests/alb-ingress-controller && cd manifests/alb-ingress-controller

 

AWS Load Balancer 컨트롤러를 배포하기 전, 우리는 몇 가지 작업을 수행해야 합니다. controller가 워커 노드 위에서 동작되기 때문에 IAM permissions를 통해, AWS ALB/NLB 리소스에 접근할 수 있도록 만들어야 합니다. IAM permissions는 ServiceAccount를 위한 IAM roles를 설치하거나 워커 노드의 IAM roles에 직접적으로 붙일 수 있습니다.

 

 

IAM OIDC

AWS Load Balancer 컨트롤러를 배포하기 전, 클러스터에 대한 IAM OIDC(OpenID Connect) identity Provider를 생성합니다. 쿠버네티스가 직접 관리하는 사용자 계정을 의미하는 service account에 IAM role을 사용하기 위해, 생성한 클러스터(현재 실습에서의 eks-demo)에 IAM OIDC provider가 존재해야 합니다.

 

 

 

$ eksctl utils associate-iam-oidc-provider \
    --region ${AWS_REGION} \
    --cluster eks-demo \
    --approve

 

생성한 IAM OIDC 자격 증명 공급자는 IAM 콘솔 Identity providers 메뉴 혹은 아래의 명령어를 통해 확인할 수 있습니다.

먼저, 클러스터의 OIDC provider URL을 아래의 명령어들을 통해 확인합니다.

 

$ aws eks describe-cluster --name eks-demo --query "cluster.identity.oidc.issuer" --output text
# e.g. https://oidc.eks.ap-northeast-2.amazonaws.com/id/8A6E78112D7F1C4DC352B1B511DD13CF

 

 

위의 결과 값에서 /id/ 뒤에 있는 값을 복사한 후, 아래 명령어를 수행 후 결과 값이 출력되면 IAM OIDC identity provider가 클러스터에 생성이 된 것입니다.

 

$ aws iam list-open-id-connect-providers | grep 8A6E78112D7F1C4DC352B1B511DD13CF

 

만약, 아무 값도 나타나지 않으면 생성 작업을 수행해야 합니다. 

# AWS Load Balancer Controller에 부여할 IAM Policy를 생성
$ aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.1/docs/install/iam_policy.json

 

 

AWS Load Balancer Controller를 위한 ServiceAccount를 생성합니다.

EKS 클러스터를 배포할 때, AWS Load Balancer Controller와 관련된 IAM policy를 Addon 형태로 워커 노드에 추가하는 방법도 있습니다. 하지만 본 실습에서는 여기 의 자료를 참고하여 진행합니다.

 

$ eksctl create iamserviceaccount \
    --cluster eks-demo \
    --namespace kube-system \
    --name aws-load-balancer-controller \
    --attach-policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --approve

 

 

AWS Load Balancer controller를 클러스터에 추가하는 작업을 수행합니다. 먼저, 인증서 구성을 웹훅에 삽입할 수 있도록 cert-manager를 설치합니다. Cert-manager는 쿠버네티스 클러스터 내에서 TLS인증서를 자동으로 프로비저닝 및 관리하는 오픈 소스입니다.

kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml

 

 

Load balancer controller yaml 파일을 다운로드 합니다.

 

wget https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.1/v2_4_1_full.yaml

 

yaml 파일에서 클러스터의 cluster-name을 편집합니다. 본 실습에서는 eks-demo로 설정합니다.

 

spec:
    containers:
    - args:
        - --cluster-name=eks-demo # 생성한 클러스터 이름을 입력
        - --ingress-class=alb
        image: amazon/aws-alb-ingress-controller:v2.4.1

 

그리고 yaml 파일에서 ServiceAccount yaml spec을 없애줍니다. AWS Load Balancer Controller를 위한 ServiceAccount를 이미 생성했기 때문입니다. 아래의 내용을 삭제한 후, yaml 파일을 저장합니다.

 

 

---
apiVersion: v1
kind: ServiceAccount
metadata:
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: aws-load-balancer-controller
  name: aws-load-balancer-controller
  namespace: kube-system

 

 

 

AWS Load Balancer controller 파일을 배포합니다.

 

 

$ kubectl apply -f v2_4_1_full.yaml

# 배포가 성공적으로 되고 컨트롤러가 실행되는지 확인
$ kubectl get deployment -n kube-system aws-load-balancer-controller
NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
aws-load-balancer-controller   0/1     1            0           5s

# service account가 생성된 것을 확인
$ kubectl get sa aws-load-balancer-controller -n kube-system -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::~:role/eksctl-eks-demo-addon-iamserviceaccount-kube-Role1-...
  creationTimestamp: "2022-07-15T06:22:13Z"
  labels:
    app.kubernetes.io/managed-by: eksctl
  name: aws-load-balancer-controller
  namespace: kube-system
  resourceVersion: "8406"
  uid: 5227d4fd-...
secrets:
- name: aws-load-balancer-controller-token-fbtg6
$

 

Addon

클러스터 내부에서 필요한 기능들을 위해 실행되는 파드들

 

애드온에 사용되는 파드들은 디플로이먼트, 리플리케이션 컨트롤러 등에 의해 관리됩니다. 그리고 이 애드온이 사용하는 네임스페이스가 kube-system입니다. Yaml 파일에서 네임스페이스를 kube-system으로 명시했기에 위의 명령어로 파드 이름이 도출되면 정상적으로 배포된 것입니다. 

 

# 로그 확인
$ kubectl logs -n kube-system $(kubectl get po -n kube-system | egrep -o "aws-load-balancer[a-zA-Z0-9-]+")

# 자세한 속성 값 확인 명령어
$ ALBPOD=$(kubectl get pod -n kube-system | egrep -o "aws-load-balancer[a-zA-Z0-9-]+")
$ kubectl describe pod -n kube-system ${ALBPOD}