본문으로 건너뛰기

스테이트 머신 기반의 도커 이미지 빌더

· 약 4분

한 달에 한 번, 내가 속한 조직의 팀은 해커톤을 진행한다. 해커톤의 주제는 Cozy Night이다. 점심 시간을 포함해 4시간 정도로 진행되며, 결과를 낸 후 공유한다.

24시간 주차장이라는 물리적 공간에서 안정적으로 실행되어야하는 제품을 만들어야하는 미션을 가진 우리 팀은 6개월에서 1년 후의 Cozy해지는 모습을 상상하면서 해커톤이라는 형식으로 실험을 할 기회가 주어진다.

내가 정한 주제는 도커 빌드를 서버에서 해주는 잡 워커이다.

CI/CD를 쓰면 되지 않냐고 할 수 있는데, 도구를 선택하기보다, 우리 상황에 맞는 문제를 먼저 식별해서, 적절한 기술과 도구를 선택한다는 말이 더 맞는 방향이다.

이번 해커톤에는 설계 능력과 스테이트 머신과 같은 개념을 구성원들과 함께 관념화시키는데도 중점을 두었다.

문제

팀에서 서비스되는 백엔드 마이크로서비스의 65%는 우리가 만든 자체 업무 도구인, Controlplane이라는 업무 도구를 통해 이루어진다. 개발자가 도구를 의식하지 않아도 AX의 워크플로우 파이프라인에 통합된다. 설계, 개발, 테스트, 모니터링, 옵스, 코드리뷰, 지표 등 여러가지 도구를 웹 기반으로 접근할 수 있기에 노트북에 따로 개발 환경을 구성할 필요도 없고, 심지어 아이패드로 개발하는 사람도 있다.

하지만, 만능 도구는 없다. 최근 AWS 관리형 쿠버네티스 서비스인 EKS의 메이저 버전을 업데이트를 해야하는 상황이 생겼는데, AWS에서는 관리의 용이함과 보안을 이유로, 일정 시간이 지나면 강제로 업데이트를 해버린다. 우리는 업데이트가 아니라 신규 구축 후 이전하는 방법을 택했다. 쿠버네티스의 코어 서비스인 CoreDNS와 같은 의존성을 수동으로 업데이트하면 반드시 순단이 발생되고, 어떤 장애가 발생할 지 예측하기 어렵기 때문이다.

상술하듯 24시간 돌아가는 서비스, 일 HTTP 트래픽 9천만을 다루는 인프라를 업데이트하는 것은 위험도가 상당히 커서, 2달 이상의 검증과 테스트를 반복하며 이루어졌다.

우리 작업은 달리는 자동차의 바퀴를 교체한다고 농담처럼 이야기하곤 했었는데 사실이다. 우리 인프라 업데이트해야 하니, 전국 약 700여개의 주차장에 잠깐 주차하지 말아주세요 라고 할 수 없다.

마이크로서비스 환경에서 업데이트를 하다보면 종종 순환참조를 겪게된다. 서비스가 늘어나는 곳에서는 실행 순서가 있어서 괜찮은데, 이번 EKS 업데이트작업처럼 신규 구축을 하다보면 예상치못했던 순환참조를 발견하게된다. 우리 개발 도구의 코드 관리 서비스가 떠 있어야 코드를 실행할 수 있는데, 화면에 잠깐 뜨지 않는 것만으로 개발자는 내 코드를 날린 것 같은 패닉이 온다.

그래서 우리는 독립적으로 실행 가능한, 특정 파드의 프로세스가 아니라, 파드 배포 이미지가 필요했다. 내가 개발한 데모는 프로세스처럼 운영되는 MSA 서비스를 파드 형태로 실행시키는 배포이미지를 만들어주는 서비스를 만드는 것이다.

설명이 좀 어려운데 단순 기술적으로 설명하면, 워커 하나가 돌면서 배포 이미지 생성 요청을 받으면, 상태 머신이 코드 다운로드, 의존성 설치, 도커 이미지 빌드, AWS ECR에 푸시하는 각 절차를 처리하는 이벤트 기반의 잡 파이프라인이다.

설계

에이전트 기반의 코딩에서는 이제 코드가 산출물이 아니라, 설계서가 산출물이다. 설계에는 반드시 담겨야 할 정보를 다아야 한다. 그런데 나는 아직 이 워크플로우가 낯설다. 코드를 직접 작성하는 습관이 편안해서 그런지, 먼저 작성해보는게 직관적이어서 그런지 잘 모르겠다.


설계에서의 필수 요소는 다음과 같다.

  • 서비스 목적
  • API
    • 메서드/엔드포인트
    • 요청 파라미터/바디
    • 동작
    • 응답 코드/결과
  • 스키마
    • 필수/선택 스키마
  • 이벤트
  • 스테이트 머신
    • 상태 정의
    • 동작
    • 전이 기준
    • 상태 흐름
  • 프로세스/함수
    • 에이전트에게 구현에 대한 힌트를 준다.
  • 제약 사항

상태 기반 실행 엔진

문제를 단순하게 보면 “docker build를 대신 해주는 서비스”지만, 실제로는 그렇지 않다.

  • 빌드는 언제든 실패할 수 있다
  • 중간 상태를 알아야 한다
  • 언제든 중단할 수 있어야 한다

제어 가능한 실행 흐름이 필요했으며, 그래서 이를 상태로 정의했다.

INIT → VALIDATING → QUEUED → PREPARING → BUILDING → PUSHING → VERIFYING → COMPLETED

데모

PUT API로 Job을 생성하면, 워커가 작업 큐에서 일감을 가져와 이미지를 만든다.

상태가 변할 때마다 이벤트를 발행한다.

이미지 생성 로그를 확인할 수도 있다.

이미지 레지스트리에 빌드가 가능한 가상 컴퓨팅 이미지가 올라간다.

결론

개발 아이디어의 결과를 결론짓기 보다는, AX시대의 개발 경험에 대한 내용으로 마무리하려고 한다.

개발자의 일하는 방식, 워크플로우가 완전히 바뀌었다. 내가 겪는 문제를 추상화된 문서와 지식 베이스를 검색하는 방식에서, LLM 이 문제를 직접 해결해주는 코드를 생성한다. 하지만 에이전트가 코드를 대신 작성하면, 개발자가 무엇을 해야할까. 코딩을 에이전트가 대신 해준다면 개발자는 뭘 해야 할까? 쇼츠에서 보듯 시켜놓고 핸드폰만 보고 있어야 할까 아니면 생성하는 과정을 단순히 구경하고 있어야 할까? 개발자는 작업 지시자에 가까워진다.

나는 워크플로우를 이해한 높은 수준의 의도와 인풋을 던지는 것이 결국 개발자가 가질 부분이라고 생각한다. 도구와 코드는 언제든 바뀔 수 있지만, 문제를 상태와 흐름으로 정의해 해결하는 설계 능력은 "설계하는 설계"를 만드는 기초 자산으로 남는다.