그린 파인애플님의 블로그
[ERP 구축기 #11] Git Push에서 Kubernetes 배포까지 — GitOps 파이프라인 구축기 본문
[ERP 구축기 #11] Git Push에서 Kubernetes 배포까지 — GitOps 파이프라인 구축기
그린 파인애플 2026. 9. 22. 22:06웹 애플리케이션 개발이 어느 정도 마무리되면서 이제는 개발한 서비스를 어떻게 배포하고 운영할 것인가를 고민해야 했다.
지금까지 여러 프로젝트를 경험하면서 Spring Boot 내장 Tomcat으로 애플리케이션을 직접 구동하는 방식부터 JEUS와 같은 상용 WAS, Jenkins를 이용한 배포 자동화, Kubernetes 기반의 운영 환경까지 여러 가지 방식을 접해봤다.
Spring Boot 내장 Tomcat만으로 운영하면 구조가 단순하고 관리하기도 편하지만, 배포 과정에서 서비스 중단이 발생할 수 있고 향후 이중화나 무중단 배포 환경을 구성하려면 추가적인 고민이 필요했다.
JEUS와 같은 상용 WAS를 도입하는 방법도 있었지만, 현재 서비스 규모에 비해 라이선스와 운영 비용이 부담스러웠다.
Docker Compose를 이용해 애플리케이션을 이중화하고 Nginx를 이용해 LB로 이중화하여 운영하는 방법도 검토했다.
현재 규모만 생각하면 충분히 괜찮은 방법이었지만, 앞으로의 서비스 확장과 무중단 배포, 장애 발생 시 자동 복구(Self-Healing), 선언형 배포 관리, 모니터링 환경 확장까지 고려하면서 Kubernetes 기반으로 운영 환경을 구성해보기로 했다.
다만 현재는 소규모 내부 서비스인 만큼 처음부터 무거운 Kubernetes 환경을 구성하기보다는 상대적으로 가볍게 운영할 수 있는 k3s를 선택했다.
개인적으로도 평소 Kubernetes에 관심이 있어 따로 공부하면서 CKA(Certified Kubernetes Administrator) 자격증까지 취득했다. 하지만 개발과 인프라의 업무 영역이 명확하게 분리된 환경에서는 공부하면서 배운 내용을 실제 서비스에 처음부터 직접 적용해볼 기회가 없었다
이럴 때 아니면 언제 해보겠어? 이번기회에 개발부터 배포, 운영 인프라까지 직접 구축해보자!
라는 생각도 들어 이번 기회에 단순히 Kubernetes에 애플리케이션을 올리는 것에서 끝내지 않고, Jenkins와 Argo CD를 이용한 GitOps 기반의 배포 환경까지 직접 구축해보기로 했다.


내부 시스템이다보니 최소한의 관리포인트로 안정적인 인프라를 만들기 위해 이것저것 찾아보았고
gitOps 구축을 위해 github, jenkins, k3s, argoCD 를 이용하기로 했다
Jenkins만으로도 이미지 빌드부터 Kubernetes 배포까지 구성할 수 있지만, CI와 CD의 역할을 분리하고 Git에 정의된 배포 상태를 기준으로 Kubernetes 환경을 편하고, 일관되게 관리하기 위해 Argo CD를 구축을했다
Jenkins는 소스 빌드와 컨테이너 이미지 생성 및 GHCR Push까지 담당하고, Argo CD는 Git에 정의된 Helm 배포 구성을 기준으로 실제 Kubernetes 클러스터의 상태를 동기화하도록 구성했다
컨테이너 이미지 관리도 클라우드를 이용한다면 ECR(Elastic Container Registry) 을 이용하면 간단했지만 물리서버를 이용해야하는 환경이었기에 harbor, docker hub등을 고려했으나 프로젝트 규모와 운영 환경을 고려했을 때 별도의 Registry 서버를 운영하기보다 GitHub Container Registry(GHCR)를 활용하는 것이 관리와 비용(무료) 측면에서 효율적이라고 판단했다

kustomize, helm 중 어떤걸 사용할까 고민을 하다가 향후 AI관련 애플리케이션뿐만 아니라 PostgreSQL, Valkey, 모니터링 Stack 등 다양한 Kubernetes 리소스를 동일한 방식으로 패키징하고 환경별 설정을 관리하기 위해 Helm을 선택했다.
🛠️ Application Repository와 Infrastructure Repository를 분리관리
Jenkins로 이미지 빌드가 되도록 pipeline을 구축했고, 플랫폼 인프라를 관리하는 repo를 별도로 만들어서 물리서버가 다운되어서 사용을 못하거나 클라우드로 이전을 고려하여 빠르게 재구축을 할수 있도록 했다

🛠️ 빠른 배포를 위한 빌드시 병렬 처리와 캐싱 적용
배포를 하면서 이미지 빌드를 할때 매번 docker hub에서 이미지를 여러가지 당겨오다보니 빌드시간이 오래걸렸고, 그만큼 네트워크 대역폭도 많이 차지했기에 개선할 방법을 찾아보았다
1.다운로드 받아야할 이미지를 1개의 기초 이미지로 통합하여 만들고, jdk와 node 버전을 변경해야할때만 따로 빌드해서 사용하기로 했고 만들어진 이미지와 의존성이 있는 패키지들은 캐싱 pvc를 만들어서 담아두고 빌드를 하도록 했다
2.웹앱의 프론트와 백엔드 빌드시 병렬로 빌드가 되게 했으며
stage('06. Build and Push Images') {
parallel {
stage('Backend Image') {
when {
anyOf {
expression { params.COMPONENT == 'All' }
expression { params.COMPONENT == 'Backend' }
}
}
steps {
container('buildkit') {
sh '''
buildctl-daemonless.sh build --frontend dockerfile.v0 \
--local context=cheil_be --local dockerfile=cheil_be \
--import-cache type=registry,ref=${BACKEND_IMAGE}:buildcache \
--export-cache type=registry,ref=${BACKEND_IMAGE}:buildcache,mode=max \
--output type=image,name=${BACKEND_IMAGE}:${IMAGE_TAG},push=${PUSH_IMAGES}
'''
}
}
}
stage('Frontend Image') {
when {
anyOf {
expression { params.COMPONENT == 'All' }
expression { params.COMPONENT == 'Frontend' }
}
}
steps {
container('buildkit') {
sh '''
buildctl-daemonless.sh build --frontend dockerfile.v0 \
--local context=cheil_fe --local dockerfile=cheil_fe \
--import-cache type=registry,ref=${FRONTEND_IMAGE}:buildcache \
--export-cache type=registry,ref=${FRONTEND_IMAGE}:buildcache,mode=max \
--output type=image,name=${FRONTEND_IMAGE}:${IMAGE_TAG},push=${PUSH_IMAGES}
'''
}
}
}
}
}
3.Pod에는 liveness/readiness probe를 적용하여 애플리케이션 상태를 지속적으로 확인하고, 비정상 상태의 컨테이너는 자동으로 재시작되도록 구성했다.
또한 신규 버전 배포 과정에서 정상적으로 기동되지 않는 경우 이전 버전으로 자동 Rollback 되도록 구성했다
이렇게 적용후 코드에 문제가 있어서 배포가 실패했을때 빠른 원복, 빌드할때는 4~5분정도 소요되던 시간을 절반가량 단축할수 있었다

🛠️ 일관된 운영 및 배포를 위한 ArgoCD
argoCD에서는 웹앱을 배포하고 관리할수 있도록 구성을 했고, 서비스 인프라에 문제가 있을때 SSH로 연결하여 명령어로 작업을 진행해도 되지만
웹앱 뿐만 아니라 PostgreSQL, Valkey, Grafana Stack 등의 Kubernetes 리소스도 Helm으로 관리하고 Argo CD에 등록하여, Git에 정의된 구성과 실제 클러스터 상태를 한 곳에서 확인하고 관리, 동기화할 수 있도록 구성했다.


서비스 사용자가 많아질 경우 pod 증설도 빠르게 할수 있는것도 테스트를 진행했고, blue/green 배포, rollback도 정상적으로 되는걸 확인했다
🛠️ Jenkins에서 SSL인증서 갱신 간편화
HTTPS 이용을 위해서는 주기적으로 SSL인증서 갱신을 해야한다
외부CA기관에서 발급받은 인증서를 사용하는 경우 자동 갱신이 어려웠기 때문에, PEM 인증서와 Private Key를 Jenkins Parameter로 전달하면 Kubernetes TLS Secret을 누구든 간편하게 갱신할 수 있도록 별도의 jenkins Job을 구성했다.


📕 쿠버네티스 기반 인프라와 gitops를 직접 구축해보며...
변경된 코드를 Push하는 것부터 이미지 빌드, Registry 저장, Kubernetes 배포까지 직접 구성하면서 개발뿐만 아니라 실제 서비스를 운영하기 위해 필요한 인프라 구조를 경험할 수 있었다.
특히 개발과 인프라를 함께 운영해야 하는 환경이다 보니 반복적으로 해야 하는 작업을 최대한 자동화하는 방향으로 구축했다.
GitHub → Jenkins → GHCR → Argo CD → k3s로 이어지는 배포 Pipeline을 구성하고, Helm을 이용해 애플리케이션과 인프라 구성을 코드로 관리했다. 여기에 Grafana 모니터링과 Alertmanager 알림, 인증서 관리까지 추가하면서 작은 규모지만 개발부터 배포와 운영까지 이어지는 환경을 직접 구축할 수 있었다.
아직 개선할 부분은 많지만 앞으로 실제 서비스를 운영하면서 필요한 도구들을 하나씩 추가해보고, 장애 대응과 모니터링 경험도 함께 쌓아보려고 한다.
'개발 > [ERP] 풀스택 AI개발' 카테고리의 다른 글
| [ERP 구축기 #10] 경력증명서 입력만 몇 시간? PDF 파싱으로 DB 입력 자동화하기 (0) | 2026.09.15 |
|---|---|
| [ERP 구축기 #09] Redis 캐싱 대체용으로 적용한 Valkey (0) | 2026.09.14 |
| [ERP 구축기 #08] 엑셀과 전화로 관리하던 기술인 교육관리를 알림 발송으로 자동화하기 (0) | 2026.09.04 |
| [ERP 구축기 #07] 양식이 제각각인 HWPX 문서를 자동 생성해 비용 절감하기 (0) | 2026.09.04 |
| [ERP 구축기 #06] 반복되는 API 호출 줄이기 - Redis와 React Query 캐싱 (0) | 2026.08.28 |