안녕하세요 오픈소스컨설팅에서 클라우드 엔지니어 업무를 수행하고 있는 인수영입니다.

들어가면서

요즘 IT시장에서 핵심 기술로 대두되고 있는 컨테이너 기술은 계속해서 꾸준히 발전하고 있으며,
Private 및 Public 환경에서 많은 사람들이 Kubernetes를 이용하기도하고, 도입하기 위해 시도하고
있습니다.

이 포스팅에서는 Amazon에서 Kuberntes를 구축하시려는 분들이 누구나 손 쉽게 따라하실 수 있도록 Amazone EKS 환경 구축 방법을 기준으로 내용을 다루어 보겠습니다. 

EKS는 뭘까요?

Elastic Kubernetes Service의 약자로, AWS에서 지원하는 Kubernetes 서비스입니다.

EKS는 어떻게 배포할 수 있나요?

  • 클라우드에서 Amazon EKS 실행
    • EC2 배포방식
    • Fagate 배포방식
  • AWS Outposts에서 Amazon EKS 실행
  • AWS EKS Anywhere 실행

크게 총 3가지의 배포 방식이 있으며, 이번 포스팅에서는 “클라우드에서 Amazon EKS 실행”의 EC2 배포방식에 대해서 다뤄볼 것입니다.

사전 준비 사항으로 AWS 계정과, 외부 통신이 가능한 서버 또는 VM이 필요합니다. 
저는 외부랑 통신이 가능한 Ubuntu를 준비했고 console이라는 hostname을 가지고 있습니다.

AWS Console에서의 EKS Cluster 배포 준비

먼저 EKS 배포하기 위해 AWS Console의 IAM을 통해 사용자를 추가하겠습니다.

저희는 AWS CLI를 통해 명령어를 수행할 것이기 때문에 AWS 액세스 유형을 자격 증명을 액세스 키로 선택하겠습니다.

 사용자는 EKS를 관리하기 위한 권한정책을 가져야하며,  권한정책은 클러스터 관리, 노드, Pod 실행 등 무수히 많은 정책으로 세밀하게 관리할 수 있습니다. 이 포스트에서는 편의상 AdministratorAccess 권한을 부여하도록 하겠습니다.

Note. 실 운영을 필요로하는 기업이나, 고객사들에서는 경험 상 AdministratorAccess 권한을 부여해주지 않습니다. 그렇기 때문에 사전에 EKS 배포를 위해서 필요한 권한정책을 하나하나 확인해가는 것이 필요합니다.

태그는 선택사항으로 별도로 지정하지 않습니다.

사용자 생성 프로시저를 통한 입력값을 한번 더 검토합니다.

사용자는 생성완료 되었으며, 액세스 키 ID와 비밀 액세스 키 ID는 별도로 기입해두도록 합니다.

외부 VM에서의 EKS Cluster 배포 준비 

이제 EKS를 배포할 차례입니다.

배포 방법은 Terraform을 사용하는 방법도 있고, AWS CLI를 통해 배포하는 방법도 있으며,
이 포스트에서는 저희는 Terraform을 이용하여 배포하도록 하겠습니다.

먼저 사전에 준비해 둔 외부 통신 가능한 서버 또는 VM에 접속하여  필요한 패키지 다운로드 및 설치,
구성을 해야 합니다.

아래 순서대로 따라오시면 문제 없이 진행될 것이라고 생각됩니다.

필수 패키지 설치 및 구성파일 설정

첫번째, Terraform 명령어를 설치해줍니다.

root@console:~# apt-get update && sudo apt-get install -y gnupg software-properties-common
root@console:~# wget -O- https://apt.releases.hashicorp.com/gpg | \
                gpg --dearmor | \
                sudo tee > /usr/share/keyrings/hashicorp-archive-keyring.gpg
                
root@console:~# gpg --no-default-keyring \
                --keyring /usr/share/keyrings/hashicorp-archive-keyring.gpg \
                --fingerprint

root@console:~# echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
                https://apt.releases.hashicorp.com $(lsb_release -cs) main" | \
                sudo tee > /etc/apt/sources.list.d/hashicorp.list

