[Hands-On] AWS EKS (Amazon Elastic Kubernetes Service) 이해하기

1. AWS EKS 란?

AWS EKS는 Amazon Web Services(AWS)에서 제공하는 완전관리형 컨테이너 오케스트레이션 서비스입니다. EKS는 Kubernetes, 즉 쿠버네티스를 기반으로 하며, 사용자는 인프라 관리를 AWS에 맡기고, 애플리케이션 배포에 집중할 수 있습니다.

2. AWS EKS의 주요 장점

완전관리형 서비스

EKS는 완전관리형 서비스로서, 쿠버네티스 클러스터를 설정, 운영, 유지 관리하는 복잡한 작업을 AWS가 대신 수행합니다. 이를 통해 개발자는 인프라 걱정 없이 애플리케이션에 집중할 수 있습니다.

확장성

EKS는 AWS의 다양한 서비스와 연동이 가능합니다. 이를 통해 사용자는 애플리케이션의 확장성을 쉽게 관리할 수 있습니다. 또한, AWS Fargate와 함께 사용함으로써 서버리스 컨테이너를 실행할 수 있습니다.

보안 및 준수

EKS는 AWS의 IAM 을 이용하여 클러스터의 보안을 강화합니다. 또한, AWS의 다양한 보안 서비스와 연동하여, 데이터 보호 및 규정 준수를 지원합니다.

2.1 AWS EKS의 주요 단점

AWS EKS를 이용하면 많은 이점이 있지만, 몇 가지 단점도 고려해야 합니다.

비용

EKS는 완전관리형 서비스이기 때문에, 이에 대한 비용이 발생합니다. 또한, 클러스터를 실행하는 데 필요한 EC2 인스턴스나 다른 AWS 리소스에 대한 비용도 추가로 청구됩니다. 따라서, 크기가 작은 프로젝트나 예산이 제한적인 경우 비용 부담이 클 수 있습니다.

복잡성

EKS는 쿠버네티스를 기반으로 하기 때문에, 쿠버네티스에 대한 이해가 필요합니다. 쿠버네티스는 강력한 컨테이너 관리 Tool 이지만, 학습 곡선이 가파르고 복잡한 편입니다. 따라서, 쿠버네티스에 익숙하지 않은 사용자에게는 EKS의 사용이 어려울 수 있습니다.

유연성

EKS는 AWS에서 관리하는 서비스이므로, 사용자가 직접 컨트롤할 수 없는 부분이 있습니다. 예를 들어, 컨트롤 플레인의 세부 설정을 변경할 수 없거나, 특정 버전의 쿠버네티스를 사용하고 싶어도 AWS가 지원하는 버전만 선택할 수 있습니다.

3. EKS Hands-On

AWS의 완전관리형 쿠버네티스 서비스인 Amazon Elastic Kubernetes Service (EKS) 에 대한 실습을 진행 하겠습니다. 이 Hands-on 에서는 EKS 클러스터를 생성하고, 애플리케이션을 배포하고, AWS EKS에 대해 좀 더 깊게 다뤄 보겠습니다.

3.1 AWS Cloud9 생성 [Hands-On]

먼저 EKS Cluster 접근을 위해 AWS Cloud9 을 사용합니다.

AWS Cloud9은 클라우드 기반의 통합 개발 환경(IDE)입니다. Cloud9은 웹 브라우저를 통해 코드 작성, 실행, 디버깅 등의 작업을 할 수 있게 해주며, 서버리스 애플리케이션을 쉽게 개발 및 배포 할 수 있는 기능을 제공합니다.

이런 조합은 아래와 같은 장점을 제공합니다.

효율적인 개발 환경

Cloud9은 브라우저 기반의 통합 개발 환경(IDE)을 제공하므로, 어디서나 쉽게 애플리케이션을 개발할 수 있습니다. 또한, Cloud9은 다양한 프로그래밍 언어를 지원하므로, EKS에서 실행할 애플리케이션을 다양한 언어로 작성할 수 있습니다.

서버리스 개발 환경

