정윤진 피보탈 프린시플 테크놀로지스트

▲ 정윤진 피보탈 프린시플 테크놀로지스트

[컴퓨터월드] 다운타임 없는 서비스 구축을 위해 중요한 부분을 차지하고 있는 도구가 바로 연속 개선(Continuous Integration, CI)과 연속 배포(Continuous Deploy 또는 Delivery, CD)다. 어떻게 번역하느냐에 따라 달라질 수 있지만 CI는 지속적 개선이나 통합으로, CD는 지속적 배포 또는 배달로 불리기도 한다. 보통은 CI/CD 로 묶어 약어로 사용한다.

대부분의 애플리케이션은 일정 단계에 다다를 경우 기능의 추가 또는 변경이 어려워진다. 데이터베이스의 스키마 변경 또는 도메인 참조 모델이 바뀌는 것처럼 손대기 어려운 부분이 원인일 수도 있지만, 대부분은 전체 코드에서 특정 부분의 변경이 미칠 영향에 대해 예측할 수 없기 때문이다.

따라서 애플리케이션의 새로운 코드를 테스트와 함께 커밋하고, 이 커밋을 단위로 매번 동일하도록 프로덕션으로 배포되기 전에 빌드하고, 테스트를 통해 무결성을 검증하고, 릴리즈를 위한 프로덕션 메인라인에 포함하는 등의 동작 전반을 CI라고 한다. 사전적으로는 ‘하루에 몇 번이라도 필요할 때 개발자들이 구현한 코드를 메인라인에 포함할 수 있도록 하는 방법’을 말하며, 익스트림 프로그래밍(eXtreme Programming, XP)에서 사용하는 방법 중 하나다. 각 단계에 따라 다양한 테스트 도구와 개발팀이 작성한 스크립트 등이 파이프라인이라 불리는 흐름을 지나며 프로덕션에 배포할 코드를 준비한다.

이렇게 준비된 코드를 언제든 원할 때 프로덕션에 릴리즈 하는 방법을 CD라고 부른다. XP에서는 개발된 기능의 빠른 피드백을 받기 위해 이 릴리즈를 매우 짧은 주기로 실행한다. CD를 구현하는 목표가 코드를 짧은 배포 주기로 시장에 보다 자주 선보이기 위해서라고 해도 과언이 아니다.

시장에는 현재 다양한 CI/CD 도구가 상용 및 오픈소스로 존재하며, 필요에 따라 다양한 선택이 가능하다. 아마 ‘젠킨스(Jenkins)’라는 이름을 한번쯤은 들어 보았으리라 생각하며, 깃허브(Github)를 통해 다양한 오픈소스에 기여하는 사람은 ‘트래비스CI(TravisCI)’에 익숙할 것이다.

▲ 컨커스(Concourse)

대부분의 CI/CD 도구는 동작 방식이 유사한데, 보통 코드 저장소에 새로운 코드가 업로드 되면 이를 트리거로 지정한 동작을 순차적으로 수행한다. 지정한 동작이란 업데이트된 새로운 커밋을 바탕으로 사용자가 원하는 테스트 스크립트 또는 바이너리를 실행하거나, 다른 서비스와 연동 테스트를 수행하는 것을 말한다. 경우에 따라서는 이슈 트래커와 같은 도구, 또는 웹훅을 통해 다른 수많은 도구와의 연동도 가능하다. 위의 그림은 피보탈에서 만들어 오픈소스 및 상용으로 공급하고 있는 도구 ‘컨커스(Concourse)’이며, 자세한 CI/CD 적용은 다음의 링크에 설명돼 있다. [링크]

코드 저장소에 커밋이 업로드 되면 해당 커밋을 CI/CD 도구가 가져다가 테스트를 수행한다. 각각의 녹색 상자는 ‘작업(job)’라 불리는 일련의 태스크(Task)들로 구성되어 있다. 개발자는 태스크를 통해 쉘 스크립트 또는 각종 테스트 도구들의 구동을 설정하고, 이런 태스크들이 모여 ‘작업’이 된다. 검정색의 코드 저장소에 신규 커밋이 발생하면 이를 감지하고 사용자가 설정한 작업이 동작하는 식이며 일련의 과정들은 컨테이너에서 동작한다.

