정리/AI 시대에 개발자가 알아야 할 인프라 구성 배포 with 클로드 코드

- 2W(7.6~7.12) : Chapter 3,4(78p) - 배포 파이프라인(GitOps), 관측가능성(프로메테우스,그라파나,로키)

그느 2026. 7. 13. 05:51

이 책은 바이브코딩을 통해 인프라를 생성, 조작, 운영 등을 경험해 보는 데에 초점을 맞춘 책입니다. 가상의 회사 Notiflex의 앱 생성부터 해당 서비스가 성장함에 따른 리소스 분배, 최적화 / 코드를 위한 CI/CD 환경 적용 / 모니터링을 위한 인프라 스택 구성 등에 대해 배울 수 있을 것으로 기대됩니다.

 

진도는 가시다 님의 해당 책 스터디 구성에 따라 진행할 예정입니다.

 

- 1W(6.29~7.5) : Chapter 1,2(56p) - 개요, 실습 환경 구성(GKE)
- 2W(7.6~7.12) : Chapter 3,4(78p) - 배포 파이프라인(GitOps), 관측가능성(프로메테우스,그라파나,로키)
- 3W(7.13~7.19) : Chapter 5,6(68p) - 무중단 배포(Blue/Green), 시크릿 관리, Valkey 캐시
- 4W(7.20~7.26) : Chapter 7,8,9(85p) - App of Apps 패턴, 카프카/템포/크론잡, GitAIOps

 

이번 주는 개인적으로 ops 직무의 가장 중요한 부분이라고 생각되는 챕터였다.(실제 많은 공고에서 해당 부분에 대한 언급을 많이 봐왔기 때문에...)

역시 CI/CD, 모니터링까지 진행하라는 채팅만으로 막힘없이 진행되었다.

 

 

 

해당 실습 진행 시 CI/CD 진행 도식도

 

# 로컬 배포에서 Kubernetes GitOps CI/CD 환경으로 전환하는 가이드

이 가이드는 로컬 PC나 서버에서 단순히 `uvicorn main:app` 등으로 띄워 배포하던 애플리케이션을 **GitHub Actions(CI)****ArgoCD(CD)**를 결합하여 쿠버네티스(Kubernetes) 환경에서 완전 자동화된 CI/CD 파이프라인으로 전환하는 설계 방법과 구체적인 설정값 예시를 다룹니다.

---

## 1. 전체 CI/CD 아키텍처 흐름

로컬 배포 상태에서 자동화 파이프라인으로 전환할 때 추가되는 각 컴포넌트의 유기적 관계입니다.

```
[개발자 PC] ──(1) 코드 Push──> [GitHub 저장소]
                                 │
                   ┌─────────────┴─────────────┐
                   ▼ (2) 트리거                 ▼ (4) 자동 push (Manifest 업데이트)
           [GitHub Actions CI]           [GitHub Actions Runner]
                   │                             │
                   ▼ (3) Docker Build & Push     │
            [Docker Registry] <──────────────────┘
            (Docker Hub, Artifact Registry)
                   ▲
                   │ (6) 이미지 Pull & 배포
                   │
           [Kubernetes 클러스터] <──(5) Sync 감지── [ArgoCD Controller]
```

---

## 2. 변경해야 할 파일 목록 & 구체적인 파일 내용 예시

FastAPI/Uvicorn 애플리케이션을 기준으로 전환하는 예시입니다.

### 파일 구조 (GitHub 저장소)
```text
repository-root/
├── app/
│   └── main.py              # 1. 애플리케이션 코드
├── Dockerfile               # 2. 컨테이너 이미지 빌드 스펙
├── .github/workflows/
│   └── ci.yaml              # 3. GitHub Actions CI 파이프라인 설정
├── k8s/
│   └── deployment.yaml      # 4. 쿠버네티스 배포 매니페스트
└── argocd/
    └── application.yaml     # 5. ArgoCD Application 설정 (GitOps 등록용)
```

---

### ① 애플리케이션 소스 코드 (`app/main.py`)
로컬에서 돌리던 코드와 동일하지만, 로컬의 특정 IP/포트 바인딩 설정을 지우고 환경 변수를 활용할 수 있게 합니다.

