Project Nexus: Docker를 넘어, 진짜 인프라로

불완전 연소된 ProtoStar를 살리고 다음을 준비하기 위한 플레이그라운드의 필요성, 3년차 개발자 수준의 인프라 역량을 만드는 여정


출발점: 불완전연소된 ProtoStar 그리고…

1년차 메인 서버 개발자로 역할을 수행했다. 그리고 이젠 3년차 개발자의 역량을 갖추어야 다음 도전이 가능하리라 생각하고 있었다. 그런데 AI는 여기서 한 발 더 나아가, 개발자에게 요구되는 역량을 크게 변화시켰다.

그 점을 고려하지 않는다면 생존에서 불가피할 것이라는 생각을 하였고, 결과적으로 AI 와 DevOps 의 역량을 갖추고, 백엔드 개발자로서 제대로된 인프라를 구축하는 역량을, 소프트웨어 아키텍처이자, 오케스트레이터가 되어야 한다고 판단했다.

그리하여 토스 러너스 하이 2기와 함께 시작한 Protostar 프로젝트는 나름 성공적이었다. Next.js 기반의 프론트엔드-챗봇을 구현하고, 백엔드는 Nest.js, FastAPI 를 이용하며 고가용성 체계를 구축하는 과정은 확실히 단순한 백엔드 설계를 넘어서는 여러 도전 요소들을 갖고 있고, 그 결과가 현재 블로그 상에 올라가 있는 챗봇이다.

자못 훌륭하며, 개인적으로 1달이란 시간에 이걸 했다는 사실은 자부심을 가지기에 충분하지 않을까? AI도 DevOps 도 백엔드 설계 역량도 보여줄 수 있는 것들이 있었으니, 자랑스럽게 자랑을 인터뷰 상에서 할 수 있다면 좋겠다 생각한다.

하지만 한편으로 아쉬움은 있다.

기획의 한계, 고려사항들이 있단 점에서 온전한 서비스로의 확장은 포기했다-는 점은 제외하더라도, 기술적 아쉬움, 특히 DevOps 경험에 대한 아쉬움이 크게 남았다.

k8s 방식을 정복할 시간이 부족해 포기했다. 또한 무엇보다 Docker 로 구현 시 안되는 건 없지만, 그렇다고 ‘온전하게’ 유기적으로 동작하지 않는다고 느낀 부분들이 있었다. Docker Swarm, ReplicaSet 등을 기반으로 고가용성을 구현할 순 있다. 하지만 한계는 명백했다. k8s 를 선택했을 때 얻을 수 있는 이점에 대해 다시 한 번 떠오르게 되었다.

뿐만 아니라 온프레미스 서버에 약 100여만원을 투자하여 나만의 홈랩을 꾸미게 되면서 깨달은게 있다.

실무 경험이 중요한 이유는, 실무 수준에서의 책임감, 안정성, 고려할 사항 등, 단순히 개인의 자그마한 데모 수준에서는 알 수 없는 ‘실무의 깊이’와 ‘실무의 너비’가 존재한다. 그런 점에서 인프라를 개인의 신분으로 지원 없이 AWS, GCP 등에 올린다면? 유료 사용에서 한계가 발생하고, 할 수 있는 수준의 제약이 발생했을 것이다.

그런데 홈랩으로 꾸미게 되면서, 그러한 한계가 상당 부분 사라졌다. 결국 ‘규모의 경제’는 곧 경험인 것이다.

덕분에 과감히 인프라 선택이 가능하고, 효과적으로 기술을 적용할 수 있었다. 그렇다면 할 일은 무엇인가? 그건 결국 ‘앞으로 가는 것’ 아니겠는가? 결국 인프라는 있으니 더 명료하게 IaC(Infrastructure as Code)를 구현하고, 내가 경험할 수 있는 최선의 인프라 위에서 또 다른 도전을 해야 그게 진짜가 되지 않을까?

그런 점에서 나만의 플레이그라운드, 기반이 필요하다고 판단했다. 그것이 Nexus(기반), 완전한 k8s 기반의 GitOps 서버 클러스터 구축 프로젝트이다.


깨달음: 지향할 푯대는 어디로 향하는가?

Docker만 쓰던 시절의 한계

Docker는 훌륭한 도구다. 메인 서버로 1년 간 살면서, Docker 로 옮긴 레거시 서버들은 덕분에 엄청난 포텐셜을 얻었고, 최적화, 관리 편의성을 얻었기에 지금의 내 경험, 이력을 만들 수 있었다고 해도 과언이 아니다. 그런 점에서 서비스를 바로 시작하기에 Docker 만한 컨테이닝은 없다고 생각한다.

하지만 막상 ‘고가용성’이란 목표를 지향했을 때 Docker 는 굉장히 아쉬움을 불러일으켰다.

  1. 데몬에 종속된 구조: dockerd가 죽으면 모든 컨테이너가 영향을 받는다. 단일 장애점(SPOF)이 존재한다는 점은 고가용성을 생각할 때, 문제였다. 하나의 컨테이너가 과도한 사용량을 차지하게 되었을 때, 전체 시스템은 문제가 발생한다. AWS 에서 인스턴스를 여러개 분산하는 대안도 있다. 그러나 이는 또 다른 복잡도의 서막이며 대안이 되진 못했다. 어디까지나 보완책이었다.
  2. 보안 취약성: 기본적으로 root 권한이 필요하다는게 생각보다 큰 부담이었다. rootless 모드는 있지만 2차 시민 취급이었다. 또한 이러한 보안 이슈로 공식 이미지들 마다 다르게 권한이 설정되는 등으로 문제가 되었다.
  3. k8s와의 괴리감: Docker Compose로 개발하고, k8s YAML로 배포한다? 로컬과 프로덕션 환경이 달라지고 이는 완벽하지 않은 환경 통제였다. ‘완벽함’이 필요한 백엔드 환경 구축에서 한 점의 오차는 ‘아마추어’란 사실을 증명하는 꼴이라고 생각이 들었다. 플랫폼이 다르면 증상도 달라지고, 특히 이전 후기에서도 다뤘듯, 각 개별 설계가 의존성이 없어도, 관계의 통합은 의존성을 만들고 새로운 증상을 유도한다.
  4. 스크립트 단위의 파편화된 관리 구조: Dockerfile, docker-compose.yml, Jenkinsfile, 쉘 스크립트 등, CI/CD 파이프라이닝을 구축해보고 얻은 결론은 명확했다. 각각 분리되어 각 역할을 보기엔 명료해보이고 유기적이게 보인다. 하지만 반대로 그렇기에 한 곳을 수정하면 예상하지 못한 곳의 문제가 발생할 수 있고, 이는 결국 ‘단독’으로 볼 때만 ‘희극’이며 ‘전체’를 볼 땐 ‘비극’이었다.
  5. 상태관리의 어려움: PostgreSQL 이나, Redis, 모니터링 등의 Stateful 서비스에 대한 백업/ 복구 전략에서 수동으로 해야 하는 영역이 존재하며, 고가용성 구성이 상당히 복잡했다.

엔터프라이즈 환경에서 요구하는 역량

AI를 기반으로 약 100개 정도의 주요 기업들의 백엔드 엔지니어 직군의 공고문을 딥리서치 해보았다. 내가 3년차 수준을 인정 받길 원한다면 단순히 “Docker 써봤어요”로는 부족했다. 이를 압축해서 정리하면 다음과 같았다.

  • 컨테이너 오케스트레이션: Kubernetes를 실무에서 사용할 수 있고, 이를 기반으로 서비스의 생명주기 제어가 가능한가?
  • 보안 의식: 특히 최근의 중요사항이자, 국내에서도 중요해지고 있는 영역으로 서버들 사이의 격리가 명료한가? rootless 컨테이너, 권한 분리, 이미지 스캐닝의 경험이 있는가?
  • 자동화: CI/CD 파이프라인의 현대화, GitOps, 롤링 업데이트 등을 통해 서비스의 무결성이 확보되는가? 개발 생산성을 확보 하는가?
  • 관찰성: 메트릭, 로그, 추적 시스템 구축하여 운영 문제를 소프트웨어 엔지니어링 방식으로 해결할 수 있는가? SRE(Site Reliability Engineering) 방식으로 대규모 시스템의 안정성, 확장성, 가용성을 극대화 가능한가?

