Jenkins와 AWX를 이용한 CI/CD 파이프라인 구축
안녕하세요.
주식회사 스푼 라디오에서 데브옵스 엔지니어 역할을 맡고 있는 Jonthan(최준영)입니다.
스푼 라디오는 오디오 팀에서 음성 솔루션을 자체 기술로 개발하여 서버로 사용하고 있습니다.
글로벌 서비스를 지향하는 회사답게 우리는 AWS의 여러 리전에서 해당 음성 서버를 가동하고 있습니다.
이전까지는 각각의 리전에 서버를 수동으로 배포하였지만, 실수의 위험을 줄이고 시간을 절약하기 위해 자동화가 필요했습니다.
이번 글은 자동화 과정과 음성 서버 개발의 변경과정에서 탄생한 파이프라인을 소개하기 위해 작성하였습니다.
들어가기 전에
자동화라 함은, 사람의 개입을 최소화하고 멱등성을 유지하면서 output을 내는 것이라 생각합니다.
그 조건을 만족하기 위해 Terraform을 이용해 AWS 인프라 구축을 했고, 구축된 인프라 위에 어플리케이션을 지속 통합 / 지속 배포 하기 위해 Jenkins와 AWX를 사용했습니다.
지금 까지는?
서버의 증설을 위해서
- AWS의 기본 AMI에 우리 회사가 필요로 하는 기본 패키지 및 바이너리들을 설치하여 ec2 가동
- 오디오 팀에서 개발한 어플리케이션 설치
- AWS CF를 생성하고 ec2와 연동 및 도메인 등록
- 등록한 도메인과 API 서버의 연결
나열하고 보니 별거 아닌 것처럼 보이지만,
우리는 AWS의 6개 리전에 해당 서버들을 전개하고 있었고, 수많은 사용자들을 수용하기 위해 서버의 수 역시 4대 이상 유지하고 있었습니다. 게다가 이벤트를 위한 증설 및 테스트 환경 구축 등 작업해야 하는 양은 계속해서 늘어가고 있었습니다.
한 마디로 서버 생성이 매우 번거롭고 휴먼 에러로 실수하기 딱 좋은 작업 이었던 겁니다.
기대효과
위와 같은 문제를 타파하기 위해 젠킨스로 자동화된 파이프라인을 구축하기로 결정하였고 아래와 같은 변화를 기대했습니다.
- 배포자는 젠킨스 하나의 관리포인트만 알면 됩니다.
- 수동 배포는 시간이 오래 걸리지만 파이프라인은 20분 내로 배포 할 수 있게 됩니다.
- 젠킨스에서 AWX를 호출하여 파이프라인을 가동하는데, 소요되는 시간을 측정하고 줄일 수 있습니다(ec2 생성, Docker build & pull).
- 가이드에 따라 모든 사람이 배포 할 수 있습니다.
본론
기존의 수동 배포 방식
한 땀 한땀 AMI provisioning, 바이너리 설치, CF 생성 및 도메인 주소 연결을 하면 30분 정도 걸려서 한 대의 서버가 나옵니다. 필요한 만큼 해당 리전에 환경을 구성하면 아래와 같은 도식도가 나옵니다.
이 구성의 문제점은 아래에 자세히 나와 있지만 너무 많은 시간 소모와 트래픽의 비효율성 발생 이였습니다.
- 최소 4대로 구성된 서비스 지역부터 20대 까지, 트래픽에 따라 서버양이 달라지니 구성 시간도 다르고 길어졌습니다(2시간 이상!).
- BJ와 청취자의 endpoint가 제각각이고 지저분하고 복잡한 구조였습니다.
- 로드 밸런서의 부재로, API 서버가 음성서버를 R/R 방식으로 BJ에게 할당해주는데, 트래픽을 고려하지 않다보니, 인기있는 BJ의 방송이 한 서버에 몰려 과부하가 발생하기도 했습니다.
파이프라인의 필요성 대두
오디오 팀은 위와같은 문제를 인지하고 있었고 하나의 endpoint로 트래픽을 관리하도록 개발 방식을 바꿨습니다.
인프라 팀 역시 endpoint 안쪽의 여러 서버를 구성하는 자동화에 대해 고민하기 시작했고, AMI 생성 및 AXW 호출 등의 작업을 하는 젠킨스 파이프라인이 탄생했습니다.
기존 수동 배포 방식은 여러 리소스를 수동으로 사용해야 했던데 비해, 관리 포인트가 젠킨스 하나로 줄어 실수 할 일이 줄어들었습니다.
- Jenkins
파이프라인을 구축하는 방법은 Jenkinsfile에 groovy 언어로 작성하는 법을 사용하였습니다. 함수를 정의하여 중복을 최소화하고 그 함수에서 Python 스크립트를 실행하는 등 여러 방법을 이용하였습니다. 스푼 라디오는 인프라가 AWS에 구축되어 있어, Python boto 라이브러리를 주로 이용 하였습니다.
기존의 AWS에서 제공하는 AMI에 스푼 라디오가 필요로 하는 프로비저닝 작업을 진행하는 것으로 파이프라인이 시작됩니다. 해당 작업은 Packer라는 오픈소스를 이용하여 진행 되며 베이스 AMI를 만드는 것이기 때문에 한 번 실행하여 만든 AMI를 재사용 할 수 있다는 장점이 있었습니다(물론 프로비저닝이 변경되면 재빌드 필요).
또한, 소스코드의 특정한 태그 브랜치를 따라 Jenkins에서 도커 이미지 빌드 후, ECR에 올리는 과정이 실행되고, 이후에는 ansible을 통해 AMI와 도커 이미지를 이용한 서버 구축이 실행됩니다.
- AWX
Jenkins에서 파이프라인이 실행되면서 ansible이 실행됩니다. AWX는 ansible을 UI화 하여 보여주는 웹 브라우저 클라이언트입니다.
AWX에 상황에 맞는 ansible 템플릿을 등록해 주고 Jenkins에서 필요한 템플릿을 실행하며
- ec2 생성
- docker image 관리
- target group 등록
- 구 ec2 target group에서 제거
등의 작업을 진행합니다.
플레이북이 실행되기 위한 기본 파라미터들은 젠킨스에서 던져주고, 환경별로 고정값을 가진 값들은 Vault라는 오픈소스 키스토어에 저장하여 사용했습니다.
서버의 대수에 상관없이 프로비저닝 된 AMI를 이용하여 ec2를 가동하므로 도커 이미지 크기의 관리 및 ec2 생성시간이 중요 포인트로 바뀌었습니다. 이 파이프라인을 걸치면 아래와 같은 도식도가 나옵니다.
- 1대의 서버 배포를 위해 리소스 생성, 바이너리 설치, 어플리케이션 설치 등을 직접 진행하며 확인하는데 30분이 걸린 반면, 파이프라인에서는 5분이면 1대의 서버를 배포할 수 있습니다.
- BJ도 하나의 endpoint를 사용하고 청취자도 하나의 endpoint를 사용함으로써 방송을 이용하게 됐습니다.
- 로드 밸런서를 통해 BJ의 방송이 적절하게 분산됐습니다.
나가며
CI/CD가 통합되어 젠킨스에서 배포 할 경우
- 음성 서버의 배포시간을 120분에서 20분으로 단축
- BJ와 청취자의 endpoint를 하나로 관리
- endpoint내에 많은 서버를 파이프라인으로 자동 배포
- 사용하지 않는 구 서버는 람다를 통해 파기
등이 가능해졌습니다.
정리
- 파이프라인을 처음부터 끝까지 작성한 적은 처음이였으며, 팀원들 및 서버 개발자들과 계속해서 커뮤니케이션 하며 요구사항을 수정 및 반영해야 했습니다.
- 그 과정에서 저의 사고방식 변화, 새로운 기술의 도입 등 생산적인 경험을 할 수 있었습니다.
- 무엇보다, 파이프라인 구축 후 개발자들이 배포 할 때 편하게 진행하는 모습을 보니 마음이 편해졌습니다.
- 인프라 팀에서 더욱 다양한 업무를 새로운 방법으로 진행 할 생각에 즐겁고, 파이프라인 구축에 맞춰 컨테이너로 개발 환경을 전환한 오디오 팀에도 감사의 말씀 드립니다.
-끝-