root@console:~# apt update
root@console:~# apt-get install terraform

root@console:~# terraform --version
Terraform v1.3.1
on linux_amd64

두번째 AWS 명령어를 사용하기 위해 awscli를 설치해 줍니다.

root@console:~/awscli# curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 44.9M  100 44.9M    0     0  37.4M      0  0:00:01  0:00:01 --:--:-- 37.4M

root@console:~/awscli# unzip awscliv2.zip
Archive:  awscliv2.zip
...
root@console:~/awscli# sudo ./aws/install
You can now run: /usr/local/bin/aws --version

root@console:~/awscli# aws --version
aws-cli/2.8.0 Python/3.9.11 Linux/5.4.0-126-generic exe/x86_64.ubuntu.20 prompt/off

세번째로 eks 관리를 위해 eksctl 명령어를 설치해 줍니다.

root@console:~# curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
root@console:~# sudo mv /tmp/eksctl /usr/local/bin
root@console:~# eksctl version
0.113.0

이제는 Terraform을 이용한 EKS 배포를 위해 환경변수 파일들을 다운로드 받고, 필요한 파일을 가져오도록 하겠습니다.

root@console:~# git clone https://github.com/terraform-providers/terraform-provider-aws.git
Cloning into 'terraform-provider-aws'...
remote: Enumerating objects: 416992, done.
remote: Counting objects: 100% (5/5), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 416992 (delta 1), reused 2 (delta 1), pack-reused 416987
Receiving objects: 100% (416992/416992), 395.62 MiB | 19.03 MiB/s, done.
Resolving deltas: 100% (299475/299475), done.
Updating files: 100% (10131/10131), done.

root@console:~# cd terraform-provider-aws/
root@console:~/terraform-provider-aws# ls
CHANGELOG.md  LICENSE    ROADMAP.md  examples  go.sum          internal  mkdocs.yml  skaff                             tools    website
GNUmakefile   README.md  docs        go.mod    infrastructure  main.go   names       terraform-registry-manifest.json  version

root@console:~/terraform-provider-aws# cd examples/eks-getting-started/
root@console:~/terraform-provider-aws/examples/eks-getting-started# ls
README.md  eks-cluster.tf  eks-worker-nodes.tf  outputs.tf  providers.tf  variables.tf  vpc.tf  workstation-external-ip.tf

root@console:~# cp -rp /root/terraform-provider-aws/examples/eks-getting-started /root/aws-eks

EKS 배포를 위한 구성파일은 .tf 확장자를 가지고 있으며, 모두 Terraform 스크립트이며, 파일을 하나씩 살펴보겠습니다.

eks-clsuter.tf: EKS 클러스터에 필요한 IAM role과 SecurityGroup, EKS 클러스터 대한 값이 있습니다.

resource "aws_iam_role" "osc-cluster" {
  name = "terraform-eks-osc-cluster"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "eks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "osc-cluster-AmazonEKSClusterPolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy"
  role       = aws_iam_role.osc-cluster.name
}

resource "aws_iam_role_policy_attachment" "osc-cluster-AmazonEKSVPCResourceController" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController"
  role       = aws_iam_role.osc-cluster.name
}

resource "aws_security_group" "osc-cluster" {
  name        = "terraform-eks-osc-cluster"
  description = "Cluster communication with worker nodes"
  vpc_id      = aws_vpc.osc.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "terraform-eks-osc"
  }
}

resource "aws_security_group_rule" "osc-cluster-ingress-workstation-https" {
  cidr_blocks       = [local.workstation-external-cidr]
  description       = "Allow workstation to communicate with the cluster API Server"
  from_port         = 443
  protocol          = "tcp"
  security_group_id = aws_security_group.osc-cluster.id
  to_port           = 443
  type              = "ingress"
}

resource "aws_eks_cluster" "osc" {
  name     = var.cluster-name
  role_arn = aws_iam_role.osc-cluster.arn

  vpc_config {
    security_group_ids = [aws_security_group.osc-cluster.id]
    subnet_ids         = aws_subnet.osc[*].id
  }

  depends_on = [
    aws_iam_role_policy_attachment.osc-cluster-AmazonEKSClusterPolicy,
    aws_iam_role_policy_attachment.osc-cluster-AmazonEKSVPCResourceController,
  ]
}