```python
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"message": "Hello GitOps World!"}

@app.get("/health")
def health_check():
    return {"status": "UP"}
```

---

### ② `Dockerfile` (컨테이너화)
애플리케이션을 컨테이너 이미지로 빌드하기 위한 정의서입니다. Uvicorn을 컨테이너 내에서 안전하게 가동합니다.

```dockerfile
FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY ./app ./app

# 0.0.0.0으로 바인딩하여 쿠버네티스 서비스가 접근할 수 있도록 설정
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
```

---

### ③ 쿠버네티스 배포 매니페스트 (`k8s/deployment.yaml`)
쿠버네티스 상에 Pod을 띄우기 위한 명세서입니다. **CI 과정에서 이미지 태그(`image:`) 영역이 자동으로 수정됩니다.**

```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-app
  namespace: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: fastapi-app
  template:
    metadata:
      labels:
        app: fastapi-app
    spec:
      containers:
        - name: app
          # CI(GitHub Actions)가 빌드할 이미지 주소. 빌드 시 마다 태그(tag)가 변경됨
          image: docker.io/myusername/fastapi-app:sha-default
          ports:
            - containerPort: 8000
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
  namespace: myapp
spec:
  selector:
    app: fastapi-app
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8000
  type: ClusterIP
```

---

### ④ GitHub Actions CI 파이프라인 (`.github/workflows/ci.yaml`)
코드가 main 브랜치에 Push될 때 자동으로 작동하여 **1) 이미지를 빌드 및 푸시**하고, **2) `k8s/deployment.yaml`의 이미지 태그를 새롭게 바꿔 Git에 커밋/푸시**합니다.

```yaml
name: CI & GitOps Deploy

on:
  push:
    branches:
      - main
    paths:
      - 'app/**'          # app 폴더 내의 소스코드 변경만 감지해 작동

permissions:
  contents: write         # 워크플로가 레포지토리에 직접 git push할 수 있는 권한 허용

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v3

      # Docker Hub 로그인 (GitHub Repository Secrets에 저장된 자격 증명 사용)
      - name: Log in to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      # Git Commit Short SHA 추출하여 이미지 태그로 활용
      - name: Get Short SHA
        id: sha
        run: echo "SHA=sha-${GITHUB_SHA::7}" >> $GITHUB_ENV

      # Docker 이미지 빌드 및 푸시
      - name: Build and Push Docker Image
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myusername/fastapi-app:latest
            myusername/fastapi-app:${{ env.SHA }}

      # [중요] k8s/deployment.yaml의 이미지 태그를 새로 빌드한 이미지 태그로 자동 치환
      - name: Update Kubernetes Manifest
        run: |
          sed -i "s|image: docker.io/myusername/fastapi-app:.*|image: docker.io/myusername/fastapi-app:${{ env.SHA }}|g" k8s/deployment.yaml

      # 변경된 매니페스트 파일을 Git 저장소에 커밋 및 푸시
      - name: Commit & Push Changes
        run: |
          git config --global user.name "github-actions[bot]"
          git config --global user.email "github-actions[bot]@users.noreply.github.com"
          git add k8s/deployment.yaml
          git commit -m "image update to ${{ env.SHA }} [skip ci]"
          git push origin main
```

---

### ⑤ ArgoCD Application 설정 (`argocd/application.yaml`)
쿠버네티스 내부에 설치된 ArgoCD에 "이 레포지토리의 k8s 폴더를 감시하여 싱크를 맞춰라"라고 지시하는 설정입니다.

```yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: fastapi-gitops-app
  namespace: argocd
spec:
  project: default
  source:
    targetRevision: HEAD
    path: k8s                 # 감시할 대상 매니페스트가 보관된 폴더 경로
  destination:
    namespace: myapp          # 배포될 쿠버네티스 네임스페이스
  syncPolicy:
    automated:                # 소스 변경 감지 시 자동으로 클러스터 상태를 업데이트(GitOps)
      prune: true             # Git에서 삭제된 리소스를 클러스터에서도 자동 삭제
      selfHeal: true          # 클러스터 리소스를 수동 변경 시 Git 상태로 자동 복원
```

---

## 3. GitHub 설정값 및 수정해야 할 사항

