스타트업에서 CI/CD와 배포 자동화가 필요한가?

제 생각을 먼저 적자면 “필요하다” 입니다.

물론 이렇게 생각 할 수도 있습니다.

회사에 개발자라고 해봤자 두명밖에 없는데 ..그냥 대충 형상관리하면서 대충 서버에 직접 배포하면되는거 아닌가?

얼핏보면 충분히 합리적입니다. 개발환경을 만드는 일은 굉장히 귀찮고 시간이 걸리는 일이며, 생각보다 많은 것들을 새로 배워야합니다. 눈을 살짝 돌리면 최대한 빨리 출시해서 시장을 선점하고 싶어하는 관리자가 보입니다. 그렇다면 개발환경 같은 사소한 문제는 “나중에 만들면되지”라는 생각으로 넘어가고 싶은 달콤한 유혹에 빠집니다.

하지만 곰곰히 생각해본다면 이는 분명히 문제가 있습니다.

1. 몸집이 커지면 움직이기 힘들다.

프로젝트가 어느정도 진행된 후에 CI/CD 환경을 구성한다고하면, 불어난 몸집만큼 움직이기 힘들 것입니다. 단순히 옮겨야 할 것이 많아져서 그럴 수도 있겠지만, 구성원에게 이미 익숙하게 자리잡은 환경과 프로세스를 바꾼다는건 즐겁지 않은 일입니다.

2. 프로젝트의 유연함이 떨어진다.

배포와 테스트는 정말 귀찮고 많은 신경을 요하는 작업입니다. 하나의 예를 들어보겠습니다.

ex) 새로운 빌드를 서비스 중단 없이 배포

  1. 새 인스턴스를 준비한다.
  2. 개발환경을 세팅한다.
  3. 새 빌드를 업로드한다.
  4. 정상작동하는 지 간단한 테스트를 진행한다.
  5. 트래픽을 새 인스턴스로 옮긴다.
  6. 모든 것이 잘 동작하길 기도한다.

한번 새로운 빌드를 배포할때마다 위와 같은 프로세스를 따라 진행하게 된다면, 귀찮고 피곤하며 휴먼 에러에 대한 부담감을 떠안게 되는 배포는 누구나 피하고 싶게 될 것입니다. 배포를 두려워 한다면 배포 주기가 길어지게 되며, 이는 유연한 상황 대처를 하는데 있어서 불리하게 작용합니다.

3. 이상적인 개발 문화의 정착을 위하여

개발자들이 그리는 스타트업의 모습은 무엇일까요? 아마 다음과 같은 모습이 아닐까 싶습니다.

이런 모습이 아닐까..

  1. 자유롭고 도전적인 회사 문화
  2. 새로운 기술들의 최전선
  3. 멋진 서비스(제품)를 만들겠다는 열정이 가득한 공간

개발자가 스타트업을 택한다면, 회사에게 기대하는건 물론 연봉과 복지같은 직접적인 보상도 있겠지만, 스타트업에서만 배우고 느낄 수 있는 것들이 있어서라고 생각합니다.

따라서 그러한 기대에 부응하려면 회사는 누가봐도 낡은.. 주먹구구식 방법으로 일을 진행하는 것보다는 몸집이 작기 때문에 택할 수 있는 세련된 방법을 사용하는, 개발자들이 개발에만 집중할 수 있는 환경을 갖춘 회사를 만들기 위해서도 분명 필요한 일입니다.


해결해야 할 첫번째 문제

위와 같은 이유를 근거로, 지난글인 Bizcowork Devlog를 시작하며에서 언급했던 해결해야할 문제 중 첫번째로 배포, 빌드의 자동화를 선택했습니다.

이야기에 앞서 하나 고백할 것이 있다면, 저는 부끄럽게도 자동화된 배포, 빌드 환경을 구축해본 적도, 사용해 본 적도 없습니다. 전 직장에서는 그저 로컬에서 동작시킨 코드들을 압축해서 서버에 FTP로 바로 업로드하여 배포하고 잘되길 기도했을 뿐이었기에, 관련 지식이 전무합니다. 그리하여 이 글을 따라 환경을 구성하는 경우 모든 책임은 본인에게 있으며 저와 Bizcowork은 이를 책임지지 않습니다.


고려해야 할 것

문제는 선택했으니, 어떤 방향으로 접근할지를 고민해봤습니다. 이제 막 개발에 들어간 플랫폼이니 유연하고 확장이 자유롭게 만들고 싶었고, 동시에 현재 회사의 규모에 맞게 비용을 최대한 절감하고 싶었습니다.

문제는 확장성과 비용 절감을 동시에 만족하기가 어려웠다는 점입니다. 배포와 확장을 용이하게 하기 위해 서비스를 최대한 나누고 싶었는데, 그렇다면 필연적으로 컨테이너가 늘어나게 되고, 이를 관리하기 위해서 쿠버네티스를 도입한다면 배보다 배꼽이 더 큰 상황이 되어버릴 겁니다. 아무리 확장성을 생각한다고 해도 매달 불필요한 지출이 생기는 것은 기분 좋은 일이 아닙니다.

