LY Corporation Tech Blog

LY Corporation과 LY Corporation Group(LINE Plus, LINE Taiwan and LINE Vietnam)의 기술과 개발 문화를 알립니다.

ChatOps를 통한 업무 자동화(feat. Slack Hubot)

들어가며

안녕하세요. LINE NEXT DevOps 팀에서 블록체인 플랫폼과 DOSI, GAME DOSI의 쿠버네티스 운영 및 인프라를 담당하고 있는 이동원입니다. 현재 LINE NEXT에서는 'NFTs for ALL'이라는 슬로건을 기반으로 DOSI Wallet과 DOSI Citizen, DOSI Store, GAME DOSI 등 다양한 서비스를 제공하고 있습니다. DevOps 팀에서는 이런 서비스가 24시간 365일 가용성을 유지하며 안정적으로 운영되도록 여러 가지 자동화 방안을 고민하고 있는데요. 이번 글에서는 Slack Hubot으로 일감 관리와 애플리케이션 배포, 미들웨어 설정 배포, 서비스 유지 보수 관리 등 여러 가지 작업을 ChatOps 기반으로 자동화한 경험을 소개해 보려고 합니다.

LINE NEXT DevOps 팀 소개

LINE NEXT DevOps 팀은 개발 팀과 협업해 소프트웨어를 원활하게 개발할 수 있도록 돕는 모든 일을 합니다. 서비스를 만드는 과정에서 반복적이고 비효율적인 부분을 찾아 자동화하고, 문제가 생길 수 있는 부분을 사전에 예측해서 예방할 수 있도록 공유합니다. 이를 통해 빠르게 제품을 출시할 수 있도록 개발 및 운영 사이클을 가속화하고 안정화합니다. 

DevOps 팀에서는 이를 지원하기 위해 필요한 시스템과 도구를 만들어 운용하고 있습니다. 각 개발 조직에서 만든 프로덕트를 빠르게 프로덕션에 출시할 수 있도록 CI(Continuous Integration) 도구를 제공 및 운영하고 있으며, 공급할 수 있도록 CD(Continuous Delivery) 플랫폼을 운용하고 서비스를 지원하고 있습니다.

모니터링 시스템을 구축해서 운용하는 것 역시 저희 팀의 대표적인 업무입니다. 작업 요청서 작성을 포함한 배포 프로세스를 설계하고 배포 후 모니터링을 통해서 변경 작업이 전체 시스템에 어떤 영향을 주는지 면밀히 검토하고 측정하며, 이상 발생 시 빠르게 롤백해 시스템의 항상성을 유지하는 역할을 수행합니다. 모니터링할 때에는 다양한 레이어에서 임계치를 산정해 알람을 받고 있으며, 서비스를 안정적으로 운영할 수 있도록 상시 감시하며 개선 활동을 진행하고 있습니다. 

다음은 DevOps에서 담당하는 모니터링 레이어입니다. 각 레이어별로 다방면으로 모니터링하고 있으며, 알람을 받으면 초도 분석을 수행하고 개발 팀에 신속하게 공유해서 사전에 문제를 방지할 수 있도록 조치합니다.

항목모니터링 화면
쿠버네티스 모니터링kubernetesmonitoringscreenshot
네트워크 모니터링networkmonitoringscreenshot
인프라와 애플리케이션 성능 모니터링infra and app perf monitoring screenshot
프런트엔드 접속 모니터링kubernetes monitoring screenshot

ChatOps 도입 배경

DevOps 팀에서는 MSA(microservice architecture)로 구성한 멀티 모듈 애플리케이션의 배포 관리를 담당하고 있습니다. 보통 일 단위로 다수의 배포 요청이 들어오며, 때로는 같은 시간대에 여러 팀에서 배포를 요청할 때도 있습니다.

저희는 이와 같은 배포 작업을 신속하고 안정적으로 수행하고 싶었고, 진행 상황을 모두에게 공유할 수 있으면 좋겠다고 생각했습니다. 또한 현재 Slack을 통해서 배포를 요청하고 있는 각 개발 팀에서도 현재 어떤 작업이 어떻게 진행되고 있는지 일감 현황을 한눈에 보고 싶다는 니즈가 있었는데요. 이를 해결하기 위해 ChatOps를 도입했습니다.

ChatOps란

ChatOps란 실시간 커뮤니케이션을 기반으로 서비스 장애 상황이 발생했을 때 문제를 빠르게 해결하기 위한 도구입니다. 봇(bot)을 활용해 대화에 빠르게 대응하며 상태를 확인하고 보고해 줍니다.

ChatOps를 이용하면 사람, 도구, 프로세스, 자동화가 연결됩니다. 개발자나 운영자는 더 이상 터미널에 접속하거나 도구에 직접 접근할 필요 없이 봇에게 명령하면 됩니다. 봇이 작업을 수행한 뒤 결과를 공유해 주며, 모든 유관 부서가 같은 채팅 앱에서 실시간으로 공유 받기 때문에 소통이 빨라지고 정보의 투명성이 올라갑니다. 

이와 같은 ChatOps를 구현할 수 있는 도구는 여러 가지가 있는데요. 그중 사내에서는 사용할 수 있는 도구로 Hubot이 있었습니다.

Hubot 소개

