안녕하세요 서후아빠입니다. ^_^
이번 세션은 미리 구성된 VPC에 eksctl과 AWS 콘솔을 각각 이용하여 EKS 클러스터를 배포하는 실습을 해보겠습니다. EKS 클러스터 배포는 AWS 콘솔, eksctl, CloudFormation, CDK, Terraform 등 다양하며, 가장 많이 사용하는 배포 방법은 eksclt이며, Code에 익숙하지 않은 경우 AWS 콘솔을 사용하는 것을 권고드립니다.
또한, 서비스를 외부에 노출하기 위한 Ingress Controller와 Pod에서 사용할 Image를 위한 ECR 리포지토리도 함께 살펴보도록 하겠습니다.
구성도
cluster-sg는 node-sg나 master-sg를 포함하는 상위 영역 - 관리 편의를 위해 하위 영역(node-sg, master-sg)만 정책 설정 Master node는 Control Plane이라고도 합니다. |
사전 작업
인프라 생성 : vpc, subnet, igw, routing table, iam, ec2 등은 설명 생략합니다.
2022.07.02 - [Networking] - [실습] Amazon VPC 구성요소 생성하기
1단계 : 실습 환경 생성 (Cloud9, SKIP 가능)
Cloud9 > Environments > Create environment
Details | New EC2 instance | Network settings |
Name : workspace Environment type : New EC2 instance (or Existing compute) |
Instance type : t3.small Platform : Amazon Linux 2 Timeout : 30 minutes |
Connection : AWS Systems Manager VPC settings : vpcA Subnet : pubA-sn-a |
Cloud9는 Visual Studio 같은 코딩 환경을 제공하는 AWS 서비스입니다. Platform : Amazon Linux 2, Ubuntu Server 18.04 LTS Connection : AWS Systems Manager, Secure Shell |
Cloud9 > Environments > workspace 생성 확인
IAM Role을 생성하여 Cloud9에 권한을 부여합니다. - IAM > Roles > Create role > AdministratorAccess 권한 부여된 Role 생성 (Name : workspaceRole) - EC2 > Instances > 인스턴스 선택 > Actions > Security > Modify IAM role > workspaceRole 선택 > Update IAM role |
Cloud9 > Environments > workspace의 Open 클릭
Open 클릭 시 웹페이지 접근 안되는 경우 - EC2 > Instances > 인스턴스 선택 > Public IPv4 address 연결상태 확인 : 연결되지 않은 경우 EIP 생성하여 연결 |
Cloud9 웹페이지 > 우측 상단 톱니바퀴 클릭 > AWS Settings > AWS managed temporary credentials(Disabled)
Cloud9 경우, IAM credentials를 동적으로 관리, 해당 credentials는 EKS IAM authentication과 호환되지 않으므로 비활성화 |
Cloud9 웹페이지 > 가운데 둥근 '+' > New Terminal
# Temporary credentials이 없는지 확실히 하기 위해 기존 자격 증명 파일 제거
rm -vf ${HOME}/.aws/credentials
# workspaceRole 적용 확인
aws sts get-caller-identity --query Arn | grep workspaceRole
# AWS CLI 업데이트
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
export PATH=/usr/local/bin:$PATH
source ~/.bash_profile
# kubectl 설치
sudo curl -o /usr/local/bin/kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.23.13/2022-10-31/bin/linux/amd64/kubectl
sudo chmod +x /usr/local/bin/kubectl
kubectl version --client=true --short=true
# jq 설치 : JSON 형식의 데이터를 다루는 커맨드라인 유틸리티
sudo yum install -y jq
# bash-completion 설치
sudo yum install -y bash-completion
# eksctl 설치
sudo curl --silent --location "https://github.com/weaveworks/eksctl/releases/latest/download/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
sudo mv -v /tmp/eksctl /usr/local/bin
eksctl version
# 현재 리전을 기본 리전으로 설정
export AWS_REGION=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.region')
echo "export AWS_REGION=${AWS_REGION}" | tee -a ~/.bash_profile
aws configure set default.region ${AWS_REGION}
aws configure get default.region
# 현재 실습하는 AWS ID(ex : 111111111111)를 환경 변수로 등록
export ACCOUNT_ID=$(curl -s 169.254.169.254/latest/dynamic/instance-identity/document | jq -r '.accountId')
echo "export ACCOUNT_ID=${ACCOUNT_ID}" | tee -a ~/.bash_profile
cat ~/.bash_profile | tail -8
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH
source $HOME/.nvm/nvm.sh
[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" # Load RVM into a shell session *as a function*
export AWS_REGION=ap-northeast-2
export ACCOUNT_ID=111111111111
# EBS 용량 증설 (10GiB > 30GiB) : 생략 가능, 차후 용량 부족시 실행
wget https://gist.githubusercontent.com/joozero/b48ee68e2174a4f1ead93aaf2b582090/raw/2dda79390a10328df66e5f6162846017c682bef5/resize.sh
sh resize.sh
df -h
일반 EC2에서 위 작업을 진행하는 경우는 aws 명령을 수행하기 위해 aws cli 로그인 과정을 진행하시기 바랍니다. - aws cli 명령어를 수행하는 IAM User는 AdministratorAccess 권한을 부여 |
2단계 : EKS 클러스터 및 Node group 생성 (eksctl 활용, 약 20분 소요)
기존 VPC에 클러스터 배포하는 샘플 파일 (clusterA.yaml)
첨부 파일에서 AWS_REGION, vpc-id, sg-id, subnet-id, AWS_ACCOUNT 등은 수정해서 사용하시기 바랍니다. |
클러스터 배포
# 작업 폴더 생성 (첨부 파일의 내용을 여기에 붙여넣기)
mkdir ~/environment/clusterA
cd ~/environment/clusterA
# cluster 배포
eksctl create cluster -f clusterA.yaml
# 노드 수 및 상태 확인
kubectl get nodes
eksctl 배포는 CloudFormation Stack을 이용하는 방식이기 때문에 Stack(eksctl-*)을 삭제할 경우 EKS 클러스터 관련 모든 리소스가 삭제되므로 주의하시기 바랍니다. |
Node 목록 보이지 않는 경우 : AWS Console credential 권한 추가 (Cloud9 경우)
# role ARN 정의
rolearn=$(aws cloud9 describe-environment-memberships --environment-id=$C9_PID | jq -r '.memberships[].userArn')
echo ${rolearn}
# 직전 명령어 결과에서 assumed-role이 확인되면 아래 작업 추가적으로 수행
assumedrolename=$(echo ${rolearn} | awk -F/ '{print $(NF-1)}')
rolearn=$(aws iam get-role --role-name ${assumedrolename} --query Role.Arn --output text)
# identity 맵핑
eksctl create iamidentitymapping --cluster clusterA --arn ${rolearn} --group system:masters --username admin
kubectl describe configmap -n kube-system aws-auth
Node 목록 보이지 않는 이유 - Cloud9의 IAM credential을 통해 EKS 클러스터를 생성하였고, 현재 콘솔에 접근한 IAM entity(사용자 또는 역할)와 다르므로 - SSO를 이용하여 접속하는 경우도 AWS Console credential을 EKS 클러스터에 추가 필요 $ kubectl describe configmap -n kube-system aws-auth # 현재 권한 조회 $ kubectl edit configmap -n kube-system aws-auth # 각 SSO 사용자에 대한 권한 추가 apiVersion: v1 data: mapRoles: | - groups: - system:bootstrappers - system:nodes rolearn: arn:aws:iam::111111111111:role/eksctl-clusterA-nodegroup-node-grou-NodeInstanceRole-JIVPICHX06NW username: system:node:{{EC2PrivateDNSName}} - groups: - system:masters rolearn: arn:aws:iam::111111111111:role/AWSReservedSSO # 해당 SSO ID에 대한 rolearn 입력 username: admin ...... 참조 URL : https://sh-t.tistory.com/170 |
EKS > Cluster > clusterA 선택 > Compute (tab) : Node group과 2개의 Node 구동 확인
EC2 > Instances : 2개의 Node 구동 확인
EC2 > Launch templates : Node Auto Scaling용 템플릿 생성 확인
EC2 > Auto Scaling Groups : Node Auto Scaling Group 생성 확인
2단계 : EKS 클러스터 및 Node group 생성 (AWS 콘솔 활용, 약 20분 소요)
EKS 클러스터 생성
EKS > Clusters > Create EKS cluster
Configure cluster | Specify networking | Configure logging | Select add-ons | Configure selected add-ons settings |
Name : clusterA Kubernetes version : 1.27 Cluster service role : eksClusterRole Secrets encryption : Disabled Tags (Key/Value) : environment/prod |
VPC : vpcA Subnets : priA-sn-a, priA-sn-c Security groups : master-sg Choose cluster IP address : IPv4 Configure Kubernetes service IP address range : 192.168.0.0/16 Cluster endpoint access : Public - CIDR block : 0.0.0.0/0 |
Control plane logging - API server : Enable - Audit : Enable - Authenticator : Enable - Controller manager : Enable - Scheduler : Enable |
기본값 | Amazon VPC CNI - Version : 기본값 CoreDNS - Version : 기본값 kube-proxy - Version : 기본값 |
eksClusterRole : AmazonEKSClusterPolicy, AmazonEKSVPCResourceController Secrets encryption : Enable 시 KMS key 선택 Subnets : EKS를 구성할 경우 Subnet은 22bit같이 충분히 넓은 대역을 사용 Security groups : Worker node와 Master node 포함하여 EKS 클러스터 내 통신을 제어하는 개념 Kubernetes service IP address : ClusterIP가 할당되는 CIDR 표기법 IP 범위 - RFC-1918 network range : 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 Cluster endpoint access(=Master node에 포함되어 있는 API server의 endpoint) 흐름 - Public (기본값) : kubectl > Public NLB > API server & kube-proxy - Public and private : kubectl > Public NLB > API server > kube-proxy - Private(보안 우수, 동일 VPC에서만 접근 가능) : kubectl > Private NLB > API server & kube-proxy Configure logging : CloudWatch Logs에 저장, 보관 기간 별도 설정 필요 |
Node group 생성
EKS > Cluster > clusterA 선택 > Compute (tab) > Node groups의 Add node group
Configure node group | Set compute and scaling configuration | Specify networking |
Node group configuration - Name : clusterA-ng - Node IAM role : eksNodeRole Launch template - Use launch template : Disabled - Launch Template Name : - Kubernetes labels (Key/Value) : nodegroup-type/nodegroup Kubernetes taints (Key/Value/Effect) : -/-/- Tag (Key/Value) : nodegroup/clusterA-ng |
Node group compute configuration - AMI type : Amazon Linux 2 (AL2_x86_64) - Capacity type : On-Demand (or Spot) - Instance types : t3.medium - Disk size (GiB) : 20 Node group scaling configuration - Desired size : 2 - Minimum size : 2 - Maximum size : 4 Node group update configuration - Maximum unavailable : Number (or Percentage) - Value : 1 node |
Node group network configuration - Subnets : priA-sn-a, priA-sn-c Configure remote access to nodes : Enable - EC2 Key Pair : clusterA-ec2 - Allow remote access from : Selcted security groups (or All) - Security groups : workspace-sg |
eksNodeRole - AmazonEKSWorkerNodePolicy, AmazonEKS_CNI_Policy, AmazonEC2ContainerRegistryReadOnly, AmazonEC2ContainerRegistryPowerUser, CloudWatchAgentServerPolicy, AmazonSSMManagedInstanceCore - awsLoadBalancerController, fsx, fsx, externalDNS, certManager 등 정책은 필요 시 별도 생성하여 추가 - 1개의 Role에 최대 10개의 Policy 연결 가능하며, 10개 초과 시는 아래 링크에서 상향 요청 ※ URL : https://docs.aws.amazon.com/general/latest/gr/aws_service_limits.html Launch template - AWS에서 제공하는 EKS AMI를 이용하여 eks-cluster의 설정값으로 자동 생성됨 - 기존 EKS Node group 템플릿 있는 경우 선택도 가능 Taint Effect : 노드마다 설정 가능하며 설정된 노드는 pod가 스케줄되지 않음, 노드를 지정된 역할만 수행할 때 사용 - NoSchedule : toleration이 없으면 pod 스케쥴링되지 않으며 기존 실행 중인 pod에는 미적용 - NoExecute : toleration이 없으면 pod 스케줄링되지 않으며 기존 실행 중인 pod도 toleration이 없으면 종료시킴 - PreferNoSchedule : toleration이 없으면 pod 스케줄링 안하려고 하지만, 클러스터 내 자원이 부족하면 taint가 걸려있는 노드에도 스케줄링될 수 있음 ※ toleration : taint를 무시할 수있음 ※ Taint Effect는 예를 들어 특정 Node 작업으로 배포된 모든 Pod를 다른 Node로 이동시킬 때 사용하기도 함. Instance types, Disk size : Max Pod를 계산하여 충분한 용량을 선택 Subnets : Node가 배포되는 영역으로, Cluster Subnets 하위 영역 Configure remote access : 필요 시 Worker Node에 대해서 SSH 접속 허용하는 출발지 서버를 지정 |
EKS > Cluster > clusterA 선택 > Compute (tab) : Node group과 2개의 Node 구동 확인
EC2 > Instances : 2개의 Node 구동 확인
EC2 > Launch templates : Node Auto Scaling용 템플릿 생성 확인
EC2 > Auto Scaling Groups : Node Auto Scaling Group 생성 확인
3단계 : Ingress Controller 생성
EKS 클러스터에 IAM OIDC(OpenID Connect) identity Provider 생성
# 작업 폴더 생성
mkdir -p ~/environment/clusterA/controller/ingress-controller
cd ~/environment/clusterA/controller/ingress-controller
# IAM OIDC identity Provider 생성 (${AWS_REGION} : ap-northeast-2)
eksctl utils associate-iam-oidc-provider --region ${AWS_REGION} --cluster clusterA --approve
# 생성 결과 확인
aws eks describe-cluster --name clusterA --query "cluster.identity.oidc.issuer" --output text
https://oidc.eks.ap-northeast-2.amazonaws.com/id/4C48AEA72E4AC42AD6CE3D8FBB9F1FC9
# IAM 등록 확인 (AWS 콘솔 > IAM > Identity providers)
aws iam list-open-id-connect-providers | grep 4C48AEA72E4AC42AD6CE3D8FBB9F1FC9
"Arn": "arn:aws:iam::111111111111:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/4C48AEA72E4AC42AD6CE3D8FBB9F1FC9"
IAM OIDC identity Provider : EKS > Clusters > 클러스터 선택 > Overview (tab) > OpenID Connect provider URL |
인그레스 컨트롤러에 부여할 IAM Policy 생성
# 정책 파일 다운로드
sudo curl -o iam-policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v2.4.4/docs/install/iam_policy.json
# 정책 생성
aws iam create-policy --policy-name AWSLoadBalancerControllerIAMPolicy --policy-document file://iam-policy.json
인그레스 컨트롤러용 Service Account (SA, K8S에서 관리하는 사용자 계정) 생성 및 IAM Policy 연결
# $ACCOUNT_ID : 111111111111
eksctl create iamserviceaccount --cluster clusterA --namespace kube-system --name aws-load-balancer-controller --attach-policy-arn arn:aws:iam::$ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy --override-existing-serviceaccounts --approve
IAM OIDC(OpenID Connect) identity Provider는 Service Account가 IAM Role을 사용하기 위해 필요한 전제 조건 "failed to create service account kube-system/aws-load-balancer-controller: checking whether namespace "kube-system" exists: Unauthorized" : kube-system이라는 namespace가 존재하여 생성하지 않았다는 의미, 무시 |
인증서 구성을 WebHook에 삽입할 수 있도록 cert-manager 설치
kubectl apply --validate=false -f https://github.com/jetstack/cert-manager/releases/download/v1.5.4/cert-manager.yaml
cert-manager는 K8S 클러스터 내에서 TLS인증서를 자동으로 프로비저닝 및 관리하는 오픈 소스 |
인그레스 컨트롤러 생성
# 배포 파일 다운로드 및 수정
sudo wget https://github.com/kubernetes-sigs/aws-load-balancer-controller/releases/download/v2.5.2/v2_5_2_full.yaml
sudo vi v2_5_2_full.yaml
...
595 --- # 삭제
596 apiVersion: v1 # 삭제
597 kind: ServiceAccount # 삭제
598 metadata: # 삭제
599 labels: # 삭제
600 app.kubernetes.io/component: controller # 삭제
601 app.kubernetes.io/name: aws-load-balancer-controller # 삭제
602 name: aws-load-balancer-controller # 삭제
603 namespace: kube-system # 삭제
...
854 - --cluster-name=clusterA # 클러스터 이름 변경
# 배포
kubectl apply -f v2_5_2_full.yaml
# 배포 결과 확인
kubectl get deployment -n kube-system aws-load-balancer-controller # 1개 동작 확인
# 기타 확인
kubectl get sa -n kube-system aws-load-balancer-controller -o yaml # service account 생성 확인
kubectl logs -n kube-system $(kubectl get pod -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} # 속성값 확인
Addon이 사용하는 네임스페이스 : kube-system ※ Addon : 클러스터 내부에서 필요한 기능들을 위해 실행되는 Pod |
4단계 : 도커 이미지 및 ECR 리포지토리 생성, 도커 이미지 업로드
도커 샘플 파일 (Dockerfile)
첨부 파일에서 2개의 도커 이미지를 만드는 이유는 이후에 진행되는 LB 테스트 목적입니다. |
도커 이미지 생성
# 작업 폴더 생성 (첨부 파일의 내용을 여기에 붙여넣기)
mkdir ~/environment/images
cd ~/environment/images
# 도커 이미지 빌드 (second도 빌드)
cd first
docker build -t httpd-first .
docker images
# 도커 컨테이너 구동 (second도 구동)
docker run -p 8080:80 --name httpd-first-container httpd-first
# 도커 컨테이너 상태 정상 확인 (second도 상태 확인)
docker ps
docker logs -f httpd-first-container
docker exec -it httpd-first /bin/bash
root@xxx# exit
# 컨테이너 웹페이지 접속 확인 (second-container-id로 접속 시 "It page02!" 출력)
docker inspect -f "{{ .NetworkSettings.IPAddress }}" <first-container-id> // 컨테이너 IP 확인
172.17.0.2
curl 172.17.0.2:80/
<html><body><h1>It works!</h1></body></html>
curl 172.17.0.2:80/page01/index.html
<html><body><h1>It page01!</h1></body></html>
# 컨테이너 정지 및 삭제 (second도 중지 및 삭제)
docker stop httpd-first-container
docker rm httpd-first-container
Cloud9 웹페이지 > 상단 Tools > Preview > Preview Running Application > "It Works!" 출력됩니다. 불필요한 이미지 삭제하는 명령어 예시 : docker rmi [도커 이미지명] |
ECR 리포지토리 생성, 도커 이미지 업로드
Cloud9 웹페이지 > Terminal
# ECR 리포지토리 생성(${AWS_REGION} : ap-northeast-2)
aws ecr create-repository --repository-name httpd-first --image-scanning-configuration scanOnPush=true --region ${AWS_REGION}
aws ecr create-repository --repository-name httpd-second --image-scanning-configuration scanOnPush=true --region ${AWS_REGION}
# AWS CLI 이용하여 도커 클라이언트를 ECR 레지스트리에 인증 (${AWS_REGION} : ap-northeast-2, $ACCOUNT_ID : 111111111111)
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com
# 도커 이미지 태그 설정 및 업로드 (특정 리포지토리에 푸쉬될 수 있도록 태그 설정)
cd ~/environment/images/first
docker tag httpd-first:latest $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/httpd-first:latest
docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/httpd-first:latest
cd ~/environment/images/second
docker tag httpd-second:latest $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/httpd-second:latest
docker push $ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/httpd-second:latest
ECR 리포지토리 생성은 ECR 콘솔에서 진행해도 됩니다. : Amazon ECR > Repositories > Create repository 위 명령어는 "Amazon ECR > Repositories > 리포지토리 선택 > View push commands" 에서 제공됩니다. |
연계된 URL
[실습] EKS - Cluster에 대해서 kubectl 접근 허용
[실습] EKS - Service를 외부에 노출하기 (ALB, NLB)
[실습] EKS - Persistent Volume을 pod에 연결하기 (EBS, EFS, FSX for Lustre)
참고 URL
EKS에 관련된 Security group 3가지, Cluster endpoint access 3가지
The connection to the server localhost:8080 was refused 해결방법
2단계~3단계 자동 실행 스크립트 샘플
스크립트 샘플 파일
1단계 및 4단계는 유지하고, 2~3단계는 테스트 시에만 잠깐 동작하는 경우 사용하세요 스크립트 동작 시 조건 - cloud9에서 실행 - 2~3단계에서 필요한 수정된 파일이 있어야 함 - 첨부 파일의 AWS_REGION, ACCOUNT_ID : 변수 처리되지 않은 경우는 실제 값을 입력 지울 때는 CloudFormation에서 생성된 스택을 역순으로 지우면 클러스터가 깨끗히 지워집니다. |
스크립트 실행
# 작업 폴더 이동 (첨부의 파일을 여기로 이동)
cd ~/environment/clusterA
# 권한 부여 및 실행
chmod 775 apply.sh
sh apply.sh
'Compute' 카테고리의 다른 글
[이론/실습] EC2 Auto Scaling 구성, 동적 조정 및 스케줄링 (2) | 2022.12.20 |
---|---|
[Tip] Amazon EC2 다양한 Error 상황 알아보기 (0) | 2022.08.04 |
[이론] 도커 (Docker) 기본 개념 (0) | 2022.07.26 |
[Tip] Windows에서 EC2 RDP 접속 2가지 방법 알아보기 (0) | 2022.07.13 |
[Tip] EC2 터미널 접속하는 4가지 방법 알아보기 (0) | 2022.07.12 |