안녕하세요, 오늘은 Continuous Integration / Continuous Deployment (CI/CD) 자동화 개선 여정에 대한 글을 소개드립니다. 기존의 Jenkins 중심 배포 방식에서 Kubernetes(k8s에 대한 더 자세한 포스트는 1,2,3 앞선 포스트 참고해주세요!), Helm, 그리고 Argo CD를 활용하여 더욱 안정적이고 자동화된 배포 환경을 구축한 과정인데요. 어떤 문제를, 어떻게 해결했는지 단계별로 살펴보겠습니다.
CI/CD란?
CI는 Continuous Integration(지속적 통합), CD는 Continuous Deployment(지속적 배포)의 약어입니다. 소프트웨어 개발 및 배포 프로세스를 자동화하는 방법론입니다.
- CI: 개발자가 코드 변경 사항을 자주 병합할 수 있도록 자동으로 빌드, 테스트 하는 과정
- CD: 새로운 코드 변경 사항을 자동으로 운영 환경에 배포하는 과정으로 보다 빠르고 안정적으로 애플리케이션을 제공하도록 지원
CI/CD를 도입하면 코드 변경이 빠르고 안정적으로 반영될 수 있어, 배포 속도 향상, 오류 감소, 그리고 운영 부담을 최소화 할 수 있습니다.
도입배경
기존에 배포방식은 Jenkins 중심으로 CI/CD 파이프라인을 운영했습니다. Jenkins는 오픈소스 자동화 서버로, CI/CD 파이프라인을 구축하는 데에 많이 사용하지만, 점점 관리가 어려워져 여러가지의 문제점이 발생하게 되었습니다.
Jenkins의 역할 과부하
낮은 CD 자동화 수준
배포 중 Downtime 발생
운영 비용 상승
이러한 문제를 해결하기 위해 Kubernetes, Helm, Argo CD를 점진적으로 도입하며 배포 환경을 개선해 나갔습니다.
STEP 1: 기존 Jenkins 기반 CI/CD파이프라인
기본적인 CI/CD 프로세스는 Jenkins를 활용하여 다음과 같은 방식으로 구성되었습니다.

- 개발자가 코드 변경 사항을 로컬에서 커밋(commit) 및 푸시(push)
- Jenkins가 변경 사항을 감지하고 빌드(build) 수행
- Docker 이미지를 생성하여 Private Image Registry에 업로드
- 개발 서버의 Private Image Registry에 이미지 푸시(push)
- Jenkins가 배포 트리거(trigger deploy) 실행
- 개발 서버에서 새로운 이미지를 Pull 후 컨테이너로 배포 (SCMS, DCM, MariaDB)
- AWS ECR Private Registry에도 동일한 이미지 업로드
- AWS 서버의 ECS 클러스터에 배포 트리거 실행
- ECS에서 새로운 이미지를 Pull 후 컨테이너 배포 (SCMS, DCM, MariaDB)
✅ 결과 및 효과
Jenkins를 활용한 CI/CD 환경 구축으로, 코드 변경 사항이 커밋될 때마다 자동으로 빌드 및 배포가 이루어질 수 있었습니다. 또한, Private Image Registry와 AWS ECR을 활용하여 개발 서버와 AWS 서버에서 동일한 이미지를 사용할 수 있도록 구성함으로써 이미지 불일치 문제를 방지하고 운영 안정성을 높였습니다.
뿐만 아니라, 기존의 배포 방식에서 벗어나 ECS(Elastic Container Service)를 도입하여 컨테이너 기반 배포를 수행함으로써 운영 효율성을 개선하였습니다. 이를 통해 컨테이너 오케스트레이션을 보다 효과적으로 관리할 수 있었으며, 확장성과 유지보수성도 강화되었습니다.
❌한계점
기존 CI/CD 환경에서는 Jenkins가 CI와 CD의 대부분을 담당하여 역할이 과부하되고, CI/CD가 명확히 분리되지 않아 유지보수 부담이 증가하였습니다. 또한, Jenkins가 여전히 SSH를 통한 수동 배포 방식을 유지하고 있어 CD 자동화 수준이 낮았으며, 효율적인 배포 프로세스를 운영하기 어려웠습니다.
배포 과정에서도 도커 컨테이너를 중지 후 재시작하는 방식이 사용되면서, 서비스가 일시적으로 중단되는 다운타임(Downtime) 문제가 지속적으로 발생했습니다. 뿐만 아니라 AWS 리소스 사용량 증가로 운영 비용이 상승하였고, 비용 절감이 중요한 과제로 떠올랐습니다.
이러한 문제들을 해결하고 배포 자동화 환경을 구축하기 위해 Kubernetes를 도입하게 되었습니다.
STEP 2: k8s 도입 - 다운타임 없는 배포 구축
다운타임을 줄이고 배포 자동화를 강화하기 위해 Kubernetes (k8s)를 도입했습니다.
배포 프로세스가 아래와 같이 변경 되었습니다:

- Jenkins에서 Docker 이미지를 빌드하고 Private Image Registry에 업로드하는 과정은 1단계와 동일
- Private Image Registry를 Kubernetes 클러스터 내부에 배치
- Kubernetes가 배포 작업을 수행함 (기존 Jenkins의 역할 분리)
- Master 노드가 클러스터를 컨트롤하고, Worker 노드에서 애플리케이션 컨테이너(Pod)를 실행하는 구조로 구성
✅ 결과 및 효과
기존에는 AWS를 활용하면서 클라우드 리소스 비용이 지속적으로 증가했지만, 사내 서버에 Kubernetes를 구축하여 AWS 사용을 중지함으로써 비용 문제를 해결할 수 있었습니다.
또한 Zero Downtime 배포를 구현하였습니다. Kubernetes의 기본 배포 정책인 Rolling Update를 활용하면 기존 Pod을 유지한 상태에서 새로운 버전의 컨테이너로 점진적인 교체가 가능하므로 서비스가 중단 없이 지속적인 운영이 가능합니다.
이와 함께, CI/CD의 역할을 분리하여 운영 효율성을 높였습니다. 기존에는 Jenkins가 CI뿐만 아니라 배포(CD)까지 담당하여 과부하가 발생했지만, 이제는 Kubernetes가 배포를 직접 수행하도록 변경하여 CI/CD의 역할을 구분하고 배포 자동화를 더욱 강화할 수 있었습니다.
❌한계점
Jenkins가 여전히 배포 트리거 역할을 담당하고 있어, 아직 완전한 CD 자동화가 이루어지지 않았습니다 😢
STEP 3: Jenkins에 k8s 컨트롤 권한 부여

업데이트된 배포방식은 아래와 같습니다:
- Jenkins에 "Kubernetes Config"를 등록하여 컨트롤 권한을 부여함으로써 배포 방식을 더욱 효율적으로 개선함
- 기존에는 Jenkins가 SSH를 사용하여 원격 서버에서 배포 작업을 수행했지만, 이제는 kubectl 명령어를 직접 실행하여 Kubernetes에 배포할 수 있도록 변경
✅ 결과 및 효과
이로써 배포 자동화가 구현되었으며, Jenkins는 더 이상 SSH를 통해 수동 배포를 수행하지 않고 Controller 역할을 맡아 Kubernetes API를 직접 호출하여 배포를 진행할 수 있게 되었습니다. 이를 통해 보다 안정적이고 체계적인 자동화가 가능해졌습니다.
❌한계점
폐쇄망 환경에서는 Jenkins가 Kubernetes API에 접근할 수 없기 때문에 자동 배포가 불가능하다는 한계점이 존재합니다. 폐쇄망 내에서 Kubernetes를 운영하는 경우, Jenkins가 직접 배포할 수 없으므로 GitOps 방식(예: Argo CD) 또는 폐쇄망 내부에서 별도의 배포 시스템을 운영하는 방안을 고려해야 합니다.
STEP 4: Helm 및 Argo CD 도입
Helm은 k8s의 패키지 매니저로, Helm Chart라는 패키징 형식을 사용하여 애플리케이션 배포를 자동화함으로써 프로세스를 간소화 할 수 있습니다. Argo CD는 GitOps 방식을 지원하는 쿠버네티스 네이티브 CD 도구입니다. Argo CD는 Git 저장소를 지속적으로 모니터링하여, 변경사항이 감지되면 자동으로 배포를 수행하기 때문에 수동으로 배포 명령을 실행하지 않아도 CI/CD 완전 자동화가 됩니다.
폐쇄망 환경에서는 Bitbucket이나 GitHub와 같은 외부 호스팅된 Git 서비스에 접근할 수 없기 때문에, 내부에서 운영할 수 있는 독립적인 Git 저장소가 필요합니다. 따라서 내부에서 운영할 수 있는 오픈소스 Git 저장소인 Gitea
를 도입하여 프로젝트를 관리했습니다.

구현방식은 아래와 같습니다:
- Jenkins에서 Docker 이미지를 빌드하여 Private Image Registry에 업로드
- Argo CD가 Git 저장소(Gitea)를 지속적으로 모니터링
- 새로운 이미지가 Private Image Registry에 업로드되면, Argo CD가 이를 반영하도록 Git Manifest 파일을 자동 업데이트
- Argo CD가 Git 저장소의 변경 사항을 감지하면 자동으로 Kubernetes에 배포
Helm 차트 구성 예시
# Chart.yaml
apiVersion: v2
name: my-go-helm-chart
version: 0.0.1
# values.yaml
namespace: k8s-v5
name: my-go
app: my-go-app
ports:
port: 1323
targetPort: 1323
nodePort: 31323
replicas: 1
images:
repository: "xxx.xxx.xx.xx:32768/my-go"
tag: "latest"
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.name }}
namespace: {{ .Values.namespace }}
labels:
apps: {{ .Values.app }}
spec:
selector:
matchLabels:
app: {{ .Values.app }}
replicas: {{ .Values.replicas }}
template:
metadata:
labels:
app: {{ .Values.app }}
annotations:
rollme: {{ randAlphaNum 5 | quote }}
spec:
containers:
- name: {{ .Values.app }}
image: "{{ .Values.images.repository }}:{{ .Values.images.tag }}"
imagePullPolicy: Always
ports:
- containerPort: {{ .Values.ports.port }}
restartPolicy: Always
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.name }}
namespace: {{ .Values.namespace }}
labels:
app: {{ .Values.app }}
spec:
type: NodePort
selector:
app: {{ .Values.app }}
ports:
- protocol: TCP
port: {{ .Values.ports.port }}
targetPort: {{ .Values.ports.targetPort }}
nodePort: {{ .Values.ports.nodePort }}
위와 같이 values.yaml
에 설정된 변수를 활용하여, deployment.yaml
과 service.yaml
이 동적으로 설정되도록 구성하였습니다. 이를 통해 배포 환경을 Helm 차트를 통해 쉽게 관리하고, 변경 사항을 적용할 수 있습니다.
또한 Argo CD를 통해 업데이트 및 동기화(Sync) 과정을 확인할 수 있습니다.
아래 이미지에서는 Argo CD가 자동으로 애플리케이션을 최신 상태로 유지하는 과정을 보여줍니다.

