LINE 오픈챗 서버 원클릭 릴리스 자동화 시스템 개발기

LINE DEVELOPER DAY 2020에서 주승환 님이 발표하신 The journey to the automated deployment in OpenChat server 세션 내용을 옮긴 글입니다.

안녕하세요. 오픈챗 데브(OpenChat dev) 팀 주승환입니다. 저희 팀에서는 릴리스를 자동화하기 위해 그동안 많은 노력들을 해왔고 그 결과 클릭 한 번으로 전체 릴리스를 수행할 수 있게 되었습니다. 이번 세션에서는 그 과정에서 저희가 고민했던 부분들과 자동화를 통해 무엇을 얻었는지 공유하려고 합니다.

먼저 오픈챗 서버의 릴리스 방식을 소개하고 기존 프로세스의 문제점과 자동화를 통해 이루고자 했던 목표를 설명하겠습니다. 그다음 각각의 파트를 자동화한 방식과 그 결과를 설명하고 마지막으로 앞으로 남아 있는 과제를 공유하겠습니다.

 

오픈챗 서버 개발 팀의 릴리스 프로세스

먼저 오픈챗 서버 개발 팀의 릴리스 프로세스를 간단히 소개하겠습니다.

저희는 매주 전체 컴포넌트를 릴리스하고 있습니다. 일주일 간의 릴리스 전체를 관장하는 ‘릴리스 마스터’라는 역할을 두고 매주 한 명씩 돌아가며 맡습니다. 모든 팀원이 릴리스에 참여하고 각 사람은 보통 한두 개의 컴포넌트를 담당합니다. 전체 릴리스 시간은 약 1시간에서 1시간 반 정도 소요됩니다. 릴리스는 크게 네 단계로 나누어 진행합니다.

첫 번째 단계는 채팅방을 통해 관련 개발자들에게 릴리스 시작을 공유하는 단계입니다. 사소한 프로세스로 느껴질 수 있지만 만약 오픈챗 서버 릴리스 때문에 다른 스토리지나 서버에 장애가 발생했을 때 문제의 원인을 빠르게 파악할 수 있는 중요한 단서가 됩니다. 현재 저희는 LINE 오픈챗 방과 LINE 그룹방에 릴리스 시작을 공지하고 있습니다.

다음으로 각자 담당하는 컴포넌트 서버에 코드를 배포하고 재시작하는 단계가 있습니다. 현재 대부분의 LINE 서비스는 PMC라는 사내 툴을 이용해 배포하고 있는데요. PMC UI에서 배포 버튼을 클릭한 후 전체 서버에 배포가 완료될 때까지 기다려야 합니다. 배포가 완료되면 재기동 버튼을 눌러 해당 서버를 재기동합니다.

세 번째는 새로운 버전의 코드를 릴리스한 후 예상치 못한 문제가 있는지 모니터링하는 단계입니다. 문제 발생 후 필요하다면 롤백도 합니다. 모니터링 프로세스에 대해서는 뒤에 별도로 설명하겠습니다.

마지막으로 모니터링 결과에 이상이 없다면 릴리스가 완료됐다는 것을 다시 채팅방에 공유합니다. 이 단계까지 완료되면 전체 릴리스가 종료됩니다.

 

기존 릴리스 방식의 문제점

그럼 앞서 설명한 기존 릴리스 방식에 어떤 문제점이 있었는지 살펴보겠습니다. 먼저 릴리스를 진행할 때 실수가 발생할 수 있습니다. 물론 다들 신중하게 진행하겠지만 사람은 언제나 실수를 할 수 있습니다. 실제로 옵션을 잘못 선택해 전체 그룹의 서버가 동시에 내려가 큰 장애로 이어질 뻔한 적도 있었습니다. 두 번째로 릴리스에 전체 팀원이 참여하기 때문에 매주 소중한 개발 인력이 낭비되고 있었습니다. 서비스의 요구 사항은 계속 늘어나고 있었기 때문에 이런 낭비를 줄이는 것 역시 중요한 이슈였습니다. 마지막으로 릴리스할 때마다 반복적으로 수행하는 수동 작업들이 꽤 많다는 점이었습니다.

