우리FIS 아카데미 2차 기술세미나 | 클라우드 엔지니어링 과정 | 서가영
기존 배포 방식에서는 다음과 같은 문제가 반복됩니다.
| 문제 | 설명 |
|---|---|
| 추적 불가 | 누가, 언제, 무엇을 배포했는지 알 수 없음 |
| 드리프트(Drift) | 클러스터 실제 상태와 코드가 달라지는 불일치 발생 |
| 롤백 난이도 | 장애 시 이전 버전을 찾느라 시간 낭비 |
| 환경 불일치 | dev/staging/prod 배포 방식이 사람마다 다를 수 있음 |
| 분류 | 기술 |
|---|---|
| Container Orchestration | Kubernetes (minikube) |
| GitOps | ArgoCD v3.3.5, ApplicationSet |
| CI/CD | GitHub Actions |
| Registry | AWS ECR |
| Monitoring | Prometheus, Grafana |
| Notification | Slack Webhook |
| Application | Node.js (Express.js) |
개발자
│ git push (코드 변경)
▼
GitHub (tech-seminar-source)
│ Actions 자동 트리거
▼
GitHub Actions CI
├── Docker 이미지 빌드
├── AWS ECR 이미지 푸시 (sha-xxxx 태그)
└── GitOps repo image 태그 자동 업데이트 → commit & push
↓
GitHub (tech-seminar-gitops)
│ ArgoCD 변경 감지 (3분 이내)
▼
ArgoCD + ApplicationSet
├── gitops-monitor-dev → dev 클러스터 🟡 자동 배포 (replicas: 1)
├── gitops-monitor-staging → staging 클러스터 🔵 자동 배포 (replicas: 2)
└── gitops-monitor-prod → prod 클러스터 🔴 수동 승인 (replicas: 3)
↓
Slack #배포-알림 채널 알림
tech-seminar-source/ ← 소스 코드 레포 (CI 트리거)
├── src/
│ ├── index.js ← Express.js 대시보드 서버
│ └── public/style.css
├── Dockerfile
└── .github/workflows/ci.yaml ← GitHub Actions 파이프라인
tech-seminar-gitops/ ← 배포 선언 레포 (ArgoCD가 팔로우)
├── apps/
│ └── applicationset.yaml ← 멀티 클러스터 배포 전략
└── manifests/
├── dev/deployment.yaml
├── staging/deployment.yaml
└── prod/deployment.yaml
| 파일 | 역할 |
|---|---|
applicationset.yaml |
"어디에, 무엇을, 어떻게 배포할지" 전략 |
manifests/*/deployment.yaml |
"실제로 어떤 컨테이너를 띄울지" 선언 |
ci.yaml |
코드 변경 시 자동으로 이미지 빌드 + 배포 선언 업데이트 |
| 환경 | replicas | 배포 방식 | 용도 |
|---|---|---|---|
| dev | 1 | 자동 배포 (Auto-Prune) | 개발자 테스트, 리소스 절약 |
| staging | 2 | 자동 배포 (Auto-Prune) | 팀 QA, 약간의 트래픽 대응 |
| prod | 3 | 수동 승인 (Manual) | 실사용자, 고가용성 + 안전 게이트 |
- 자동 배포용 템플릿
# applicationset-auto.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: gitops-monitor-auto
namespace: argocd
spec:
generators:
- list:
elements:
- env: dev
server: https://kubernetes.default.svc
- env: staging
server: https://192.168.49.3:8443
template:
metadata:
name: "gitops-monitor-{{env}}"
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: "#배포-알림"
notifications.argoproj.io/subscribe.on-sync-failed.slack: "#배포-알림"
notifications.argoproj.io/subscribe.on-degraded.slack: "#배포-알림"
spec:
project: default
source:
repoURL: [tech-seminar-gitops 레포지토리 URL]
targetRevision: HEAD
path: manifests/{{env}}
destination:
server: "{{server}}"
namespace: gitops-monitor
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- 수동 검증용 템플릿
# applicationset-manual.yaml
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: gitops-monitor-manual
namespace: argocd
spec:
generators:
- list:
elements:
- env: prod
server: https://192.168.49.4:8443
template:
metadata:
name: "gitops-monitor-{{env}}"
annotations:
notifications.argoproj.io/subscribe.on-deployed.slack: "#배포-알림"
notifications.argoproj.io/subscribe.on-sync-failed.slack: "#배포-알림"
notifications.argoproj.io/subscribe.on-degraded.slack: "#배포-알림"
spec:
project: default
source:
repoURL: [tech-seminar-gitops 레포지토리 URL]
targetRevision: HEAD
path: manifests/{{env}}
destination:
server: "{{server}}"
namespace: gitops-monitor
syncPolicy:
syncOptions:
- CreateNamespace=trueArgoCD는 3분마다 Git 상태와 클러스터 상태를 비교하고 자동으로 맞춥니다.
① Git에 새 커밋 감지 (3분 폴링 or Webhook)
↓
② Repository Server: YAML 파일 렌더링 (Desired State 확보)
↓
③ Application Controller: Desired State vs Actual State 비교
↓
일치 → Synced (대기)
불일치 → OutOfSync → 자동 동기화 실행
↓
④ 쿠버네티스 API 서버에 apply 요청
↓
⑤ 스케줄러 → 워커 노드에 Pod 생성
↓
⑥ Healthy + Synced 상태로 업데이트
↓
① 무한 반복
git push → GitHub Actions (빌드 + ECR 푸시)
→ GitOps repo image 태그 자동 업데이트
→ ArgoCD 감지
→ dev/staging 자동 배포
→ prod 수동 승인 후 배포
→ Slack 알림
1. 장애 주입
- 작업 중인 레포지토리의 코드에 장애 발생 코드 작성 후
git push
2. 장애 확인
kubectl get pods -n gitops-monitor --context dev -w
# → CrashLoopBackOff 발생3. GitOps 롤백
# 배포 이력 확인
git log --oneline -5
# 한 줄로 롤백
git revert HEAD --no-edit
git push
# → ArgoCD 감지 → 이전 정상 이미지로 자동 배포롤백 흐름 요약
① process.exit(1) 추가 → git push
↓
② GitHub Actions → ECR 푸시 → GitOps 레포 image 태그 업데이트
↓
③ ArgoCD 감지 → CrashLoopBackOff 발생
↓
④ git revert HEAD → git push (한 줄!)
↓
⑤ ArgoCD 감지 → 이전 정상 이미지로 자동 배포
↓
⑥ Running 복구
상황
staging/prod 클러스터를 ArgoCD에 등록하기 위해 argocd cluster add 실행 시 오류 발생
# 시도 1 - kubeconfig 서버 주소가 127.0.0.1이라 접근 불가
dial tcp 127.0.0.1:65007: connect: connection refused
# 시도 2 - IP를 192.168.58.2로 변경했으나 여전히 실패
dial tcp 192.168.58.2:8443: i/o timeout
# 시도 3 - docker network connect 후에도 CLI 레벨에서 차단
error dial proxy: dial tcp 192.168.49.3:8443: connect: operation timed out
원인 분석
- kubeconfig의 서버 주소가
127.0.0.1로 설정되어 있어 IP를192.168.58.2로 변경했으나i/o timeout지속 - minikube docker 드라이버가 각 클러스터를 독립된 bridge 네트워크로 분리하고 있어 서로 통신 불가임을 확인
- 추가로
argocd cluster addCLI 자체가 내부 프록시를 경유하는 구조라 직접 IP 지정으로도 우회 불가
해결
docker network connect로 staging/prod 컨테이너를 dev 네트워크에 연결해 IP를 할당한 뒤, argocd cluster add 대신 ArgoCD cluster Secret을 kubectl로 직접 생성하여 등록
# staging/prod 컨테이너를 dev 네트워크에 연결
docker network connect dev staging
docker network connect dev prod
# IP 확인
docker network inspect dev | grep -A4 "Containers"# kubectl로 직접 Secret 생성
apiVersion: v1
kind: Secret
metadata:
name: staging-cluster
namespace: argocd
labels:
argocd.argoproj.io/secret-type: cluster
type: Opaque
stringData:
name: staging
server: "https://192.168.49.3:8443"
config: |
{
"tlsClientConfig": {
"insecure": true
}
}
⚠️ 재시작 시 주의: minikube를 껐다 켜면 docker 네트워크 연결이 초기화되므로docker network connect재실행 필요
상황
컨테이너를 중지했다가 재실행 시 kubelet 초기화 실패
unable to load bootstrap kubeconfig: stat /etc/kubernetes/bootstrap-kubelet.conf: no such file or directory
원인
minikube v1.38.1이 k8s v1.35.1을 완전히 지원하지 못하는 호환성 문제. kube-scheduler가 RBAC 권한을 줄줄이 거부당하는 증상 발생
해결
안정적으로 동작이 확인된 k8s v1.33.0으로 다운그레이드
minikube start --profile dev \
--cpus 3 --memory 4096 \
--driver docker \
--kubernetes-version v1.33.0