Hubot은 GitHub에서 사내용으로 제작하기 시작해 발전을 거듭한 뒤 현재는 오픈소스로 공개된 챗봇입니다. Node.js 기반이며, Slack과 쉽고 편리하게 연계할 수 있습니다. 또한 CoffeeScript나 JavaScript 등으로 스크립트를 작성해 강력한 기능을 추가할 수 있다는 강력한 장점(hubot-scripts)이 있고, 여러 가지 도구와 연계해 호출하거나 응답을 받고 채널에 알림을 전달하는 프로세스를 설계할 수 있습니다. 

저희는 사내에서 Hubot으로 Slack의 Workflow와 연계해 사내 버그 트래킹 시스템(Jira)에 일감을 자동으로 등록할 수 있다는 것을 알게 됐습니다. 또한 Hubot은 Jira뿐 아니라 다른 다양한 도구와도 연계할 수 있었는데요. 이를 이용하면 DevOps 팀에서 사용하는 여러 가지 도구를 연계하는 연계 지점을 만들어 작업을 자동화할 수 있겠다는 생각이 들어서 바로 Hubot 앱 사전 조사를 시작했고, 약 한 달 정도 조사한 뒤 실제 서비스에 적용했습니다.

그럼 어떻게 Slack Hubot을 설계하고 개발했는지 그 과정을 살펴보겠습니다.

Slack Hubot 설계

저희는 Hubot이 Slack에서 요청자의 의뢰를 받아 여러 가지 도구와 연계해 주는 인터페이스 역할을 수행하도록 설계했습니다. 설계하면서 어떤 목표를 세우고 어떻게 아키텍처를 구성했는지 살펴보겠습니다. 

설계 목표

저희 팀에서는 다양한 도구를 도입해 사용하고 있었습니다. 먼저 배포 같은 경우 쿠버네티스를 사용하면서 GitOps 기반의 ArgoCD를 사용하고 있었습니다. 따라서 ArgoCD의 Sync 기능으로 배포가 가능했으며 이를 Hubot이 호출할 수 있게 연계하면 배포가 가능할 것이라고 생각했습니다. NGINX 설정 배포 역시 Ansible이라는 도구를 활용해 스크립트(Ansible playbook)를 작성해 놓았기에 이를 Hubot이 호출하면 미들웨어도 제어할 수 있을 것이라고 생각했습니다. 그 외에도 다양한 운영 업무가 Jenkins 잡으로 구성돼 있었는데요. Hubot이 Jenkins API를 통해 잡을 실행하고 실행 결과를 채팅으로 공유해 준다면 보다 편리하게 작업을 진행할 수 있을 것이라고 생각했습니다.

또한 기존에는 도구를 사용할 때 각 도구별로 별도로 접속해야 했고 파라미터도 수동으로 설정해야 했습니다. 아무래도 실수가 발생하기 쉬운 구조였는데요. Hubot을 도입하면 작업 실행 자체가 모든 사람이 함께 참여하고 있는 채널에서 진행되기 때문에 자연스럽게 다수가 확인하게 되면서 작업 안정성도 높일 수 있을 것이라고 생각했습니다.

이처럼 Hubot을 도입해 여러 곳에서 빈번하게 들어오는 배포 요청을 보다 쉽고 편하게, 그러면서 더욱 안정적으로 처리하기 위해 세부적으로 다음과 같은 목표를 세웠습니다. 

  • 배포 요청을 Jira와 연계해 일감 관리
  • 배포 공지와 배포 알림을 채팅으로 전달
  • 서비스 안정 지표 자동화 모니터링
  • 언제, 어디서나 손쉽게 배포 및 롤백

Slack Hubot 아키텍처

위와 같은 목표를 달성하기 위해 Elasticsearch와 Jenkins, Jira, Verda(사내 클라우드) 등 여러 가지 도구와 연계해 명령을 수행하고 그 결과를 Slack으로 응답해 주는 구조로 Hubot을 설계했습니다. 아래 그림과 같이 아키텍처는 크게 세 가지 레이어로 나뉘어 있습니다

  • 요청 레이어: 사내 Slack에 접속해 Hubot을 실행할 권한이 있는 사용자가 요청 및 응답을 받는 영역
  • Slack - Hubot 레이어: Hubot 앱이 Slack으로 받은 응답을 분석해 타깃 도구를 호출하고 결과를 응답하는 영역
  • 인프라스트럭처 레이어: 팀 내에서 사용하는 다양한 도구들이 실제로 작업을 수행하는 영역

이와 같은 아키텍처를 구성하기 위해서 각 도구의 API를 조사해 호출 방식을 이해하는 과정을 거쳤습니다.

slack hubot architecture

Slack Hubot 개발

Slack Hubot 개발은 다음과 같은 단계로 진행했습니다. 

  1. Hubot 도커라이징(Dockerizing)
  2. Hubot CI/CD 파이프라인 구성
  3. Slack Hubot 동적 대화 설계
  4. Slack Hubot 기능 구현 1 - Slack Workflow와 이모지, Jira를 연계한 자동 일감 관리
  5. Slack Hubot 기능 구현 2 - 여러 도구와 연계해 배포 및 미들웨어 제어

각 단계를 자세히 살펴보겠습니다.

Hubot 도커라이징

