“지금 테스트서버 쓰시는 분?” (GitOps로 브랜치별 배포 시스템 구축하기) (1/2)

김희철
레몬베이스 팀블로그
11 min readSep 30, 2022

--

안녕하세요. 레몬베이스 Backend Engineer로 일하고 있는 찰스(Charles) 입니다.

많은 개발팀에서 필수적으로 만들어서 사용하고 있는 것이 바로 테스트 서버일것 같아요. 저희도 테스트 서버를 구축하여 개발과 QA하는 과정에서 사용중인데요, 이번 글에서는 “테스트 서버 쓰시는분?” 이라는 슬랙 메시지에서 출발하여 한정적인 테스트 서버 자원으로 인한 대기 비용과 커뮤니케이션 비용을 GitOps 도입으로 개선한 레몬베이스 엔지니어링팀의 이야기를 해보려고 합니다 🙂

글은 총 두편으로 나눠서 작성할 예정이며, 내용은 아래와 같아요.

  1. GitOps로 브랜치별 배포 시스템 구축하기 (1/2) — 현재의 테스트 환경과 문제점 그리고 GitOps
  2. GitOps로 브랜치별 배포 시스템 구축하기 (2/2) — 레몬베이스에서 구성한 브랜치별 배포 시스템

현재의 테스트 환경

먼저 저희 개발 조직의 경우 3개의 스쿼드가 서로 다른 제품을 개발하고 있습니다. 그에 따라서 각 스쿼드 별로 테스트 용도로 사용할 수 있는 서버가 한 개씩 존재하고, Github Actions를 이용해 클릭 한번으로 각 서버에 원하는 브랜치를 배포할 수 있는 환경까지 구성되어 있어요.

배포를 위한 Github Actions
배포를 위한 Github Actions
배포 성공 시 슬랙 알림
배포 성공 시 슬랙 알림
간단하게 그려본 서버 구성
간단하게 그려본 서버 구성

올해 2월에 입사한 저는 이전 직장에서도 위와 비슷한 구성을 활용해서 테스트와 프로덕션 인프라를 구축했었기 때문에 큰 어려움이나 문제는 느끼지 못하고 있었습니다. 그렇게 몇 개월 정도 근무하던 중, 슬랙 채널에 가끔씩 보이던 메시지가 있었는데요. 아래처럼 서버 사용 여부를 확인하고 다른 서버를 찾거나 기다리는 내용이었습니다. 검색을 해보니 생각보다 빈번하게 주고받고 있던 걸 확인할 수 있었어요.

테스트 서버 쓰세요? 한 번씩 보던 메시지였지만 조금 다르게 느껴졌습니다.
테스트 서버 쓰세요? 한 번씩 보던 메시지였지만 조금 다르게 느껴졌습니다.

테스트 환경의 문제점

한정된 수량의 서버 자원

왜 위와 같은 상황이 발생했을까 생각해보니 엔지니어의 인원과 스쿼드가 늘어나면서 서버의 개수보다 한번에 개발하는 기능의 종류가 많아져 발생하게 된 것이었습니다. 또한 테스트 서버를 공유하다 보니 단순 커뮤니케이션 비용이나 대기 시간이 필요한 것 뿐만 아니라, 이전 배포로 스키마 등이 달라졌다면 새로 배포한 기능이 작동하도록 보정도 필요하게 되는 문제가 있었어요. 이는 병목으로 작용해서 전체적인 속도를 늦추고 있었고 앞으로 팀이 커지고 엔지니어의 수가 늘어날수록 더 크게 다가올 거라는 생각에 이르렀습니다.

새로운 서버를 구성하고 삭제하기가 어려움

테스트 서버의 개수보다 개발하는 기능의 수가 많아져서 발생한 문제이니 서버의 개수를 늘리면 괜찮지 않을까 생각할 수 있을 것 같아요. 하지만 단순하게 늘리는 방법에는 아래와 같은 한계가 있었습니다.

  • 추가 삭제에는 적어도 몇 시간 정도 전체적인 인프라 구성을 아는 엔지니어에게 의존적인 상황이 발생한다
  • 만약 인프라의 변경사항이 있으면 서버마다 똑같은 설정을 해줘야 한다
  • 사용하는 인원이 적은 경우에는 리소스 낭비로 이어지게 된다
  • 인프라에 대한 권한을 누구에게 얼만큼 부여할 것인지, 또 휴먼 에러는 어떻게 방지할 것인지 고민이 필요하다

개선을 위한 첫걸음