eks-worker-nodes.tf: EKS Worker 노드에 대한 IAM role과 NodeGroup AutoScale, NodeGroup 값이
있습니다.

resource "aws_iam_role" "osc-node" {
  name = "terraform-eks-osc-node"

  assume_role_policy = <<POLICY
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
POLICY
}

resource "aws_iam_role_policy_attachment" "osc-node-AmazonEKSWorkerNodePolicy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy"
  role       = aws_iam_role.osc-node.name
}

resource "aws_iam_role_policy_attachment" "osc-node-AmazonEKS_CNI_Policy" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy"
  role       = aws_iam_role.osc-node.name
}

resource "aws_iam_role_policy_attachment" "osc-node-AmazonEC2ContainerRegistryReadOnly" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  role       = aws_iam_role.osc-node.name
}

resource "aws_eks_node_group" "osc" {
  cluster_name    = aws_eks_cluster.osc.name
  node_group_name = "osc"
  node_role_arn   = aws_iam_role.osc-node.arn
  subnet_ids      = aws_subnet.osc[*].id

  scaling_config {
    desired_size = 1
    max_size     = 1
    min_size     = 1
  }

  depends_on = [
    aws_iam_role_policy_attachment.osc-node-AmazonEKSWorkerNodePolicy,
    aws_iam_role_policy_attachment.osc-node-AmazonEKS_CNI_Policy,
    aws_iam_role_policy_attachment.osc-node-AmazonEC2ContainerRegistryReadOnly,
  ]
}

outputs.tf: 이 파일에 설정된 값을 통해 EKS 배포완료 후 OutPut 확인하여 정상 배포되었음을 확인 합니다.

locals {
  config_map_aws_auth = <<CONFIGMAPAWSAUTH


apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: ${aws_iam_role.osc-node.arn}
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes
CONFIGMAPAWSAUTH

  kubeconfig = <<KUBECONFIG


apiVersion: v1
clusters:
- cluster:
    server: ${aws_eks_cluster.osc.endpoint}
    certificate-authority-data: ${aws_eks_cluster.osc.certificate_authority[0].data}
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: aws
  name: aws
current-context: aws
kind: Config
preferences: {}
users:
- name: aws
  user:
    exec:
      apiVersion: client.authentication.k8s.io/v1beta1
      command: aws-iam-authenticator
      args:
        - "token"
        - "-i"
        - "${var.cluster-name}"
KUBECONFIG
}

output "config_map_aws_auth" {
  value = local.config_map_aws_auth
}

output "kubeconfig" {
  value = local.kubeconfig
}

providers.tf: EKS를 생성할 AWS Key 값이 있습니다.

terraform {
  required_version = ">= 0.12"
}

provider "aws" {
  region = var.aws_region
  access_key = "ACCESS_KEY"
  secret_key = "SECRET_KEY"
}

data "aws_availability_zones" "available" {}

# Not required: currently used in conjunction with using
# icanhazip.com to determine local workstation external IP
# to open EC2 Security Group access to the Kubernetes cluster.
# See workstation-external-ip.tf for additional information.
provider "http" {}

variables.tf: EKS를 생성할 AWS region과 EKS 클러스터 이름 값이 있습니다.

variable "aws_region" {
  default = "ap-northeast-2"
}

variable "cluster-name" {
  default = "terraform-eks-osc"
  type    = string
}

vpc.tf: 생성하는 EKS가 사용할 Network 환경을 구축합니다. (VPC, SubNet, Route)

resource "aws_vpc" "osc" {
  cidr_block = "10.0.0.0/16"

  tags = tomap({
    "Name"                                      = "terraform-eks-osc-node",
    "kubernetes.io/cluster/${var.cluster-name}" = "shared",
  })
}

resource "aws_subnet" "osc" {
  count = 2

  availability_zone       = data.aws_availability_zones.available.names[count.index]
  cidr_block              = "10.0.${count.index}.0/24"
  map_public_ip_on_launch = true
  vpc_id                  = aws_vpc.osc.id

  tags = tomap({
    "Name"                                      = "terraform-eks-osc-node",
    "kubernetes.io/cluster/${var.cluster-name}" = "shared",
  })
}

