Post

CSR에서 SSR로, Istio까지 GitOps로 (2) — 도입 전후 한눈에

본격적인 과정에 들어가기 전에, ArgoCD 를 도입하기 전의 빌드·배포 구조와 ArgoCD 기반으로 Istio 와 모든 애플리케이션이 빌드·배포되는 구조를 나란히 놓고 본다. 백엔드는 앞선 시리즈에서, 프론트와 Istio 는 이 시리즈에서 옮겼다. 둘을 합친 그림이다.

TO-BE 는 목표 구조다. 그중 PoC 로 검증한 부분과 아직 목표인 부분은 이 글 끝에서 나눠 적었다.


한 문장으로

“젠킨스와 사람이 클러스터에 직접 쓰던 구조”에서 “Git 에 원하는 상태를 적고, ArgoCD 만 클러스터에 쓰는 구조”로 바뀌었다.

나머지는 전부 이 한 가지 변화에서 따라 나온다.

 AS-ISTO-BE
방식명령형 — 무엇을 할지를 순서대로 실행한다선언형 — 어떤 상태여야 하는지를 적는다
클러스터에 쓰는 주체젠킨스 잡 여러 개 + 설정 잡 + 사람ArgoCD 하나
진실의 원천클러스터 (Git 에는 재료만 있다)Git
“지금 뭐가 떠 있나”클러스터에 접속해 본다Git 과 ArgoCD 화면을 본다

AS-IS — ArgoCD 도입 전

AS-IS 구성 빨간 화살표가 클러스터에 “쓰는” 경로다. 쓰는 주체가 흩어져 있고, 결과 상태는 Git 에 없다

앱별로 어떻게 배포됐나

백엔드 — 젠킨스가 코드 빌드 → Kaniko 이미지 빌드 → helm upgrade --install 까지 했다. 차트의 values.yaml 은 껍데기에 가깝고, 실제 값(서비스 메시 설정, Vault 연동 여부, replicas, probe 지연 등)은 젠킨스 스크립트 안의 변수였다. ConfigMap·Secret 은 별도 설정 잡이 만들었다. 이 값들을 하나씩 추적해 values 파일로 옮긴 과정은 앞선 시리즈 3편에 있다.

프론트(CSR) — 이미지가 아니라 파일을 배포했다. 실제 잡의 핵심 명령은 이랬다.

1
2
3
4
5
6
7
8
9
10
// 빌드 결과를 파드 안으로 직접 밀어 넣는다
kubectl exec -it $pod -n $namespace -- rm -rf /var/www/app/frontend
kubectl cp $cache_path/$commit/target/. $pod:/var/www/app/frontend/ -n $namespace

// 환경값은 런타임에 env.js 로 만들어 다시 cp
echo "window.__LM_DOMAIN__ = \"$VITE_LM_DOMAIN\";" >> /tmp/env.js
kubectl cp /tmp/env.js $pod:/var/www/app/frontend/env.js -n $namespace

// 마지막으로 nginx 재시작
kubectl exec $pod -n $namespace -- nginx -s reload

배포 결과는 파드 안의 파일로만 남는다. 무엇이 배포됐는지는 젠킨스 빌드 기록과 파드 안 env.js 를 봐야 안다.

웹서버(nginx) — 이미지는 Kaniko 로 만들었지만, 설정은 스크립트가 치환해 젠킨스가 직접 ConfigMap 을 만들었다.

1
2
3
4
5
6
sh replace-n.sh $namespace $buildcluster        // 네임스페이스 한 단어만 sed 치환
kubectl create configmap $name-cm --from-file=.../addon/$nginx_config_file \
  -o yaml --dry-run=client | kubectl apply -f -
helm upgrade --install $name services/helm/nginx -f ...-override-values.yml
// 배포 후 파드에 들어가 보안 설정을 손으로 적용
kubectl exec ${pod} -- sh -c 'chmod 400 /etc/shadow && ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime'

치환이 한 단어뿐이라 conf 파일이 환경 수만큼(21개) 복제됐고, 이미지에 들어가야 할 설정을 배포 후 exec 로 넣어 파드가 재생성되면 사라졌다.