안전한 통신을 위해 GitHub에서 직접 설정해야 하는 보안 정보입니다.

### GitHub Repository Secrets 등록
GitHub 저장소의 `Settings` -> `Secrets and variables` -> `Actions`로 이동하여 다음 두 가지 보안 변수를 추가합니다:
*   `DOCKER_USERNAME`: Docker Hub 로그인 아이디
*   `DOCKER_PASSWORD`: Docker Hub 로그인 패스워드 또는 개인 액세스 토큰 (PAT)

---

## 4. ArgoCD 설정값 및 수정해야 할 사항

쿠버네티스 클러스터에서 진행해야 할 네트워크 연동입니다.

1. **GitHub 비공개 레포지토리 접근 권한 (Private Repository 사용 시)**:
   ArgoCD Web UI의 `Settings` -> `Repositories` 메뉴에서 레포지토리 주소와 함께 GitHub **PAT(Personal Access Token)** 자격 증명을 등록하여 프라이빗 코드를 당겨올 수 있게 허용해야 합니다.
2. **Namespace 생성**:
   애플리케이션이 구동될 네임스페이스(`myapp`)가 클러스터에 미리 만들어져 있어야 합니다:
   ```bash
   kubectl create namespace myapp
   ```
3. **Application 등록**:
   작성한 `argocd/application.yaml` 파일을 적용하면 ArgoCD 대시보드에 연동이 시작됩니다:
   ```bash
   kubectl apply -f argocd/application.yaml
   ```

 

# GitOps 기반 CI/CD 파이프라인 흐름 및 상세 작동 단계

이 문서는 개발자가 코드를 GitHub에 푸시하는 시점부터 Kubernetes 클러스터에 Rolling Update가 배포되는 순간까지의 전체 파이프라인 처리 단계를 정리한 문서입니다.

---

## 1. 파이프라인 흐름 요약

```text
[개발자]                   [GitHub Actions]             [Container Registry]             [Git Repository]             [ArgoCD]                  [Kubernetes]
   │                             │                              │                               │                         │                          │
   ├── 1. 코드 수정 & Push ─────>│                              │                               │                         │                          │
   │                             ├── 2. CI 워크플로 작동         │                               │                         │                          │
   │                             ├── 3. Docker 이미지 빌드 ──────>│                               │                         │                          │
   │                             │      (커밋 해시 태그 지정)    │                               │                         │                          │
   │                             │                              │                               │                         │                          │
   │                             ├── 4. k8s 매니페스트 이미지 ─────────────────────────────────>│                         │                          │
   │                             │      태그 수정 및 Git Commit/Push                             │                         │                          │
   │                             │                                                              │                         │                          │
   │                             │                                                              ├── 5. YAML 변경 감지 ───>│                          │
   │                             │                                                              │                         │                          │
   │                             │                                                              │                         ├── 6. 새로운 명세 배포 ──>│
   │                             │                                                              │                         │   (Sync & Apply)         ├── 7. Rolling Update
   │                             │                                                              │                         │                          │      (Pod 교체)
```

---

## 2. 각 단계별 상세 작동 원리

### 1단계: 개발자 코드 수정 및 원격 Push
*   **주체**: 개발자 (Developer)
*   **설명**: 개발자가 로컬 PC에서 기능을 개발하고 변경 사항을 테스트한 후, 원격 저장소(`main` 브랜치)에 코드를 푸시합니다.
*   **대상 경로**: `app/` 폴더 내의 소스코드 파일들

### 2단계: GitHub Actions의 변화 감지 (CI Trigger)
*   **주체**: GitHub Actions
*   **설명**: 원격 저장소에 Push가 오면 GitHub Actions가 내장된 트리거 조건(`paths: ['app/**']`)을 확인하여 워크플로 실행을 결정합니다.
*   **주의점**: `app/` 외부 파일(예: `k8s/` 안의 매니페스트 파일)만 변경되었을 때는 워크플로가 돌지 않도록 격리하여 불필요한 이미지 빌드 및 파이프라인 무한 트리거를 사전에 예방합니다.