먼저 Hubot을 도커라이징했습니다. 도커라이징이란 애플리케이션을 Docker 컨테이너에서 실행할 수 있도록 만드는 과정입니다.

Hubot은 Slack에서 쉽게 추가할 수 있습니다. Slack 앱 디렉터리에서 Hubot을 검색한 뒤 아래와 같이 Slack에 추가 버튼을 누르면 간단하게 추가됩니다.

slack add hubot screenshot

slack hubot token screenshot

Hubot은 Node.js 기반의 컨테이너를 기반으로 Slack 토큰을 주입받아 작동합니다. 아래 코드는 컨테이너라이징(containerizing)을 위한 Dockerfile 샘플입니다. Hubot에 Slack 토큰을 주입한 뒤 코드 마지막 줄처럼 Hubot 실행 명령어에 --adapter slack 옵션을 추가하면 Slack과 통신할 수 있습니다.

# Hubot needs node to run.
FROM node:16
ENV HUBOT_SLACK_TOKEN ""
ENV HUBOT_NAME "LINE NEXT HUBOT"
ENV HUBOT_OWNER "LINE NEXT DEVOPS"
ENV HUBOT_DESCRIPTION "LINE NEXT HUBOT"
EXPOSE ${EXPOSE}
 
# Create a user to run Hubot as.
RUN useradd hubot -m
COPY . /home/hubot
RUN chown -R hubot:hubot /home/hubot
 
USER hubot
WORKDIR /home/hubot
RUN npm install
 
# Set a default command to run Hubot!
CMD ./bin/hubot -n --adapter slack

Hubot CI/CD 파이프라인 구성

Dockerfile을 이용해 컨테이너로 만들 준비를 마친 뒤 내부에서 개발하며 협업하기 위해서 CI/CD 파이프라인을 구성했습니다. 파이프라인은 두 가지 방식(푸시나 태그 생성)으로 작동시킬 수 있도록 구성했으며, ArgoCD를 통해서 GitOps 기반으로 운영하고 있습니다. Hubot을 개발하는 브랜치에서 develop 브랜치에 푸시하거나 master 브랜치에 태그를 생성하면 이를 트리거로 Jenkins 파이프라인이 작동합니다. 

hubot ci/cd pipeline

  1. 두 가지 방식 중 하나로 CI/CD 트리거 작동
    • develop 브랜치: 커밋 해시(hash) 기반 이미지 생성
    • master 브랜치: 태그 기반 이미지 생성
  2. CI 파이프라인 실행
    • 빌드 시작 알림 → Git 체크아웃 → Harbor 로그인 → 이미지 빌드(도커라이징) → Harbor 푸시 → 빌드 종료 알림
  3. CD 실행
    • Helm 차트가 업데이트되면 ArgoCD 배포 작동

Slack Hubot 동적 대화 설계

Hubot을 이용해서 작업을 진행하기 위해서는 단발성으로 Hubot에게 문구를 전달하고 응답하는 형식이 아니라 지속적으로 대화를 이어나갈 수 있는 방법이 필요했습니다. 이를 위해 조사하면서 동적 대화가 가능한 hubot-conversation을 발견했고, 검토 후 적용하기로 결정했습니다.

Hubot은 특정 문구를 인지해서 응답하는 단순한 형태의 스크립트를 제공합니다. 이 스크립트를 이용해 지속적으로 사용자와 대화하기 위해 사용자가 입력하면 Hubot이 다음 선택지를 전달하고, 사용자가 선택하면 다시 Hubot이 응답하는 방식으로 대화가 이어지도록 설계했습니다. 간단한 예시 코드와 함께 살펴보겠습니다.

var Conversation = require("hubot-conversation");
module.exports = function(robot) {
    var switchBoard = new Conversation(robot);
 
    robot.respond(/clean the house/, function(msg) {
        var dialog = switchBoard.startDialog(msg);
 
        msg.reply("Sure, where should I start? Kitchen or Bathroom");
        dialog.addChoice(/kitchen/i, function(msg2) {
            msg2.reply("On it boss!");
        });
        dialog.addChoice(/bathroom/i, function(msg2) {
            msg.reply("Do I really have to?");
            dialog.addChoice(/yes/, function(msg3) {
                msg3.reply("Fine, Mom!");
            });
        });
    });
 
    robot.respond(/.*the mission/, function(msg) {
        msg.reply(
            "You have 5 seconds to accept your mission, or this message will self-destruct"
        );
        var dialog = switchBoard.startDialog(msg, 5000); //5 Second timeout
        dialog.dialogTimeout = function(msg2) {
            msg2.emote("Boom");
        };
        dialog.addChoice(/yes/i, function(msg2) {
            msg2.reply("Great! Here are the details...");
        });
    });
};

위 코드를 보면 clean the house 혹은 *the mission 어구로 대화 전체 흐름이 선택됩니다. 이후 그 흐름 안에서 Hubot이 응답하면 addChoice 메서드를 통해 답변하며 대화를 이어나가는 방식으로 코드를 설계할 수 있습니다.

이와 같이 설계할 때 매번 모든 명령 구문(command)을 기억하는 것은 어렵습니다. 이에 선택지 답변에 숫자를 붙여서 대화를 이어나갈 때 마치 메뉴를 선택하듯 숫자로 명령을 선택할 수 있게 설계했는데요. 조금 더 자세히 살펴보겠습니다.

