이 연재글은 EKS(Elastic Kubernetes Service) 실습의 1번째 글입니다.

EKS

EKS는 Elastic Kubernetes Service 의 약자로 Amazon에서 만든 관리형 Kubernetes 서비스 입니다. EKS를 사용하면 Kubernetes 설치부터 운영까지 맡아서 하지 않아도 되기 때문에 쉽게 Kubernetes를 이용할 수 있습니다. 다만 AWS의 ELB, VPC 등 EKS를 실행하기 위해 여러 서비스가 활용되기 때문에 AWS를 처음 사용하는 분들에게는 다소 어렵게 느껴질 수 있습니다. 그럼에도 불구하고 직접 Kubernetes Cluster를 구성하고 관리하는 것보다는 쉽게 Kubernetes를 사용할 수 있습니다.

Kubernetes 클러스터를 구성하는 머신을 node라고합니다. Kubernetes 클러스터의 node는 물리적이거나 가상 일 수 있습니다. Control Plain을 구성하는 Control-plane-node type은 클러스터의 ‘브레인’역할을 합니다. Data Plain을 구성하는 Worker-node type은 pod를 통해 실제 컨테이너 이미지를 실행합니다.

EKS 작업 환경 구성

AWS 계정 생성

k8s를 관리하기 위한 관리자 권한을 가진 IAM 사용자를 생성합니다. ( AdministratorAccess policy 적용) 이하 작업부터는 새로 생성한 IAM 계정으로 작업을 진행합니다.

IAM – Users – Add user

Next: Permissions – Attach existing policies directly – AdministratorAccess 검색

Next: Tags -> Next: Review -> Create user

Role 생성

workspace용 role 생성

IAM – Roles – CreateRole

Next: Permissions – AdministratorAccess 검색

Next: Tags -> Next: Review -> Role name 작성후 Create Role

kubernetes cluster용 role 생성

Workspace용 Role 생성과 동일하게 진행합니다. IAM – Roles – CreateRole – EKS – EKS – Cluster 선택후 Permission은 AmazonEKSClusterPolicy, AmazonEKSServicePolicy 선택하여 Role을 생성합니다.

워크 스페이스 생성

EKS cluster에 연결하여 kubernetes에 작업 명령을 내리기 위한 장비(EC2 인스턴스)를 생성합니다.

인스턴스 생성

  • EC2 – Launch instance – Amazon Linux 2 AMI – 64-bit (x86) 선택
  • Instance Type 선택 – 적당한 사양 선택 후 Next
  • Configure Instance Details
    • Network: EKS cluster를 생성할 VPC 선택
    • Subnet: EKS cluster를 생성할 Subnet 선택
    • IAM role: 위에서 생성한 workspace용 role 적용
  • Review and Launch
    • Launch클릭 – Choose an existing key pair – pem 파일 선택 – 체크박스 체크 후 – Launch Instances

인스턴스 접속

$ ssh -i pem파일 ec2-user@EC2장비PublicIP

k8s 운영 환경 구성

workspace 인스턴스에 터미널로 접속하여 아래 내용을 진행합니다.

aws configure

위에서 생성한 IAM 계정의 credential을 설정합니다.

$ aws configure
AWS Access Key ID [None]: IAM AccessKey ID
AWS Secret Access Key [None]: IAM Secret Access Key
Default region name [ap-southeast-1]: 작업하는 Region
Default output format [None]: json

K8S 도구 설치

// kubectl 설정을 저장하기 위한 기본 ~/.kube 디렉터리 생성
$ mkdir -p ~/.kube
// kubectl 설치
$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
// kubectl 명령어 동작 확인
$ kubectl version --short --client
Client Version: v1.19.2
// eksctl 설치
$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
$ sudo mv -v /tmp/eksctl /usr/local/bin
// eksctl 명령어 동작 확인
$ eksctl version
// helm 설치
$ wget https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz
$ tar -zxvf helm-v3.3.1-linux-amd64.tar.gz
$ sudo mv linux-amd64/helm /usr/local/bin/helm
$ helm repo add eks https://aws.github.io/eks-charts
$ helm repo list | grep eks-charts
// JQ 설치
$ sudo yum -y install jq