Cloud9은 AWS 서비스와 통합되어 있어, 서버리스 애플리케이션을 쉽게 개발하고 테스트할 수 있습니다. 이를 통해 EKS의 서버리스 옵션인 Fargate를 이용한 애플리케이션 개발이 용이해집니다.

협업 지원

Cloud9은 실시간으로 여러 사람이 함께 코드를 작성하고 테스트할 수 있는 협업 기능을 제공합니다. 이를 통해 팀원들과 함께 EKS 애플리케이션을 개발 및 배포 하는데 유용합니다.

자동화 지원

Cloud9은 AWS CLI와 통합되어 있어, EKS 클러스터를 관리하거나 애플리케이션을 배포하는 등의 작업을 자동화하는 데 유용합니다.

이처럼, AWS Cloud9 과 EKS를 함께 사용하면, 클라우드 환경에서 쿠버네티스 애플리케이션을 효율적으로 개발하고 배포할 수 있습니다. 이를 통해 개발 및 애플리케이션 배포 효율성을 높이고, 개발 과정 및 배포 환경에서 발생할 수 있는 복잡성을 줄일 수 있습니다.

– EKS Cluster를 생성하기 위해, “eks-user” 라는 IAM User를 생성합니다.
– 원활한 테스트를 위해 “eks-user” 에게 “AdministratorAccess” IAM Policy 를 할당합니다.
– Cloud9 의 이름을 설정해주고 Cloud9은 EC2 인스턴스를 기반으로 동작합니다. 사용자는 필요에 따라 EC2 인스턴스의 타입을 선택할 수 있으며, 사용하지 않는 시간에는 자동으로 중지시켜 비용을 절약할 수 있습니다. 이 실습에서는 새로운 Cloud9 용 EC2 인스턴스를 생성합니다.
– Cloud9 의 인스턴스의 OS는 Amazon Linux2 를 선택하고 인스턴스 유형은 t3.small을 선택합니다.
– SSH 를 통해 Cloud9 환경에 액세스 하도록 설정하고 VPC는 기존에 생성한 vpc 및 퍼블릭 서브넷을 선택 후, Cloud9 환경을 생성합니다.
– Cloud9 이 생성 된것을 확인할 수 있습니다.

3.2 AWS Cloud9 Settings [Hands-On]

– 생성된 Cloud9 으로 돌아가서, Cloud9의 기존 자격증명과 임시 자격 증명등을 비활성화 합니다. Cloud9에서 화면 우측 상단의 톱니 바퀴 모양을 선택하고, 설정 환경을 아래와 같이 선택합니다. Cloud9 설정환경에서 “AWS managed temporary credential” 을 비활성 합니다.
rm -vf ${HOME}/.aws/credentials 

## Cloud9 환경에서 위 명령어를 입력합니다. Cloud9 Terminal에서 임시 자격증명을 사용하지 않도록 기존 자격 증명 파일을 제거합니다.
# AWS CLI Upgrade
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
source ~/.bashrc
aws --version
# AWS CLI 자동완성 설치 
which aws_completer
export PATH=/usr/local/bin:$PATH
source ~/.bash_profile
complete -C '/usr/local/bin/aws_completer' aws

## AWS 명령줄 인터페이스(CLI)는 AWS 서비스를 관리하는 통합 도구입니다. 도구 하나만 다운로드하여 구성하면 여러 AWS 서비스를 명령줄에서 제어하고 스크립트를 통해 자동화할 수 있습니다.
– $ aws sts get-caller-identity 는 AWS CLI 명령어의 일부로, AWS Security Token Service (STS) 를 이용해 현재 사용자의 자격 증명에 대한 세부 정보를 반환하는 명령어 입니다. 위 명령어를 통해 Cloud9이 제대로 된 사용자의 자격증명을 사용하고 있는지 확인할 수 있습니다.

4. Kubectl 설치 [Hands-On]

kubectl 은 쿠버네티스 클러스터를 제어하는 커맨드 라인 인터페이스(CLI) 도구입니다. 이 도구를 사용하면 쿠버네티스 클러스터의 상태를 확인하거나, 클러스터 내의 리소스를 생성, 업데이트, 삭제하는 등의 작업을 수행할 수 있습니다.