그래서 저는 이런 문제들을 해결하고자, 자동화를 도입해보기로 했습니다 🙂 문제 정의와 요구사항을 정리하던 중, 프론트엔드 챕터의 Jamie와 백엔드 챕터의 Noah도 같은 문제 의식을 가지고 있다는 것을 알게 되었고, 3명이 모여 논의를 시작했어요.

어떤 방식으로 진행하면 좋을까 고민해 본 결과, 우선은 스쿼드 업무에 영향이 없도록 온/오프라인으로 하루에 30분~1시간만 모여서 진행하기로 하고 개인의 부담을 줄이기 위해 매일 메인 드라이버, 서브, 서기를 번갈아가며 진행하기로 하였습니다.

그리고 문제를 해결하기 위한 요구사항을 정리했는데요, 아래는 저희가 생각했던 요구사항 중 일부 입니다.

  • 현재 어떤 작업이 배포되어있는지 알 수 있어야 한다
  • 인프라에 관련된 지식이 없어도 브랜치와 연결된 서버를 쉽게 생성할 수 있다
  • 배포된 각 서버는 서로에게 영향을 주지 않도록 한다

위 요구사항들을 만족한다면 테스트 서버에 대한 병목을 해결할 수 있을 것이라고 생각했기에, 처음에는 스크립트를 이용해 인프라를 생성/삭제하려고 했습니다. 하지만 다른 비슷한 사례를 조사하던 중 GitOps에 대해서 알게 됐어요. GitOps에 대해 가볍게 조사를 좀 더 해보니, 요구사항을 만족할 뿐만 아니라 더 편리하게 관리할 수 있더라고요.

이렇게 FE 엔지니어 1명과, 쿠버네티스는 들어보기만 한 BE 엔지니어 2명의 브랜치별 배포 시스템 구축 여정이 시작되었습니다.

GitOps

그렇다면 저희가 적용한 GitOps는 무엇이고, 어떠한 흐름으로 배포가 진행되는지 알아볼게요 🙂

GitOps란?

Weaveworks에서 시작된 GitOps는 클라우드 네이티브 어플리케이션을 위한 CD(Continuous Delivery)를 구현하는 방법입니다. 핵심 아이디어는 현재 환경에서 원하는 인프라에 대한 선언적 설명을 포함하는 Git 저장소를 이용해여 인프라 환경을 저장소의 설명된 상태와 일치하도록 만드는 자동화된 프로세스를 갖는 것입니다. https://www.gitops.tech/

즉 GitOps는 Git 저장소에 인프라에 대한 내용까지 함께 선언적으로 작성하여 어플리케이션에 배포를 자동화하는 방법입니다.

GitOps의 배포 흐름

풀 타입 배포 https://www.gitops.tech/
풀 타입 배포 https://www.gitops.tech/

각 컴포넌트들은 아래와 같은 역할을 하는데요, 각 컴포넌트간에 연결도 살펴보시면 도움이 될 것 같습니다.

  • Application Repository: 어플리케이션이 동작하는 소스코드가 있는 저장소
  • Build Pipeline: 코드의 변경사항이 있을 때 트리거 되는 서비스. 또한 컨테이너 이미지를 빌드하고 인프라에 대한 업데이트를 진행함. (레몬베이스로 보자면 Github Actions가 해당 됨)
  • Image Registry: Build Pipeline에서 빌드한 컨테이너 이미지가 올라갈 저장소
  • Environment Repository: 인프라에 대한 선언적인 코드들이 있는 저장소
  • Operator: Environment Repository와 실제 배포된 환경을 지켜보고 있다가 차이가 발생했을때 인프라를 다시 배포해주는 역할

전체적인 흐름을 한번 살펴보았으니, 이번엔 GitOps를 활용한 예시를 한번 살펴보겠습니다.

GitOps를 적용하기 위한 도구로는 Flux, ArgoCD, Jenkins X등이 있어요. 그중에 저희는 설치도 비교적 간단하고 쉬운 관리를 위한 UI도 지원하는 ArgoCD를 선택하게 되었습니다. 세가지 도구를 비교한 글도 있으니 참고해보시면 좋을 것 같아요 🙂 추가적인 도구들은 awesome-gitops에서도 살펴보실 수 있어요.