현재 Region을 기준으로 aws-cli 구성

$ export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
echo "export AWS_REGION=${AWS_REGION}" >> ~/.bash_profile
aws configure set default.region ${AWS_REGION}
aws configure get default.region

EKS Worker node에 적용할 Role 생성

role 내용이 많으므로 script 및 명령어로 직접 생성합니다. 본문 내용중 arn:aws:iam::IAM계정번호을 수정 후 실행해야 합니다.

$ cat > eksWorkerNodeRole.json << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "ec2.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
EOF
$ aws iam create-role --role-name eksWorkerNodeRole --assume-role-policy-document file://eksWorkerNodeRole.json
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::aws:policy/CloudWatchLogsFullAccess
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonRoute53FullAccess

$ cat > EKSAutoscailerPolicy.json << EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "autoscaling:DescribeAutoScalingGroups",
                "autoscaling:DescribeAutoScalingInstances",
                "autoscaling:DescribeLaunchConfigurations",
                "autoscaling:DescribeTags",
                "autoscaling:SetDesiredCapacity",
                "autoscaling:TerminateInstanceInAutoScalingGroup",
                "ec2:DescribeLaunchTemplateVersions"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}
EOF

$ aws iam create-policy --policy-name EKSAutoscailerPolicy --policy-document file://EKSAutoscailerPolicy.json
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::IAM계정번호:policy/EKSAutoscailerPolicy

$ cat > ALBIngressControllerIAMPolicy.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "acm:DescribeCertificate",
                "acm:ListCertificates",
                "acm:GetCertificate"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:AuthorizeSecurityGroupIngress",
                "ec2:CreateSecurityGroup",
                "ec2:CreateTags",
                "ec2:DeleteTags",
                "ec2:DeleteSecurityGroup",
                "ec2:DescribeAccountAttributes",
                "ec2:DescribeAddresses",
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInternetGateways",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets",
                "ec2:DescribeTags",
                "ec2:DescribeVpcs",
                "ec2:ModifyInstanceAttribute",
                "ec2:ModifyNetworkInterfaceAttribute",
                "ec2:RevokeSecurityGroupIngress"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "elasticloadbalancing:AddListenerCertificates",
                "elasticloadbalancing:AddTags",
                "elasticloadbalancing:CreateListener",
                "elasticloadbalancing:CreateLoadBalancer",
                "elasticloadbalancing:CreateRule",
                "elasticloadbalancing:CreateTargetGroup",
                "elasticloadbalancing:DeleteListener",
                "elasticloadbalancing:DeleteLoadBalancer",
                "elasticloadbalancing:DeleteRule",
                "elasticloadbalancing:DeleteTargetGroup",
                "elasticloadbalancing:DeregisterTargets",
                "elasticloadbalancing:DescribeListenerCertificates",
                "elasticloadbalancing:DescribeListeners",
                "elasticloadbalancing:DescribeLoadBalancers",
                "elasticloadbalancing:DescribeLoadBalancerAttributes",
                "elasticloadbalancing:DescribeRules",
                "elasticloadbalancing:DescribeSSLPolicies",
                "elasticloadbalancing:DescribeTags",
                "elasticloadbalancing:DescribeTargetGroups",
                "elasticloadbalancing:DescribeTargetGroupAttributes",
                "elasticloadbalancing:DescribeTargetHealth",
                "elasticloadbalancing:ModifyListener",
                "elasticloadbalancing:ModifyLoadBalancerAttributes",
                "elasticloadbalancing:ModifyRule",
                "elasticloadbalancing:ModifyTargetGroup",
                "elasticloadbalancing:ModifyTargetGroupAttributes",
                "elasticloadbalancing:RegisterTargets",
                "elasticloadbalancing:RemoveListenerCertificates",
                "elasticloadbalancing:RemoveTags",
                "elasticloadbalancing:SetIpAddressType",
                "elasticloadbalancing:SetSecurityGroups",
                "elasticloadbalancing:SetSubnets",
                "elasticloadbalancing:SetWebAcl"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:CreateServiceLinkedRole",
                "iam:GetServerCertificate",
                "iam:ListServerCertificates"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cognito-idp:DescribeUserPoolClient"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "waf-regional:GetWebACLForResource",
                "waf-regional:GetWebACL",
                "waf-regional:AssociateWebACL",
                "waf-regional:DisassociateWebACL"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "tag:GetResources",
                "tag:TagResources"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "waf:GetWebACL"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "wafv2:GetWebACL",
                "wafv2:GetWebACLForResource",
                "wafv2:AssociateWebACL",
                "wafv2:DisassociateWebACL"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "shield:DescribeProtection",
                "shield:GetSubscriptionState",
                "shield:DeleteProtection",
                "shield:CreateProtection",
                "shield:DescribeSubscription",
                "shield:ListProtections"
            ],
            "Resource": "*"
        }
    ]
}
EOF