Hubot 대화 설계

Hubot을 이용해 작업을 진행하려면 정해진 명령어가 있어야 한다고 생각했습니다. 다만 모든 명령어를 숙지하는 것은 어렵기 때문에 선택지를 제공하는 방식으로 명령어를 설계했습니다. 이때 명령어 선택 흐름이 너무 깊어지면 사용자 친화적이지 않을 것이기 때문에 꼭 필요한 선택만 넣어서 최대한 간결하게 설계했습니다.

먼저 사용자는 '헬프' 혹은 'help'를 입력해서 Hubot을 호출합니다. 이것이 명령의 진입점으로, 이후로는 간단하게 번호를 입력하는 것으로 명령을 선택합니다. 순차적으로 명령을 선택해서 입력하다가 가장 마지막 응답에서는 지금까지 선택한 내용을 보여준 뒤 최종 확인을 받습니다. 이를 통해 작업 안정성을 높였습니다.

  • '헬프' 입력 → 기능 선택 → 배포 리포지터리 선택 → 애플리케이션 선택 → 내 선택 확인 → 수행

아래는 주로 사용할 배포와 버전 확인의 명령 흐름을 설계한 예시입니다.

챗봇 기능대화형 메뉴 설계
배포 기능chatbot func flowchart
버전 확인 기능ver check func flowchart

Slack Hubot 기능 구현 1. Slack Workflow와 이모지, Jira를 연계한 자동 일감 관리

앞서 말씀드린 것처럼 모든 작업은 각 팀에서 Slack으로 요청하면서 시작합니다. 다양한 요구 사항이 여러 채널과 스레드에서 들어온 뒤 각각 처리가 진행되는데요. 이를 한눈에 볼 수 있으면 좋겠다는 니즈가 있었습니다. 이를 충족하려면  Slack Hubot과 Workflow, 이모지를 이용해 사내에서 이슈 트래킹 도구로 사용하고 있는 Jira와 연계하는 것이 좋겠다고 생각했고, 요청할 때 개발 팀에서 보다 쉽게 진행할 수 있도록 카테고리를 분류하기로 했습니다.

카테고리를 분류하기 위해 약 1년 동안 들어온 일감 요청을 모두 분석해 표를 작성했습니다. 아래는 작성한 표 중 일부를 예시로 가져온 것입니다. 먼저 크게 일반, 쿠버네티스, 인프라, 배포로 요청을 분류한 뒤 각 대분류별로 다시 상세하게 요청을 분류했습니다(이 과정에서 팀의 역할과 책임을 보다 분명하게 인식하는 부수 효과도 얻을 수 있었습니다). 

대분류요청 분류옵션스레드 내 정보
일반 지원 문의권한(Jenkins, Harbor, Git, Verda)
  • 요청 요약
  • 참고 내용 URL(사내 위키, Jira 등)
  • 문의 상세 내용
  • 긴급도
    • 긴급하지 않음
    • 적기에 시행, 긴급하지 않음(일주일 이내)
    • 긴급(1일 이내)

추가 질문이나 공유해야 할 자세한 정보가 있다면 이 스레드에 적어 주시기 바랍니다.

DevOps 팀원이 이 작업을 수행할 때까지 기다려 주십시오.

자동화
기타 지원
쿠버네티스 문의CI/CD(Jenkins, Helm, Harbor, ArgoCD) 
  • 요청 요약
  • 단계(Alpha, Beta, RC, Prod)
  • 참고 내용 URL(사내 위키, Jira 등)
  • 문의 상세 내용
  • 긴급도
    • 긴급하지 않음
    • 적기에 시행, 긴급하지 않음(일주일 이내)
    • 긴급(1일 이내)

정보를 위해 다음 문서를 참고해 주세요.

  • CI/CD: Jenkins 이관 작업
  • 쿠버네티스 클러스터
    • Alpha: 01_Kubernetes - Alpha
    • Beta: 02_Kubernetes - Beta
    • RC: 03_Kubernetes - RC
    • Prod: 04_Kubernetes - PROD
  • 모니터링: 쿠버네티스 모니터링(Prometheus, Grafana)
  • 로그 수집: 쿠버네티스 로그 수집

추가 질문이나 공유해야 할 자세한 정보가 있다면 이 스레드에 적어 주시기 바랍니다.

DevOps 팀원이 이 작업을 수행할 때까지 기다려 주십시오.

모니터링(Prometheus, Grafana)
모니터링(Prometheus, Grafana)
기타 지원
인프라 문의도메인, 로드밸런서 문의
  • 요청 요약
  • 단계(Alpha, Beta, RC, Prod)
  • 참고 내용 URL(사내 위키, Jira 등)
  • 문의 상세 내용
  • 긴급도
    • 긴급하지 않음
    • 적기에 시행, 긴급하지 않음(일주일 이내)
    • 긴급(1일 이내)

정보를 위해 다음 문서를 참고해 주세요.

  • CI/CD: Jenkins 이관 작업
  • 쿠버네티스 클러스터
    • Alpha: 01_Kubernetes - Alpha
    • Beta: 02_Kubernetes - Beta
    • RC: 03_Kubernetes - RC
    • Prod: 04_Kubernetes - PROD
  • 모니터링: 쿠버네티스 모니터링(Prometheus, Grafana)
  • 로그 수집: 쿠버네티스 로그 수집

