AI 서비스 도입 (1) - 배포 자동화, CI/CD 구축기

탄이·2024년 1월 2일
0
post-thumbnail

AI 서비스를 신규로 도입하려는데 AI 부서의 코드 배포를 자동화하고 지속적인 통합, 지속적인 배포가 가능하게 배포라인을 잡아달라는 요구를 받았다.

당시 요청 부서의 상황은

  • 깃헙 repository에서 브랜치 관리를 안 하고 있었음
    - 단일 브랜치로 작업했고 개발 테스트용 브랜치의 필요성을 절감하지 못했음
  • 배포 툴과 방식에 대해 익숙하지 않아 내가 알아보고 몇 가지 안을 준비해야하는 상황
  • Docker와 Elastic Beanstalk를 사용했으면 좋겠다는 정도의 요구사항이 있었음

현황과 부서의 요구사항에 맞춰 설계 작업에 들어갔다.

0. 사전 작업

브랜치 분리 요청

신규 서비스는 백엔드에서 AI 서비스 (ML 작업을 직접 하는 코드인지는 아직 확인이 안 됐다. 나에게 코드를 확인할 권한도 없기도 했고.)를 호출하고, 응답받는 과정이었고 이를 위한 서버도 띄워야 했다.
회사는 개발 테스트용 환경이 별도 구축돼 있었고, 모든 개발자들이 환경별 테스트를 했기 때문에 AI 서비스도 이를 따라야 테스트가 원활했다.
그래서 담당자에게 브랜치 분리의 필요성을 설명하고, 참고를 위해 백엔드에서 관리하는 방법을 설명했다.
실제 코드 관리는 해당 부서에서 해주시겠지만 브랜치 분리의 필요성에 공감해줬고, 환경별 마더브랜치를 알려줘서 깃헙쪽 작업은 정리가 됐다.

배포 방식 선택 요청

두 가지 안을 제안했다.
현재 백엔드, 프론트엔드에서 사용중인 Jenkins를 이용하는 방법과 Github action을 통한 방식을 각각 설명하며 원하는 것을 알려달라고 했다.

Jenkins 배포 방식

  • 사내 개발팀 모두 jenkins로 배포 중이기에 회사 내 통일성을 가져갈 수 있음
  • 배포 시점과 브랜치 머지 시점을 다르게 가져갈 수 있음 (장점이자 단점)
    - 환경별 마더 브랜치로 머지 후에도 추가 수정 작업 후 배포가 가능
    - 다만 배포를 위한 스텝이 하나 더 있는 것처럼 느낄 수 있음
    • Jenkins를 배포하려면 별도 ip로 접속 후, 로그인을 거쳐 배포하는 과정이 번거로울 수도 있기 때문

Github action 배포 방식

  • 환경별 마더 브랜치에 머지하면 그 즉시 배포가 되기 때문에 편리하게 여길 수 있음
  • 다만 현 담당자의 퇴사 후, 인수인계가 잘 되지 않으면 배포방식에 대해 유지보수성이 떨어질 수 있다는 우려도 있음

각 방식의 장단을 들은 AI 부서에서는 통일성을 최우선으로 생각해 Jenkins로 배포할 수 있게 작업을 요청했다.

1. 설계

각 단계별 인프라 서비스는 아래처럼 정해졌다.

  • 코드 관리 : github
  • Docker image build : Jenkins
  • Docker image push : AWS ECR
  • Docker.aws.json 저장 : AWS S3
  • Deploy : AWS Elastic Beanstalk

이에 기반한 배포 플로우는
1) Jenkins에서 빌드할 소스 코드를 Github Repo에서 가져온다
2) 이미지 빌드가 완료되면 AWS ECR에 push 한다
3) S3에 Docker관련 Json 파일을 업로드하고
4) Elastic Beanstalk에 배포를 한다
5) 그 과정에서 beanstalk은 S3에 업로드된 Docker.aws.json 파일을 다운로드 받고
6) 다운받은 파일을 기반으로 배포가 진행된다.

이렇게 설계까지 짜는 것은 어렵지 않았다.

2. 구축

작업은 AWS쪽과 Jenkins 스크립트 작성으로 분리해서 작업했다.
AWS는 콘솔에서 필요한 데이터만 입력해주면 끝나지만 Jenkins는 스크립트를 짜야했기 때문.

(1) AWS

1) Elastic Beanstalk

배포 한 번으로 관련 인프라(로드 밸런싱, 오토 스케일링, 어플리케이션 상태 모니터링 등)를 관리해주는 기능이다.

어플리케이션 하나에 두 환경을 구축할 수 있었기에 운영과 개발 테스트 환경, 두 가지를 구성했다.