위 파이프라인에서는 테스트 실행 결과에 문제가 없다면 ‘블루/그린(Blue/Green)’을 통해 클라우드 파운드리라 불리는 클라우드 환경에 배포한다. 링크에서의 배포 구성은 피보탈 웹 서비스(Pivotal Web Services)의 무료로 사용할 수 있는 클라우드 플랫폼에 배포를 수행한다.

▲ 라우팅을 사용한 블루/그린 배포

블루/그린 배포란 클라우드 서비스의 장점을 이용한 다운타임이 제로에 가깝도록 할 수 있는 배포 방식이다. 애플리케이션의 이전 버전을 블루로, 새로운 버전을 그린으로 취급한다. 언제든 새로운 리소스를 사용할 수 있는 클라우드의 장점을 사용해 새로운 버전인 그린을 새로운 환경에 배포한다. 즉 기존 버전의 애플리케이션과 새로운 버전의 애플리케이션이 함께 존재하는 방식이다.

이런 방법을 사용하면 매우 다양한 배포 방식을 선택할 수 있다. 첫 번째는 동일한 라우팅에 두개의 서로 다른 버전의 애플리케이션을 모두 추가하고 외부에서 유입되는 트래픽의 비율을 조절하는 형태다. 예를 들어 10개의 컨테이너가 필요하다면 1개는 새로운 버전의 애플리케이션이 동작하는 컨테이너로 라우팅을 추가한다.

이때 라운드 로빈(Round-Robin) 방식의 로드 밸런싱이 적용되어 있다면 9:1의 비율로 트래픽이 분산된다. 배포를 담당하는 팀은 새로운 컨테이너에서 발생하는 로그를 확인하고, 시스템의 동작 상태를 체크해 문제가 없는 경우 점진적으로 비율을 조절해 나간다. 8:2에서 7:3으로, 다시 6:4로 변경하다가 결국 1:9를 지나 새로운 버전의 애플리케이션으로만 100%의 트래픽을 모두 보내는 방식이다.

또는 새로운 버전의 애플리케이션을 그린으로 10개의 컨테이너에 모두 배포하고, 블루로 지정된 라우팅을 순식간에 모두 그린으로 할당되도록 구성할 수도 있다. 이때 새롭게 배포된 애플리케이션의 정상 동작이 확인될 때까지 기존의 블루 애플리케이션이 동작하는 10개의 컨테이너를 유지하다가, 문제가 발생하면 종전의 서비스로 다시 라우팅만 바꿔서 롤백할 수 있다. 만약 문제가 없다면 종전의 블루 애플리케이션이 동작하는 모든 컨테이너를 종료하면 된다.

여기에 조금 더 신중을 기하는 방식은 바로 ‘카나리(Canary) 업데이트'다. 카나리 업데이트란 새로운 버전의 애플리케이션을 배포해 보고 문제가 없다고 판단된 경우에 배포를 확장하는 방식이다.

▲ 넷플릭스 OSS, ‘카옌타’

넷플릭스의 경우 카나리 배포를 자동화된 프로세스로 처리한다. 넷플릭스가 2018년 4월 발표한 ‘카옌타’는 구글과 협업으로 만들어진 자동화된 카나리 배포 도구다. 자세한 내용을 원한다면 다음의 넷플릭스 테크 블로그의 링크를 참조하길 바란다. [링크]

‘카옌타’가 정교하게 동작하려면 애플리케이션이 동작하는 전체 플랫폼에서 텔레메트리라고 불리는 애플리케이션의 실시간 동작 상태에 대한 정교한 모니터링과 CD 배포 도구가 필요하다. 텔레메트리란 시스템의 상태에 대한 정보를 실시간 또는 실시간에 가깝게 원격에 전달하고 수신하는 체계를 말한다.

