[devOps] 전통의 CICD 방식 vs CI-CD 분리 방식(GitOps)

ijnuyh·2025년 9월 25일

TIL

목록 보기
16/16
post-thumbnail

devops의 설명을 들으면서, 과거의 CI/CD 방식과 현재의 분리 방식이 나오게 된 차이를 작성해보겠다.

우선, 전통적 방식을 작성하자면

CI/CD

1. 개념

  • Jenkins가 모든 것을 직접 처리하는 Push 기반의 전통적인 CI/CD
  • Jenkins가 소스 코드를 빌드하고, 그 결과물(컨테이너 이미지)을 배포 명세서(deploy.yaml)에 직접 반영한 뒤, kubectl apply 명령어로 쿠버네티스 클러스터에 직접 밀어넣는(Push) 구조

2. 프로세스 흐름

- **빌드 및 이미지 생성**: 애플리케이션 코드를 빌드하고 새 버전의 도커 이미지를 만듭니다.
- **배포 파일 수정**: Jenkins 작업 공간(workspace) 내에 있는 `deploy.yaml` 파일의 이미지 태그를 새 버전으로 **임시 수정**을 진행한다.
- **직접 배포 (Push)**: Jenkins가 `kubectl apply` 명령어를 실행하여 수정된 명세서를 클러스터에 직접 적용하고 배포를 완료한다.

3. Dev에서의 단점

  • 형상 관리 부재가장 큰 문제. 
    deploy.yaml = 배포하기위한 명세. 이는 로컬에 있음. 그 형상에 대한 정보를 알 수 없음.
    배포에 사용된 deploy.yaml은 Jenkins 작업 공간에만 존재하며, 
    Git에 저장된 deploy.yaml은 여전히 이전 이미지 태그를 가리킵니다.
    이로 인해 Git과 실제 클러스터의 상태가 달라지는 '환경 드리프트(Environment Drift)' 발생.

  • 불명확한 진실의 원천(Source of Truth): 현재 클러스터에 배포된 버전이 무엇인지 확인하려면 kubectl 명령어로 직접 클러스터를 조회해야 합니다. Git 저장소는 더 이상 신뢰할 수 있는 정보 소스가 아닙니다.

  • 보안 취약점 : Jenkins가 쿠버네티스 클러스터를 직접 제어할 수 있는 강력한 권한(Credentials)을 가져야 함. Jenkins가 해킹당하면 전체 클러스터가 위험에 노출될 수 있습니다.

  • 복잡한 롤백: 이전 버전으로 롤백하려면 이전 Jenkins 빌드를 다시 실행하거나, kubectl rollout undo 같은 명령어를 수동으로 실행해야 합니다.
    과정이 복잡하고 실수가 발생하기 쉽습니다.

4. Ops에서의 단점

사실 이 방식의 가장 큰 단점은, 운영 (Devops의 ops)에서의 차이인데,
운영을 하면서 진행하면서 시스템이 안정적이고, 신속하게 장애를 대응해야합니다.

이 방식은 Push를 jenkins가 스스로 명세서에 반영해서 push해주는데, 정작 개발자는 그 컨테이너 이미지 태그를 모르기 때문입니다.

그래서 장애가 발생하면, 원인을 파악하기 어렵고 복잡합니다. 그리고 롤백하기 위해선 위의 단점에 작성했다시피, 이전 빌드를 찾아서 다시 실행해야하는데, 수동으로 진행하면서 위험부담이 큽니다.

또한, 시스템의 현재 상태를 알기 위해서 k8s 명령, 프로메테우스, jenkins 대시보드 등 모두 따로 확인해야해서 일관된 정보를 얻기 힘들고, 로그가 계속 남는다고 보장할 수 없고, 정보를 취합하는데 많은 시간이 소요되게 됩니다.


그럼 이제 현재 사용되는 Jenkins / ArgoCD로 나뉘는 방식에 대해서 정리해보자면,

CI -> CD