추가 질문이나 공유해야 할 자세한 정보가 있다면 이 스레드에 적어 주시기 바랍니다.

DevOps 팀원이 이 작업을 수행할 때까지 기다려 주십시오.

인증서 문의
서버 문의
데이터베이스 문의(Kafka, Redis, MySQL)
네트워크 문의(접근 제어 목록, NAT 화이트리스트)
기타 지원
프로덕션 배포 요청N/A
  • 배포 타깃 애플리케이션
  • 배포 타깃 날짜
  • TTS(Trouble Tracking System) URL
  • 작업 상세 내용

가능한 아래 일정으로 신청 부탁드립니다.

  • 정기 배포: 매주 화, 목 13:00 ~ 18:00

배포 당일 이전에 아래의 작업 완료 부탁드립니다.

  • Git 태깅 버전 준비
  • Helm 차트 타깃 버전 업데이트

추가 질문이나 공유해야 할 자세한 정보가 있다면 이 스레드에 적어 주시기 바랍니다.

DevOps 팀원이 이 작업을 수행할 때까지 기다려 주십시오.

위와 같이 카테고리를 분류한 뒤 Slack Workflow를 만들어서 Hubot과 연계해 Jira API를 호출하도록 구성했습니다. 이를 통해 일감 등록과 완료가 자동으로 가능해졌는데요. 먼저 Slack의 Workflow 기능 및 이모지 기능을 이용할 때 Hubot에게 일감 등록과 완료와 관련된 특정 문구가 발송되도록 설정하고, 각 팀원은 각자 이니셜로 Slack 이모지를 만듭니다. 이후 Slack으로 일감이 들어왔을 때 담당할 팀원의 이모지를 입력하면 해당 인원에게 자동으로 일감이 할당됩니다. 작업 완료 후에는 'DONE' 이모지를 붙이면 자동으로 종료됩니다. 또한 모든 일감은 Jira에 Slack 스레드를 남겨 놓아 참조할 수 있게 해뒀는데요. 이렇게 하면 완료된 일감은 Jira에서 자동으로 종료되기 때문에 현재 진행 중인 일감만 확인할 수 있어서 일정이나 일감을 훨씬 효율적으로 관리할 수 있습니다.

일감 신규 생성담당자 지정일감 처리 후 종료
slack hubot register new workslack hubot appoint a person in chargeslack hubot work done

Slack Hubot 기능 2 - 여러 도구와 연계해 배포 및 미들웨어 제어

Hubot을 통해서 일감 등록 및 일정 관리를 자동화했지만 아직 애플리케이션 버전 확인이나 배포, 재시작 등 수동으로 작업해야 하는 부분이 많이 남아 있었습니다. 앞서 말씀드린 것처럼 Hubot을 이용하면 여러 가지 도구와 연계해서 작업을 수행한 뒤 작업 결과를 Slack 메시지로 전송할 수 있고, 동적 대화 기능을 이용하면 작업 상세 설정도 대화 형식으로 진행할 수 있습니다. 이에 저희는 Hubot을 ArgoCD와 Jenkins와 연계해서 배포와 미들웨어 제어 기능을 개발했습니다.

실제 제공하는 기능은 다음과 같습니다(호출 권한은 Hubot 설정으로 구성했습니다).

slack hubot function list

  • 애플리케이션 제어: 쿠버네티스에서 서비스하는 애플리케이션을 제어합니다.
  • NGINX 제어: 미들웨어인 NGINX 설정을 제어합니다.
  • 운영 잡 제어: 내부에서 사용하는 운영 잡을 제어합니다.

애플리케이션 제어 - ArgoCD와 연계해 애플리케이션 버전 확인, 배포, 재시작 제어

LINE NEXT에서는 독립된 망에 쿠버네티스를 설치해 사용하고 배포 도구로 ArgoCD를 사용합니다. 저희는 ArgoCD의 API를 조사해서 Hubot과 연계하는 방법으로 개발을 진행했습니다.

현재 배포 프로세스는 다음과 같습니다.

  1. 배포 시작 공지
  2. ArgoCD 로그인
  3. 애플리케이션 정보 확인(동기화 상태: 'out of sync') 후 변경 버전 확인
  4. 애플리케이션 목록의 각 애플리케이션마다 다음 작업 수행
    1. 애플리케이션 배포(동기화 상태: 'synced')
    2. 애플리케이션 헬스 상태 확인(애플리케이션 헬스 상태: 'healthy')
  5. 배포 완료 공지 

위 작업을 매번 수동으로 진행하려면 많은 리소스가 필요합니다. 또한 이런 프로세스로 여러 팀을 지원하고 있다 보니 이를 자동화하면 효과가 클 것이라고 판단했고, 배포 프로세스를 Hubot으로 코드화했습니다.

deploy process hubot code
애플리케이션 제어 전체 프로세스

이제 사용 예시를 살펴보겠습니다. 배포 의뢰와 배포 실행, 배포 결과는 다음과 같이 진행됩니다. 

1. 배포 요청2. 버전 확인