이런 정보에 포함된 내용은 애플리케이션이 사용하는 프로세서, 메모리, 디스크와 같은 자원의 상태뿐만 아니라 애플리케이션의 응답, 지연시간, 스레드 등 신규로 배포된 애플리케이션이 ‘정상적으로 동작한다’고 판명할만한 모든 데이터다. 이런 정보를 애플리케이션이 동작하는 모든 노드에서 수집하고, 저장해서 분석할 수 있어야 한다.

넷플릭스는 이렇게 수집된 데이터를 분석해 ‘테스트 기준’과 비교하는 방법을 사용한다. 이 같은 방법을 카나리 배포에 적용하기 위해 ‘카옌타’는 CD 도구와 연동해 다음과 같이 동작한다.

1. 새로운 버전의 코드가 코드 저장소에 업로드 된다.
2. CI 도구는 업로드된 새로운 코드에 사전에 정의된 파이프라인대로 테스트를 수행한다.
3. 테스트가 정상적으로 종료되었다면 CD 도구는 기존에 동작하는 버전을 유지한 채 두 개의 버전, 즉 베이스라인(Baseline)과 카나리를 배포한다.
4. 새롭게 배포된 두개의 버전에 모두 트래픽을 흘린다. 대부분의 트래픽은 프로덕션으로 흐르며, 아주 일부의 트래픽만을 이 두 개의 버전에 흐르도록 한다.
5. 두 개 버전의 애플리케이션 동작 상태에 대한 정밀한 상태 정보를 취합한다.
6. 취합된 정보에서 베이스라인과 카나리 두개 애플리케이션에 대한 정보만을 추출해 애플리케이션 상태를 비교한다.
7. 베이스라인보다 카나리에 문제가 있다면 배포를 중지 또는 수동 배포를 선택하도록 하고, 문제가 없다면 그대로 업데이트를 진행한다.

▲ 넷플릭스 카옌타에서 애플리케이션의 버전간 상태 비교

위 그림의 왼쪽은 각 테스트 지표를 나타낸다. 수집된 텔레메트리 정보를 바탕으로 베이스라인과 카나리의 상태를 비교하고, 구 버전과 신 버전간의 차이, 그리고 수행한 비교 테스트 결과를 보여준다.

각각의 테스트 결과를 통해 해당 버전의 카나리 업데이트에는 점수가 매겨진다. 그리고 이 점수를 바탕으로 CD 시스템은 카나리 배포에 사용한 새로운 버전의 애플리케이션을 프로덕션으로 확장할 것인지 여부를 결정한다. 점수를 매기는 방법은 전체 테스트 중 몇 개가 통과(Pass)했는가가 기준이다. 예를 들어 10개 중 8개가 통과했다면 80%가 되는 식이다. 넷플릭스의 ‘카옌타’는 이 비교 알고리즘에 맨-위트니 U 테스트(Mann-Whitney U test)를 사용하며, 이는 샘플 A와 샘플 B에서 각각 랜덤으로 추출한 값을 비교하는 알고리즘이다.

▲ ‘카옌타’를 통한 ‘스피내커’ 카나리 배포 결과

넷플릭스에서는 배포(CD) 도구로 ‘스피내커(Spinnaker)’를 사용하는데, 위 그림에서는 ‘스피내커’와 ‘카옌타’의 연동을 통해 수행된 카나리 배포에 대한 자세한 정보를 제공한다. 실행된 카나리 배포가 점수를 어떻게 받았고 베이스라인과 카나리에 사용한 아마존 머신 이미지(AMI)의 ID가 무엇이었는지의 여부를 제공하며, 레포트를 통해 더 자세한 정보를 확인할 수도 있다.

CI/CD의 배포 구현에 대해 많이 언급하곤 하지만, 넷플릭스의 카옌타처럼 분석을 통해 자동화 하는 경우는 매우 드물다. 테스트와 배포는 신규 커밋이 발생할 때마다 동작한다. 물론 커밋별로 발생한 업데이트를 매번 릴리즈 할지, 아닐지의 결정은 파이프라인에서 구성할 수 있다.