1.개념

  • Git을 중심으로 상태를 관리하는 GitOps 워크플로우의 CI 부분을 담당하며, 배포는 별도의 도구(Argo CD 등)가 처리하는 Pull 기반 모델
  • 빌드와 테스트 후, 변경된 배포 명세(deploy.yaml)를 Git 저장소에 커밋하고 푸시하는 것만.
  • 실제 배포(CD)는 클러스터 내부에 설치된 GitOps 도구(예: Argo CD, Flux)가 담당.

2. 흐름

  • 빌드 및 이미지 생성: 첫 번째 방식과 동일하게 새 버전의 이미지를 만듭니다.
  • 배포 파일 수정 및 Git Pushdeploy.yaml 파일의 이미지 태그를 새 버전으로 수정한 뒤, 이 변경사항을 Git 저장소('gitops' 브랜치)에 커밋하고 푸시합니다.
  • (여기까지가 Jenkins의 역할) 이 다음은 argo CD가 합니당
  • 동기화 및 배포 (Pull): 쿠버네티스 클러스터에서 실행 중인 GitOps 에이전트(Argo CD)가 'gitops' 브랜치의 변경사항을 감지하고, 클러스터의 상태를 Git에 명시된 최신 상태로 자동으로 동기화(배포).

3.장점

  • 완벽한 형상 관리: 배포에 사용되는 deploy.yaml의 모든 변경 이력이 Git에 기록됩니다.
    Git이 바로 클러스터 상태를 나타내는 '진실의 원천(Single Source of Truth)'이 됩니다.
    한가지의 source가 되는거죠.

  • 명확한 감사 및 추적git log를 통해 누가, 언제, 어떤 변경사항을 배포했는지 명확하게 추적할 수 있습니다.
    github는 신이야

  • 향상된 보안 : Jenkins는 더 이상 쿠버네티스 클러스터 접근 권한이 필요 없습니다. Git 저장소에 Push할 권한만 있으면 됩니다. 배포 권한은 클러스터 내부의 GitOps 에이전트만 가지므로 공격 표면이 크게 줄어듭니다.
  • 간편하고 안전한 롤백 : 배포에 문제가 생겼을 때, 그냥 git revert 명령어로 이전 커밋으로 되돌리고 푸시하면 GitOps 에이전트가 알아서 클러스터를 이전 상태로 복원해 줍니다. 매우 빠르고 안정적입니다.
  • 개발자 경험(DX) 향상: 개발자는 쿠버네티스를 몰라도 익숙한 git 명령어나 Pull Request를 통해 배포를 요청하고 관리할 수 있습니다.

직접 배포를 진행하면, Jenkins에서 Jenkins파일로 빌드를 진행할 수 있었는데요,
그러면 기존 Repo에 자동으로 gitops 라는 브랜치가 생기게 됩니당

그 다음, ArgoCD에서 git-repo를 connect하고, create application을 진행합니다

이때 !!!!
application이 바라보는 브랜치는 gitops, source를 선택한다? 하면 k8s라는 폴더가 됩니다(deploy, service가 있는 폴더)

이해가 대충 되셨나요?


그래서 이전과 현재 방식을 비교하자면,
절차적방식과 선언적 방식이라고 차이를 얘기할 수 있겠죠??

절차적 방식 vs 선언적 방식

  • 전통적 방식 (절차적, Imperative): "이미지를 빌드하고, 파일을 수정한 뒤, kubectl을 실행해라" 와 같이 Jenkins에게 어떻게(How) 배포할지 절차를 하나하나 명령합니다.
  • GitOps 방식 (선언적, Declarative): "우리가 원하는 상태는 이 deploy.yaml과 같아" 라고 Git에 무엇을(What) 원하는지 선언합니다. 그러면 GitOps 에이전트가 현재 상태와 원하는 상태의 차이를 파악하고 그 차이를 맞추는 작업(배포)을 스스로 수행.
profile
ad astra per aspera

0개의 댓글