개발 팀에서 개발 코드를 준비하고 해당 버전으로 Helm 차트(배포 명세서)를 업데이트한 뒤 DevOps 팀에 배포 요청을 의뢰합니다. 
request deploy

계획한 배포 버전을 준비하고 Helm 차트 업데이트 여부를 확인합니다.

check version

3. 배포 진행4. 배포 결과 전달

배포 목록에 있는 애플리케이션을 선택하고 작업을 수행합니다. 

deploy

배포 결과를 전달합니다. 

  • 배포 성공 시 메시지
    deploy success message
  • 배포 실패 시 메시지
    deploy failure message

배포 도구인 ArgoCD에 따로 접속하지 않고 Slack Hubot을 통해서 간단한 대화로 배포 작업을 실행한 뒤 그 결과를 모든 관계자가 동시에 받을 수 있게 돼 작업 효율이 높아졌습니다.

아래는 배포 작업 전과 작업 진행 중, 작업 완료 후의 ArgoCD 화면을 캡처한 것입니다. 

배포 작업 전

Git으로 관리하는 Helm(배포 명세 파일)의 배포 버전이 업데이트되면 아래와 같이 OutOfSync 상태로 바뀌고 배포 준비 상태가 됩니다.

before deploy

배포 작업 진행

Helm에 업데이트된 배포 버전을 확인한 뒤, 예정된 배포 버전이라면 배포를 수행합니다. Git 내용과 일치하기 때문에 상태는 Synced로 바뀝니다. 배포 중에는 아직 신규 버전의 애플리케이션이 준비가 안된 상태이기 때문에 HealthProgressing 상태가 됩니다.

during deploy

배포 작업 완료

신규 버전의 애플리케이션이 모두 준비 완료되고 HealthHealthy 상태가 되면 Slack Hubot이 스레드에 배포 완료 메시지를 전송합니다.

after deploy

NGINX 제어 - Jenkins와 연계해 NGINX 설정 배포, 점검 모드 실행, 실시간 크론잡 수행 제어

저희 팀에서는 Jenkins에 여러 운영 잡을 만들어 사용하고 있습니다. 이때 Hubot과 Jenkins를 연계하면 더 이상 Jenkins에 접속해서 수동으로 파라미터를 조작할 필요가 없습니다. Hubot에게 시킨 뒤 결과를 전달받기만 하면 됩니다. 이 방식은 공개된 채널에서 작업을 진행하기 때문에 유관 부서나 팀원이 함께 작업에 동참하는 효과가 발생해서 작업 안정성도 높아집니다.

Jenkins와의 연계는 Jenkins API를 호출하고 폴링 형태로 잡 상태를 확인해서 결과를 Slack으로 전달하는 방식으로 구성했습니다. LINE NEXT의 서비스는 앞단에 미들웨어로 NGINX 프락시를 구성해 사용하고 있는데요. NGINX 설정 업데이트가 자주 발생하기 때문에 NGINX 설정을 안정적으로 배포하면서 배포 정보를 공유할 수 있는 방법이 필요했습니다. 이에 NGINX 설정 배포를 Ansible로 구성해 두고 Jenkins에서는 Ansible을 호출하도록 아래와 같이 구성했습니다.

nginx control process
NGINX 제어 전체 프로세스

아래는 NGINX 설정 작업 중 점검 모드 설정을 배포하는 예시입니다. 

NGINX 설정 배포 요청NGINX 설정 배포작업 결과 전달

점검 모드 요청(점검 모드 수행이 필요한 서비스 작업 요청) 

NGINX conf request

점검 모드 수행(타깃 서비스 선택 및 점검 모드 설정 배포) 

NGINX conf deploy

  • 배포 성공 시 메시지
    deploy success message
  • 배포 실패 시 메시지
    deploy failure message

문제가 발생해 긴급하게 서비스를 점검해야 할 때에도 시간과 공간에 제약을 받지 않고 ChatOps를 통해서 바로 서비스 점검 모드를 수행할 수 있습니다. 아래는 GAME DOSI에서 Slack Hubot으로 서비스 점검 모드를 수행한 예시입니다. 

NGINX 설정 작업 전game dosi screenshot
NGINX 설정 작업 후game dosi after nginx deploy

Slack Hubot 적용

Slack Hubot을 개발한 뒤 조직에 전파해 나간 과정과 사용자가 보다 쉽고 안전하게 사용할 수 있도록 모듈화한 과정을 살펴보겠습니다. 

Slack Hubot 전파

Jira와 연계해 일감을 등록하고 관리하는 것을 시작으로 동적 대화를 적용하면서 여러 가지 명령을 수행할 수 있다는 것을 확인했습니다. 이에 따라 최초에는 배포 기능만 존재했지만 이후 여러 가지 운영 작업을 연결해 수행할 수 있도록 구성했습니다.

현재 DevOps 팀에서는 독립망 내에 설치형 쿠버네티스 클러스터를 직접 설치해서 인프라 자원을 DevOps 팀에서 관리하고 있습니다. 또한 CI/CD 빌드 배포 파이프라인를 구성하고 모니터링 로그 수집까지 모든 내용을 자동화해 하나의 파이프라인으로 구성해 놓았습니다. 이에 DevOps 팀에서는 비록 DevOps 팀에서 수행 및 관리 역할을 추가로 맡게 되더라도 그동안 개발 팀에서 각자 배포하던 방식을 중앙 배포하는 방식으로 바꿔서 신속하면서 정확하게 배포 서비스를 제공하고 싶었습니다.