Istio — 사람이 스크립트를 읽어 순서대로 실행했다(1편). 클러스터 13개의 과목 목록이 스크립트에 하드코딩돼 있었다. 과목이 하나 늘면 목록 수정 → 스크립트 실행 → istioctl 재적용 → 네임스페이스 라벨 → 젠킨스 잡 분기 추가를 해야 했고, 한 단계라도 빠지면 503 인데 빠졌다고 알려 주는 곳이 없었다.

AS-IS 의 문제

문제어디서 드러났나
상태가 Git 에 없다배포 버전·실제 conf·override 값·라벨·exec 결과가 클러스터에만 있다
쓰는 주체가 많다잡 여러 개 + 설정 잡 + 사람. 서로의 변경을 모른다
확인하려면 접속해야 한다그래서 확인용 sh 를 또 만든다
롤백 = 재빌드이전 상태가 Git 에 없어 “다시 빌드해서 덮는다”
젠킨스가 모든 클러스터 권한을 가진다젠킨스 하나가 뚫리면 모든 앱 클러스터에 쓸 수 있다
사람에게 의존한다Istio 설치 방법을 아는 사람이 떠나자 설치를 못 했다

TO-BE — ArgoCD 기반

TO-BE 구성 초록 화살표(sync)가 클러스터에 쓰는 유일한 경로다. 젠킨스는 이미지를 만들고 Git 에 태그를 적는 데서 멈춘다

구성 요소하는 일AS-IS 와 비교
인프라 레포차트 + 환경별 values 파일 + ArgoCD 설정 + Istio 래퍼 차트스크립트가 빠지고 “원하는 상태”가 들어왔다
젠킨스체크아웃 → Kaniko → 레지스트리 → 이미지 태그를 Git 에 커밋하고 끝배포 단계가 없어졌다. 앱 클러스터 kubeconfig 가 필요 없다
Kaniko·레지스트리그대로같다
ArgoCDGit 을 보고 렌더링해 클러스터에 적용. 상태 화면·이력·알림새로 생긴 유일한 “쓰는 주체”
AppProjectinfra(Istio, 클러스터 리소스 허용) / 앱용(네임스페이스 범위)권한 경계가 코드로 생겼다
대상젠킨스가 하는 일Git 에 있는 것ArgoCD 가 하는 일
백엔드빌드 → 도메인별 이미지 태그 파일 커밋공통 / 도메인 / 이미지 태그 3단 values, NamespaceApplicationSet 이 도메인별 Application 을 만들어 sync
프론트(SSR)Kaniko → 이미지 태그 파일 커밋values, nginx.conf 템플릿, Namespace·Gateway·VS 템플릿nginx + Next.js 파드, ConfigMap, Service, Ingress, Gateway, VS 를 한 번에 맞춘다
nginx 설정(없어졌다)템플릿 1개 + valuesConfigMap 을 차트가 만든다. 설정이 바뀌면 파드 재시작까지
Istio—version·revision·gateways 목록base → istiod → 과목별 게이트웨이 순으로 설치
네임스페이스·라벨—각 앱 차트의 Namespace.yml먼저 만들고 Istio 주입 라벨까지 관리. 삭제는 막는다

그대로 둔 것

전부 갈아엎지 않았다. 바꿀 이유가 있는 것만 바꿨다.

그대로이유
Kaniko + 기존 빌드 차트 + PVC 공유이미 이미지 기반으로 잘 돌고 있었다
이미지 태그 규칙 <시각>-<커밋해시>같은 커밋을 다시 빌드해도 태그가 겹치지 않아 ArgoCD 가 변경을 감지한다
헬름 차트 구조기존 차트를 복사해 개조. 어노테이션 체계 유지
nginx 앞단개발팀 답변과 운영에서 다듬어진 conf
과목마다 게이트웨이 하나, 이름 규칙전임자가 그린 mesh 구조. 관리 방식만 Git 으로
젠킨스없애지 않았다. 역할을 CI 로 좁혔다

같은 일을 할 때 무엇이 다른가

플로우 비교 빨강은 사람이나 젠킨스가 클러스터에 직접 쓰는 단계, 초록은 ArgoCD 가 하는 단계

