Amazon EKS 구축과 CI/CD 파이프라인 구축 - 핸즈온

최다찬

업데이트:

주제

이번에는 따라하면서 EKS와 CI/CD 파이프라인을 구축 해볼 수 있는 EKS CI/CD
파이프라인 구축 핸즈온을 준비 해봤습니다. 기존에 포스팅했던 ‘ArgoCD를 활용한
K8 CICD pipeline’은 핸즈온이라기 보다는 전체적인 개념과 구축 과정에 대한 정리였다고 하면 이번에는 순수하게 직접 따라하면서 해볼 수 있도록 준비했어요. 전체적인 개념을 먼저 파악하려면 아래 글을 먼저 읽을 것을 권장합니다.

사전 요구 사항

이 글에서 다루게 될 기술과 사전 요구 사항이에요.

  • aws 테스트 계정과 aws access key
  • awscli 설치 및 Access Key 등록
      brew install awscli
      aws configure
      # 발급 받은 AWS Access Key를 입력합니다. 저는 편의상 Admin 권한이 있는 원타임 Key를 사용했어요.
    
  • terraform 설치
      brew tap hashicorp/tap
      brew install hashicorp/tap/terraform
    
  • helm 설치
      brew install helm
    
  • git 설치
      brew install git
    
  • git Fork : 띵스플로우 인프라팀에서 공개하는 핸즈온 교육에 필요한 코드입니다. 링크
    반드시 Fork 또는 clone 후 본인의 public repo로 먼저 push 하세요.
      git clone https://github.com/thingsflow/thingsflow-eks-cicd-hands-on.git
      # 본 핸즈온은 public repo 기준으로 작성했습니다.
    

Terraform을 활용한 EKS 구축

EKS 스펙

terraform/_terraform.auto.tfvars 파일에 정의된 EKS 스펙은 간단하게 아래와 같습니다.

  • Cluster version : 1.22
  • Public Access : True
  • Node Groups
    • Builders : (각종 Controller 및 Grafana, Argo CD 배포)
    • Workers : (대고객 서비스 POD배포)

Terraform Apply

먼저 _terraform.auto.tfvars 파일에서 VPC 값을 수정 합니다. subnet_id 와 azs는
반드시 두개 이상 넣어 주셔야 합니다.
핸즈온에서는 public을 subnet을 넣어 주세요. 입력된 VPC Subnet에 EKS가 Provisioning 됩니다.
image

아래와 같이 terraform 명령어를 실행하세요.

# terraform init 명령어를 사용해 terraform을 초기화 합니다.
cd terraform
terraform init

# 초기화가 완료되면 terraform apply 명령으로 aws 리소스를 생성합니다.
terraform apply

# 약 10분 정도 소요 됩니다.

Add On Controller 설치

Provisioning이 완료 되면 사진과 같은 메시지와 함께 Output 데이터가 출력됩니다.
image

terraform/sh/ 디렉터리 경로에 scripter.tf에 의해 shell이 자동으로 추가 되는데 이
shell에는 EKS를 운영하기 위해 필요한 필수 Add On Controller 설치 명령어가 들어있고 내용은 아래와 같아요.

  • aws-load-balancer-controller : 외내부 통신을 위해 Ingress와 ELB를 통합 해주는 역할.
  • cert-manager : k8s 내부에서 HTTPS 통신을 위한 인증서를 생성하고 관리 하는 역할
  • metrics-server : k8s의 리소스 모니터링.
  • cluster-autoscaler : 워크로드를 위한 자원이 부족 할때 worker 노드를 scale out 하는 역할
  • secrets-store-csi-driver : AWS Secret Manager와 k8s를 통합 해주는 역할

아래와 같이 add on 설치 Shell을 실행하세요.

cd sh
# eks에 연결합니다.
./00.update-kubeconfig.sh

# 연결이 잘 되었는지 kubectl 명령어를 실행해봅니다. 
# 혹시 제대로 실행이 안될 경우 내가 셋팅한 aws access key의 권한을 확인 하십시오.
kubectl get node -A

# cert-manager와 aws-load-balancer-controller를 설치 합니다.
./01.aws_load_balancer_controller.sh

# metric-server와 cluster_autoscaler를 설치 합니다.
# sudo 명령어가 있어서 비밀번호를 요구 할 수도 있습니다. 로컬 PC 또는 작업 서버의 비밀번호를 입력하세요.
./02.cluster_autoscaler.sh