이때 Hubot이 아주 적절한 해결책이라고 생각했습니다. DevOps 팀에서는 단순히 배포만 수행하는 것이 아닙니다. 배포가 전체 시스템에 어떤 영향을 주는지 면밀히 모니터링하고 알람을 받는 역할도 수행합니다. 또한 쿠버네티스에서의 배포는 단순히 애플리케이션 버전 변경뿐 아니라 쿠버네티스 오브젝트(디플로이먼트, 레플리카셋, 파드) 변경 작업도 포함됩니다. 따라서 전체적인 작업을 DevOps 팀에서 담당하되 개발 팀의 요청 및 작업이 적시에 적절하게 수행될 수 있도록 Hubot을 통해 배포를 지원하기로 결정했습니다.

물론 초기에는 아무래도 새로운 프로세스를 도입하는 것이고, 아직 많은 분들이 경험해 보지 못한 ChatOps를 통한 배포였기 때문에 다수의 개발 조직을 설득해서 적용하는 것이 상당히 힘들었습니다. 이에 저희는 먼저 시범으로 한 팀을 선정해 프로세스를 도입해서 ChatOps를 통한 배포를 시작한 뒤 점진적으로 다른 팀으로 전파하는 방향으로 전략을 세웠고, 이 전략으로 조직 전체에 성공적으로 전파해서 개발 팀과 쉽고 편하게 협업하며 신속하고 정확하게 배포를 수행하고 있습니다. 

모듈화로 기능 개발 편의 향상

Hubot은 동적 대화 프레임워크를 별도로 지원하지 않습니다. 따라서 애플리케이션 아키텍처를 별도로 구성해야 하는데요. 저희는 개발 초기에 협업을 고려하지 않고 하나의 파일에서 여러 기능을 제공하도록 구성했습니다. 그 때문에 가독성이 떨어져서 각 기능이 어떤 역할을 하는지 이해하기 어려웠습니다. 이에 누구라도 개발에 투입되면 빠르게 소스 코드를 이해할 수 있고, 서로 영향을 주지 않고 각 기능을 개발할 수 있도록 모듈화했습니다.

아래는 소스 코드 구성을 모듈화한 예시입니다. 

├── function -----------> Separation for each function
│   ├── function1.js
│   ├── function2.js
│   ├── function3.js
│   ├── function4.js
│   ├── utils.js ------> Common Function
├── help.js ------------> main command
├── jira.coffee  -------> Jira Work Register
├── lib
│   ├── constants.js
│   └── Dialog.js -----> Multiple-Choice Customizing
└── middleware.coffee --> Authority Control
  • function 폴더: 해당 폴더에 각 기능을 파일 단위로 분리합니다. 또한 utils.js에 공통으로 사용하는 기능(도구 로그인, 비동기 상태 체크 등)을 넣어두고 각 기능에서 참조하는 방식으로 구성합니다.
  • help.js: 주 명령이 시작되는 곳으로 '헬프' 혹은 'help'로 호출할 수 있게 구성합니다.
  • jira.coffee : Jira API를 활용해 일감을 등록하고 처리를 완료하는 기능을 구성합니다.
  • lib: 공통으로 사용하는 응답 문구 등으로 구성합니다.

아래는 help.js 샘플 코드입니다. 각 기능을 모듈로 나눠 삽입하는 방식으로 구성해서 기능 추가하는 부분을 손쉽게 다룰 수 있도록 설계했습니다. 그 덕분에 다른 파일에 영향을 주지 않고 신규 기능을 추가할 수 있습니다. 

//module import
var Conversation = require("hubot-conversation");
var request = require("request");

module.exports = function(robot) {
    var switchBoard = new Conversation(robot);

    robot.respond(/헬프|help|HELP/, function(msg) {
      var dialog = switchBoard.startDialog(msg);

      //func 1. check target version
      version.checkVersion(dialog);

      //func 2. deploy
      deploy.deployApp(dialog);

      //func 3. deploy
      restart.restartApp(dialog);

      //func 4. deploy nginx
      nginx.triggerCronjob(dialog);      

      //func 5. set maintenance
      maintenance.setMaintenanceJob(dialog);

      //func 6. trigger cronjob
      cronjob.triggerCronjob(dialog);

      //func 7. block wallet users
      block.blockUser(dialog);

      //etc. cancel work
      dialog.addChoice(/^취소$/, function(msg) {
           msg.reply("_*작업 요청을 취소했습니다.*_" + "\n_* :us: Request canceld*_");
      });
  });   
};

Slack Hubot 적용 효과

지금까지 Hubot을 어떻게 설계하고 개발해서 적용했는지 살펴봤습니다. 아직 '과연 Hubot을 꼭 사용해야 할까?'라고 생각하는 분들을 위해 Hubot을 적용해서 저희가 어떤 이점을 얻었는지 말씀드리겠습니다. 이 이점들이 ChatOps 사상이 무엇인지 가장 잘 설명한다고 생각합니다. 

작업 시간 단축