쿠버네티스에서 눈을 돌려서 ECS로 눈을 돌려 최대한 작은 규모로 구성한다고 해도, 컨테이너 하나당 하나의 Fargate 서비스가 필요하다던가, 최소 m5zn.large의 EC2 인스턴스가 필요했습니다. 저는 이보다 짠 내 나는 구성을 원했습니다.


작고 소중한 CI/CD 구성

그리하여 생각해낸 기본적인 아이디어는 아주 작은 EC2 위에 서비스를 전부 몰아넣고 이를 Docker로 분리해두는 겁니다. 그렇다면 언제든 ECS로 다시 구성을 해야 할 때 비용이 적게 들 겁니다. 그리고 이를 하나의 Docker compose 설정으로 관리하고, 배포를 할 때는 각자의 서비스 컨테이너만 업데이트해 준다는 컨셉으로 구성했습니다.

graph TB A(Code) -->|Push| B[Github] B(Github) -->|Build| C[TravisCI] C(TravisCI) -->|Build Failed| B[Github] C(TravisCI) -->|Save Buildfile| D[AWS S3] C(TravisCI) -->|Request Deploy| E[AWS Codedeploy] D(AWS S3) -->|Give Buildfile| E[AWS CodeDeploy] E(AWS Codedeploy) -->|Get Buildfile| D[AWS S3] E(AWS Codedeploy) -->|Deploy| F[AWS EC2]

위와 같은 Flow로 배포는 진행되며 간단히 설명하자면, Code를 푸시하면 Github에서 Travis CI로 빌드를 요청하고 빌드 성공시 빌드 파일을 스토리지인 S3에 업로드, 그 후에 AWS의 배포 서비스인 Codedeploy에 배포 요청을 합니다. Codedeploy에서는 빌드파일을 S3에서 가져와 EC2에 정해진 배포그룹에 맞춰 서비스를 배포합니다.


.
│   docker-compose.yml
└───deploy
│   └───hancup-backend
│   └───hancup-frontend
└───webserver

위와 같이 디렉토리를 구성하였고, 배포는 deploy 디렉토리 내에 서비스별로 나누어서 이루어지게됩니다.

다음은 docker-compose 설정입니다.

version: '3'

services:
  hancup-backend:
    build:
      context: ./deploy/hancup-backend
    volumes:
      - ./deploy/hancup-backend:/backend
    ports:
      - "8000:8000"
  hancup-frontend:
    build:
      context: ./deploy/hancup-frontend
    volumes:
      - ./deploy/hancup-frontend:/frontend
      - "/frontend/node_modules"
    ports:
      - "3000:3000"
  nginx:
    image: nginx:latest
    ports:
      - "80:8080"
    volumes:
      - ./webserver/nginx-proxy.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - hancup-backend
      - hancup-frontend

테스트 환경이므로 최대한 간단하게 구성을 하여, 배포시 단 한번의 docker-compose up 명령으로 서버를 세팅할 수 있게 해두었습니다.


그래서.. 무중단 배포는요?

위의 환경을 갖추었으면 무중단 배포를 적용하는 건 간단한 일입니다. ELB ( AWS Elastic Load Balancing )와 Auto Scaling 그룹을 세팅하고, Codedeploy에서 해당 그룹에 Blue/Green 배포를 진행하면 됩니다. 세팅 후에 배포를 하게 되면 Code Deploy에서 자동으로 현재 실행 중인 그룹을 복사한 복제본을 만들고 복제본에 새 빌드를 배포하기 시작합니다. 무사히 배포가 완료되었다면, ELB에서 트래픽을 배포된 Auto Scaling 그룹으로 보내고 기존 인스턴스를 종료합니다.

image-20201228123137629

Blue/Green으로 배포가 된 모습


마치며

이로서 명령어 하나로 빌드부터 배포까지 한번에 실행할 수 있는 환경을 갖추었습니다. 구성하는데 일주일을 홀라당 내다버렸지만 감수 할만한 일이었다고 느낄만큼 정말 마법같은 일입니다.

힘든시간의 잔재들..

혹시나 이글을 보고 따라 하는 용기 있는 분들이 있다면 따라하는 분들의 소중한 시간을 아껴드리고자, 튜토리얼도 작성할 생각입니다. 다만 시간을 너무 많이 써버린 관계로 당분간은 일정을 쫓아가는데 집중해야 할 거 같아서 언제가 될지는 모르겠습니다.

  • Version control 도입

  • Automated deploy system, Build System 구축

  • Monitering System 도입.

  • Testing enviorment, Staging enviorment 구축

  • Test driven devlopement 도입

  • Code review 도입

  • Bug tracking system 도입

이제 5개의 과제가 남았네요, 아직 멀었다는 생각뿐입니다. 직접 CI/CD 환경을 구축하면서 많은 걸 배우고 느낄 수 있었던 것 같습니다. (대부분은 제 게으름에 대한 자아성찰입니다)
모든 CI/CD 환경이 그렇 듯, 이것이 정답은 아닙니다. 그저 현재 회사 환경에 맞추어 구성을 하였고, 원래 계획 했었던 목표인 비용절감과 빌드, 배포 시스템 자동화를 이루었으니 첫번째 문제는 나쁘지 않게 풀어낸 것 같다고 생각합니다.