지난 인프라 아키텍처에 이어서 전적으로 AWS를 활용하여 추가로 개선해보았다.
앤서블을 활용하여 이미지 빌드 및 push, run까지 스크립트로 작업을 분산하고 관리하는 것으로 작업 부하를 줄이고 안정성을 향상시킬 수 있었다.
막상 배포된 형태는 단일 컨테이너 상에 서비스가 돌아가고 있었기때문에 아쉬움이 남아 확장성과 고가용성을 고려해 ECS를 사용해 배포해보기로 했다.
전체 구성은 위와 같다. 아래에서 차근히 설명을 덧 붙여보도록 하겠다.
나는 이번 프로젝트를 진행하면서 칸반보드라는 서비스 특성상 유연, 확장이라는 키워드가 중요하다고 생각했다. 이를 충족하기 위해서 관리가 어려운 자체 오케스트레이션 도구(Docker Swarm 등)를 사용하는 것보다 완전 관리형 서비스인 ECS를 이용하기로 결정했다. (그리고 한번 써보고 싶었음ㅎ)
오토스케일링, 로드밸런싱과 같은 중요한 기능을 붙이기도 쉬운데 관리까지 용이하다?! 안써볼 이유가 없다....
기존에 사용했던 Ansible과 Docker hub를 사용하지 않고 AWS의 ECR에 이미지를 push 하는 것으로 변경했다.
Jenkins에서 ECS Cluster에 배포하기 위해서는 AWS 명령어로 태스크를 생성하는 것이 필요했지만 나는 시행착오를 줄이기 위해 우선 AWS 콘솔에서 수동으로 배포하는 작업을 거쳤다.
앤서블을 사용하지 않은 이유를 설명하기 전에 앤서블의 핵심 역할을 먼저 이해해야 한다.
현재 나의 ansible-playbook.yml은 두가지로 나누어져있는데 이미지 빌드 작업, 컨테이너 실행 작업이다. 만일 내가 EC2 kanban-server에서 지속적으로 서비스를 하게 된다면 각 작업을 독립적으로 관리하고 재사용할 수 있는 측면에서 유용할 것이다.
또한 앤서블은 분산된 서버의 작업을 스크립트 파일을 사용하여 일괄적으로 처리할 수 있는 것이 큰 장점이라고 할 수 있는데 ECS를 사용한다면 서버 인프라 관리와 관련된 대부분의 작업들을 ECS에서 처리할 수 있기때문에 앤서블로 작업을 수행할 필요성이 줄어들어 사용하지 않는 것으로 판단했다.
그렇다면 이제 ECR에 업로드하기 위한 젠킨스 파이프라인을 작성해보도록 하자.
젠킨스 서버에 docker-compose가 설치되어있다고 가정한다.
Docker in Docker의 경우 젠킨스와 같은 CI/CD를 구축할때 빈번하게 발생한다고 하는데 다음에 자세히 다뤄보도록 하겠다.
pipeline {
agent any
environment {
GIT_REPO = "https://github.com/haeseung123/kanbanBoard.git"
TARGET_BRANCH = "develop"
AWS_CREDENTIAL_NAME = {젠킨스에 등록된 AWS CREDENTIAL NAME}
ECR_URI = "------------.dkr.ecr.ap-northeast-2.amazonaws.com"
IMAGE_NAME = 'kanban-server'
}
stages {
stage('git clone') {
steps {
git branch: "${TARGET_BRANCH}", changelog: false, poll: false, url: "${GIT_REPO}"
}
}
stage('build project') {
steps {
sh '''
docker compose --env-file .development.env build
docker tag ${IMAGE_NAME}:latest ${ECR_URI}/${IMAGE_NAME}:latest
'''
}
}
stage('push image') {
steps {
script {
docker.withRegistry("https://${ECR_URI}', 'ecr:ap-northeast-2:${AWS_CREDENTIAL_NAME}") {
docker.image("${ECR_URI}/${IMAGE_NAME}:latest").push()
}
}
}
}
}
}
절차는 간단하다 프로젝트 이미지를 빌드하고 ECR에 푸쉬하기.
여기서 도커 허브에 푸쉬하는 것이 아닌 AWS private 레지스트리에 업로드 하기 위함이라 명령어가 변경된다.
간단하게 보면 배포형태는 다음과 같다.
그림처럼 두개의 태스크를 묶어 ALB로 로드밸런싱을 해주었다.
이번 환경에서는 ALB의 DNS 이름으로 접근하여 결과를 확인할 수 있게끔 배포를 진행해보겠다.
ECS를 본격적으로 구축하기 전에 선행 작업이 필요하다.
새로운 VPC를 생성할 때 요로코롬 서브넷을 생성해주고 ~,~
ALB를 위한 타겟그룹을 만들 때에는 ECS Fargate를 대상으로 하기 때문에 IP 유형으로 선택하여 생성해준다.
내 API 서버의 포트는 3000번이지만 로드밸런싱을 80으로 접속해서 뿌려줄 것이기 때문에 상태 health check의 프로토콜도 80으로 설정해주도록 한다.
"EC2 -> 로드밸런서"로 이동하여 생성해주면 되는데 "Listeners and routing"에서 HTTP:80번으로 설정하여 ALB에서 80번으로 받아 kanban-server의 3000번으로 포트 포워딩되도록 할 것이다.
ECS는 컨테이너가 실행될 환경을 EC2와 Fargate로 설정할 수 있다.
Fargate를 선택한 이유에 대해 간단히 남겨보자면 EC2 기반의 경우 인스턴스에 대한 접근과 세부적인 세팅이 가능한만큼 직접 관리해야하는 불편함이 있다. 반면 Fargate의 경우 AWS 자체적으로 배포와 운영 등 자동으로 관리해주기 때문에 선택했다.
태스크의 시작 유형을 AWS Fargate로 설정해주고 그 밖에 태스크 크기나 IAM 역할 등 필요한 설정을 완성해주면 된다.
인프라 요구사항 작성이 끝났다면 컨테이너에 대한 설정을 해주면 되는데 아래처럼 ECR에 있는 칸반서버의 이미지 URI를 넣어주면 된다.
포트 매핑의 경우 칸반서버가 3000번으로 열리기때문에 컨테이너 포트를 다음과 같이 설정해주었다.
추가로 내 서버는 환경 변수가 있어서 개별적으로 태스크 정의 시에 꼭 놓치지말고 환경 변수를 추가해줘야한다.
서비스 생성을 통해 태스크를 어떤 식으로 배포할 것인지 작업을 생성하고 관리할 수 있다.
"시작 유형" : "Fargate"
"작업 개수" : "2"
.
.
.
앞서 컨테이너 인스턴스를 Fargate로 정했기때문에 시작 유형도 동일하게 지정해준다.
작업 개수의 경우 서비스 초기에 실행할 인스턴스(task)개수를 입력한다. 나는 로드밸런싱 동작을 확인하기 위해 2개가 실행되도록 했다.
추가로 미리 생성해뒀던 ALB까지 연결해주면 설정 끝!
이제 배포된 상태를 확인해보면 된다.
요로코롬 두개의 태스크가 잘 동작하는 것을 볼 수 있다.
또한 작업 그룹이 잘 배포되었는지 확인하려면 EC2의 target group으로 이동하면 알 수 있다.
참고로 여기서 상태가 왜 Unhealthy로 나오냐면????
API 서버에서 상태 검사 경로의 GET "/"을 작성하지 않았기때문에 404 not found로 확인된다.
ALB의 DNS 주소로 먼저 들어갔을때 보이는 화면
배포된 서버 각각의 공인 아이피로 들어갔을때 보이는 화면
보이는 것과 같이 ECS를 이용한 배포가 성공적으로 완료됐음을 알 수 있다.
이번 개선기를 통해 복잡한 구성의 다른 컨테이너 오케스트레이션 서비스를 도입하는 것보다 ECS를 이용해 손쉽게 배포하고 공부할 수 있어서 즐거웠다.