$ aws iam create-policy --policy-name ALBIngressControllerIAMPolicy --policy-document file://ALBIngressControllerIAMPolicy.json
aws iam attach-role-policy --role-name eksWorkerNodeRole --policy-arn arn:aws:iam::IAM계정번호:policy/ALBIngressControllerIAMPolicy

K8S Cluster 생성

터미널에서 eksctl 명령어를 이용하거나 aws console을 통하여 k8s cluster를 생성할 수 있습니다.

eksctl을 이용하여 eks cluster 생성

참고

$ eksctl create cluster \
--name eks-cluster-demo-mesh \
--nodes-min 2 \
--nodes-max 3 \
--nodes 2 \
--node-ami=t3.medium \
--region=ap-southeast-1 \
--vpc-private-subnets=subnet-01887582564722d0b,subnet-0cf77158921f1e7a2,subnet-0cf77158921f1e7a2 \
--vpc-public-subnets=subnet-9ac904fc,subnet-5d53a115,subnet-a0f74ff9 \
--auto-kubeconfig \
--full-ecr-access \
--appmesh-access

aws eks console로 eks cluster 생성

Create Cluster

  • Name : cluster 이름
  • Cluster Service Role : 위에서 생성한 k8s cluster용 role 선택
  • vpc, subnes : default 또는 eks용으로 생성한 vpc, subnet 선택
  • 생성 시간은 약 15분 소요

K8S Cluster Node Group 생성

  • AWS EKS는 Worker Node와 Node Group이라는 것으로 이루어져 있습니다. Worker Node는 실질적인 Pod가 띄워질 인스턴스이고 이 인스턴스들을 그룹으로 묶는 개념이 Node Group입니다.
  • Master Node는 AWS가 직접 관리해주고 Worker Node를 프로비저닝하여 사용자가 직접 관리할 수 있도록 Node Group을 통해 Worker Node 머신(EC2)를 생성 합니다.

K8s Cluster 상세 화면 Compute 탭에서 Add Node Group을 클릭합니다.

  • name: Node group명 / Node IAM Role : 위에서 생성한 eksWorkerNodeRole을 선택 후 Next
  • instanceType: worker node instance 사양을 선택한다.
  • Node Group scaling configuration – min/max/desire를 적당한 값으로 세팅 후 Next
  • Subnets : default 또는 eks용으로 생성한 vpc, subnet 선택
  • Allow remote access to nodes
    • 노드에 대한 보안 원격 접속을 허용하려면 ON
    • SSH Key pair : 노드 접속을 위한 SSH key pair(pem)을 선택.
    • Allow remote access from : 노드에 원격으로 액세스 할 수있는 소스 IP 범위를 설정 후 Next
  • 설정 내용 확인 후 Create

워크스페이스 kubeconfig 설정 업데이트

생성한 eks cluster를 사용할 수 있도록 kubeconfig 설정을 업데이트 합니다. 설정이 정상적으로 업데이트 되면 이후부터는 kubernetes cluster에 명령을 내려 작업을 진행할 수 있습니다.

$ aws eks --region ap-southeast-1 update-kubeconfig --name 클러스터명
// 확인
$ kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   13m
연재글 이동
[다음글] ECR(Elastic Container Registry)에 Docker 이미지 배포하기