현재 기준으로 오픈챗 서버 팀에서 관리하고 있는 컴포넌트의 수는 총 7개입니다. 그중 두 개의 컴포넌트는 카나리(canary) 릴리스 대상이기 때문에 소수의 카나리 그룹을 먼저 배포하고 전체 서버를 배포하는 두 단계를 거칩니다. 편의상 각 작업을 수행하는 데 드는 비용이 동일하다고 가정하고, 세 파트 별로 수동 작업 수를 계산해 보았더니 전체 7개 컴포넌트 릴리스와 그중 2번의 카나리 릴리스를 위해 필요한 작업 수는 총 41번이었습니다.

 

릴리스 자동화 작업

위에서 언급한 문제점들을 바탕으로 릴리스 자동화의 목표를 다음과 같이 설정했습니다. 첫 번째는 릴리스 작업 중 발생할 수 있는 인간의 실수를 방지하는 것, 두 번째는 릴리스에 투입되는 인력을 줄이는 것, 마지막은 릴리스 작업 중 수행하는 수동 작업의 횟수를 줄이는 것이었습니다. 각 부분 별로 자동화한 방식을 설명하겠습니다.

 

릴리스 공유 자동화

먼저 릴리스 공유를 자동화한 부분부터 말씀드리겠습니다.

LINE 오픈챗 방의 경우는 저희 팀에서 만든 가상 계정과 오픈챗 서버 메시징 API를 함께 이용했습니다. LINE 그룹방의 경우는 LINE에서 제공하는 LINE Notify를 이용해 메시지 전송을 자동화했습니다. 아래는 저희가 만든 봇으로 LINE 오픈챗 방에 릴리스 시작을 공유하는 모습과 LINE Notify를 이용해 LINE 그룹방에 공유하는 모습입니다.

 

배포 자동화

다음은 배포 자동화입니다. PMC에서는 UI뿐 아니라 API도 제공하고 있기 때문에 이를 이용해 쉽게 자동화할 수 있었습니다. 

먼저 PMC의 배포 UI를 호출한 후 작업 완료 여부를 폴링(polling)해서 체크합니다. 이때 작업의 상태 정보 역시 PMC API를 통해 가져올 수 있습니다. 배포 작업이 성공했다면 재기동 API를 호출한 후 주기적으로 완료를 체크합니다. 앞서 봤던 공유와 배포 자동화는 큰 어려움 없이 쉽게 자동화할 수 있었습니다.

 

모니터링 자동화

모니터링은 위에서 자동화한 부분과 비교해 상대적으로 추상적이고 변수도 많기 때문에 자동화를 하기에 까다로운 부분입니다. 자동화를 하기 전에 우리가 평소에 어떻게 모니터링을 하는지를 먼저 생각해 보았습니다. 모니터링은 크게 두 가지로 나뉩니다. 첫 번째는 메모리와 디스크 GC(garbage collection)와 같은 시스템 레벨의 모니터링입니다. 시스템 레벨에서 발생한 문제에 대해선 현재 모든 팀원이 이메일로 알림을 받고 있습니다. 두 번째는 서비스 에러 로그에 대한 모니터링입니다. 이 부분은 IMON이라는 사내 모니터링 시스템에서 제공하는 Kibana를 통해 직접 로그를 확인하고 있습니다. IMON Kibana에서는 아래 그림에서처럼 시간대별 에러 로그 수와 어떤 에러 로그가 발생했는지를 알 수 있습니다.