이런 식으로 버전에 넘버링은 자동으로 채번되고, 생성일자도 모두 로그가 남아서 관리가 다소 용이하다.
캡쳐에는 없지만 소스도 모두 남아있어 배포된 버전의 json 파일도 다운로드가 가능했다.

2) ECR (Elastic Container Registry)

별도의 도커 repo를 구성하는 방법도 있었지만 최소한의 노력과 설정으로 빠르게 구성하기 위해, 그리고 요청 부서의 요구사항으로 ECR을 사용했다.
IAM으로 권한 관리하기도 편했다.

운영과 개발 테스트 환경용은 분리했다.


역시 최신 이미지는 자동으로 표기해주고, 푸시 로그도 모두 남기 때문에 히스토리 관리가 편리했다.

3) 로드 밸런서

beanstalk에서 로드 밸런서까지 자동으로 만들어서 연결해주지만, 정책상 도메인 매핑이 필요해 관리 부서에 DNS NAME을 전달했다.
AWS 로드밸런서와 연결된 IP주소는 변경될 수 있어서 DNS Name을 이용해서 CNAME 레코드를 생성하라고 권장한다.
다행히 이 작업은 금방 끝났다.

(2) Jenkins

기존에 스크립트를 짜 본 적은 없었기 때문에 찾아가며 짜야했다.
주된 예시는 파이프라인이 많았다.
Freestyle project로 만들까 잠시 고민도 했지만, 파이프라인 형식이 전체 플로우를 알고 싶어하는 해당 부서의 요구사항에도 잘 맞다 생각했다.
또 처음 해 본 작업이라 실패나는 구간을 확인하기 편리하기 때문에 최종적으로 파이프라인 방식으로 설정했다.

과정은 총 3가지로 구성했다.
깃헙에서 코드 가져오기 -> 도커 이미지 빌드하기, 빌드한 이미지 ECR에 푸시하기 -> Elastic beanstalk에 배포하기

각 스텝별로 참고할만한 자료는 많았었기 때문에 차근차근 작성했고, 오탈자에 유의하며 작성을 완료했다.

3.문제 상황 발생

스크립트도 완료했고, AWS쪽 작업도 잘 돼 있는데 자꾸 젠킨스 instance에서 Docker image build 할 때 실패가 났다.
원인을 못 찾아서 한참을 헤맸다.

첫번째 의심 : 스크립트 오류

처음 스크립트를 짜보다 보니, 스크립트 내 오류가 있는 건 아닌가 싶었다.
ChatGPT에게도 물어보고, 구글 내 검색을 해보며 문법 오류를 다시 점검했으나 이상 없었다.

두 번째 의심 : 젠킨스 EC2의 권한 문제

AWS에 떠 있는 젠킨스 서버가 github에서 코드를 복사해오지 못하는 것 아닌가, 혹은 이미지 빌드 후 ECR에 push할 때 권한의 문제가 있는 것은 아닌가 의심했다.
하지만 AWS IAM에서 FullAccess 권한을 줬고, github에서도 정상적으로 복사해 오는 것을 젠킨스 서버 내에서 확인할 수 있었다.

세 번째 의심 : docker image 오타

스크립트와 다른 파일 내 오타가 있어서 이미지명 불일치가 실패 원인일까 의심돼 모든 파일과 스크립트를 다시 훑어보고, cmd+f 로 확인했으나 역시 이 때문도 아니었다.

결국 원인은...

정말 한참을 헤매다가 젠킨스 EC2 서버에 들어가서 다시 확인했더니 서버 내에 docker 설치가 안 돼 있었다. 그러니 docker 관련 명령어가 안 먹혔던 것이다.
해당 인스턴스 내 docker가 설치 돼 있다고 착각했던 이유는, 과거 devOps의 흔적인 듯 하나 빈 docker 디렉토리가 있었기 때문이었다.

docker --version

이라도 한번만 쳐봤으면 빨리 알았을텐데 짐작만으로 작업했던 것이 느린 이슈 해결의 원인이었던 것이다.

4.작업 종료

중간에 docker 설치 체크가 안 되면서 아쉽게 시간을 허비했지만, 최종 예정 일정보다 3일 일찍 구축을 완료했다.
이후 배포부터 서비스 호출까지 모두 이슈없이 됐고, 운영 환경 배포일에도 정상 작동되는 것 확인했다.
현재까지 서버 이슈 없이 정상 작동 잘 되는 중이다.

5.마무리하며

이번 작업은 처음 해보는 작업이 많아, 검색과 약간의 공부가 필수적이었다.
그리고 짐작으로 다음 스텝을 진행한다는 것이 얼마나 돌아가는 길인지도 깨달았다.
어떠한 작업을 할 떄, 짐작과 추측만으로 작업하지 말고 꼭 확인하는 절차를 거칠 필요성을 체감한 프로젝트였다.

profile
백엔드 개발자의 로그

0개의 댓글