아래 이미지는 Argo CD에서 관리하는 애플리케이션의 상태를 보여줍니다.
Pod의 실행 상태, 컨테이너 이미지 정보 등을 확인할 수 있습니다.

✅ 결과 및 효과
Helm을 활용해 애플리케이션 배포를 표준화하고, GitOps 기반의 Argo CD를 적용해 배포 자동화를 구축하였습니다. 이제 Jenkins는 CI(Continuous Integration)만 담당하고, CD(Continuous Deployment)는 Argo CD가 관리하도록 변경하여 CI/CD의 역할이 명확히 분리되었습니다.
이로 인해 Git 저장소의 변경 사항만으로도 자동으로 배포가 이루어지는 환경이 구축되었습니다.
❌한계점
Argo CD는 Git 저장소의 변경 사항을 감지하여 배포를 수행하기 때문에 Private Image Registry만 업데이트하는 것만으로는 배포가 자동으로 이루어지지 않습니다. 즉, 새로운 컨테이너 이미지가 등록되더라도 Git 저장소(Gitea)의 Manifest 파일이 함께 변경되지 않으면 Argo CD가 이를 인식하지 못해 배포가 트리거되지 않는 문제가 발생합니다.
이를 해결하기 위해 Argo CD Image Updater 플러그인을 추가로 도입했습니다.
STEP 5: Argo CD Image Updater 플러그인 도입
🧐 Argo CD Image Updater란? Argo CD Image Updater는 Argo CD에서 제공하는 플러그인으로 Private Image Registry에 새로운 이미지가 등록되면 이를 자동으로 감지하고, Git 저장소의 Manifest 파일을 자동으로 수정하고 이를 기반으로 배포를 트리거합니다.
구현방식은 아래와 같습니다:

- 새로운 컨테이너 이미지가 Private Image Registry에 업로드됨
- Argo CD Image Updater가 새로운 이미지 태그를 감지함
- Argo CD Image Updater가 Git 저장소의 Manifest 파일을 업데이트하여 최신 이미지 태그를 반영
- Argo CD가 Git 저장소의 변경 사항을 감지하고 자동으로 배포 트리거
- Kubernetes 클러스터 내에서 새로운 이미지로 재배포 진행됨
✅ 결과 및 효과
Argo CD Image Updater을 통해 Private Image Registry의 변경 사항을 자동으로 감지하고 Git 저장소의 Manifest 파일을 업데이트하는 방식으로 배포 자동화를 구현함으로써 운영 효율성을 높일 수 있었습니다.
이를 통해 운영자의 개입 없이 CI/CD를 자동화하여 배포 프로세스를 효율적으로 관리할 수 있고, Zero Downtime 배포가 가능해졌습니다. 또한, 폐쇄망 환경에서도 내부 Image Registry와 Git 저장소를 활용하여 안정적인 지속적 배포(CD)를 실현할 수 있게 되었습니다.
마치며... in conclusion
이번 개선을 통해 초기 배포 과정에서 발생한 문제를 해결했으며, 그 결과 CI/CD 자동화
, Zero Downtime 배포
, Kubernetes 환경 패키지화
, 폐쇄망 자동 배포
, 비용 절감
이라는 다섯 가지 주요 효과를 얻을 수 있었습니다.
특히, Helm과 Argo CD를 도입해 CI/CD의 역할을 분리하고 GitOps 방식으로 배포 프로세스를 관리하여 더욱 안정적이고 신뢰할 수 있는 배포 환경을 구축했습니다. 또한 AWS 같은 클라우드 서비스에 의존하지 않고 사내 서버 기반으로 자동화된 배포 프로세스를 운영하여 비용 절감 효과도 얻을 수 있었습니다.
앞으로도 확장성과 유지보수성을 지속적으로 강화하고, 더욱 안정적인 배포 환경을 만들어 나갈 계획입니다.
감사합니다!
V2X.Dev그룹 V2G.PnC팀 김혜민
📌 참고자료 References: