Atlassian을 K8s에 올리기로 한 이유는 무엇일까?
이 글은 "엔터프라이즈 JVM 애플리케이션의 Cloud-Native 전환기" 시리즈의 1편입니다.
프로젝트를 시작하게 된 계기
혹시 서버가 OOM으로 죽어, 원인 파악을 위해 며칠동안 로그를 분석한 경험이 있으신가요?
저는 Atlassian 솔루션 엔지니어로 일하면서 꽤 기억에 남는 장애를 몇 번 겪었습니다. 분산 클러스터 환경에서 정확히 1분 주기로 Full GC가 터지는 문제였는데, 처음에는 원인조차 잡기가 어려웠습니다.
서버에 직접 붙어서 GC 로그를 뒤지고, 메모리가 튀는 시점에 Heap Dump를 떠서 객체 참조 상태를 하나씩 분석하고 나서야 겨우 원인을 찾을 수 있었습니다.
알고 보니 매일 돌아가는 배치 스크립트에서 객체를 필요 이상으로 만들어내는 로직이 문제였습니다. 해당 부분을 리팩토링한 뒤에야 Full GC가 멈췄습니다.
그때 이런 생각이 들었습니다.
"컨테이너 환경에서 리소스 제한과 JVM 메트릭 모니터링이 갖춰져 있었다면, 이 문제를 훨씬 빨리 감지할 수 있지 않았을까?"
메모리 점유율이 85%를 넘는 순간 알림이 왔다면, Heap Dump를 뜨기 전에 미리 대응할 수 있었을 겁니다. 하지만 당시 운영 환경에는 그런 체계가 없었고, 사후에 문제를 분석하는 방식으로 대응할 수밖에 없었습니다.
이 경험이 이 프로젝트를 시작하게 된 직접적인 계기입니다. 2년 넘게 운영해온 Atlassian 시스템을 Kubernetes 위에 올리고, JVM 모니터링과 GitOps 배포 자동화까지 갖춘 환경을 직접 만들어보기로 했습니다.
왜 Atlassian 인가
"그냥 Spring Boot 예제 앱으로 하면 안 되나요?"라는 질문이 나올 법합니다.
저도 처음에 잠깐 그런 생각을 했지만, 생각할수록 Atlassian을 선택해야 할 이유가 더 많았습니다.
Atlassian 앱(Jira, Confluence)은 일반적인 웹 애플리케이션과 몇 가지 점에서 다릅니다.
- JVM 엔터프라이즈 앱 특유의 까다로움을 직접 다룰 수 있습니다
Jira, Confluence 같은 Atlassian 앱은 힙 메모리를 수백 MB에서 수 GB 단위로 사용합니다. GC 튜닝이 성능에 직접적인 영향을 주는 환경이에요.
컨테이너 환경에서 JVM 메모리 설정을 잘못하면 OOM Killer에 의해 컨테이너가 조용히 죽어버리는 상황도 발생합니다. 이런 문제를 직접 다뤄보고 싶었습니다. - Shared Home 구성으로 스토리지 경험까지 쌓을 수 있습니다
여러 노드가 동일한 파일 시스템을 공유해야 하기 때문에, 단순히 컨테이너를 올리는 것 이상으로 스토리지 구성을 신경 써야 합니다. NFS나 EFS 같은 공유 스토리지 설정 경험을 쌓을 수 있습니다. - 2년 넘게 직접 운영해온 시스템입니다
어떤 상황에서 장애가 나고, 어떤 설정이 중요한지 몸으로 익힌 시스템입니다. 처음 보는 앱을 가져다 쓰는 것보다 훨씬 의미 있는 시행착오를 할 수 있다고 판단했습니다.
환경 제약과 기술 선택
로컬 환경이 Mac M3 Pro(18GB RAM)이다 보니 몇 가지 제약이 있었습니다.
ARM 아키텍처 — GitLab을 SaaS로 우회한 이유
처음에는 GitLab을 K8s에 직접 올리려 했으나, GitLab의 Kubernetes 이미지가 aarch64(ARM)를 아직 완전히 지원하지 않습니다. 억지로 올리는 방법이 없진 않지만, 그 과정에서 시간을 낭비하는 건 비효율적이라고 판단했습니다.
그래서 gitLab.com(SaaS)을 외부 CI/CD 도구로 연결**하는 방향으로 설계를 바꿨습니다. 실제 기업 환경에서도 외부 SaaS와 내부 클러스터를 연동하는 방식을 많이 씁니다. 오히려 더 현실적인 아키텍처라고 생각합니다.
OrbStack과 k3s — 메모리를 아끼기 위한 선택
가상화 도구는 OrbStack을 선택했습니다. Docker Desktop 대비 메모리 사용량이 훨씬 적고, M3 환경에서 안정적으로 동작합니다. Atlassian 앱이 JVM 메모리를 많이 잡아먹는 만큼, 가상화 레이어에서 메모리를 아끼는 게 중요했습니다.
K8s 배포판은 k3s를 선택했습니다. 정식 K8s는 컨트롤 플레인 구성 요소만으로도 상당한 메모리를 잡아먹지만, k3s는 단일 바이너리로 훨씬 가볍게 동작합니다.
나중에 AWS EKS로 전환하면서 무엇이 달라지는지 비교하는 것 자체도 좋은 학습이 될 것 같았습니다.
전체 아키텍처
이 프로젝트는 세 단계로 나눠서 진행합니다. 로컬에서 충분히 테스트를 진행한 다음, 클라우드로 올리는 흐름입니다. 로컬에서 설계 실수를 충분히 반복하고 나서 클라우드로 올리면 비용 낭비 없이 테스트를 할 수 있기 때문에, 아래의 순서로 진행하려고 합니다.
┌─────────────────────────────────────────────┐
│ 1부. 로컬 환경 (Mac M3 + OrbStack) │
│ │
│ Rocky Linux 9 (Ansible 프로비저닝) │
│ ↓ │
│ k3s 클러스터 │
│ ├── MetalLB (로드밸런서) │
│ ├── NGINX Ingress │
│ ├── Atlassian (Jira, Confluence) │
│ ├── PostgreSQL │
│ ├── NFS Server (Shared Home) │
│ ├── ArgoCD + Helm (GitOps) │
│ └── Prometheus + Grafana + JMX Exporter │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 2부. CI/CD 및 워크플로우 │
│ │
│ GitLab.com (SaaS) │
│ ├── 소스 코드 관리 │
│ ├── CI/CD 파이프라인 (.gitlab-ci.yml) │
│ └── Jira 이슈 연동 (변경 배포 프로세스) │
└─────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────┐
│ 3부. AWS EKS 전환 │
│ │
│ Terraform (IaC) │
│ ├── VPC, EKS 클러스터 │
│ ├── RDS (PostgreSQL → Managed) │
│ ├── EFS (NFS → Managed) │
│ ├── ALB + Route53 (MetalLB+NGINX → Managed)│
│ └── 전체 스택 EKS 이전 │
└─────────────────────────────────────────────┘
기술 선택 이유
나중에 “왜 이걸 썼나요?” 라는 질문에 대답할 수 있어야 하기 때문에, 각 기술을 선택한 이유를 정리해두겠습니다.
k3s — 로컬 메모리를 아껴야 했습니다. 프로덕션 환경이 아닌 학습 목적이니 가벼운 배포판을 선택하는 게 맞습니다.
ArgoCD — Git에 정의된 상태와 클러스터 실제 상태를 지속적으로 비교하고 자동으로 동기화합니다. Helm만 쓰면 이 보장이 없습니다. GitOps 패턴을 직접 경험해보고 싶어서 선택했습니다.
Ansible — 노드를 날리고 다시 세울 때 동일한 환경을 보장합니다. 수동 설치는 반드시 "왜 이 환경에서만 되는 거지?" 하는 상황을 만들어냅니다.
Terraform — AWS 인프라를 코드로 관리합니다. terraform destroy로 내리고 terraform apply로 다시 올리는 방식으로 EKS 비용을 제어할 계획입니다.
이 프로젝트가 추구하는 것
이 프로젝트의 목표는 "Atlassian을 K8s에 올리는 것" 자체가 아닙니다.
실무에서 운영하던 시스템을 Cloud-Native 환경으로 전환하는 전체 과정을 직접 경험하는 것입니다. 로컬에서 삽질하고, CI/CD를 붙이고, 클라우드로 이전하는 과정에서 배우는 것들을 최대한 날것 그대로 기록할 예정입니다.
완성된 결과물보다 과정에서 막혔던 부분들이 더 도움이 된다고 생각하거든요.
다음 편에서는 Rocky Linux + Ansible로 노드를 프로비저닝하는 과정을 다루겠습니다. 막히는 부분이 많을수록 글이 풍성해진다는 마음으로, 천천히 기록해 나가겠습니다. 🙂
'프로젝트 > 엔터프라이즈 JVM 애플리케이션의 Cloud-Native 전환기' 카테고리의 다른 글
| 3-2. ArgoCD로 GitOps 배포 파이프라인 구축하기 (0) | 2026.05.06 |
|---|---|
| 3-1. Helm으로 ArgoCD 설치하고, Ansible로 자동화하기 (1) | 2026.04.29 |
| 2-2. ansible-playbook 역할 기반으로 재구성하기 (0) | 2026.04.22 |
| 2-1. OrbStack + Ansible로 k3s 클러스터 구축하기 (0) | 2026.04.08 |