본 실습 에서는 AWS 공식 kubectl 설치문서를 통해 kubectl 1.24 버전을 설치하여 진행하였습니다.

– kubectl 1.24 버전을 설치합니다

5. EKS Cluster 생성 [Hands-On]

– EKS Cluster를 구성하기 위해 Cluster 의 이름은 “eks-kyobo”로 지정하고 kubernetes 버전은 1.24로 선택해 줍니다. EKS는 Control Plane이 AWS 리소스를 대신 관리하도록 허용하는 IAM 역할이 필요합니다. “EKS-Cluster-Role” 의 IAM 역할은 다음과 같습니다.
## EKS-Cluster-Role

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:UpdateAutoScalingGroup",
                "ec2:AttachVolume",
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CreateRoute",
                "ec2:CreateSecurityGroup",
                "ec2:CreateTags",
                "ec2:CreateVolume",
                "ec2:DeleteRoute",
                "ec2:DeleteSecurityGroup",
                "ec2:DeleteVolume",
                "ec2:DescribeInstances",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVolumes",
                "ec2:DescribeVolumesModifications",
                "ec2:DescribeVpcs",
                "ec2:DescribeDhcpOptions",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeAvailabilityZones",
                "ec2:DetachVolume",
                "ec2:ModifyInstanceAttribute",
                "ec2:ModifyVolume",
                "ec2:RevokeSecurityGroupIngress",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAddresses",
                "ec2:DescribeInternetGateways",
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:ApplySecurityGroupsToLoadBalancer",
                "elasticloadbalancing:AttachLoadBalancerToSubnets",
                "elasticloadbalancing:ConfigureHealthCheck",
                "elasticloadbalancing:CreateListener",
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:CreateLoadBalancerListeners",
                "elasticloadbalancing:CreateLoadBalancerPolicy",
                "elasticloadbalancing:CreateTargetGroup",
                "elasticloadbalancing:DeleteListener",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:DeleteLoadBalancerListeners",
                "elasticloadbalancing:DeleteTargetGroup",
                "elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
                "elasticloadbalancing:DeregisterTargets",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeLoadBalancerPolicies",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeTargetGroupAttributes",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetHealth",
                "elasticloadbalancing:DetachLoadBalancerFromSubnets",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:ModifyLoadBalancerAttributes",
                "elasticloadbalancing:ModifyTargetGroup",
                "elasticloadbalancing:ModifyTargetGroupAttributes",
                "elasticloadbalancing:RegisterInstancesWithLoadBalancer",
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:SetLoadBalancerPoliciesForBackendServer",
                "elasticloadbalancing:SetLoadBalancerPoliciesOfListener",
                "kms:DescribeKey"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "iam:CreateServiceLinkedRole",
            "Resource": "*",
            "Condition": {
                "StringEquals": {
                    "iam:AWSServiceName": "elasticloadbalancing.amazonaws.com"
                }
            }
        }
    ]
}
– EKS 에서 사용할 VPC 와 퍼블릭 서브넷 및 프라이빗 서브넷 및 보안 그룹을 선택합니다.
– 클러스터 엔드포인트 액세스를 퍼블릭 및 프라이빗 으로 설정할 경우, 클러스터 VPC내 Kubernetes API 요청은 프라이빗 VPC 엔드포인트를 사용하며, 인터넷에서 클러스터 API 서버에 액세스 할 수 있습니다.
– 본 실습에서는 단순 테스트 용도로 진행함으로 로그를 따로 CloudWatch로 전송하지 않기 때문에 선택하지 않고 넘어갑니다.
– AWS EKS에서 사용하는 core-dns, kube-proxy, 그리고 Amazon VPC CNI 는 쿠버네티스 클러스터의 핵심 컴포넌트 들 입니다.

CoreDNS 는 쿠버네티스에서 서비스 디스커버리를 담당하는 DNS 서비스입니다. 이를 통해 서비스의 이름을 실제 네트워크 주소로 변환하여 파드 간의 통신을 가능하게 합니다. 예를 들어, 파드에서 다른 서비스의 이름으로 요청을 보내면, CoreDNS가 이를 받아 해당 서비스의 IP 주소로 변환하여 요청을 전달합니다.