resource "aws_internet_gateway" "osc" {
  vpc_id = aws_vpc.osc.id

  tags = {
    Name = "terraform-eks-osc"
  }
}

resource "aws_route_table" "osc" {
  vpc_id = aws_vpc.osc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.osc.id
  }
}

resource "aws_route_table_association" "osc" {
  count = 2

  subnet_id      = aws_subnet.osc.*.id[count.index]
  route_table_id = aws_route_table.osc.id
}

EKS 배포

이제 EKS 배포를 시작합니다.

root@console:~/aws-eks# terraform init
Initializing the backend...
...

root@console:~/aws-eks# terraform apply
...
aws_eks_cluster.osc: Still creating... [10s elapsed]
aws_eks_cluster.osc: Still creating... [20s elapsed]
aws_eks_cluster.osc: Still creating... [30s elapsed]
...
aws_eks_cluster.osc: Creation complete after 10m3s [id=terraform-eks-osc]
...
aws_eks_node_group.osc: Creation complete after 1m48s [id=terraform-eks-osc:osc]
╷
│ Warning: Deprecated attribute
│
│   on workstation-external-ip.tf line 17, in locals:
│   17:   workstation-external-cidr = "${chomp(data.http.workstation-external-ip.body)}/32"
│
│ The attribute "body" is deprecated. Refer to the provider documentation for details.
╵

Apply complete! Resources: 18 added, 0 changed, 0 destroyed.

AWS Console에서 EKS 클러스터가 생성 되었음을 다시 한번 확인할 수 있습니다.

EKS Cluster 배포 확인

배포 완료 후 Kubernetes 명령어 사용을 위해 kubectl 명령어를 설치해주고, EKS kubeconfig 파일을 받습니다.

EKS에서는 Control Plane(Master) 노드를 AWS 자체에서 관리하기 때문에, “kubectl get nodes” 명령시, Worker 노드만 확인할 수 있습니다.

root@console:~# curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.23.7/2022-06-29/bin/linux/amd64/kubectl
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 44.4M  100 44.4M    0     0  6061k      0  0:00:07  0:00:07 --:--:-- 7454k

root@console:~# chmod +x ./kubectl
root@console:~# mkdir -p $HOME/bin && cp ./kubectl $HOME/bin/kubectl && export PATH=$PATH:$HOME/bin
root@console:~# echo 'export PATH=$PATH:$HOME/bin' >> ~/.bashrc

root@console:~# kubectl version --short --client
Client Version: v1.23.7-eks-4721010

root@console:~# aws configure
AWS Access Key ID [None]: AWS_ACCESS_KEY
AWS Secret Access Key [None]: AWS_SECRET_KEY
Default region name [None]: ap-northeast-2
Default output format [None]: json
root@console:~# aws eks update-kubeconfig --region ap-northeast-2 --name terraform-eks-osc
Added new context arn:aws:eks:ap-northeast-2:144229005818:cluster/terraform-eks-osc to /root/.kube/config

root@console:~# kubectl get nodes
NAME                                            STATUS   ROLES    AGE    VERSION
ip-10-0-0-156.ap-northeast-2.compute.internal   Ready    <none>   7m5s   v1.23.9-eks-ba74326

AWS에서 EC2가 하나 생성된 것을 확인할 수 있습니다.

AWS ALB Ingress 배포 준비

EKS Ingress를 생성할 때 애플리케이션 트래픽을 로드밸런싱하는 ALB(Application LoadBalancer)가 프로비저닝 됩니다.

ALB 사용을 위해 ALB Ingress Controller를 구성하도록 하겠습니다.

IAM OIDC 자격증명 공급자 생성
(https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/id_roles_providers_create_oidc.html)

EKS의 Service Account에 IAM Role을 적용하기 위해 IAM OIDC 자격증명 공급자를 생성합니다.

그리고 IAM Role을 만들어 줍니다. Role 이름은 AWSLoadBalancerControllerIAMPolicy 이며, 이 Role은 AWS 로드 밸런서 컨트롤러가 사용자를 대신하여 AWS API를 호출할 수 있도록 허용합니다