배포를 수행하기 위해 준비하는 시간이 기존에 비해 많이 단축됐습니다. 기존에는 개발 팀과 DevOps 팀이 Zoom에 모여서 배포를 진행했는데요. 모든 사람이 Zoom에 모이는 것만으로 종종 지연이 발생하곤 했습니다. 또한 DevOps 팀에서 배포하기 위해서는 독립망의 VPN에 접속한 뒤 다시 배포 도구에 접속해 수동으로 배포를 진행해야 했는데요. 사전에 미리 준비하지 않는다면 이 부분 역시 시간 지연으로 이어졌습니다.

Hubot을 도입하고 난 후에는 따로 Zoom에 모일 필요 없이 배포를 희망하는 시간에 딱 맞춰 배포를 진행할 수 있게 됐습니다. 또한 도구에 별도로 접속할 필요가 없기 때문에 도구에 접속해서 수동으로 배포를 진행하기 위해 들이는 시간도 절약할 수 있게 됐습니다. 

작업 정확성 향상

배포를 수행하기 위해 밟아야 하는 작업 절차가 간소화되면서 작업 정확성이 높아졌습니다. 기존에는 여러 개발 팀에서 동시다발적으로 배포를 진행하는 경우 아무래도 사람이 수동으로 진행하다 보니 순서를 착각하거나 잘못된 애플리케이션을 배포하는 등 실수할 가능성이 높았습니다.

하지만 Hubot을 통해서 배포 작업을 수행하면 Hubot이 비동기적으로 배포 상태를 확인하기 때문에 동시다발적으로 여러 개별 스레드에서 접수된 요청도 빼먹거나 잘못 수행하는 일 없이 정확하고 안정적으로 작업을 수행할 수 있었고, 작업 상태도 쉽게 확인할 수 있었습니다. 더불어 DevOps 팀에서는 배포 수행 후 모니터링 대시보드를 보면서 특이 사항이 있는지만 확인하면 될 정도로 작업 리소스를 줄일 수 있었습니다.

쉽고 빠르고 투명하게 정보 공유

기존에는 수동으로 배포한 뒤 배포 완료된 애플리케이션을 확인해 다시 수동으로 공지했는데요. 배포 작업을 Zoom에 모여서 진행했기 때문에 배포가 어떤 상태로 진행되고 어떤 애플리케이션이 배포되는지 Zoom에 참여하지 않은 다른 팀은 알 수가 없었습니다.

Hubot 도입 후에는 공개된 채널과 스레드에서 배포 작업을 진행하기 때문에 자연스럽게 모두에게 정보가 공개되며, 공유된 정보를 기반으로 특정 팀의 배포 상태를 모두가 즉각 확인할 수 있게 됐습니다. 이는 ChatOps의 가장 강력한 장점이라고 할 수 있는데요. 메시징 플랫폼을 통해서 정보를 다방면으로 공유하니 이슈가 발생하더라도 더 빠르게 해결할 수 있고, 누구나 채팅으로 편하게 의견을 낼 수 있어서 업무 효율이 더욱 높아졌습니다.

향후 계획

LINE NEXT에서는 Hubot으로 적은 인력으로도 최고의 효율을 낼 수 있다는 확신을 갖게 됐습니다. Hubot은 마치 또 하나의 팀원이 추가된 것처럼 운영 업무를 신속하고 정확하게 처리하면서 모든 정보를 쉽고 빠르게 공유할 수 있는 강력한 기능을 탑재하고 있습니다. 이런 Hubot을 활용해 앞으로 다음과 같은 기능을 추가하려고 합니다.

  • 모니터링 기능: 여러 가지 레이어를 통해서 알림을 받고 있지만, 종종 실시간으로 현재 모니터링 대시보드를 캡처해서 보고 싶을 때가 있습니다. 이때 Hubot에게 알림을 요청하면 Datadog과 같은 모니터링 도구에 접속해서 대시보드 화면을 캡처해 Slack 스레드에 공유해 주는 기능을 고려하고 있습니다.
  • 작업 승인 기능: 애플리케이션 배포나 미들웨어 배포, 점검 모드, 재시작 등의 작업은 실제 프로덕션에서 인프라를 제어하는 작업이니만큼 2인 1조 작업 기능을 추가하려고 합니다. 작업자가 요청하면 최종 단계에서 승인자가 승인 메시지를 입력해 명령을 실행해야 실제 작업이 수행되도록 만드는 기능을 고려하고 있습니다.

마치며

지금까지 Hubot을 이용해 여러 가지 업무를 자동화한 사례를 소개했습니다. 이번 글에서 말하고자 하는 바는 반드시 Hubot을 써야 한다는 것은 아닙니다. DevOps의 진보된 사상인 ChatOps를 도입하면 보다 효율적으로 일할 수 있다는 것을 알려드리고 싶었습니다. Slack이라는 강력한 메시징 플랫폼을 활용해서 채팅만의 강력한 기능(쉽고 편한 정보 공유, 누구나 참여 가능한 공개 채널)을 업무에 활용한다면 기존과 비교해 업무 효율을 수십 배 높일 수 있다고 생각합니다. ChatOps에 관심을 갖고 업무에 도입하려는 분들에게 도움이 되길 바라며 이만 마치겠습니다. 긴 글 읽어주셔서 감사합니다.