Kube-proxy는 쿠버네티스 클러스터 내에서 네트워크 트래픽을 관리하는 컴포넌트입니다. 이는 서비스를 통한 파드 간의 통신을 가능하게 하며, 로드 밸런싱 기능도 제공합니다. 예를 들어, 한 파드가 다른 파드에 요청을 보낼 때, kube-proxy는 이 요청을 적절한 대상 파드로 라우팅합니다.

Amazon VPC CNI 는 Amazon EKS에서 사용하는 네트워크 인터페이스입니다. 이를 통해 파드가 Amazon VPC의 네트워크 리소스를 직접 활용할 수 있게 됩니다.

AWS EKS Cluster를 생성할 경우 위 컴포넌트 들은 기본적으로 설치가 됩니다.
– 각 컴포넌트의 버전이 기본적으로 설치되고 EKS Cluster를 생성합니다. EKS Cluster 생성은 몇 분정도 걸릴 수 있습니다.
– EKS Cluster 가 생성된 걸 확인할 수 있습니다.

6. EKS Cluster Node Groups 생성 [Hands-On]

EKS는 관리형 노드 그룹(Managed Node Group)을 제공합니다. 관리형 노드 그룹은 AWS에서 워커 노드의 생명주기를 관리해주는 서비스로, 사용자는 노드에 대한 운영 부담을 줄이고 쿠버네티스 애플리케이션에 집중할 수 있습니다. 관리형 노드 그룹을 사용하면 노드의 패치 및 업데이트, 노드 장애 복구 등의 작업을 AWS가 자동으로 수행해줍니다.

– EKS 노드 그룹의 이름과 노드의 IAM 역할을 지정해 줍니다.
– 실습에서 사용한 노드의 IAM Role 은 다음과 같습니다
## AmazonEC2ContainerRegistryReadOnly

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:GetRepositoryPolicy",
                "ecr:DescribeRepositories",
                "ecr:ListImages",
                "ecr:DescribeImages",
                "ecr:BatchGetImage",
                "ecr:GetLifecyclePolicy",
                "ecr:GetLifecyclePolicyPreview",
                "ecr:ListTagsForResource",
                "ecr:DescribeImageScanFindings"
            ],
            "Resource": "*"
        }
    ]
}
## AmazonEKS_CNI_Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AssignPrivateIpAddresses",
                "ec2:AttachNetworkInterface",
                "ec2:CreateNetworkInterface",
                "ec2:DeleteNetworkInterface",
                "ec2:DescribeInstances",
                "ec2:DescribeTags",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeInstanceTypes",
                "ec2:DetachNetworkInterface",
                "ec2:ModifyNetworkInterfaceAttribute",
                "ec2:UnassignPrivateIpAddresses"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:CreateTags"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:network-interface/*"
            ]
        }
    ]
}
## AmazonEKSWorkerNodePolicy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeRouteTables",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeVolumes",
                "ec2:DescribeVolumesModifications",
                "ec2:DescribeVpcs",
                "eks:DescribeCluster"
            ],
            "Resource": "*"
        }
    ]
}
– Worker Nodes 에 대한 AMI 를 선택하고 용량 유형 및 인스턴스 유형 및 노드의 개수 등을 설정 합니다. 본 실습에서는 생성되는 노드의 개수를 3개로 지정 하였습니다.
– 노드가 실행될 VPC의 서브넷 을 지정하고 Node Group 을 생성합니다. 노드 그룹을 생성하는 데는 몇 분이 걸릴 수 도 있습니다.
– 잠시 기다리면 노드 그룹이 생성 되었고 위에서 지정한 생성될 노드의 개수에 맞게 3개의 Worker Nodes가 생성 된걸 확인할 수 있습니다.
– EC2 인스턴스 에서 EKS Worker Nodes 3개가 실행되는걸 확인할 수 있습니다.

7. EKS Cluster 통신 확인 [Hands-On]