테스트와 배포를 사람이 매번 수행하는 것은 서비스 업데이트의 빈도를 낮추고, 실수가 발생할 가능성을 높인다. 사람은 어려운, 위험한, 귀찮은, 반복적인 일을 꾸준히 하지 않는다. 즉 이런 자동화 체계가 없다면 자연스럽게 업데이트 빈도가 줄어들기 때문에, 넷플릭스는 이를 방지하고자 매번 발생하는 일을 자동화 처리하는 것이다.

이런 자동화를 구현하려면 다음과 같은 환경이 사전에 구현돼 있어야 한다.

- 트래픽의 정교한 라우팅 적용과 요청과 응답 데이터 수집이 가능한 API 게이트웨이
- 애플리케이션의 동작 상태를 모니터링하고 수집할 수 있는 텔레메트리 체계
- 각각의 애플리케이션이 동작하는 노드에서 수집된 정보를 모아서 분석할 수 있는 환경
- 애플리케이션을 선택적으로 배포하고 API 게이트웨이의 라우팅을 변경할 수 있는 CD 도구

이런 도구는 A/B 테스트를 고도로 발전시킨 형태라고 볼 수 있다. A/B 테스트란 어떤 기능이나 디자인에 새로운 변경이 생겼을 때(즉 새로운 버전이 생겼을 때) 두 환경을 함께 서비스에 배포해서 사용자로 부터 일종의 선호도 조사를 통해 하나를 선택하는 테스트 체계를 말한다. 이 체계가 존재한다면 새로운 디자인이 적용된 버전의 애플리케이션을 함께 배포하고 고객의 클릭 스트림을 모아 더 선호하는 디자인으로 자연스럽게 배포할 수 있도록 구현할 수 있다.

넷플릭스의 카옌타를 사용해 보고 싶다면 다음의 구글과 넷플릭스 링크를 참조해 보자. [구글] [넷플릭스]

이 방법들이 보기에 너무 복잡하다면 앞서 살펴본 ‘컨커스’가 좋은 선택이 될 수 있다. ‘컨커스’는 피보탈의 다양한 CI/CD 도구 사용 경험을 바탕으로 직접 제작한 오픈소스 도구다.

‘컨커스’의 장점은 먼저 파이프라인 구성이 매우 쉽다는 점이다. ‘컨커스’는 기본적으로 리소스, 태스크, 그리고 작업(job)의 세가지 조합으로 CI/CD 를 구현한다. 간략히 설명하면, 리소스는 파이프라인의 작업에 사용할 오브젝트들, 이를테면 도커(docker) 이미지, 깃허브, S3 같은 것들이다. 태스크는 컨커스 내에서 구성할 수 있는 일의 가장 작은 단위이며, 입력과 출력이 있는 일종의 함수처럼 생각할 수 있다. 작업은 태스크와 리소스들을 연결해서 실제 파이프라인을 구성한다.

컨커스 내에서 이들은 YAML 파일을 통해 정의된다. 이렇게 정의된 내용을 바탕으로 커밋된 코드를 필요에 따라 다양한 파이프라인으로 만들어 낼 수 있다. 그리고 사용의 편의를 위해 도커 이미지 업로드나 신규 코드의 다운로드, 병렬처리, 머지 등 다양한 처리 방법이 키워드로 존재한다. 따라서 각각의 개발팀들은 자신의 서비스에 맞게 파이프라인을 디자인해서 테스트와 배포를 자동화 할 수 있으며 필요에 따라 웹훅을 통해 다양한 외부 도구들과 연동이 가능하다.

각 팀에서 사용하는 파이프라인과 각 태스크의 최종 상태, 그리고 각각의 테스트가 수행한 결과 등을 매우 직관적으로 확인할 수 있는 그래픽 인터페이스(GUI)를 제공한다. 누구라도 이 도구에 접근할 수 있는 권한이 있다면 굳이 코드나 스크립트를 살피지 않아도 전체 CI/CD 과정을 한눈에 확인할 수 있다. 다음의 링크에서 이를 확인할 수 있다. [링크]