저희는 수동으로 에러 로그를 확인하고 있었던 두 번째 부분을 자동화하기로 결정했습니다. 그렇다면 우리는 에러 로그를 모니터링하는 동안 언제 서비스에 문제가 발생했다고 생각할까요? 첫 번째는 릴리스 후에 새로운 에러가 나타났을 때 릴리스 때문에 문제가 발생했다고 생각할 수 있고, 두 번째는 기존에 발생했던 에러가 릴리스 후 급격히 늘어났을 때입니다. 이를 바탕으로 다음과 같이 자동화 방법을 정했습니다.

먼저 IMON ElasticSearch API를 통해 특정 기간의 에러 로그를 수집합니다. 수집한 에러 로그를 각 에러별로 집계한 후 그 결과를 릴리스 전과 후 시점으로 나누어 비교합니다. 예를 들어 Day1~Day3 기간 동안의 에러 로그를 수집한다고 가정하겠습니다.

각 날짜별로 발생한 로그를 IMON ElasticSearch 검색 API를 이용해 가져옵니다. 날짜별로 가져온 결과를 각 에러별로 집계하면 Day1부터 Day3까지의 전체 에러 카운트를 구할 수 있습니다. 이런 방식으로 얻은 두 개의 결과입니다.

배포 시각이 T라고 했을 때 왼쪽은 T로부터 이전 10일간의 결과이고 오른쪽은 T부터 모니터링하는 현재 시점까지의 결과라고 가정하겠습니다. 아래는 오른쪽 결과에서 새로운 에러가 발생한 케이스입니다. 릴리스 때문에 새로운 에러가 나타난 경우로 볼 수 있으므로 릴리스에 문제가 있다고 감지합니다.

아래는 왼쪽 결과의 에러보다 오른쪽 결과의 에러 수가 더 많은 케이스입니다. 배포 전 10일간의 에러 수보다 배포된 지 얼마 지나지 않은 시점에 에러 수가 더 많다는 것은 에러가 급격하게 증가하였다는 것을 의미합니다. 이때도 역시 릴리스에 문제가 있다고 감지합니다.

아래는 모니터링 자동화의 전체 흐름입니다.

배포 후에 새로운 에러 또는 증가한 기존 에러가 있는지 확인합니다. 문제가 있다면 바로 팀 채팅방에 발생한 에러를 공유합니다. 만약 없다면 5분 후에 한 번 더 체크합니다. 이 과정을 총 세 번 반복합니다. 세 번 검사하는 동안 문제가 없다면 모니터링을 종료합니다.

공유와 배포, 모니터링, 자동화 스크립트를 모두 Python으로 작성했고 이를 Jenkins 잡(job)으로 연동했습니다. Jenkins 잡을 빌드하면 앞서 설명한 릴리스 프로세스의 4단계가 모두 자동으로 실행됩니다.

 

릴리스 자동화 결과

이제 저희는 매주 릴리스를 할 때 릴리스 마스터가 Jenkins 잡의 빌드 버튼을 단 한 번만 클릭하면 됩니다.

이전 릴리스 방식은 실수가 발생할 가능성이 있었고 모든 팀원이 참여했으며 총 41번의 수동 작업이 필요했습니다.

자동화된 후에는 실수가 발생할 가능성이 사라졌고 릴리스에 필요한 인원은 릴리스 마스터 한 명으로 줄었으며 필요한 수동 작업 수도 단 한 번으로 줄었습니다.

 

향후 과제

이제 저희 팀원들은 릴리스가 주던 부담감에서 해방됐습니다. 하지만 여전히 많은 과제들이 남아 있습니다.

우선 모니터링을 IMON의 에러 로그에 의존하고 있기 때문에 다방면으로 문제를 감지할 수 있도록 모니터링을 강화해야 합니다. 또한 문제가 발생했을 때 롤백 자동화와 각 단계 파이프라이닝, 대화형 봇 도입 등도 앞으로의 과제로 남아 있습니다. 이번 글은 여기서 마치지만 서버 릴리스의 자동화는 앞으로도 계속될 것입니다. 아래에서 발표 영상도 확인하실 수 있습니다. 긴 글 읽어주셔서 감사합니다.