# secrets-store-csi-driver를 설치 합니다. (본 핸즈온에서는 스킵 가능합니다.)
./03.secrets-store-csi-driver.sh

Add On Controller가 정상적으로 설치 되었을때 화면 입니다. EKS 구축이 완료되었습니다. image

k8s CI/CD 파이프라인 구축

image

GitActions와 Argo CD를 사용해서 사진과 같은 CICD Workflow를 구현 할겁니다.

  1. Commit & PUSH
  2. Github Action (CI)
  3. ECR PUSH
  4. Kustomize Image newTag 수정
  5. Argo CD가 변경 사항 확인
  6. 변경 사항 업데이트
  7. 최신 이미지 PULL

Argo CD Installation

먼저 k8-cicd-argocd/argo-cd/values-eks.yaml 파일에서 subnets를 수정 합니다.
외부 통신을 위한 Ingress용 이기 때문에 Public Subnet이여야 합니다.(두개 이상) repositories에서 url을 본인의 git repo url로 수정합니다. image

# ArgoCD를 설치 합니다. 미리 정의해 놓은 Makefile을 실행합니다.
make upgrade-eks

# kubectl 명령으로 argocd POD가 정상적으로 배포 됐는지 확인 합니다.
kubectl get pod -n argocd

# kubectl 명령으로 argocd Ingress가 정상적으로 배포 됐는지 확인 합니다.
# 결과값으로 나오는 ADDRESS 컬럼의 ALB 도메인을 저장합니다.
kubectl get ingress -n argocd

# 아래 명령어로 Argo CD 초기 패스워드를 확인 합니다.
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d

ID : admin
Password : 위에 명령어 결과값 (마지막에 '%'가 있다면 '%'는 제외)
  • 브라우저에서 ALB 도메인을 호출하면 Argo CD에 로그인 할 수 있습니다.
  • EC2 Load balancer 메뉴에 가면 Argo CD용 ALB가 하나 생긴 것을 확인 할 수 있는데 처음에 설치한 aws-load-balancer-controller에 의해서 alb와 Ingress가 통합 된 것입니다.
  • 만약에 ALB 도메인으로 접속이 되지 않으면 EC2 Load Balancer 메뉴에서 ALB 상태를 확인하세요.

Application Deployment

제일 먼저 AWS ECR Console로 들어가서 private repository 하나를 생성합니다.
image

그 다음 아래와 같이 Container를 빌드하여 PUSH 합니다. 참고로 사진과 같이 ECR에서 ‘푸쉬 명령 보기’ 버튼을 클릭 해서 방법을 참고 하셔도 됩니다.
image