매우 복잡하게 보이는 화면은 ‘컨커스’ 개발을 위한 CI/CD 파이프라인을 보여준다. 검정색은 리소스, 각각의 녹색 상자는 작업을 포함하고 있는 태스크를 나타낸다. ATC라고 되어 있는 녹색 사각형을 클릭해보자. 녹색은 마지막으로 업로드된 커밋이 정상적으로 테스트됐음을 의미한다. 즉 bash exit 코드가 0이라는 의미이며, 반대로 빨강색은 테스트가 실패했음을, 노랑색은 지금 테스트를 수행 중임을 의미한다.

상단의 숫자들은 각 커밋에 따라 해당 테스트가 수행된 횟수를 의미한다. 각각의 넘버링은 각각의 커밋이다. 클릭을 통해 어떤 테스트가 언제 수행됐는지, 그리고 그 로그가 어떻게 남았는지 확인할 수 있다.

▲ ‘컨커스’ CI/CD 파이프라인

위의 그림에서 가장 좌측 상단에 집 모양 좌측의 3개 가로선을 클릭해 보자. 그럼 ‘컨커스’를 개발하기 위한 팀이 각각 사용 중인 파이프라인들을 볼 수 있다.

아래의 그림은 좌측의 prs를 클릭하면 나오는 파이프라인이다. 비교적 간단한 모습을 볼 수 있는데, 현재 노랑색으로 막 테스트가 시작되었음을 알 수 있다. 마지막으로 커밋된 Go-concourse의 테스트는 실패했으며, 아마도 개발자가 테스트가 어디서 실패했는지를 확인하고 코드를 손보고 있을 것이다.

▲ 컨커스가 스노우 플레이크를 대처하는 방식

이 같은 파이프라인은 모든 개발팀에 필요하다. ‘컨커스’는 각각의 팀에서 파이프라인을 작성하고 적용할 수 있으며, 각각의 테스트가 컨테이너에서 수행 가능하도록 지원한다. 그림 좌측의 리스트는 각각의 기능을 담당해서 개발하는 팀들이 각자의 CI/CD 파이프라인을 사용하고 있음을 의미한다. 관리자는 전체 상태를 확인할 수 있으며, 이를 통해 ‘스노우 플레이크’라 불리는 각각 팀의 리소스 및 도구의 사용에 발생하는 파편화를 방지할 수 있다.

대단위의 팀에서 ‘컨커스’를 사용하기 위해 클러스터로 구성할 수도 있지만, 쉽게 시작할 수 있는 간단한 CI/CD 파이프라인을 원하는 경우라면 도커 이미지를 통해 시작해 볼 수 있다. 넷플릭스의 ‘스피내커’나 다른 기타 도구를 사용하는 것보다는 훨씬 수월할 것이다. 아래의 링크를 참조하도록 하자.
▲학습: https://concoursetutorial.com/
▲샘플 파이프라인 구성:https://github.com/pivotalservices/concourse-pipeline-samples
▲설치: https://concourse-ci.org/install.html
▲스프링 클라우드 파이프라인:https://cloud.spring.io/spring-cloud-pipelines/

물론 CI/CD 구현을 위해 위에 소개한 두 개의 도구만 사용할 수 있는 것은 아니다. 아래 링크는 정적 페이지 도구 ‘휴고(Hugo)’를 통한 블로깅 방법을 소개한 페이지다. 여기에서는 ‘트래비스CI’ 를 사용해 깃허브와 연동하는 방법을 설명한다. ‘휴고’는 마크다운을 사용해서 블로그 포스트를 작성할 수 있고, 이렇게 작성된 포스트는 빌드를 통해 정적 페이지로 만들어진다. [링크]

마크다운을 이용해 새로운 포스트를 작성해서 깃허브에 업로드 하면 ‘트래비스CI’가 이를 감지하고 ‘휴고’를 통해 빌드한 후 클라우드 파운드리를 통해 배포한다. 물론 깃허브에서는 무료 웹 페이지를 사용할 수 있는 환경도 제공하므로, 이를 응용한다면 깃허브에 웹 페이지 배포를 수행하도록 변경할 수도 있으며 추가 테스트를 삽입해 원하는 행동을 구현할 수도 있다.

최근 넷플릭스와 피보탈이 제공하는 다양한 서비스 관련 도구들을 보고 있으면 대단하다는 생각과 함께, 어떻게 그 수많은 팀들이 다양한 도구들을 전체 생태계 내에서 활발하게 사용하고 있는지에 대한 의문이 생긴다.