상황AS-ISTO-BE나아진 것
앱 배포젠킨스가 cp·reload 또는 helm upgrade젠킨스가 태그 커밋 → ArgoCD sync태그 커밋이 곧 배포 기록
nginx 설정 변경21개 중 해당 파일 수정 → 잡 재실행템플릿 또는 values 수정 → push이력·리뷰가 Git 에
과목 추가스크립트 → istioctl → 라벨 → 잡 분기Istio values +1줄, 앱 values +1 → push빠지면 ArgoCD 에 Missing 으로 보인다
롤백이전 빌드 찾아 재빌드태그 커밋 revert 또는 ArgoCD history 롤백이미지는 이미 있다. 태그만 되돌린다
Istio 업그레이드설치 방식 조사 → 전체 일괄 적용revision 지정 → 과목별로 라벨 전환과목 단위로 옮기고 되돌린다
누가 kubectl 로 고쳤을 때아무도 모른다OutOfSync 로 보인다비교 기준이 생겼다
배포 실패젠킨스 콘솔 로그ArgoCD 화면 + 알림알림이 사람을 찾아온다

관점별로 본 변화

권한

 AS-ISTO-BE
앱 클러스터 kubeconfig젠킨스 에이전트(클러스터·네임스페이스별), 사람ArgoCD
젠킨스 권한모든 앱 클러스터 쓰기Kaniko 파드 생성 + Git 쓰기 토큰
권한 범위 정의없다AppProject 가 레포·네임스페이스·리소스 종류를 제한

숫자로

항목AS-ISTO-BE
프론트 젠킨스 잡703줄약 365줄 (배포 단계 없음)
백엔드 젠킨스 스크립트1,071줄846줄
nginx.conf21개 파일템플릿 1개 + values
클러스터에 쓰는 주체잡 여러 개 + 설정 잡 + 사람ArgoCD 1
Istio 설치사람이 4단계최초 kubectl apply 2번, 이후 커밋

대가 — 새로 생긴 것

좋아지기만 한 건 아니다.

새로 생긴 것왜 감수하나
ArgoCD 자체 운영쓰는 주체를 하나로 모으는 대가. 대신 젠킨스의 배포 로직이 사라진다
ArgoCD 고유 개념 (sync-wave, ignoreDifferences, prune…)이번 트러블슈팅 대부분이 여기서 나왔다. 한 번 익히면 앱마다 반복되지 않는다
“Synced 인데 실제론 안 바뀐” 경우ArgoCD 는 자기가 넣지 않은 필드는 지우지 않는다. Synced 가 배포 완료를 뜻하지 않는다
배포가 비동기가 됨젠킨스 잡 성공은 커밋 성공일 뿐이다. ArgoCD 화면·알림을 봐야 한다

그래도 바꾼 이유는 하나다. 복잡함이 “흩어진 스크립트와 사람의 기억”에서 “한 도구의 정해진 규칙”으로 옮겨 간다. 흩어진 복잡함은 사람이 바뀔 때마다 다시 배워야 하지만, 도구의 규칙은 문서와 커뮤니티가 있다.


어디까지 왔나

항목상태
백엔드 ArgoCD 배포 (멀티 클러스터, ApplicationSet, 알림)검증 (앞선 시리즈 2편)
프론트 SSR 배포 틀검증 (4편)
nginx.conf GitOps검증 (4편)
Istio 를 ArgoCD 로 설치, 앱 mesh 편입, 네임스페이스 라벨 코드화검증 — PoC 환경 (5편)
ArgoCD 를 툴 클러스터에 정식 구축목표
스테이징·운영 전환, 운영 Istio 를 이 방식으로목표

아직 젠킨스·사람이 직접 하는 것도 숨기지 않고 적어 둔다. 백엔드 ConfigMap/Secret 은 여전히 별도 설정 잡이 만들고, AS-IS 에서 exec 로 넣던 nginx 보안 설정은 SSR 차트에 아직 선언하지 못했다. 둘 다 7편의 과제다.


이전: (1) 왜 프론트와 Istio인가 · 다음: (3) 알고 가야 할 개념과 전제

(회사·인프라 관련 실명, 클러스터 식별자, 내부 호스트 주소, 레포·시크릿 이름 등은 전부 임의로 재구성해 게시했다.)

This post is licensed under CC BY 4.0 by the author.

© noah. Some rights reserved.