# export AWS_ACCOUND_ID=본인의 AWS ACCOUNT ID를 넣어 주세요.
# ecr Login
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin ${AWS_ACCOUND_ID}.dkr.ecr.ap-northeast-2.amazonaws.com
# git repo에 샘플 APP에서 Docker 빌드
cd sample-app
docker build -t thingsflos-hands-on .
docker tag thingsflos-hands-on:latest ${AWS_ACCOUND_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/thingsflos-hands-on:latest
docker push ${AWS_ACCOUND_ID}.dkr.ecr.ap-northeast-2.amazonaws.com/thingsflos-hands-on:latest

위에 작업이 완료 되면 git repo에 있는 아래 두개의 파일을 사진과 같이 방금 생성한 repository URL로 수정하세요.

  • kustomize/overlays/deployment-patch.yaml
  • kustomize/overlays/kustomization.yaml

image

image

또 아래의 파일에서 Subnet ID를 본인의 VPC public SubnetID로 수정하세요.(두개이상)

  • kustomize/overlays/ingress-patch.yaml image

이제 어플리케이션을 배포 할건데요. 배포 하기전에 cicd 구조를 살펴 보면 POD에서 이미지를 AWS ECR(Private)에서 가지고 오는 것을 확인 할 수 있어요. 그럼 POD에서 AWS ECR로 접근할 수 있는 권한이 필요합니다. 여러 방법이 있지만 핸즈온에서는 간단하게 k8s의 imagePullSecrets를 사용해 보려고 합니다. 먼저 아래 명령어를 실행해서 ecr-regcred라는 secret을 생성합니다. 생성한 secret은 kustomize/overlays/deployment-patch.yaml 파일 imagePullSecrets 라인에 미리 셋팅 해놨습니다.

# ${AWS_ACCOUND_ID}를 본인이 테스트 중인 AWS Account ID로 수정하세요.
# 중요한 것은 해당 명령어를 실행할때 입력한 Accound ID의 ECR 로그인 권한이 있는 AWS_ACCEESS_KEY가 등록된 서버 또는 로컬 PC에서 실행해야 합니다.
kubectl create secret docker-registry ecr-regcred \
--docker-server=${AWS_ACCOUND_ID}.dkr.ecr.ap-northeast-2.amazonaws.com \
--docker-username=AWS \
--docker-password=$(aws ecr get-login-password --region ap-northeast-2) \
--namespace=default

# 수정한 kustomize 파일을 git에 commit & push 해줍니다.
git add kustomize/
git commit -m "fix: update"
git push origin master

imagePullSecrets 셋팅까지 완료 되었으면 이제 ArgoCD를 통해서 서비스를 배포 할 준비가 다 됐어요. 아래 경로의 파일은 Argo CD의 declarative-setup 파일 입니다. 수동으로 Application을 생성 할 수도 있지만 반복된 작업은 declarative 형식의 파일을 만들어서 사용도 가능 합니다. 아래 파일의 repoURL 부분을 본인의 repo URL로 변경하세요.

  • k8-cicd-argocd/argo-declarative-setup-yaml
# 이제 Argo CD Application(k8s custom resource)을 EKS에 배포 합니다.
cd k8-cicd-argocd/argo-declarartive-setup-yaml
kubectl apply -f Application.yaml

Application.yaml을 Apply하고 Argo CD 화면으로 가면 사진과 같이 sample-app이 배포 되기 직전 상태가 됩니다.(OutOfSync) Argo CD는 1분에 한번씩 Cluster의 리소스와 Argo CD가 바라보고 있는 git repo Manifest를 비교해서 서로 다른 경우에 OutOfSync 상태를 표시 합니다. Sync 버튼을 클릭하고 -> SYNCHRONIZE 버튼을 클릭해서 워크로드를 배포 합니다.
image

배포가 완료 됐지만 POD에서 에러가 발생 합니다. 에러가 발생하면 Argo CD에서 Degraded 상태를 보여주고 빨간색으로 표시합니다. 여기서 ‘파드 클릭’ -> ‘LOG 버튼 클릭’하면 사진과 같이 어플리케이션 에러 로그를 확인 할 수 있습니다. 아래 에러는 docker build를 Mac에서하고 배포를 linux에 했기 때문에 발생한 에러 입니다. 곧 gitaction을 태울것이기 때문에 일단 넘어 가겠습니다.

exec /usr/local/bin/httpd-foreground: exec format error

image

일단 이렇게 CICD 중 CD 부분을 완성했습니다. 이 구조에서 포인트는 아래와 같아요.
중요하니 천천히 읽어 보세요.

  1. ArgoCD의 ‘sample-yaml’ Application 은 k8-cicd-argocd/argo-declarative-setup-yaml/Application.yaml로 배포 했다.
  2. sample-yaml은 Application.yaml에 정의한 thingsflow-eks-cicd-hands-on.git/kustomize/overlays를 바라보고 있다.
  3. thingsflow-eks-cicd-hands-on.git/kustomize/overlays 에 변경 사항이 발견 되면 ArgoCD는 OutOfSync를 표시한다.
  4. Container의 버전은 곧 Tag 이다.
  5. k8s manifest 관리 도구인 Kustomize는 kustomization.yaml에 Container 버전을 정의한다.
  6. Container 신규 버전을 배포하는 것은 결국에는 새로 빌드된 컨터이너 태그를 kustomization.yaml에 업데이트 하는 것이다.

GitHub Actions (CI)

위에서 말한것 처럼 이제 kustomization.yaml에 있는 태그만 변경하면 Argo CD가 변경
사항을 확인하고 새로운 버전을 배포 합니다.
github action의 역할은

  • 새로운 버전을 빌드하고
  • 빌드한 것을 ecr로 push하고
  • kustomization.yaml의 태그를 update 하는 것 입니다.

먼저 Workflow에서 사용할 민감한 정보를 Actions Secret에 등록합니다.

Github Secret 등록
git repo setting -> Security -> Secret -> Actions -> New Repository Secret

# ACTION_TOKEN_K8S를 먼저 등록합니다. 
# ACTION_TOKEN_K8S는 kustomize 파일을 clone하고 container tag를 수정 후 push할때 사용합니다.
# https://github.com/settings/tokens 에서 생성 가능 합니다.
1. ACTION_TOKEN_K8S
# AWS_ACCESS_KEY는 ECR PUSH를 할때 사용 합니다.
2. AWS_ACCESS_KEY_ID
3. AWS_SECRET_ACCESS_KEY

image

Workflow 파일 수정 .github/workflows/deploy.yaml 파일을 수정 합니다.
image

  1. 36 line : 본인이 생성한 ECR REPO 이름으로 수정
  2. 52 line : 본인이 생성한 git repo 이름으로 수정(id/repo name)
  3. 53,71 line : git 브런치 확인
  4. 55 line : 본인이 생성한 repo 이름으로 수정
  5. 62 line : git repo kustomize 경로로 수정
  6. 67 line : 본인이 생성한 repo 이름으로 수정

commit & push

git add .
git commit -m "fix: workflow update"
git push origin master

아래 사진 처럼 workflow 실행이 완료 되면 우리는 kustomize/overlays/kustomization.yaml 파일 newTag 수정, OutOfSync
두가지를 확인 할 수 있어요.
image

ArgoCD에서 Deployment가 OutOfSync 상태가 된것을 확인 할 수 있고, 클릭하면 DIFF를 통해서 어떤것이 변경 되어 있는 확인 가능해요.
이제 Sync 버튼을 클릭하면 새로운 버전의 컨테이너가 롤링 배포 됩니다.
물론 sample-yaml을 클릭해서 수동 sync를 자동으로 변경 할 수도 있습니다.
image

Service 수정 및 배포
이제 마지막으로 어플리케이션을 수정해서 배포 해보려고 합니다. 먼저 아래 명령어를 실행해서 Ingress와 연결된 ALB 주소를 확인 합니다. 그리고 접속해 보세요.

kubectl get ingress -n default

아래 사진과 같은 화면이 나올건데요. image

sample-app/index.html 파일에서 아래 사진과 같이 수정 하고 git commit & push 합니다. 그리고 workflow가 완료되면 Argo CD에서 Sync까지 해주세요.
image

그리고 다시 ALB 도메인을 호출 하면 아래 사진 처럼 배경색이 변경된 것을 확인 할 수 있어요. 제대로 배포 된 것입니다.
image

삭제

cd terraform
terraform destroy
# EC2 Load balancer 메뉴로 가서 Ingress와 통합 됐던 ALB를 삭제하세요.
# 가끔 오랜 시간동안 "aws_security_group.this[0]: Still destroying..." 메시지가 계속 나오는 경우가 있는데
# 이런 경우에는 EC2 네트워크 인터페이스 메뉴로 가셔서 보안그룹과 연결된 네트워크 인터페이스를 수동으로 삭제 해주셔야합니다.

이렇게 Terraform을 활용해서 EKS를 구축하고 Argo CD와 Github Actions를 사용해서 CI/CD 파이프라인을 구축 해봤는데요. 사실 자료를 준비하면서 이 자료를 보고 완벽하게 따라 할 수 있을까 라는 걱정도 되긴 했습니다. 범위가 생각 보다 많습니다. 그래도 최대한 모든 과정을 담으려고 노력했기 때문에 아마 큰 어려운 없이 해보실수 있을 것이라고 생각합니다.

이번 핸즈온에서는 app repository(sample-app)와 k8s manifest repository를(kustomize) 하나로 묶어서 진행했지만 보통은 별도의 git repository로 나눠서 사용하여 운영 하고 있습니다. 핸즈온을 완료 하신 분들은 이부분도 직접 해보시면 좋을 것 같습니다.

감사합니다.

띵스플로우 팀은 자기의 일을 좋아하고 잘하는 사람들 입니다. 사용자와 서비스를 중심으로 빠르게 실행하고 학습하며, 다양한 직무의 사람들이 협업을 통해 시너지를 내고 있습니다. 다양한 콘텐츠 혁신을 이루고 있는 띵스플로우 팀에 함께할 분을 찾습니다! 언제든 people@thingsflow.com로 이메일을 주시기 바랍니다!

태그: , , , ,

카테고리: ,

업데이트:

댓글남기기