결국 안정성, 효율성, 운영 최적화된 역량이 필요했다. 이러한 영역에 대한 나만의 답이 필요했고, 결국 내가 생존하기 위하여 필요한 ‘전문성’이란 무엇인가를 명확하게 정리할 수 있었다.


전략: ‘초’ 현실주의

온프레미스 서버를 프로덕션 클러스터로

보다 현실적이게 짜야 한다고 생각했다. 연습용의 minikube 정도가 아니라 프로덕션처럼 운영을 위한 구성과 실천이 되어야 한다고 판단했다. 오버 엔지니어링, 허세를 하고 싶단 말은 아니다. 현실적으로 과도하지 않으면서도 진짜 엔터프라이즈급을 지향해본다는 그 벨런스를 중요시했다. 향후 더 많은 기술의 플레이그라운드 만들기를 지향한다.

Protostar가 구동 중인 서버 어플리케이션들은 현재 두 대의 온프레미스 서버에서 동작하고 있다. 메인 서버는 서비스를, 서브 서버는 모니터링 / 빌드 및 배포 파이프라인을 담당하고 있다.

여기서 단순히 k8s 를 위한 플랫폼을 설치, k8s 용 스크립트 작성을 해도 되지만… 보다 현실적이고, 무엇보다 IaC 를 극대화하기 위해선, 온프레미스 서버들이 마치 하나처럼 동작하게 만드는 것이 반드시 필요하다고 생각했다.

결론적으로 계획은 이렇다:

  • 개발용으로는 단일 개발 PC에서 작업하여 Podman 기반으로 Docker-free 를 달성.
  • Production 은 두 개의 온프레미스 서버에 k3s 기반 Kubernetes 클러스터링을 한다. namespace 를 기반으로 역할을 설정한다. 즉, 한 대 같은 두 대를 만들고, 각 영역은 ‘목적’을 포함시킨다.
  • 현재 가동 중인 ProtoStar 서비스를 이 환경으로 완전히 마이그레이션한다.(서비스 + 모니터링 스택)
  • 위의 작업들의 종결 이후, 새로운 서비스들 역시 여기서 동작하며, 테스팅 되며, 배포 된다.

로컬에서 프로덕션까지 일관된 환경

가장 중요한 원칙: 로컬 개발 환경과 프로덕션 환경을 최대한 비슷하게 만들어내는 것이다.

기존 방식:

로컬 / 프로덕션: Docker Compose 기반, Jenkins 파이프라이닝 때문에 환경변수를 비롯 차이점 있음
→ 환경이 달라서 "내 컴퓨터에선 되는데요?" 발생, 결과적으로 이미지 차원의 변경 발생 시 2회 적용 되어야 함

새로운 방식:

로컬: Podman + k8s YAML
프로덕션: k3s + k8s YAML
→ 같은 YAML 파일을 로컬과 클러스터에서 모두 사용

Podman의 podman play kube 명령어를 쓰면 k8s YAML을 로컬에서도 그대로 실행할 수 있다. 이게 핵심이다.

계획

무작정 달려들기보단, AI 를 기반으로 구현할 항목들을 정리했고, 목표를 지정하였다. 이직 일정과 겹쳐 딜레이가 발생할 순 있으나 최대한 현실적으로 설정해보았다.

Phase 1 (1주): 도구 전환

  • Docker → Podman 로컬 개발 환경 전환
  • 기존 Dockerfile이 Podman에서도 돌아가는지 검증
  • rootless 환경의 포트 바인딩 제약 해결 (80 → 8080)

Phase 2 (0.5주): k8s 기초

  • k3s 클러스터 구축
  • Pod, Deployment, Service 개념 실습
  • kubectl 명령어 익히기

Phase 3 (0.5주): Dev 환경에 Stateless 서비스 먼저

  • React, NestJS 같은 무상태 서비스부터 배포
  • 실패해도 재배포하면 끝이라 학습 비용이 낮음
  • 서비스 간 통신 (k8s 내부 DNS) 이해