– kubectl 명령어를 사용하면, 쿠버네티스 클러스터 의 상태를 조회하거나, 쿠버네티스 리소스를 생성, 수정, 삭제하는 등의 다양한 작업을 수행할 수 있습니다.
– EKS Cluster 와 정상적으로 통신이 가능한 것을 확인하였으며, EKS Cluster를 생성할 때 기본적으로 설치되는 컴포넌트 중 CoreDNS Pods 와 Kube-Proxy Pods 도 정상 작동 하는것을 확인할 수 있습니다.

8. EKS Service , Deployments 배포 [Hands-On]

– 간단한 배포 실습을 위해 “eks-sample-app” 이라는 Namespace 를 생성하였습니다.

AWS EKS 에서의 네임스페이스(Namespace)는 쿠버네티스(Kubernetes)의 핵심 개념 중 하나로, 클러스터 내의 리소스를 논리적으로 구분하고 그룹화하는 방법을 제공합니다.

네임스페이스는 클러스터 내에서 격리된 환경을 만들어주기 때문에, 서로 다른 프로젝트, 팀, 또는 환경(예: 개발, 스테이징, 프로덕션 등)을 분리하고 관리하는데 유용합니다. 각 네임스페이스 안에는 파드(Pod), 서비스(Service), 디플로이먼트(Deployment) 등의 쿠버네티스 리소스를 생성하고 관리할 수 있습니다.
– deployments 을 배포하려면 yaml 파일을 작성하여 배포해야 합니다. “eks-sample-deployment.yaml” 파일을 작성하고 “eks-sample-linux-deployment” 배포를 생성합니다. 이 샘플 배포는 퍼블릭 리포지토리 에서 컨테이너 이미지를 가져와 클러스터에 3개의 복제본(개별 Pods)을 배포합니다. eks-sample-deployment.yaml 파일은 다음과 같습니다.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: eks-sample-linux-deployment
  namespace: eks-sample-app
  labels:
    app: eks-sample-linux-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: eks-sample-linux-app
  template:
    metadata:
      labels:
        app: eks-sample-linux-app
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: kubernetes.io/arch
                operator: In
                values:
                - amd64
                - arm64
      containers:
      - name: nginx
        image: public.ecr.aws/nginx/nginx:1.23
        ports:
        - name: http
          containerPort: 80
        imagePullPolicy: IfNotPresent
      nodeSelector:
        kubernetes.io/os: linux
– Service는 쿠버네티스에서 실행중인 애플리케이션에 대한 안정적인 네트워크 인터페이스를 제공하는 리소스입니다. 특정 파드에 네트워크 요청을 전달하는 역할을 합니다. Service는 LoadBalancer, NodePort, ClusterIP 등 여러 타입이 있습니다. “eks-sample-service.yaml” 파일은 다음과 같습니다.
apiVersion: v1
kind: Service
metadata:
  name: eks-sample-linux-service
  namespace: eks-sample-app
  labels:
    app: eks-sample-linux-app
spec:
  selector:
    app: eks-sample-linux-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
– kubectl get all -n eks-sample-app 명령어를 사용하여 eks-sample-app 네임 스페이스 안에 있는 생성된 모든 리소스를 확인할 수 있습니다.

9. 마무리

Elastic Kubernetes Service(EKS) 핸즈온을 통해, AWS에서 제공하는 컨테이너 오케스트레이션 서비스를 실제로 사용하고 구축해 보았습니다. 그리고 컨테이너화된 애플리케이션을 쿠버네티스 클러스터에 배포하고, 애플리케이션의 확장과 업데이트, 그리고 네트워크 인터페이스의 관리 등을 어떻게 수행하는지에 대해 이해하셨길 바랍니다.

하지만, EKS를 완전히 이해하고 활용하기 위해서는 쿠버네티스에 대한 깊은 이해가 필요하며, 이는 지속적인 학습을 요구합니다. 이번 핸즈온이 AWS EKS Cluster 를 구축하고 어떻게 사용하는지 도움이 되셨길 바랍니다. 감사합니다.

참고

https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/install-kubectl.html
https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/sample-deployment.html

댓글 달기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다