세상에는 수많은 도구가 있고, 이번 기고문에서 설명한 것 외에도 앞서 설명한 무중단 서비스를 위한 클라우드 애플리케이션간의 연결 구성이나 모니터링, 텔레메트리를 통한 시스템 구동 상태의 확인 등 다양한 도구들이 수많은 마이크로서비스 팀들에서 사용되고 있다는 점은 놀랍다.

엔지니어링에 있어서 폴리글럿(Polyglot)과 플랫폼은 사실 겹쳐지기 힘든 컨셉이다. 플랫폼은 표준화를 의미하고, 폴리글럿은 필요에 따라 다양한 도구를 선택할 수 있음을 의미하기 때문이다. 플랫폼에서 폴리글럿을 구현하는데 가장 필요한 것은 무엇일까, 이것이 바로 상기한 의문에 대한 해답이 아닐까 한다. 개인적으로 이에 대한 답은 ‘쉬운 사용 방법의 제공’이다. 도구가 아무리 좋아도 사용하기 어렵다면 넷플릭스 규모의 서비스에서 광범위하게 사용되기 어렵다는 생각이다.

우리는 모두 수많은 서비스를 개발하고 운영해 오면서 회사 내의, 팀 내의 전문가들이 굉장히 서로 다른 의견을 가지고 있는 경우를 많이 목격하곤 한다. 넷플릭스가 만약 실시간 시스템 상태 정보의 확인을 위해 A팀은 ELK를, B팀은 카프카를 이용한 스트림 체계를 S3와 함께 파이어호스(Firehose)로, C팀은 데이터웨어 하우징 도구를 사용했다면 어땠을까. 이는 마치 각각의 팀이 서로 다른 리눅스 배포판을 사용하고, 서로 다른 쉘을 표준으로 사용하는 것과 같다. 이런 경우에는 각 마이크로서비스간 연동이나 로그의 표준화, 텔레메트리 정보의 식별을 위한 데이터를 표준화하는데 상당한 비용이 발생할 것이며, 중복된 데이터 저장으로 인한 낭비와 각각의 체계 유지를 위해 상당한 비용이 발생할 것이다.

넷플릭스는 ‘아틀라스(Atlas)’ 뿐만 아니라 ‘서보(Servo)’나 ‘스펙테이터(Spectator)’와 같은 텔레메트리 정보 수집 도구를 라이브러리나 사이드카로 함께 각 마이크로서비스팀에 제공했다. 즉 ‘아틀라스’를 위한 클라이언트 도구를 모든 팀이 쉽게 사용할 수 있도록 제공해서 모든 마이크로서비스를 구현하는 팀들이 하나의 기능에 하나의 플랫폼으로 통합 될 수 있도록 유도한 것이다.

CI/CD 역시 마찬가지다. 우리는 배울 것이 너무나도 많은 환경에 노출되어 있으며, 세상에 있는 모든 도구를 배울 시간이 없다. 각 개인에게 배움의 중복은 필요한 것일지도 모르지만, 하나의 서비스를 운영하는 거대한 조직의 입장에서 모든 팀들이 서로 다른 도구를 사용하는 것은 상당한 비용의 낭비로 이어진다. 따라서 목적에 적합한 기능을 가진 도구의 손쉬운 사용성이야 말로 체계 구현의 핵심이다.

손쉬운 사용성을 지닌 도구를 플랫폼으로 구현하고, 이를 수많은 팀들이 재사용할 수 있는 체계를 확보할 때 회사의 서비스는 자연스럽게 마이크로서비스로 진화할 수 있을 것이다. 또한 CI/CD 플랫폼은 낮은 다운 타임과 높은 업데이트 빈도를 가지고자 하는 모든 사업 영역에서 선택이 아닌 필수다. 잦은 배포는 변화에 강한 생명력을, 언제나 동작하는 안전한 배포는 고객에게 높은 신뢰를 얻는 방법이기 때문이다.

저작권자 © 아이티데일리 무단전재 및 재배포 금지