Phase 4 (0.5주): Dev 환경에 Stateful 서비스 마이그레이션 해보기

  • PostgreSQL, Redis 같은 상태 저장 서비스
  • StatefulSet, PersistentVolume 개념
  • 데이터 백업/복구 전략 수립

Phase 5 (1주): 자동화와 관찰성

  • ArgoCD 기반 GitOps CI/CD 파이프라인 구축
  • Prometheus + Grafana 모니터링 스택

Phase 6 (1주): Production 마이그레이션

  • 지금까지의 실습을 모두 클러스터링 된 온프레미스 서버로 일체 이전한다.

도구: 왜 이 스택인가

Podman: 보안과 확장성

선택 이유 세 가지:

  1. Rootless가 기본: 일반 사용자 권한으로 컨테이너 실행. 보안 침해 시 피해 범위가 제한된다.
  2. Daemonless 아키텍처: 중앙 데몬 없이 각 컨테이너가 독립적으로 실행. dockerd가 죽어서 전체가 멈추는 일이 없다.
  3. Pod 네이티브 지원: k8s Pod 개념을 로컬에서도 그대로 사용 가능. 같은 Pod 안의 컨테이너끼리 localhost로 통신한다.

리스크:

  • 커뮤니티가 Docker보다 작아서 문제 발생 시 레퍼런스가 적을 수 있음
  • 일부 Docker 전용 도구와 호환성 이슈 가능 (예: Docker Desktop 기능들)

Kubernetes (k3s): 업계 표준

선택 이유 세 가지:

  1. 업계 표준: 대부분의 엔터프라이즈 환경이 k8s를 사용. 실무 경험으로 직결된다.
  2. 선언적 구성: YAML로 원하는 상태를 선언하면 k8s가 알아서 그 상태를 유지한다.
  3. 확장성: 단일 노드에서 시작해도 나중에 멀티 클러스터로 확장이 자연스럽다.

k3s를 선택한 이유:

  • 표준 k8s보다 가볍고 빠름 (메모리 사용량 절반)
  • 온프레미스 환경에 최적화
  • Traefik Ingress가 기본 내장

리스크:

  • 학습 곡선이 가파름. Pod, Deployment, Service, Ingress 등 개념이 많음
  • 초기 설정이 복잡할 수 있음

GitOps (ArgoCD): 자동화와 추적성

선택 이유 세 가지:

  1. Git이 진실의 원천: 모든 배포 상태가 Git 저장소에 기록됨. 언제든 이전 상태로 롤백 가능.
  2. 자동 동기화: Git에 푸시하면 자동으로 클러스터에 반영. 수동 배포 작업 제거.
  3. 가시성: 무엇이 언제 누구에 의해 배포되었는지 명확하게 추적 가능.

리스크:

  • 초기 설정이 복잡할 수 있음
  • Git과 클러스터 상태가 어긋날 경우 디버깅이 어려울 수 있음

마무리: 왜 이 여정이 중요한가

이 프로젝트는 단순히 기술 스택을 바꾸는 것이 아니다. “할 줄 안다”에서 “제대로 한다”로의 전환을 생각하고 있다.

Docker Compose로 띄우는 것과 k8s 클러스터를 운영하는 것은 완전히 다른 차원이다. 전자는 개발자의 편의를 위한 도구이고, 후자는 프로덕션 환경을 위한 플랫폼이다.

ProtoStar는 더 이상 불완전연소된 프로젝트가 아니라, 이제 내가 엔터프라이즈급 인프라를 구축할 수 있다는 것을 증명하는 살아있는 증거가 되도록 만들고 싶다. 또한 AI가 개인이 할 수 있는 영역을 극대화 시켜줄 것이니 Nexus 는 그 토대가 될 것이다. 내가 만들 다양한 어플리케이션들의 토대가 되어줄 것이다. 십년의 대장정의 모험이 있다고 하면, 그 기반 중에 기반이 되리라 생각한다.

경험이 현실이 되고, 현실이 직무가 된다. 단순히 개발자라고 불리고 싶진 않다. ‘전문가’가 되어 회사의 시스템들의 운용을 정말 ‘현실적으로’ 해내길 원한다. 그 초석을 만들고 싶다.