현재 배포되어 있는 앱들을 확인 할 수 있는 화면 https://argo-cd.readthedocs.io/en/stable/getting_started/
현재 배포되어 있는 앱들을 확인 할 수 있는 화면 https://argo-cd.readthedocs.io/en/stable/getting_started/
배포되어 있는 앱의 동기화 상태를 보여주고 클릭하여 url로 접속도 가능합니다 https://argo-cd.readthedocs.io/en/stable/getting_started/
배포되어 있는 앱의 동기화 상태를 보여주고 클릭하여 url로 접속도 가능합니다 https://argo-cd.readthedocs.io/en/stable/getting_started/

GitOps의 배포 예제

이제 ArgoCD를 통해서 실제로 앱을 배포해 보겠습니다.

ArgoCD 예제 저장소를 보면 간단한 방명록 예제가 있습니다. EKS에 ArgoCD가 설치되어있고, 어플리케이션은 빌드되어 Registry에 업로드 되어 있다고 가정하고 살펴볼게요. 먼저, 아래 어플리케이션을 정의를 사용합니다.

# https://github.com/argoproj/argocd-example-apps/

guestbook/
guestbook-ui-deployment.yaml
guestbook-ui-svc.yaml

guestbook-ui-deployment.yaml
guestbook-ui-svc.yaml

ArgoCD에서 어플리케이션을 생성하고 위에 저장소와 연결해줍니다. UI에서도 가능하지만 간단하게 CLI를 사용해봤어요.

# guestbook이라는 ArgoCD Application 생성
argocd app create guestbook --repo https://github.com/argoproj/argocd-example-apps.git --path guestbook --dest-server https://kubernetes.default.svc --dest-namespace default

# 저장소에 내용과 현재 인프라 상태를 동기화
argocd app sync guestbook
커맨드 실행후 ArgoCD에서 접속해서 본 화면
커맨드 실행후 ArgoCD에서 접속해서 본 화면

커맨드 실행후 서비스가 Healthy 상태가 되었다면 이제 쿠버네티스 클러스터 외부에서 클러스터 내부에 서비스로 HTTP 요청을 받기 위한 ingress도 배포해줍니다.

apiVersion: v1
kind: Service
metadata:
name: guestbook-sample-ingress
namespace: branch-deploy
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
type: LoadBalancer
selector:
app: guestbook-ui

ingress까지 배포가 되었다면 위처럼 어플리케이션에 접속이 가능해집니다.

GitOps로 배포하는 흐름을 설명하기 위해 설치나 환경설정을 위한 자세한 과정은 생략 하였습니다. 자세한 내용은 아래 글에서도 살펴보실 수 있어요.

레몬베이스의 구성

이렇게 동작 확인을 마치고 저희가 사용할 구조를 그려보았어요 🙂 그리고 다음 편에서는 실제로 아래 구조가 어떠한 과정들을 거쳐서 구현되었는지 설명 드리려고 합니다.

그리고…

처음에는 단순하게 설치하고 쿠버네티스 명세 정도만 배우면 될 것이라고 생각했었어요. 하지만 네트워크 문제로 이미지 저장소에 접근하지 못해서, 몇 주 정도를 원인 파악에만 시간을 사용하기도 하고, 설정의 변화에 따라 왜 동작하는지 또 왜 동작하지 않는지를 짚어가면서 차이점을 찾아가기도 하는 등 (회식도 하고 😋) 생각 이상의 많은 과정들이 있었습니다.

이런 과정들을 겪은 이후, 잘 동작하는 것을 봤을 때의 성취감은 이루말할 수 없었어요 😊 과정 중 겪었던 고생들 덕분에, AWS에서 네트워크 트래픽을 관리하거나 VPC를 운영하는 방법에 대한 지식이 부족하다고 느껴졌고, 팀에는 AWS 네트워크 스터디도 생겼습니다.

매일 진행하면서 작성했던 작업 기록

짧은 경험을 바탕으로 작성한 이 글과 다음편으로 업데이트 될 글이, 브랜치별 배포시스템을 구축하고자 하는 다른 분들에게도 도움이 되길 바랍니다. 끝으로 각자의 업무가 있는 상황 속에서도 임팩트를 만들기 위해 함께 어려움을 헤쳐나간 제이미(Jamie)와 노아(Noah)에게 감사를 전하면서 글을 마무리 할게요 🙂

이렇게 작은 의문에서부터 시작해서 큰 임팩트까지 만들어내는 경험을 함께하고 성장을 갈망하는 엔지니어 분들을 기다리고 있습니다. 레몬베이스의 엔지니어에 관심이 있으시다면 lemonbase.team 을 살펴보시거나 start@lemonbase.com 으로 편하게 메일 보내주세요!

--

--