Arn 값은 아래 Service Account 만드는 부분에서 사용해야하니 메모해두도록 합니다.

root@console:~# eksctl utils associate-iam-oidc-provider --region ap-northeast-2 --cluster terraform-eks-osc --approve
2022-10-10 04:39:17 [ℹ]  will create IAM Open ID Connect provider for cluster "terraform-eks-osc" in "ap-northeast-2"
2022-10-10 04:39:18 [✔]  created IAM Open ID Connect provider for cluster "terraform-eks-osc" in "ap-northeast-2"

root@console:~# curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/main/docs/install/iam_policy.json
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7617  100  7617    0     0  23803      0 --:--:-- --:--:-- --:--:-- 23803

# IAM Role Create
root@console:~# aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam-policy.json
{
    "Policy": {
        "PolicyName": "AWSLoadBalancerControllerIAMPolicy",
        "PolicyId": "ANPASDFFX7H5BCOTK4Y7E",
        "Arn": "arn:aws:iam::[AWS_ACCOUNT_ID]:policy/AWSLoadBalancerControllerIAMPolicy",
        "Path": "/",
        "DefaultVersionId": "v1",
        "AttachmentCount": 0,
        "PermissionsBoundaryUsageCount": 0,
        "IsAttachable": true,
        "CreateDate": "2022-10-10T04:40:54+00:00",
        "UpdateDate": "2022-10-10T04:40:54+00:00"
    }
}

위에서 생성한 IAM Role을 기반으로 Service Account를 생성해주고, EKS 클러스터 내의 TLS 인증서를 자동으로 프로비저닝 하기 위해 Cert-Manager를 배포합니다.

root@console:~# eksctl create iamserviceaccount --cluster=terraform-eks-osc --namespace=kube-system --name=aws-load-balancer-controller --attach-policy-arn=arn:aws:iam::[AWS_ACCOUNT_ID]:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve
2022-10-10 04:43:33 [ℹ]  1 iamserviceaccount (kube-system/aws-load-balancer-controller) was included (based on the include/exclude rules)
2022-10-10 04:43:33 [!]  metadata of serviceaccounts that exist in Kubernetes will be updated, as --override-existing-serviceaccounts was set
2022-10-10 04:43:33 [ℹ]  1 task: {
    2 sequential sub-tasks: {
        create IAM role for serviceaccount "kube-system/aws-load-balancer-controller",
        create serviceaccount "kube-system/aws-load-balancer-controller",
    } }2022-10-10 04:43:33 [ℹ]  building iamserviceaccount stack "eksctl-terraform-eks-osc-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2022-10-10 04:43:34 [ℹ]  deploying stack "eksctl-terraform-eks-osc-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2022-10-10 04:43:34 [ℹ]  waiting for CloudFormation stack "eksctl-terraform-eks-osc-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2022-10-10 04:44:04 [ℹ]  waiting for CloudFormation stack "eksctl-terraform-eks-osc-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2022-10-10 04:44:59 [ℹ]  waiting for CloudFormation stack "eksctl-terraform-eks-osc-addon-iamserviceaccount-kube-system-aws-load-balancer-controller"
2022-10-10 04:44:59 [ℹ]  created serviceaccount "kube-system/aws-load-balancer-controller"

# Cert-Manager 배포
root@console:~# kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.9.1/cert-manager.yaml

VPC SubNet Tag

ALB(Application Load Balancer) 리소스가 생성될 때 AWS 로드 밸런서 컨트롤러가 서브넷을 자동으로 검색할수 있도록 Amazon EKS 클러스터에서 Amazon VPC 서브넷에 태깅합니다.

EKS 클러스터에서 Ingress를 생성할때 권한오류를 방지하기 위해 IAM 의 EKS 클러스터 역할과 EKS 노드역할에 AdministratorAccess Policy를 추가합니다.

Note. 위에서 언급했던 것 처럼 실 운영을 필요로하는 기업이나, 고객사들에서는 AdministratorAccess 권한을 부여해주지 않습니다.

AWS ALB Ingress Controller 배포

