AWS EKS 서버 배포 - CI/CD
쿠버네티스 (k8s)
Kubernetes (k8s)
는 컨테이너화된 애플리케이션을 대규모로 운영하기 위한 오케스트레이션
입니다. 즉 배포
, 확장
, 관리
를 자동화하는 오픈소스 플랫폼 인데요. 주로 Docker
와 같은 컨테이너 기술과 결합하여 컨테이너 관리 플랫폼으로 사용 하게 됩니다.
Kubernetes
는 Cluster
로 구성 되어있는데 여러 대의 머신(노드)
을 묶어 컨테이너화된 애플리케이션을 배포하고 관리하는 시스템으로 되어 있습니다. 크게 Mster Node
, Worker Node
로 구성 되어 있으며 하나씩 알아보도록 하겠습니다.
Master Node
Master Node
는 Cluster
관리, API 서버
, 스케줄링
역할 등을 담당 하게 됩니다. 예를들어 Master Node
하고 Worker Node
는 물리적으로 분리 된 상태에서 특정 Worker Node
가 부하가 발생시 Master Node
는 이를 감지해서 Worker Node
에 Pod
를 증설 할지 아니면 물리적인 노드 Worker Node
를 증설할지 선택하게 됩니다.
그래서 Master Node
는 중앙 컨트롤 타워 역활 담당 그리고 Worker Node
는 실질적으로 작업을 수행하는 역활을 하게 됩니다. 이렇게 Master Node
하고 Worker Node
를 묶어서 Cluster
라고 부르게 됩니다.
Master Node
에 특징적인 부분은 앞써 이야기 한대로 Master Node
가 Worker Node
를 계속 참조하고 있다가 부하가 발생하면 Pod
를 더 증설 할 수 있겠지만 직접 개발자가 판단해서 Worker Node
안에 있는 Pod
를 증설 할 수 있습니다. 이것을 Kubectl
명령을 통해 직접 개발자가 Master Node
에게 명령을 내리고 Master Node
는 Worker Node
에 명령을 내리게 됩니다. 즉 kubectl
역활을 개발자가 하고 Kubernetes
와 서로 소통을 하기 위한 프로그램 이라고 생각하면 쉽습니다.
API 서버 (kube-apiserver)
Master Node
의 API 서버 (kube-apiserver)
는 클러스터의 중앙 집중식 관리 시스템 입니다. 개발자가 직접 외부 환경에서 Kubernetes
로 직접 통신 할 수 있는 진입점을 제공 합니다. 앞써 이야기 한대로 Worker Node
에 대한 Pod
정보 및 Pod
증설 등 개발자가 명령을 내리면 쿠버네티스 API 서버(kube-apiserver)
로 전송 전송 하게 됩니다.
스케줄러 (kube-scheduler)
Cluster
내에서 실행될 파드를 적절한 노드에 할당하는 역할을 담당하게 됩니다. 예를들어 부하로 인해 Pod
를 증설 해야 하는데 어떤 Worker Node
에 증설 해야할지를 판단 하게 됩니다. 그리고 새로 생성되거나 스케줄링되지 않은 파드를 감시하고 파드의 요구사항과 노드의 상태를 고려하여 최적의 노드를 선택 하게 됩니다.
컨트롤러 매니저 (kube-controller-manager)
컨트롤러 매니저
는 Worker Node
에 있는 Pod
를 계속 모니터링 역활을 하고 만약 특정 Pod
가 문제로 인해 죽으면 다시 Pod
를 살려내는 등 이러한 컨테이너 자원의 최적화 하는 역활을 하게 됩니다.
etcd
etcd
는 클러스터 상태 저장소 입니다. 즉 Kubernetes
실행 되기 위한 Config 관련 환경 정보 그리고 비밀값 등을 저장 하는 역활을 하게 되며 클러스터 상태값(ConfigMap
등)를 key-value
형태로 저장하는 저장소 입니다.
Worker Node
실질적인 애플리케이션 실행을 담당하는 노드 입니다. 이번에 실습하게 될 AWS 기준으로 EC2
인스턴스로 실행하게 되고 이 Worker Node
에서 Pod
가 실행 하게 됩니다.
kubelet
Master Node
의 API 서버 (kube-apiserver)
와 통신하게 되며 각각의 Pod
들을 시작, 중지, 관리하는 작업을 수행하게 됩니다. kubelet
는 각 Pod
가 성공적으로 시작되었는지 체크하고 Pod
의 상태를 주기적으로 API 서버 (kube-apiserver)
로 보고 하게 됩니다.
kube-proxy
kube-proxy
는 네트워크 프록시 및 로드 밸런서 역활을 하는 노드 수준의 구성 요소 입니다. 네트워크 트래픽을 적절히 포워딩 하도록 네트워크 규칙을 설정하여 각 파드 간의 통신이나 외부에서 파드로 접근 가능 하도록 합니다.
Kubernetes 구성 요소
namespace (네임스페이스)
Kubernetes Cluster
환경에서 논리적인 분리 하는 단위 입니다. 하나의 클러스터 내 여러 개의 작은 클러스터처럼 사용할 수 있게 해주는 기능인데, 각 네임스페이스는 독립적인 환경을 제공 해주며 예를들어 개발, 테스트, 상용 등 각각의 환경을 분리 할때 유용하게 사용됩니다. 즉 특정 서버를 물리적인 분리가 아닌 논리적으로 리소스를 그룹화 해서 마치 여러 개의 클러스터가 있는 것처럼 사용할 수 있게 합니다.
Pod
Kubernetes
에서 Pod
는 배포 가능한 가장 작은 컴퓨팅 단위 이며 하나 이상의 컨테이너의 그룹입니다. 또한 컨테이너들이 함께 실행될 수 있도록 리소스와 네트워크 네임스페이스를 공유합니다. 일반적으로는 1개의 컨테이너로 구성 되며 만약 한개의 Pod
가 두개의 독립적인 컨테이너가 존재하면 이것들을 하나의 네트워크로 묶는 역활을 하게 됩니다. 즉 만약 두개의 컨테이너가 같은 IP 를 사용하고 묶는 걸 Pod
이라고 합니다.
이렇게 그룹화 해서 묶어서 Pod
로 구성하는 이유는 2개의 컨테이너가 같은 IP 를 사용하면서 서로 다른 각각의 컨테이너 간의 긴밀한 통신 해야 하는 경우 그리고 통신을 원활하게 (속도 등) 해야 하는 경우 입니다.
Service
Service
는 Kubernetes
의 자원의 종류의 이름입니다. 주요 역활은 Pod
들 앞단에 위치 하여 추상적인 네트워크 엔티티 역활을 하게 되는데요. 즉 Cluster
내에서 실행 중인 Pod
들에게 네트워크 접근 방법 (로드 밸런싱)을 제공 하고 있습니다. 그림을 보시면 만약 외부로 부터 Pod
을 접근 하고자 할때 그러니깐 두개의 각각 Pod
안에 설치되어 있는 컨테이너에 접근 하고자 할때 앞에 Service
가 각 Pod
에게 부하를 분산해주는 부하 분산기 역할을 해줍니다.
기본적으로 Pod
는 외부 포트를 지정할 수 없는데 사용자는 특정 Pod
로 접근 해야 할때 어떨때는 1번 Pod
로 접근 해야 하고 어떤 경우에는 2번 Pod
로 접근 해야 하는 상황에서 사용자 Front 입장에서는 2개의 Pod
EndPoint 를 동적으로 컨트롤러 하기 어렵습니다. 이때 Service
가 앞에 배치해서 부하 분산기 역활 통해 각각의 Pod
로 접근 하도록 도와주게 됩니다.
그리고 Pod
는 부하에 따라서 동적으로 Pod
가 증설 될 수도 있고 새로 생성된 Pod
는 IP 를 예측하기 어렵습니다. 그래서 언제든지 확장 될 수 있는 Pod
들을 확장성 있는 서버로 설계 하기 위해 Service
가 로드밸런싱 역활로 가지게 됩니다.
1 | apiVersion: v1 |
다음은 Service
자원 예시를 보도록 하겠습니다.
1 | kind: Service |
자원 종류를 Service
로 지정 하겠다는 의미입니다.
1 | metadata: |
- name: 특정 자원의 이름
- namespace: 네임스페이스명
1 | spec |
1 | spec: |
- spec.selector.app:
label
를 지정 하는 것, 즉 특정Pod
에 지정한label
로 네트워크 정보 전파 함, 만약에 1개 이상pod
가service
의selector.app
과 매핑되면 자동으로 로드밸런싱 - spec.ports.port: 특정 서비스의 내부 포트 번호
- spec.ports.targetPort:
Service
가포워딩(forward)
하는 대상Pod
의 포트
Replicaset
ReplicaSet
는 지정된 수의 Pod
복제본을 만들어주고 항상 지정된 수로 실행 되도록 보장해주는 Kubernetes
의 리소스 입니다. 앞써 설명한 Pod
를 2개의 복제 본으로 유지 하고자 하면 직접 개발자가 정의된 yml 파일을 이용해서 apply
해서 각각 Pod
를 만들어 주면 됩니다. 이렇게 하면 2개의 yml 파일을 구성해서 관리 해야 하는데 동일한 코드 중복 문제가 있을 수 있습니다. 이것을 해소하기 위해 Replicaset
이라는 리소스를 이용해서 개발자가 원하는 몇 개의 복제본 Pod
로 구성할지 설정만 하고 하나의 yml 파일로 관리 하면 됩니다.
1 | apiVersion: apps/v1 |
1 | metadata: |
- name: 특정 자원의 이름
- namespace: 네임스페이스명
1 | spec: |
- spec.template.spec.containers:
Pod
생성시 어떤 image 컨테이너로 생성 할 것인지 정의 합니다.nginx
이라는 이미지로 생성해서 컨터네이너로 관리 하겠다는 의미 입니다. - spec.template.metadata.labels.app: 생성한
Pod
의 라벨을 지정 하는 것 입니다.
1 | spec: |
- spec.replicas: 생성한
Pod
를 몇 개replicas
로 구성 할지 지정 합니다. - spec.selector.matchLabels.app: 이 값은 라벨을 지정 하는 것인데
spec.template.metadata.labels.app
통해 지정한 라벨하고 동일하게 매칭 되어 있으면 속한Pod
들을 모니터링을 하게 되며 만약 지정한replicas
값이 2 로 지정하면 항상 지정된 수로Pod
들을 실행 되도록 보장 해줍니다.
Deployment
Kubernetes
에서 Deployment
는 애플리케이션의 무중단 배포
와 자동 복구, 스케일링, 버전 관리 등을 가능하게 해주는 핵심 리소스 입니다.
앞써 설명한 ReplicaSet
과 기본기능은 동일 하고, Deployment
이라는 리소스를 만들면 ReplicaSet
과 ReplicaSet
을 통해 Pod
를 생성 하게 됩니다. 간단하게 주요 역활에 대해 나열 하도록 하겠습니다.
- 애플리케이션의
지속적인 배포(Continuous Deployment)
- 새로운 버전의
롤링 업데이트(Rolling Update)
- 장애 발생 시
자동 복구(Self-healing)
- 버전
롤백(Rollback)
기능 제공
한마리로 ReplicaSet
의 발전된 형태가 Deployment
이라고 생각 하시면 되는데
1 | apiVersion: apps/v1 |
예시 Deployment
입니다. 차례대로 설명 하도록 하겠습니다.
1 | metadata: |
- name: 특정 자원의 이름
- namespace: 네임스페이스명
1 | spec: |
- spec.replicas: 생성한
Pod
를 몇 개replicas
로 구성 할지 지정 합니다. - spec.selector.matchLabels.app: 이 값은 라벨을 지정 하는 것인데
spec.template.metadata.labels.app
통해 지정한 라벨하고 동일하게 매칭 되어 있으면 속한Pod
들을 모니터링을 하게 되며 만약 지정한replicas
값이 2 로 지정하면 항상 지정된 수로Pod
들을 실행 되도록 보장 해줍니다.
1 | spec: |
- spec.template.metadata.labels.app: 생성한
Pod
의 라벨을 지정 하는 것 입니다. - spec.template.spec.containers.name:
Pod
생성을 하는데 containers 이름을nginx
이라고 지정 하겠다는 의미 입니다. - spec.template.spec.containers.image:
Pod
생성시 어떤 image 컨테이너로 생성 할 것인지 정의 합니다.nginx:1.25
이라는 이미지로 생성해서 컨터네이너로 관리 하겠다는 의미 입니다. - spec.template.spec.containers.ports.containerPort: 생성하고자 하는
Pod
내nginx
내부 포트를80
으로 지정 하겠다는 의미 입니다.
차례대로 설명 했고 해당 Deployment 를 apply 하도록 하겠습니다.
1 | kubectl apply -f ./deployment.yml |
그런 다음 ReplicaSet 을 확인 해보도록 하겠습니다.
1 | kubectl get replicaset -n ${네임스페이스명} |
Deployment 도 생성 되었는지 확인 해봅니다.
1 | kubectl get deployment -n ${네임스페이스명} |
Pod 도 정상적으로 생성 되었는지 확인해봅니다.
1 | kubectl get pod -n ${네임스페이스명} |
그런 다음에
spec.template.spec.containers.image
여기서 nginx:1.26
으로 버전 업그레이드 해서 다시 apply 하도록 하겠습니다.
1 | kubectl apply -f ./deployment.yml |
그런 다음에 replicaset
, deployment
, pod
차례대로 다시 조회 하도록 합니다.
1 | kubectl get replicaset -n ${네임스페이스명} |
차례대로 확인 해보면 새로운 Pod
가 생성 되었다는 것을 확인 할 수 있는데요. 여기서 중요한 부분은 Deployment
경우 새로운 버전으로 다시 apply
하게 된다면 새롭게 Replicaset
하고 Pod
가 생성하게 되고 정상적으로 생성하게 된다면 기존에 생성 했던 Replicaset
하고 Pod
는 삭제 하게 됩니다. 즉 롤링 업데이트(Rolling Update)
가 진행 됩니다.
그 다음은 롤백(Rollback)
기능을 알아보도록 하겠습니다.
1 | kubectl rollout undo deployment ${deployment 명} -n ${네임스페이스명} |
롤백 명령어 입니다. 그런 다음 Pod
를 조회 하도록 하겠습니다.
1 | kubectl get pods -n ${deployment 명} |
그런데 latest(최신 버전)
의 경우 즉 Deployment
의 template
에 변화가 없으면spec.template.spec.containers.nginx:latest
로 지정 하고 apply
를 하게 된다면 내부적으로는 버전 변화가 없기 때문에 새로운 ReplicaSet
하고 Pod
를 생성하지 않습니다. 즉 롤링 업데이트(Rolling Update)
가 진행 되지 않습니다.
강제로 새로운 ReplicaSet
및 Pod
를 생성 하고자 하면 rollout restart
명령어를 사용 해야 합니다.
1 | kubectl rollout restart deployment ${deployment명} -n ${namespace명} |
이렇게 명령어를 실행하면 latest
태그를 그대로 사용하더라도 강제로 ReplicaSet
을 생성해서 새로운 revision
생성 하게 됩니다.
Ingress
Ingress
는 Kubernetes Cluster
외부에서 내부 서비스로 들어오는 HTTP 요청의 라우팅 규칙을 정의하는 리소스 입니다. 다만, Ingress
만 만든다고 바로 작동하는 건 아니고 이를 실제로 처리할 Ingress Controller
(예: NGINX) 가 필요합니다.
ingress
가 왜 필요한지 그리고 어떤 역활을 하는지 그림으로 설명 하도록 하겠습니다.
그림에 보면 사용자가 api.server.com
으로 요청하게 된다면 api.server.com
역활을 하고 있는 LB
에 도달 하게 되고 LB
는 특정 Service
로 연결해서 각각의 Pod
로 연결하게 됩니다. 반대로 사용자가 shop.server.com
으로 요청시 해당 LB
는 특정 Service
로 연결해서 각각의 Pod
로 연결 할 수 있게 도와줍니다.
하지만 이 아키텍처의 단점은 각각의 LB (로드밸런서)
가 특정 서비스하고 연결 하고 있다는 점 입니다. 즉 api.server.com
, shop.server.com
(prefix
다름) 각각의 자원에서 전용 LB
가 각각 생성 해야 한다는 점 입니다. 만약에 앞으로 admin.server.com
이라는 서비스가 생성 되었다는 그에 맞게 LB
도 생성 해야 한다는 점 입니다.
LB
는 AWS
에서 과금이 발생하는 요소다 보니까 자원의 낭비가 발생 할 수 있는 부분이 있습니다. 그리고 각각 LB
마다 엔드포인트가 관리를 해야 해서 프론트엔드 소스코드에서도 전부 달라지는 엔드포인트 설정 및 관리를 해야 합니다.
각각의 Service
마다 LB
를 연결시키는 게 아니라 중간에 Ingress
라고 하는 자원을 만들어두고 이 Ingress
는 url 패턴
에 따라 서비스로 분기 처리를 해주게 됩니다. 즉 Ingress Controller
가 api.server.com
, shop.server.com
각각의 Ingress
로 라우팅 하는 역활을 하게 됩니다.Ingress
에서는 예를들어서 shop.server.com/${Server1 URL 패턴}
shop.server.com/${Server2 URL 패턴}
으로 각각 url 패턴으로 Service
로 가도록 합니다.
Ingress
와 Ingress Controller
차이점은?
Kubernetes
에서 Ingress
와 Ingress Controller
는 이름이 비슷해서 헷갈리지만 역할과 성격이 완전히 다릅니다. Ingress Controller
는 실질적인 라우팅을 수행 하고 Ingress
는 규칙정보 정의를 합니다.
즉 abc.server.com
이라는 도메인 통해 사용자가 접근 하게 된다면 맨 처럼 LB
는 특정 Ingress Controller
로 접근 하게 되고 여기서 주된 역활은 kubernetes Cluster
외부에서 내부 서비스로 들어오는 트래픽을 관리하고 라우팅하는 역할 하게 됩니다.Ingress Controller
로 접근 통해 맨 앞에 Prefix
단위로 특정 Ingress
로 접근 하게 되고 Ingress
는 url 패턴
에 따라 서비스로 분기 처리를 해주게 됩니다.
쉽게 생각 하자면 Ingress Controller
는 “교통경찰” 또는 “자동차 네비게이션 시스템”, Ingress
는 “도로 표지판” 으로 이해 하면 됩니다.
1 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/aws/deploy.yaml |
Ingress Controller
설치 명령어 입니다. 이때 동시에 AWS LB
도 등록 하게 됩니다. AWS 에 가서 Route53
하고 등록된 LB
하고 매핑 작업이 필요 합니다.
1 | apiVersion: networking.k8s.io/v1 |
1 | apiVersion: networking.k8s.io/v1 |
- metadata.name: 특정 자원의 이름
- metadata.namespace: 네임스페이스명 지정
1 | spec: |
- spec.rules.host: 설정하려는 도메인 이름
- spec.rules.http.paths.- path:
server.syh8088.store/members
로 호출시 /members 라는 path 로 호출 했으면 ‘nginx-service’ 로 라우팅한다는 정규표현식
1 | kubectl apply -f ./ingress.yml |
ingress
apply 명령어 입니다.
1 | kubectl get ingress -n ${네임스페이스명} |
해당 설치된 Ingress
조회 하는 명령어 입니다.
1 | NAME CLASS HOSTS ADDRESS PORTS AGE |
이렇게 설치된 ingress 목록을 확인 할 수 있습니다.
1 | http://server.syh8088.store/msmbers |
해당 명령어를 호출하면 Ingress-Controller
-> Ingress
-> Service
-> Pod
까지 접근 하게 됩니다.
실습 CI/CD 구축 해보기
지금부터 실습 통해 AWS EKS
이용해서 CI/CD
작업 하고자 합니다. 간단하게 전체적인 flow 를 설명하자면 사용자가 특정 도메인에 접근 하면 AWS Route53
통해 정해진 LB
로 접근 하게 되고 Kubernetes Ingress Controller
로 이동 하게 됩니다. 여기서 적절하게 도메인 prefix
계산해서 Ingress
로 가게되고 매핑된 Service
로 접근하게 되고 최종 목적지인 Pod
로 가게 됩니다.
개발자는 Github Action
통해 특정 브랜치에 Git Push
를 하게 된다면 Dockerfile
이용해서 Docker Image
를 만들고 만든 image 를 AWS ECR Repository
에 등록하게 됩니다. 그다음 Kubernetes
에서 지원하는 kubectl
명령어를 통해서 새롭게 Pod
를 만들면서 롤링 업데이트
진행 하게 됩니다.
IAM 역할 생성 하기
AWS IAM
서비스로 접근 해서 사용자 생성
버튼을 클릭 하도록 합니다.
원하시는 사용자 이름을 지정 한 다음에 다음
버튼을 클릭 하도록 합니다.
권한 옵션
에서 직접 정책 연결
선택 합니다. 그런 다음에 AdministratorAccess
정책을 클릭 하고 다음
버튼을 클릭 합니다.
사용자 생성
버튼을 클릭 합니다.
생선된 사용자 콘솔 로그인 URL
및 콘솔 암호
를 따로 잘 관리 하도록 합니다. 그런 다음 생성한 사용자로 다시 AWS 로그인을 하도록 합니다.
생성한 사용자에서 페이지 에서 엑세스 키 만들기
버튼을 클릭 하도록 합니다.
사용사례 에서 Command Line Interface(CLI)
선택 하도록 합니다.
엑세스 키 만들기
버튼을 클릭 하도록 합니다.
생성된 엑세스 키를 따로 잘 보관 하도록 합니다.
AWS EKS Cluster 생성 하기
AWS Elastic Kuberneties Service
서비스에 접속 하도록 합니다. 클러스터 생성
버튼을 클릭 합니다.
일반적인 실습 과정이기에 요금 절약을 위해 구성 옵션
을 사용자 지정 구성
을 클릭 합니다. 그리고 EKS 자율 모드
사용을 해제 하도록 합니다.
그런 다음 원하시는 클러스터 이름을 입력 하도록 합니다.
클러스터 IAM 역활
설정 해야 합니다. 지금 생성하는 EKS 전용 역할 생성을 위해 권장 역할 생성
버튼을 클릭 하도록 합니다.
신뢰 할 수 있는 엔티티 유형
을 AWS 서비스
로 클릭 합니다. 참고로 AWS 역할
이라는 하는 것은 AWS 자원 끼리 접근 할 수 있는 권한이라고 생각 하면 됩니다. 우리는 AWS EKS 서비스를 AWS EC2 서비스로 접근 할 수 있는 권한을 생성 해야 하기 떄문에 지금과 같은 역할 생성을 하는 겁니다.
서비스 또는 사용 사례
에서 EKS
로 선택하고 사용 사례
를 EKS - Cluster
를 선택 합니다. 이렇게 하면 AWS 에서 권장 하는 역할은 자동 선택 해서 셋팅 해줍니다.
그러면 AmazonEKSClusterPolicy
선택 하게 해줍니다.
원하시는 역할 이름을 입력 하도록 합니다.
다시 EKS Cluster 생성 페이지에서 방금 생성 한 역할
을 선택 하도록 합니다. (바로 옆에 새로고침 버튼 클릭)
다음은 2단계 네트워킹 지정
입니다. VPC
설정인데 미리 설정 해준 default 로 해서 다음 버튼을 클릭 합니다.
다음은 3단계 관찰성 구성
페이지 입니다. 기본적으로 셋팅 한것으로 해서 다음 버튼 클릭 합니다.
다음은 4단계 추가 기능 선택
페이지 입니다. 기본적으로 셋팅 한것으로 해서 다음 버튼 클릭 합니다.
다음은 5단계 선택한 추가 기능 설정 구성
페이지 입니다. 이것도 기본적으로 셋팅 한것으로 해서 다음 버튼 클릭 합니다.
검토 및 생성
페이지 입니다. 지금까지 생성한 설정 확인 및 최종 클러스터 생성 합니다.
20분 정도 지나면 생선한 EKS Cluster
생성 한 것을 확인 할 수 있습니다.
컴퓨팅
메뉴를 클릭 해서 이제 노드 그룹 추가
버튼을 클릭 하도록 합니다. 앞써 설명한대로 Kuberneties
는 Master Node
및 Worker Node
로 구성 되어 있다고 했습니다.
방금 EKS 생성은 Master Node
를 생성한 것이고, 지금은 노드 그룹 추가 통해 Worker Node
를 생성 하고자 합니다.
1단계 노드 그룹 구성
페이지에서 원하시는 노드 그룹명을 지정 하도록 합니다. 그런 후 노드 IAM 역할
을 적용 해야 합니다. 권장 역할 생성
버튼을 클릭 하도록 합니다.
신뢰 할 수 있는 엔티티 유형
을 AWS 서비스
로 클릭 합니다. 그리고 Worker Node
는 EC2 로 구성하기 때문에 사용 사례
를 EC2
로 설정 하도록 합니다.
그럼 이미지 권한 정책에서 이미 3개가 선택 되어 있습니다.
역할 이름을 지정 한 다음에 다음 버튼을 클릭 하도록 합니다.
방금 생성한 역할을 선택 하도록 합니다.
2단계 컴퓨팅 및 조정 구성 설정
페이지 입니다. 생성하고자 하는 Worker Node
인스턴스 유형을 선택 하는 항목 입니다. 일단 실습이기 때문에 원하시는 OS 를 선택해주시고 사양은 t3.small
로 선택 해도 크게 무리는 없습니다.
노드 그룹 조정 구성
에서
- 원하는 크기: 2
- 최소 크기: 2
- 최대 크기: 2
로 최소 비용을 위해 설정 하도록 합니다. 실전에서는 서비스에 따라 계산 해서 설정 해야 합니다.
3단계 네트워킹 지정
페이지에서 기본값으로 해서 다음 버튼을 클릭 하도록 합니다.
검토 및 생성
페이지에서 지금까지 설정한 데이터를 확인 후 최종적으로 노드 생성 하도록 합니다.
몇분 후 다시 컴퓨팅
메뉴 페이지로 접근 하면 생성한 노드를 확인 할 수 있습니다.
만약 나중에 노드 갯수 설정을 변경 하고자 할때 세부 정보
페이지에서 우측 상단에 편집
버튼을 클릭 합니다.
초기 설정한 노드 갯수 관련 데이터 값을 확인 할 수 있습니다. 여기서 원하시는 갯수로 설정 한 다음에 수정 하도록 합니다.
AWS CLI 설치 및 kubectl 셋팅 하기
지금까지 AWS EKS 통해 Master Node
및 Worker Node
를 생성 했습니다. 그럼 개발자가 직접 Local PC 에서 Master Node
로 접근 및 통제를 위해 AWS CLI
그리고 kubectl
설치 를 해야 합니다.
1 | https://docs.aws.amazon.com/ko_kr/cli/latest/userguide/getting-started-install.html#getting-started-install-instructions |
해당 페이지로 접근 해서 지금 사용하고 있는 OS 따라 AWS CLI
프로그램 다운로드 및 설치 하도록 합니다.
1 | aws --version |
설치 확인 합니다.
1 | aws configure |
설치가 끝나면 aws configure
명령어를 입력 합니다. AWS 에 접근 하기 위해 AWS CLI
이용 합니다. 그러기 위해서는 권한 인증을 해야 하는데 사전에 발급받은 AWS access key
, AWS secret key
입력 합니다.
다음은 Kuberneties
에 통제 하기 위해 kubectl
셋팅을 해야 합니다. kubectl
은 Kubernetes 클러스터를 제어하기 위한 커맨드 라인 인터페이스(CLI)
도구 입니다. kubectl
를 이용해서 개발자는 클러스터에 있는 리소스를 생성, 조회, 업데이트 및 삭제 등 할 수 있게 됩니다.
1 | ## 맥 OS 사용자 |
kube config 설정 하기
1 | aws eks update-kubeconfig --region ap-northeast-2 --name ${AWS EKS Cluster 명} |
해당 명령어를 이용해서 kube config 를 설정 하도록 합니다. AWS CLI
일부로 AWS EKS Cluster
와 상호 작용 하기 위해서 kubectl
구성 파일(kubeconfig
)을 자동으로 생성하거나 업데이트 합니다. 해당 명령어를 사용하면 수동으로 구성 파일을 생성하고 관리할 필요 없이, 쉽게 AWS EKS Cluster
와 연결을 설정 할 수 있게 됩니다.
1 | kubectl get nodes |
지금 현재 kubernetes
에서 설치된 Worker Node
2대를 확인 할 수 있습니다.
Kubernetes NameSpace 생성하기
1 | kubectl create namespace dev |
dev
이라는 namespace 를 생성 하도록 합니다.
AWS Route53 설정 및 LB로 라우팅 대상 설정 하기
AWS Route53
서비스에 접속해서 호스팅 영역
-> 호스팅 영역 생성
버튼을 클릭 합니다.
미리 구입한 도메인을 도메임 이름
영역에 입력 합니다. 그런 다음 호스팅 영역 생성
버튼을 클릭 합니다.
호스팅 영역
메뉴에 클릭 하면 방금 생성한 호스팅 영역 레코드
영역을 확인 해봅니다. (이 부분은 CI/CD 실습 Part 에서 다시 설명 하도록 하겠습니다.)
도메인 구입하기
가비아
홈페이지에 접속해서 원하시는 도메인을 구입 합니다.
구입한 도메인 관리
페이지로 접속 합니다.
이전에 AWS Route53
에서 호스팅 영역
생성한 생성한 레코드
영역을 입력 합니다. (맨 마지막에 . 은 제거 하고 입력 하도록 합니다.)
Docker Image 생성 및 업로드 하는 방법
AWS ECR Repository 생성 하기
AWS ECR
서비스로 접근 해서 프라이빗 레포지토리
생성 하도록 합니다.
1 | cd ${생성한 프로젝트 디렉토리} |
그 다음은 CMD 창을 열어서 해당 프로젝트 디렉토리에 이동 하도록 합니다.
1 | # 로컬에서 ecr 로그인 |
Local PC 에서 AWS ECR
로그인을 하도록 합니다.
로컬에서 도커 이미지 빌드 및 push
1 | docker build -t ${AWS ECR 생성한 레포지토리명}:latest . |
해당 프로젝트를 docker image 파일을 만드는 명령어 입니다.
1 | # 필요프로그램 설치 |
해당 프로젝트에는 Dockerfile
이 존재합니다. 미리 준비된 Dockerfile
이용해서 docker image 를 생성 하게 됩니다.
1 | docker push ${AWS ECR 생성한 레포지토리명}:latest |
생성한 docker image 를 AWS ECR
해당 레포지토리에 push 하도록 합니다. 그런 다음 정상적으로 docker image 를 생성 했는지 AWS ECR 서비스에 접속해서 확인 하도록 합니다.
지금은 이렇게 하나하나 docker 명령어를 이용해서 AWS ECR Repository
에 docker image 를 등록 했지만 github Action
을 이용해서 자동화 할 예정 입니다.
kubernetes Deployment 및 Ingress Apply 하기
Deployment Apply 하기
1 | apiVersion: apps/v1 |
앞써 Deployment
학습 관련해서 아직 설명하지 않는 부분이 있습니다.
1 | spec: |
앞써 설명 했었지만 Deployment (depl_svc.yml 파일)
에서 내용은 수정 한 것은 없지만 실전에서는 배포하고자 하는 소스코드 수정이 빈번하게 발생 할 것 입니다. 나중에 설명 하겠지만 배포시 GitHub Action
을 이용해서 Docker Image 를 생성하고 생성한 Image 를 AWS ECR Repository 에 등록 하고자 합니다.
다시 말하자면 강제로 (Deployment depl_svc.yml 파일 내용 수정 안해도) 새로운 ReplicaSet
및 Pod
를 생성 하고자 하면 rollout restart
명령어를 사용 해야 합니다.
revisionHistoryLimit
는 새로운 ReplicaSet
및 Pod
을 몇 개까지 만들 것인가를 설정 한 것 입니다. 해당 설정을 하지 않으면 지속적으로 배포 할때 마다 계속 무한대로 생성하기 때문에 제한을 두어서 관리하기 쉽게 하는 것 입니다.
spec.template.spec.containers.ports.-containerPort
: 해당 포트 번호는 배포 하고자 하는 프로젝트의 배포 할때 설정한 포트 번호하고 동일 해야 합니다.
1 | resources: |
Pod
는 논리적인 자원 이기 때문에 AWS EC2
자원 안에서 생성 하게 됩니다. AWS EC2
물리적인 자원 내에서 안에 실행 하고자 하는 Pod
가 어느정도 자원을 점유 할 것인지 설정 하는 것 입니다. 즉 해당 컨테이너가 사용 할 수 있는 최소치 와 최대치를 설정 하는 것 입니다. 참고로 이 설정을 안하면 AWS EC2
물리적인 자원을 모두 소유 하기 때문에 다른 Pod
를 생성시 균등하게 배분 할 수 없어서 해당 설정은 필요 합니다.
1 | env: |
이전에 kubectl create secret generic my-app-secrets
명령어를 통해서 my-app-secrets
이라는 secret 설정 한 데이터 DB_HOST
하고 DB_PW
Key 값을 가져오겠다는 의미 입니다.
1 | # 컨테이너 상태 확인을 통해 롤링업데이트 최적화 |
readinessProbe
경우는 앞써 설명 한 롤링 업데이트
통해 배포 한다고 말씀드렸습니다. 배포 진행시 새로운 Pod
가 생성 되면 기존 Pod
를 삭제 하는데요. 하지만 새로운 Pod
를 진행 하자 마자 기존 Pod
를 삭제하는 것은 위험한 행동 입니다.
예를들어 Spring Boot
를 서버를 띄우지만 초기화 하는 과정에서 아직 준비 중인데 기존 Pod
를 삭제하면 정상적인 Graceful Shutdown
진행 되지 않습니다. 이를 해결하기 위해서는 Spring Boot
프로젝트 내에 새로운 Pod
생성한 프로세스에서 /health
API 통해서 정상적으로 응답이 오면 기존 Pod
를 삭제 하겠다는 설정 입니다.
1 | cd ${프로젝트 디렉토리 이동} |
이제 Deployment
를 Apply 해봅시다. 미리 만들어진 depl_svc.yml
파일 이용해서 Deployment
를 Apply 합니다.
Ingress Apply 하기
앞써 Ingress
설명 관련해서
1 | kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.1/deploy/static/provider/aws/deploy.yaml |
Ingress Controller
설치를 미래 해야 합니다. 이때 동시에 AWS LB
도 등록 하게 됩니다. AWS 에 가서 Route53
하고 등록된 LB
하고 매핑 작업이 필요 합니다.
AWS Route53
접속해서 특정 Prefix 도메인을 생성된 LB 로 매핑 작업을 하도록 합니다.
1 | apiVersion: networking.k8s.io/v1 |
1 | spec: |
생성한 도메인을 등록 하도록 합니다.
1 | http: |
모든 요청을 Deployment
에서 설정한 project-backend-service
로 보내겠다는 의미 입니다.
1 | spec: |
이 부분은 SSL 인증 관련해서 설명 할때 다시 설명 하도록 하겠습니다.
1 | cd ${프로젝트 디렉토리 이동} |
Ingress
를 Apply 하는 명령어 입니다. 진행 하도록 합니다.
1 | kubectl rollout restart deployment project-backend -n dev |
이제 rollout restart
명령어를 통해서 정상적으로 롤링 업데이트가 진행 되는지 체크 해봅니다.
HTTPS 통신 인증서 작업
사용자가 로그인 하는 과정에서 아이디 및 패스워드를 입력해서 HTTP 요청을 하게 되면 중간에 요청 데이터를 가로채서 패스워드를 노출 되는 이슈가 발생됩니다. HTTPS
는 ISO Layer 7 에서 요청 데이터를 암호화 해서 이를 해당 서버까지 요청 데이터를 도착 한 후 복호화 해서 처리 하도록 해줍니다. 이를 가능 하기 위해서는 사용자가 로그인 하기전 브라우저 통해 서버로 부터 특정 암호화 키값을 전달 받게 됩니다. 그럼 특정 브라우저는 요청 할때 마다 데이터를 암호화 해서 서버로 전달하게 되고 이를 서버가 미리 준비된 복호화 키로 복호화 해서 처리 하게 됩니다. 이러한 흐름을 HTTPS 통신
이라고 합니다.
즉 서버로 부터 암호화 키값을 전달 받는데 이것을 SSL(TSL) 인증서
라고 합니다. HTTPS 통신이 가능하게 하기 위해서 우선 앞서 설명한 것 처럼 특정 서버가 클라이언트에게 인증서 (암호화 할 수 있는 공개키) 를 전달 하는데 이 인증서는 인증된 기관 CA
에서 발급 받게 됩니다.
우선 인증된 기관 CA
를 발급 받는 과정을 실습 하도록 하겠습니다.
인증서 발급
1 | ## cert-manager를 위한 namespace 생성 |
우선 cert-manager
이라는 namespace 를 생성 하도록 합니다.
- 우리 서버에서 공개키와 비밀키를 생성
- 공개키와 서버 정보로 CSR(인증서서명요청서)를 생성
- CA(인증기관)에 CSR을 제출한 후에, CA에서 도메인 소유 여부를 검증한 후에 디지털 서명을 하여 우리 서버로 인증서를 발급
1 | ## cert-manager CRDs 설치 |
cert-manager
가 제대로 작동하기 위한 기반 구조 구성 하게 됩니다. 자세히 말하자면 어떤 인증서를 발급 받기 위한 어떤 CA
선택 할 것인가 그리고 선택하고 해당 CA 에게 미리 공개키 및 비밀키를 생성 한 것 중 공개키 하고 사용하고자 하는 도메인 정보 등 CA 에게 전송 하게 됩니다.
그럼 CA 는 이를 확인 하기 위해 요청 한 도메인이 실제로 존재하는지 검증 하게 되는데 정상적으로 검증 되면 최종적으로 인증서
를 발급 받게 됩니다.
이러한 과정은 하나 하나씩 작업을 할 필요 없고 cert-manager CRDs
설치 통해 모든 일련의 과정을 해결 할 수 있습니다. 해당 명령어를 통해 자원을 설치 하도록 합니다.
1 | ## cert-manager 배포 |
실질적인 cert-manager
컨트롤러 자체(Pod, Deployment 등) 설치 하도록 합니다.
https.yml 내용 보기
1 | apiVersion: cert-manager.io/v1 |
1 | spec: |
어떤 CA 기관에서 인증서 발급 받을 것인지 설정 합니다. 여기서는 letsencrypt
이라는 기관에서 인증서를 발급 받습니다.
1 | spec: |
spec.acme.email
: 인증서 만료 또는 갱신 필요시 알람 email 을 설정 하도록 합니다.spec.acme.privateKeySecretRef.name
: 인증서를 발급받기 위해 ca와 통신시에 사용되는 Secret 이름 입니다.spec.acme.solvers.http01.ingress.class
: 도메인의 소유권을 확인하기 위해 cert-manager는 nginx기반의 ingress controller를 활용해 검증한다는 의미
1 | apiVersion: cert-manager.io/v1 |
spec.secretName
: cert-manager가 아래 secretName에서 지정한 이름으로 Secret을 생성 합니다. 중요한 것은 Ingress.yml
에서 spec.tls.- hosts.secretName
에서 설정한 값하고 동일 해야 합니다.spec.commonName
: 대표하는 도메인 이름 입니다.spec.dnsNames
: 추가적인 서브도메인을 추가하고 싶은경우에 여기에 나열 하도록 합니다. 예를들어 admin.syh8088.store
이라는 서브도메인도 추가 하고 싶으면 추가 하면 됩니다.
1 | ## 인증서 요청 명령어 |
https.yml
apply 하게 되면 cert-manager
가 이 두 자원의 정보를 보면서 CA 기관의 인증서를 요청하게 됩니다.
1 | kubectl get certificate -n dev |
certificate
조회 하도록 합니다. READY
에서 True
가 나오면 정상적으로 SSL 인증이 완료 되었다는 의미 입니다.
1 | kubectl get secret -A |
정상적으로 server-syh8088-com-tls
이라는 시크릿 자원이 생성 되는지도 확인 해봅니다.
이제부터 HTTPS
통신이 가능하게 됩니다.
Github Actions 을 이용해서 CI/CD 자동화 배포 하기
GitHub Actions
는 GitHub
에서 제공하는 직접 CI/CD
파이프라인을 자동화 할 수 있는 기능 입니다. GitHub Actions
경우는 Workflows
이라는 개념이 있습니다. Workflows
는 하나 이상의 Job
포함 하게 되는데 특정 브랜치에 Git Push
를 하게 된다면 Workflows
에서 정의된 Job
이 실행 하게 됩니다.
Workflows
정의 하는 방법은 .github/workflows
디렉토리에 YAML
형식의 파일로 저장 해야 합니다. 그럼 deploy_dev_project_with_k8s.yml
파일을 확인 해보도록 하겠습니다.
1 | name: deploy DEV backend |
1 | on: |
on.push.branches
: 특정 어떤 브랜치로 push
해야 Workflows
실행 한 것인지 설정 하는 구간 입니다.
1 | jobs: |
jobs.build-and-deploy.runs-on
: CI/CD
작업이 이루어지는 서버 환경 셋팅 부분 입니다. 지금 우리가 특정 프로젝트를 Bulid
를 진행하고 docker image
를 만든 다음에 AWS ECR Repository
에 등록 하는 작업이 필요합니다. 이러한 일련의 작업을 수행하기 위한 가상 서버 환경을 GitHub 에서 제공 해주는데 어떤 OS 로 셋팅 하겠는가 설정 하는 부분 입니다.
1 | jobs: |
GitHub
에서 제공하는 가상 서버에 actions/checkout@v2
명령어를 통해서 해당 프로젝트를 Git Clone
하겠다는 의미 입니다.
1 | jobs: |
azure/setup-kubectl@v3
명령어를 통해서 GitHub
에서 제공하는 가상 서버에 kubectl 설치 하겠다는 의미 입니다.
1 | jobs: |
aws-actions/configure-aws-credentials@v1
명령어를 수행 하게 되면 AWS CLI
설치 및 Configure
계정 셋팅 하겠다는 의미 입니다. 계정 셋팅시 GitHub
에서 제공하는 가상 서버에 해당 AWS 자원에 접근 하기 위한 ACCESS-KEY
및 SECRET
값을 가져와서 계정 셋팅을 하게 되는데요. 변수로 지정된 secrets 값은 나중에 설명 하겠지만 GitHub Secrets and variables
페이지에서 미리 셋팅 해야 합니다.
1 | jobs: |
aws eks update-kubeconfig
명령어를 이용해서 해당 AWS EKS kubernetes Cluster 이름
으로 접근 하겠다는 의미 입니다.
1 | jobs: |
docker image
만들고 image
를 AWS ECR Repository
에 등록하기 위해서는 AWS ECR
로그인 작업도 필요합니다.
1 | jobs: |
Dockerfile
파일을 이용해서 docker image
만들고 이것을 AWS ECR
지정된 Repository 에 push 하겠다는 의미 입니다.
1 | jobs: |
AWS ECR
에 등록된 docker image
에 당겨와서 docker image
기반으로 Replicaset 및 Pod
를 생성 하겠다는 의미 입니다.
github secret 에 중요 정보 추가 방법
GitHub 해당 프로젝트 접속 하셔서 Settings
페이지에 왼쪽 메뉴에서 Secrets and variables
-> Actions
접근 하도록 합니다.
New repository secret
버튼을 클릭 합니다.
Name 에 AWS_KEY
이라는 이름을 지정하고 Secret 값에는 AWS Access-Key 값을 입력하고 Add secret
버튼을 클릭 합니다.
Name 에 AWS_SECRET
이라는 이름을 지정하고 Secret 값에는 AWS Secret 값을 입력하고 Add secret
버튼을 클릭 합니다.
한번 특정 브랜치를 Git Push
를 하도록 합니다. 그럼 자동으로 Workflows
실행 하게 됩니다.
실제로 CI/CD 및 롤링 업데이트 진행 되는지 확인 해보기
1 | kubectl get pod -n ${네임스페이스명} |
Pod
조회를 하게된다면 Pod
설치가 얼마 안된 것을 확인 할 수 있습니다.
이번에 해당 스프링 부트 프로젝트 에서 HealthController
파일에서 health
API 응답을 ok3
로 변경 해서 다시 push 하도록 하겠습니다.
즉시 Pod
조회를 하게된다면 정상적으로 롤링업데이트
가 진행 되는 것을 확인 할 수 있습니다.
Github Workflows 페이지에 접속하면 정상적으로 성공 했다고 나옵니다.
지속적으로 Pod
를 조회 하게 된다면 새로운 Pod
가 생성 되기 전까지 기존 Pod
는 계속 살아 있고 새로운 Pod
가 최종 생성 되면 기존 Pod
는 삭제 되는 것을 확인 할 수 있습니다.
https//server.syh8088.store/health
API 호출하면 수정한 응답값 ok3
로 나타나는 것을 확인 할 수 있습니다.
Autoscaling - Pod 자동 확장 작업
Kubernetes
에서 Deployment
의 Autoscaling
설정 하기 위해서 Horizontal Pod Autoscaler (HPA)
이라는 자원을 사용 하게 됩니다. Horizontal Pod Autoscaler (HPA)
이란 CPU 사용량 등 사용자 정의 파라미터에 기반하여 파드의 수를 자동으로 조정 기능 입니다.
Autoscaling
동작 원리는 우선 메트릭 서버
는 HPA
에서 관리 되는 Pod
를 계속 모니터링 하게 됩니다. 모니터링 한 데이터를 HPA
에게 보고 하게 되는데요. 계속 주시하고 있다가 HPA
는 특정 서버가 최소 및 최대 임계치 설정을 관리 하고 있어서 모니터링 서버
로부터 받은 서버 자원 사용률 한계치가 넘어가게 된다면 Deployment
에게 Pod
를 더 늘리라고 명령을 내리게 됩니다. 그럼 Deployment
는 Pod
를 더 생성하게 됩니다.
적용하는 단계는 크게 3가지로 구분 할 수 있습니다.
- Deployment 설정
- 메트릭 서버 설치
- HPA 스크립트 생성 후 적용
하나하나씩 알아보도록 하겠습니다.
Autoscaling - Pod 자동 확장 작업 - Deployment 설정
1 | cd ${프로젝트 ROOT 디렉토리}\k8s\k8s-project |
depl_svc.yml 파일을 확인 및 수정 하기 위해 depl_svc.yml
파일을 열어봅시다.
1 |
|
해당 Pod
에 resource
사전 제한 설정 필요 합니다. 중요한 것은 Pod
가 생성 및 삭제 하는 과정에서 cpu 가 갑자기 튈수 있으므로 HPA
와 resource limit
의 Cpu 를 여유롭게 셋팅 해야 합니다.
Autoscaling - Pod 자동 확장 작업 - 메트릭 서버 설치
1 | ## 메트릭 서버 설치 |
메트릭 서버
의 역할은 HPA
가 Pod
의 리소스 사용량을 지속적으로 모니터링하고 이를 기반으로 자동 확장을 수행할 수 있도록 필요한 메트릭 데이터를 제공 합니다. 메트릭 서버
를 apply 하도록 합니다.
Autoscaling - Pod 자동 확장 작업 - HPA 스크립트 생성 후 적용
1 | ## hpa.yml 설치 |
HPA
를 apply 하도록 하겠습니다.
hpa.yml 파일
1 | apiVersion: autoscaling/v1 |
spec.scaleTargetRef.name
: project-backend
값으로 셋팅 하고 있는데 depl_svc.yml 파일에 spec.selector.matchLabels
이름하고 동일하게 매칭 해야 합니다.spec.minReplicas
: Pod
갯수를 최소 2대로 유지 하겠다는 의미 입니다. 참고로 depl_svc.yml
파일에서 spec.replicas
값이 서로 틀리면 hpa.yml
파일에서 설정한 값이 더 우선권이 높습니다.spec.maxReplicas
: Pod
갯수 최대 4대로 유지 하겠다는 의미 입니다.spec.targetCPUUtilizationPercentage
: cpu 사용률이 50% 까지 점유하면 Pod
를 증가 하도록 하겠다는 의미 입니다.
부하 테스트 통해 Pod Autoscaling 되는지 확인 해보기
첫번재 CMD
창을 실행해서
1 | kubectl get hpa project-backend-hpa -n dev -w |
현재 Pod
자원 조회 하도록 합니다.
1 | kubectl get pods -n dev |
두번재 CMD
창을 실행해서 설치된 Pod
조회 합니다.
1 | kubectl exec -it {Pod name} -n dev -- /bin/sh # pod 접속 |
2개 중 하나를 선택해서 해당 컨테이너로 exec
명령어를 이용해 접속 하도록 합니다.
1 | apk add --no-cache curl # curl 설치 |
서버부하를 위해서 미리 curl
설치를 하도록 합니다.
1 | while true; do curl -s http://project-backend-service/health; done |
실제로 while 문을 이용해서 /health
API 를 계속 호출 시켜 강제로 서버부하를 일으키도록 합니다.
첫번째 CMD
창에서 계속 모니터링 해보면 지속적으로 CPU 점유율이 높아지는 것을 확인 할 수 있습니다.
세번째 CMD
창을 띄어서 kubectl get pod -n ${namespace 명}
확인 해보면 Pod
가 계속 생성 되고 있는 것을 확인 할 수 있습니다.
두번째 CMD
창에서 서버부하를 멈추게 된다면 일정 시간 흐른 후 Pod 최소 갯수인 2개까지 줄어가는 것을 확인 할 수 있습니다.
Autoscaling - EC2 자동 확장 작업
Pod
통해 Autoscaling
만으로 물리적인 자원 한계치로 인해 더 이상 Pod
가 증설 할 수 없는 상황이 분명 있을 수 있습니다. 더 이상 증설 할 수 없는 Pod
는 Pending
상태로 변경이 되는데요.
이미지에 보시는 것 처럼 Pending
상태인 Pod
가 생성되고 Kubernetes Cluster Autoscaler
는 이것을 계속 모니터링 및 감지 하고 노드를 관리하고 있는 AWS Auto Scaling
그룹에 노드를 증설 시켜달라고 요청을 보내게 됩니다.
해당 AWS EKS Cluster 접속 하도록 합니다. 여기서 Auto Scaling 그룹
이라고 확인 할 수 있습니다. 실질적으로 노드를 관리 하는 역활을 담당 하고 있습니다.(EKS 가 아님) Auto Scaling 그룹
을 클릭 하도록 합니다.
여기서 최소 노드 갯수 및 최대 노드 갯수를 확인 할 수 있습니다.
Autoscaling EC2 자동 확장 - NodeGroup(ASG)에 태그 추가 작업 진행
지금까지 설명한 flow 를 진행하기 위해서는 우선 NodeGroup(ASG)
에 태그 추가 작업 진행 해야 합니다. 이 태그값의 의미는 ASG
에 대한 통제권을 Kubernetes Cluster Autoscaler
한테 맡긴다는 의미입니다. 작업을 진행 하도록 하겠습니다.
우선 AWS EKS 해당 클러스터에 접근 해서 Auto Scaling 그룹
을 클릭해서 접속 하도록 합니다.
k8s.io/cluster-autoscaler/eks_syh
k8s.io/cluster-autoscaler/enabled
해당 값을 확인 할 수 있는데요. k8s.io/cluster-autoscaler/eks_syh
키 값 value 값을 true
설정 해야 하고 k8s.io/cluster-autoscaler/enabled
키 값 value 값을 owned
로 설정 해야 합니다.
다시 말하자면 이 태그값을 하므로써 ASG
에 대한 통제권을 Kubernetes Cluster Autoscaler
한테 맡긴다는 의미이고, Kubernetes Cluster Autoscaler
가 EC2
를 증가 해달라고 요청이 오면 ASG
가 EC2
를 증가하게 되는 클러스터 오토스케일러의 통제를 받습니다.
Autoscaling EC2 자동 확장 - ID 제공업체 추가
다시 전체적인 흐름을 설명하자면 Pod
를 생성하는데 있어서 EC2
자원이 부족해 생성하고자 하는 Pod
가 Pending
상태가 되면 Kubernetes Cluster Autoscaler
가 ASG
에게 EC2
자원을 증설 해달라고 요청 하게 됩니다. 이렇게 진행하기 위해서는 Kubernetes Cluster Autoscaler
는 AWS EkS
전체 자원에 대한 모니터링 할 수 있는 권한을 가지고 있어야 합니다. 그리고 또 Kubernetes Cluster Autoscaler
가 ASG
에게 요청 할 수 있는 권한도 필요 합니다. 그리고 마지막으로 EC2
에 대한 권한도 필요 합니다.Kubernetes Cluster Autoscaler
가 필요한 권한 목록
AWS EkS
서비스 전체 자원에 대한 모니터링 할 수 있는 권한ASG
에게 요청 할 수 있는 권한EC2
권한 필요
이렇게 설정하기 위해서는 AWS IAM
에 들어가서 역할
즉 AWS 서비스 간에 접근 할 수 있는 정책
을 생성해서 부여 해야 합니다. 즉 Kubernetes Cluster Autoscaler
가 3가지 접근 할 수 있는 역할
을 생성 해야 합니다.
그런데 AWS 에서 역할
이라는 것은 AWS 서비스 (EX: EC2) 간에 권한 부여 하는 것 입니다. 하지만 Kubernetes Cluster Autoscaler
경우는 AWS EKS
안에 있는 Pod
이기 때문에 AWS 서비스 단위 라고 불리기는 어렵습니다. 이러한 부분을 해결 하기 위해서는 Kubernetes Cluster Autoscaler
이라는 Pod
단위를 신뢰 할 수 있는 엔티티
로 등록 시켜줘야 합니다.
EKS
상에서 실행되고 있는 수많은 요소들이 있을 건데 이 요소들이 AWS
상에서 독립적으로 나 신뢰할 수 있는 요소야 라고 등록이 되려면 그 보증을 EKS
가 해주게 됩니다. EKS
는 AWS 서비스 자원이기 때문에 ID 제공 업체로 추가 해주고 추가된 Id 값을 이용해서 Kubernetes Cluster Autoscaler
이라는 Pod
가 신뢰할 수 있는 엔티티
다 라고 등록을 해주는 작업을 진행 해야 합니다.
AWS EKS
서비스에 접근해서 OpenID Connect 공급자 URL
복사 하도록 합니다.
AWS IAM 서비스로 접근 해서 왼쪽 메뉴에 ID 제공 업체
버튼을 클릭 해서 공급자 추가
버튼을 클릭 하도록 합니다.
공급자 유형을 OpenID Connect
선택 합니다. 그리고 공급자 URL 를 복사 했던 OpenID Connect 공급자 URL
값을 붙여넣기 하도록 합니다. 여기서 대상은 sts.amazonaws.com
로 입력 하도록 합니다.
STS 경우는 AWS 에서 제공 해주는 보안 토큰 서비스
입니다. Kubernetes Cluster Autoscaler 같은
Pod는
STS`에 Role 사용 요청 할 때 사용 합니다.
Autoscaling EC2 자동 확장 - IAM 역할 생성
AWS IAM
서비스로 접근 해서 왼쪽 메뉴에 역할
버튼을 클릭하고 역할 생성
버튼을 클릭 하도록 합니다.
신뢰할 수 있는 엔티티 유형을 사용자 지정 신뢰 정책
로 선택 합니다. 그리고 사용자 지정 신뢰 정책
을 구성 해야 합니다.
1 | { |
<AWS_ACCOUNT_ID>
: AWS 계정 아이디값<YOUR_EKS_OIDC_PROVIDER>
: AWS EKS
서비스에 접근해서 OpenID Connect 공급자 URL
(Http 프로토콜 제외)
입력 하고 다음 버튼 클릭 합니다.
권한을 추가 해야 하는데요.
- AmazonEKSClusterPolicy
- AutoScalingFullAccess
- AmazonEC2FullAccess
이렇게 추가 해서 다음 버튼 클릭 하도록 합니다.
역할 이름을 지정 하고 최종 확인 버튼을 클릭 합니다.
부하테스트 통해 실제로 Node 가 자동 생성 되는지 확인 해보기
AWS EKS
서비스에 들어가서 노드 최대 갯수를 2 에서 3으로 수정 하도록 합니다.
실제로 cluster-autoscaler
역할을 하고 있는 autoscaler.yml
파일에 들어가서 수정 작업이 필요 합니다.
1 | apiVersion: v1 |
eks.amazonaws.com/role-arn
: 방금 생성한 cluster-autoscaler
역할 ARN 주소값
1 | containers: |
--cluster-name
: ${AWS EKS Cluster 이름}--node-group-auto-discovery=asg:tag
: k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/${AWS EKS Cluster 이름}
이렇게 수정해서 autoscaler.yml
apply 하도록 합니다.
1 | cd ${프로젝트 ROOT 디렉토리}\k8s\k8s-project |
hpa.yml
파일에 들어가서 maxReplicas
10개로 수정 및 targetCPUUtilizationPercentage
30 으로 수정하고 다시 apply 하도록 합니다.
1 | ## hpa.yml 수정 |
첫번재 CMD
창을 실행해서
1 | kubectl get hpa project-backend-hpa -n dev -w |
현재 Pod
자원 조회 하도록 합니다.
1 | kubectl get pods -n dev |
두번재 CMD
창을 실행해서 설치된 Pod
조회 합니다.
1 | kubectl exec -it {Pod name} -n dev -- /bin/sh # pod 접속 |
2개 중 하나를 선택해서 해당 컨테이너로 exec
명령어를 이용해 접속 하도록 합니다.
1 | apk add --no-cache curl # curl 설치 |
서버부하를 위해서 미리 curl
설치를 하도록 합니다.
1 | while true; do curl -s http://project-backend-service/health; done |
실제로 while 문을 이용해서 /health
API 를 계속 호출 시켜 강제로 서버부하를 일으키도록 합니다.
첫번째 CMD
창에서 계속 모니터링 해보면 지속적으로 CPU 점유율이 높아지는 것을 확인 할 수 있습니다.
노드 자원 한계로 인해 더 이상 Pod
가 생성 되지 않고 Pending
상태 인걸로 볼 수 있습니다.
1 | 'Pending' 된 pod describe 확인 해보기 |
Pending
된 pod
describe 확인 해보면 자원이 부족 하다는 에러 메시지를 확인 할 수 있습니다.
조금 기다려보면 Pending
된 Pod
가 Running
상태로 변환 되는 것을 확인 할수 있습니다.
실제로 AWS EKS 노드그룹
에서 확인 해보면 2개 였던 노드가 2개로 증설 되었다는 것을 확인 할 수 있습니다.
두번째 CMD
창에서 서버부하를 멈추게 된다면 일정 시간 흐른 후 다시 Pod
를 조회 하면 2개의 Pod
로 줄어든 것을 확인 할 수 있습니다.
AWS EKS 노드그룹
에서 확인 해보면 3개 였던 노드 갯수가 2개로 줄어들었습니다.
Cpu 점유율이 점점 줄어 들고 있는 것을 확인 할 수 있습니다.
Copyright 201- syh8088. 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.