### 3단계: Docker 이미지 빌드 및 레지스트리 업로드
*   **주체**: GitHub Actions Runner
*   **설명**:
    1.  가상 Runner에 설치된 Docker 엔진을 통해 애플리케이션 코드를 Docker 이미지로 빌드합니다.
    2.  이때 버전 식별을 위해 **Git 커밋 해시값(7자리)**을 이미지 태그로 명명합니다 (예: `sha-591942e`).
    3.  빌드가 성공하면 로그인해 둔 컨테이너 레지스트리(구글 Artifact Registry, Docker Hub 등)로 업로드(`docker push`)합니다.

### 4단계: Kubernetes Manifest의 이미지 태그 수정 및 원격 반영 (핵심)
*   **주체**: GitHub Actions Runner
*   **설명**:
    1.  레지스트리 업로드가 끝나면 리눅스 텍스트 편집 유틸인 `sed` 명령어로 레포지토리 내의 `k8s/smb/deployment.yaml` 파일 내 `image:` 영역에 쓰인 구 버전 태그를 방금 생성한 새 태그(`sha-591942e`)로 자동 변환합니다.
    2.  이후 Runner 자체에서 변경된 YAML 파일을 Git에 자동 커밋 및 푸시합니다.
    3.  이때 커밋 메시지에 `[skip ci]` 태그를 추가하여 이 자동 커밋으로 인해 다시 CI 워크플로가 오작동하는 것을 영구 방지합니다.

### 5단계: ArgoCD의 변경 사항 감지 (Sync Trigger)
*   **주체**: ArgoCD Controller
*   **설명**:
    *   쿠버네티스 내부에서 24시간 가동되는 ArgoCD는 본인에게 등록된 애플리케이션의 소스인 **Git 저장소의 특정 폴더(예: `k8s/` 폴더)를 정기적으로 폴링(polling) 또는 웹훅(webhook)을 통해 감시**합니다.
    *   4단계에서 GitHub Actions가 커밋하여 변경된 `deployment.yaml` 내의 새로운 이미지 태그명을 감지하고, "원하는 상태(Git의 새 태그)"와 "현재 상태(클러스터의 구 태그)"가 달라졌음을 인지(OutOfSync 상태)합니다.

### 6단계: ArgoCD의 동기화 실행 (Apply)
*   **주체**: ArgoCD Controller
*   **설명**:
    *   감지된 변경 정보를 바탕으로 ArgoCD가 쿠버네티스 API 서버에 새 명세(새 버전 이미지 태그가 적용된 Deployment 리소스)를 전송하고 업데이트를 지시합니다. (Self-Heal과 Automated 옵션이 적용되어 수동 개입 없이 자동 실행됩니다.)

### 7단계: 쿠버네티스 컨트롤러의 롤링 업데이트 (Rolling Update)
*   **주체**: Kubernetes default-scheduler & controller-manager
*   **설명**:
    *   쿠버네티스 디플로이먼트 컨트롤러는 이미지 변경 요청을 수신하면, 기존 실행 중이던 컨테이너 Pod들을 정의된 롤링 업데이트 기법에 따라 순차적으로 교체합니다 (오래된 Pod 삭제 -> 신규 Pod 기동).
    *   이 과정을 통해 서비스에 지장(Downtime)을 주지 않는 무중단 롤링 배포가 최종적으로 완성됩니다.

진행 중간에 따라가기가 힘들어 추가 설명을 요청

 

argocd의 대시보드

 

모니터링 부분

 

grafana 대시보드

 

후기

일단 뒤에 ops가 붙은 직종에서는 해당 파트에 대한 이해가 가장 중요하다고 생각하는데 간단하게 어떻게 구성되고 세팅되는지에 대해 약간은 알게 된 것 같다.

하지만 추후에 실무에서 이미 프로덕트로 돌아가고 있는 환경에서 ci/cd 혹은 모니터링을 추가로 붙여야 하는 상황이 왔을 때의 실제 일처리를 위해 특히나 ci/cd 부분은 좀 더 파봤고 추후에 scratch로 한번 실습을 따로 진행해 봐야겠다는 생각을 하며 마무리한다.

 

PS

항상 쿠버네티스를 로컬에서만 실습해 봐서 또 새로운 것을 알게 됐다 ㅎㅎ