ALB Ingress Controller를 배포 하겠습니다.

Yaml 파일 내의 클러스터 이름 수정 후 배포합니다.

root@console:~# curl -Lo ingress-controller.yaml https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.4.4/v2_4_4_full.yaml
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100 31860  100 31860    0     0  42765      0 --:--:-- --:--:-- --:--:-- 42765

root@console:~# cp ingress-controller.yaml ingress-controller.bak

root@console:~# diff -u ingress-controller.bak ingress-controller.yaml
--- ingress-controller.bak      2022-10-10 04:56:23.156934608 +0000
+++ ingress-controller.yaml     2022-10-10 04:56:42.652878360 +0000
@@ -728,7 +728,7 @@
     spec:
       containers:
       - args:
-        - --cluster-name=your-cluster-name
+        - --cluster-name=terraform-eks-osc
         - --ingress-class=alb
         image: amazon/aws-alb-ingress-controller:v2.4.4
         
root@console:~# kubectl apply -f ingress-controller.yaml
customresourcedefinition.apiextensions.k8s.io/ingressclassparams.elbv2.k8s.aws created
customresourcedefinition.apiextensions.k8s.io/targetgroupbindings.elbv2.k8s.aws created
role.rbac.authorization.k8s.io/aws-load-balancer-controller-leader-election-role created
clusterrole.rbac.authorization.k8s.io/aws-load-balancer-controller-role created
rolebinding.rbac.authorization.k8s.io/aws-load-balancer-controller-leader-election-rolebinding created
clusterrolebinding.rbac.authorization.k8s.io/aws-load-balancer-controller-rolebinding created
service/aws-load-balancer-webhook-service created
deployment.apps/aws-load-balancer-controller created
certificate.cert-manager.io/aws-load-balancer-serving-cert created
issuer.cert-manager.io/aws-load-balancer-selfsigned-issuer created
mutatingwebhookconfiguration.admissionregistration.k8s.io/aws-load-balancer-webhook created
validatingwebhookconfiguration.admissionregistration.k8s.io/aws-load-balancer-webhook created
ingressclass.networking.k8s.io/alb created

AWS ALB Ingress Controller 배포 확인

배포 상태를 확인합니다.

root@console:~# kubectl get all -n kube-system
NAME                                               READY   STATUS    RESTARTS   AGE
pod/aws-load-balancer-controller-5d8dcf49c-sr4v8   1/1     Running   0          26s
pod/aws-node-rhb58                                 1/1     Running   0          32m
pod/coredns-d596d9655-484lf                        1/1     Running   0          37m
pod/coredns-d596d9655-vcjzp                        1/1     Running   0          37m
pod/kube-proxy-nlwb9                               1/1     Running   0          32m

NAME                                        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)         AGE
service/aws-load-balancer-webhook-service   ClusterIP   172.20.144.11   <none>        443/TCP         26s
service/kube-dns                            ClusterIP   172.20.0.10     <none>        53/UDP,53/TCP   37m

NAME                        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/aws-node     1         1         1       1            1           <none>          37m
daemonset.apps/kube-proxy   1         1         1       1            1           <none>          37m

NAME                                           READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/aws-load-balancer-controller   1/1     1            1           26s
deployment.apps/coredns                        2/2     2            2           37m

NAME                                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/aws-load-balancer-controller-5d8dcf49c   1         1         1       26s
replicaset.apps/coredns-d596d9655                        2         2         2       37m

배포한 Ingress를 사용하기 위해 WEB 서비스를 하나 배포해보겠습니다.

Python Flask를 통해 Docker Image를 먼저 Build 하겠습니다.

root@console:~# cat osc.py
from flask import Flask
app = Flask(__name__)

@app.route('/osc')
def hello_world():
    return 'OpenSourceConsulting!'

if __name__ == '__main__':
    app.run(host="0.0.0.0")
    
root@console:~# cat Dockerfile
FROM python:3.8
RUN pip install flask
RUN pip install httplib2
RUN pip install requests
WORKDIR /root/osc
ADD osc.py .
CMD ["python3", "-u", "osc.py"]

