Personal Project - Kubernetes 아키텍처
On-Premise VMware 환경 기반 Kubernetes 3-Tier 고가용성 시스템
목차
- 🏗️ 전체 인프라 아키텍처
- 🌐 네트워크 구성
- ☸️ Kubernetes 클러스터 & Ingress 통합 구조 (mysql-cluster)
- 📝 브랜치 노트 (Branch Notes) 기능
- 🔄 CI/CD 파이프라인 흐름
- 🏢 3-Tier 애플리케이션 구조 (mysql-cluster)
- 🗄️ MySQL InnoDB Cluster (Group Replication)
- 🔗 네임스페이스 구조
- 🔐 보안 & 네트워크 정책
- 📊 리소스 할당
- 📚 Quick Reference
- 🦊 GitLab 로컬 서버 접속
디렉토리 구조
personal-project/
├── 프로젝트_계획서/ # 프로젝트 계획서 및 PPT 슬라이드
├── 프로젝트_산출물/ # 최종 산출물
│ ├── gition/ # Git + Notion 통합 협업 플랫폼 (FastAPI + React + MySQL)
│ └── k8s/ # Kubernetes 클러스터 구성 및 배포 매니페스트
├── day1-1224 ~ day12-0108/ # 일일 작업 기록 (K8s 클러스터 구축 과정)
└── docs/ # 참고 문서
🏗️ 전체 인프라 아키텍처
🌐 네트워크 구성
서버 IP 할당
| 호스트 | IP | 용도 |
|---|---|---|
| GitLab | 172.100.100.8 | Git, CI/CD, Registry |
| Bastion | 172.100.100.9 | SSH 게이트웨이 |
| NFS | 172.100.100.10 | 공유 스토리지 |
| MySQL | 172.100.100.11 | Primary (쓰기) |
| k8s-m | 172.100.100.12 | Master (Control Plane) |
| k8s-n1 | 172.100.100.13 | Worker Node 1 |
| k8s-n2 | 172.100.100.14 | Worker Node 2 |
| k8s-n3 | 172.100.100.15 | Worker Node 3 |
MetalLB IP Pool
| 항목 | 값 |
|---|---|
| Pool Name | ingress-pool |
| IP 범위 | 172.100.100.20 - 172.100.100.30 |
| 모드 | L2 (ARP) |
서비스 포트
| 서비스 | 호스트 | 포트 |
|---|---|---|
| Ingress (MetalLB) | 172.100.100.20 | 80, 443 |
| GitLab Web | 172.100.100.8 | 80 |
| GitLab Registry | 172.100.100.8 | 5050 |
| MySQL Master | 172.100.100.11 | 3306 |
| NFS Server | 172.100.100.10 | 2049 |
| MySQL Router R/W | mysql-cluster | 6446 |
| MySQL Router R/O | mysql-cluster | 6447 |
☸️ Kubernetes 클러스터 & Ingress 통합 구조 (mysql-cluster)
네트워크 흐름 요약
| 순서 | 경로 | 설명 |
|---|---|---|
| 1 | User → LoadBalancer | 172.100.100.20:80 접근 |
| 2 | LoadBalancer → Ingress | Ingress Controller로 전달 |
| 3 | Ingress → Service | path: / → Frontend, /api → API |
| 4 | Service → Pod | 로드밸런싱 |
| 5 | API → mysql-operator | mysql-cluster:6446 (Write) |
| 6 | mysql-operator → MySQL | Primary(Write) / Secondary(Read) |
| 7 | MySQL ↔ MySQL | Group Replication 동기화 |
| 8 | Operator → Cluster | 자동 Failover/복구 관리 |
📝 브랜치 노트 (Branch Notes) 기능
각 브랜치마다 Notion 스타일의 문서 페이지를 생성하여 관리
클러스터 환경에서의 브랜치 노트
데이터 흐름 순서
| 순서 | 동작 | 대상 | 설명 |
|---|---|---|---|
| 1 | git checkout | NFS | 해당 브랜치로 전환 |
| 2 | SELECT (Read) | mysql-cluster:6447 | branch_pages 조회 |
| 3 | INSERT/UPDATE (Write) | mysql-cluster:6446 | branch_pages 저장 |
브랜치별 노트 작성 흐름
클러스터 구성 포인트
| 구성 | 설명 | 이유 |
|---|---|---|
| API 3 replicas | 여러 Pod에서 동일 브랜치 노트 접근 | 고가용성 |
| NFS 공유 볼륨 | Git 저장소를 모든 Pod에서 공유 | git checkout 동기화 |
| MySQL Master | branch_pages 테이블 중앙 저장 | 데이터 일관성 |
| Ingress 로드밸런싱 | 요청마다 다른 Pod 처리 가능 | 부하 분산 |
API 엔드포인트
| Method | Path | 설명 |
|---|---|---|
GET | /api/pages/{user}/{repo}/{branch} | 브랜치 노트 조회 |
POST | /api/pages/{user}/{repo}/{branch} | 브랜치 노트 저장 |
POST | /api/git/checkout | 브랜치 전환 + 자동 페이지 생성 |
branch_pages 테이블
CREATE TABLE branch_pages (
id CHAR(36) PRIMARY KEY, -- UUID
user_id INT NOT NULL, -- FK → users
repo_id INT NOT NULL, -- FK → repositories
branch_name VARCHAR(255) NOT NULL, -- 브랜치명 (feat/login)
title VARCHAR(255), -- 페이지 제목
content JSON, -- 블록 에디터 데이터
created_at DATETIME DEFAULT NOW(),
updated_at DATETIME DEFAULT NOW() ON UPDATE NOW(),
UNIQUE KEY unique_user_repo_branch (user_id, repo_id, branch_name)
);
🔄 CI/CD 파이프라인 흐름
GitLab CI 이미지 빌드 과정
1. .gitlab-ci.yml 파이프라인 구조
stages:
- build
- deploy
variables:
DOCKER_HOST: tcp://docker:2375
DOCKER_TLS_CERTDIR: ""
# Backend 이미지 빌드
build-backend:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
command: ["--insecure-registry=172.100.100.8:5050"]
before_script:
- echo '{"insecure-registries":["172.100.100.8:5050"]}' > /etc/docker/daemon.json
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --provenance=false -t $CI_REGISTRY_IMAGE/backend:latest ./backend
- docker push $CI_REGISTRY_IMAGE/backend:latest
when: manual
# Frontend 이미지 빌드
build-frontend:
stage: build
image: docker:24.0.5
services:
- name: docker:24.0.5-dind
command: ["--insecure-registry=172.100.100.8:5050"]
before_script:
- echo '{"insecure-registries":["172.100.100.8:5050"]}' > /etc/docker/daemon.json
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
script:
- docker build --provenance=false -t $CI_REGISTRY_IMAGE/frontend:latest -f frontend/Dockerfile .
- docker push $CI_REGISTRY_IMAGE/frontend:latest
when: manual
2. 빌드 흐름
3. 주요 설정 포인트
| 설정 | 값 | 설명 |
|---|---|---|
| Docker-in-Docker | docker:24.0.5-dind | Runner 내부에서 Docker 빌드 |
| privileged | true | DinD 필수 설정 |
| insecure-registries | 172.100.100.8:5050 | HTTP Registry 허용 |
| --provenance=false | BuildKit 옵션 | Registry 호환성 |
| when: manual | 수동 트리거 | 필요시에만 빌드 |
Kubernetes 배포 과정
1. Registry Secret 설정
# GitLab Registry 인증 Secret 생성
kubectl create secret docker-registry gitlab-registry \
--docker-server=172.100.100.8:5050 \
--docker-username=root \
--docker-password=<ACCESS_TOKEN> \
-n gition
2. Deployment에서 이미지 Pull
# fastapi-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: gition
spec:
replicas: 3
template:
spec:
imagePullSecrets:
- name: gitlab-registry # Registry 인증
containers:
- name: api
image: 172.100.100.8:5050/root/gition/backend:latest
imagePullPolicy: Always # 최신 이미지 Pull
3. 배포 명령어
# 이미지 업데이트 후 배포
kubectl rollout restart deployment/api -n gition
kubectl rollout restart deployment/frontend -n gition
# 배포 상태 확인
kubectl rollout status deployment/api -n gition
kubectl get pods -n gition -w
4. 전체 배포 흐름
5. containerd 설정 (K8s 노드)
# 모든 K8s 노드에서 실행 (insecure registry 허용)
sudo mkdir -p /etc/containerd/certs.d/172.100.100.8:5050
sudo tee /etc/containerd/certs.d/172.100.100.8:5050/hosts.toml > /dev/null <<EOF
server = "http://172.100.100.8:5050"
[host."http://172.100.100.8:5050"]
capabilities = ["pull", "resolve", "push"]
skip_verify = true
EOF
sudo systemctl restart containerd
🏢 3-Tier 애플리케이션 구조 (mysql-cluster)
데이터 흐름 순서
| 순서 | 경로 | 설명 |
|---|---|---|
| 1 | User → Ingress | gition.local 접속 |
| 2 | Ingress → Frontend | path: / → React 앱 |
| 3 | Ingress → API | path: /api, /auth → FastAPI |
| 4 | API → mysql-operator | :6446 (Write) 또는 :6447 (Read) |
| 5 | mysql-operator → MySQL | Primary(Write) / Secondary(Read) |
| 6 | MySQL ↔ MySQL | Group Replication 동기화 |
| 7 | MySQL → Local PV | 각 노드별 데이터 저장 |
| 8 | Operator → Cluster | 자동 Failover/복구 관리 |
MySQL Router 연결 정보
| 용도 | 호스트 | 포트 | 설명 |
|---|---|---|---|
| 쓰기 (R/W) | mysql-cluster | 6446 | Primary로 라우팅 |
| 읽기 (R/O) | mysql-cluster | 6447 | Secondary들로 로드밸런싱 |
🗄️ MySQL InnoDB Cluster (Group Replication)
InnoDB Cluster 특징:
- ✅ 자동 Failover: Primary 장애 시 Secondary 중 하나가 자동 승격
- ✅ 동기 복제: Group Replication 기반 데이터 일관성 보장
- ✅ MySQL Router: 애플리케이션 단일 엔드포인트 제공
- ✅ Operator 관리: 자동 클러스터 생성/복구
자동 Failover 아키텍처
Failover 테스트 방법
# 1. 현재 Primary 확인
kubectl exec -it mysql-cluster-0 -n gition -c mysql -- \
mysql -uroot -p -e "SELECT member_host, member_role FROM performance_schema.replication_group_members"
# 2. Primary Pod 삭제
kubectl delete pod mysql-cluster-0 -n gition
# 3. 새 Primary 확인 (30초~1분 후)
kubectl exec -it mysql-cluster-1 -n gition -c mysql -- \
mysql -uroot -p -e "SELECT member_host, member_role FROM performance_schema.replication_group_members"
✅ 자동 Failover 성공 시 애플리케이션은 MySQL Router를 통해 무중단으로 새 Primary에 연결됩니다.
스토리지 아키텍처
| 스토리지 | 용도 | 특징 |
|---|---|---|
| Local PV | MySQL 데이터 | 고성능, 노드별 |
| NFS | SQL Dump 백업 | 공유, 7일 보관 |
🔗 네임스페이스 구조
🔐 보안 & 네트워크 정책
📊 리소스 할당
| 노드 | vCPU | RAM | 역할 |
|---|---|---|---|
| Bastion | 2 | 1GB | SSH Gateway |
| GitLab | 2 | 4GB | CI/CD, Registry |
| NFS | 1 | 1GB | Persistent Storage, Backup |
| MySQL | 2 | 4GB | Master Database (Docker) |
| k8s-m | 4 | 4GB | Control Plane |
| k8s-n1 | 4 | 4GB | Worker (Frontend, API, MySQL) |
| k8s-n2 | 4 | 4GB | Worker (Frontend, API, MySQL) |
| k8s-n3 | 4 | 4GB | Worker (API, MySQL) |
📚 Quick Reference
IP 주소 정리
| 서비스 | IP | 포트 |
|---|---|---|
| Ingress (External IP) | 172.100.100.20 | 80, 443 |
| GitLab Web | 172.100.100.8 | 80 |
| GitLab Registry | 172.100.100.8 | 5050 |
| MySQL Master | 172.100.100.11 | 3306 |
| NFS Server | 172.100.100.10 | 2049 |
Pod 구성
| Deployment/StatefulSet | Replicas | Image | Port |
|---|---|---|---|
| frontend | 2 | 172.100.100.8:5050/root/gition/frontend | 80 |
| api | 3 | 172.100.100.8:5050/root/gition/backend | 3001 |
| mysql-cluster | 3 | mysql/mysql-server:8.0 | 3306, 6446, 6447 |
| mysql-router | 2 | mysql/mysql-router:8.0 | 6446, 6447 |
Ingress 라우팅
| Path | Service | Port |
|---|---|---|
| / | frontend-svc | 80 |
| /api | api-svc | 3001 |
| /auth/github | api-svc | 3001 |
| /health | api-svc | 3001 |
kubectl 자주 사용 명령어
# 클러스터 상태 확인
kubectl get nodes -o wide
kubectl get pods -A
# gition 배포 상태
kubectl get all -n gition
# Ingress 확인
kubectl get ingress -n gition
kubectl get svc -n ingress-nginx
🦊 GitLab 로컬 서버 접속
접속 아키텍처
접속 방법
# 1. SSH 터널 설정 (Windows/Mac에서)
ssh -L 8080:172.100.100.8:80 -J pista@192.168.45.9 pista@172.100.100.12
# 2. 브라우저 접속
# http://localhost:8080
# 3. 로그인
# Username: root
# Password: (초기 비밀번호 또는 변경된 비밀번호)
GitLab 프로젝트 구조
| 경로 | 설명 |
|---|---|
root/gition | 메인 프로젝트 |
root/gition/backend | FastAPI 백엔드 |
root/gition/frontend | React 프론트엔드 |
Container Registry 이미지
| 이미지 | 경로 | 용도 |
|---|---|---|
| backend | 172.100.100.8:5050/root/gition/backend:latest | FastAPI API 서버 |
| frontend | 172.100.100.8:5050/root/gition/frontend:latest | React + Nginx |