root@console:~# docker build -t osc:1.0 .
root@console:~# cat flask-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: osc-webserver
  labels:
    app: osc
spec:
  replicas: 1
  selector:
    matchLabels:
      app: osc
  template:
    metadata:
      labels:
        app: osc
    spec:
      containers:
      - name: osc-webserver
        image: osc:1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 5000
          name: flask
---
apiVersion: v1
kind: Service
metadata:
  name: osc-webserver-service
spec:
  type: NodePort
  selector:
    app: osc
  ports:
    - port: 5000
      targetPort: 5000

root@console:~# kubectl apply -f flask-deployment.yaml
deployment.apps/osc-webserver created
service/osc-webserver-service created

root@console:~# cat flask-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: osc-ingress
  annotations:
    kubernetes.io/ingress.class: alb
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: instance
spec:
  rules:
  - http:
      paths:
      - path: /osc
        pathType: Prefix
        backend:
          service:
            name: osc-webserver-service
            port:
              number: 5000
				
root@console:~# kubectl apply -f flask-ingress.yaml
ingress.networking.k8s.io/osc-ingress created

root@console:~# kubectl get pod,svc,ing
NAME                                 READY   STATUS    RESTARTS   AGE
pod/osc-webserver-6cdc5cfd77-27rjc   1/1     Running   0          7m45s

NAME                            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/kubernetes              ClusterIP   172.20.0.1      <none>        443/TCP          47m
service/osc-webserver-service   NodePort    172.20.204.46   <none>        5000:31359/TCP   7m45s

NAME                                    CLASS    HOSTS   ADDRESS                                                                      PORTS   AGE
ingress.networking.k8s.io/osc-ingress   <none>   *       k8s-default-oscingre-f4ce67a57c-571439759.ap-northeast-2.elb.amazonaws.com   80      5m56s

Ingress 정책이 정상적으로 만들어 졌고, AWS console에서도 내용을 확인할 수 있습니다.

서비스가 정상적으로 호출되는 것을 확인할 수 있습니다.

AWS EKS Cluster 삭제

terraform destroy 명령으로 구성한 EKS를 지울 수 있습니다.

root@console:~/aws-eks# terraform destroy
...
Destroy complete! Resources: 18 destroyed.

마치며.

여기까지 AWS에 EKS 클러스터 구축 및 간단한 WEB 서비스 배포까지 진행해보았습니다.

AWS에 EKS 클러스터 배포방식은 앞서 말씀드린 바와 같이, EC2 방식과 Fargate를 이용한 방식이 있는데요.

Fargate를 이용하면, Pod당 1개의 EC2가 배포되며, 사용하는 리소스만큼의 비용에 대해서만 지불하면되고 인프라적 측면의 관리가 별도로 필요하지 않다는 장점이 있습니다.

하지만 Fargate에서는 DaemonSet 방식의 배포가 불가능하며, Privileged Container를 지원하지 않기 때문에 GPU Pods 사용에 제한적일 수 있습니다. 또한 Resource가 제한적이기 때문에 AWS에서 지원하는 구성을 사용할 수 밖에 없습니다.

인프라의 관리가 필요없이 어플리케이션에 집중을 위해서는 Fargate가 더 나은 선택일 수도 있겠네요.

선택은 사용자의 몫입니다. 🙂

다음에는 AWS EKS Cluster에 ECR(Elastic Container Registry)을 이용한 CI/CD 구축 내용을 포스팅 해보도록 할께요!  

참고URL

https://flask-docs-kr.readthedocs.io/ko/latest/quickstart.html  * https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/getting-started.html  * https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/alb-ingress.html  * https://docs.aws.amazon.com/ko_kr/eks/latest/userguide/aws-load-balancer-controller.html  * https://aws.amazon.com/ko/fargate/faqs/
https://aws.amazon.com/ko/fargate/pricing/?nc=sn&loc=2 

안녕하세요? 오픈소스컨설팅에서 클라우드 엔지니어 직무를 수행하고 있는 인수영입니다. 항상 낙천적인 마음 가짐으로 살고 있으며 새로운 기술에 도전하는 것을 좋아합니다!

Leave a Reply

Your email address will not be published. Required fields are marked *