376 lines
11 KiB
Markdown
376 lines
11 KiB
Markdown
|
|
# vexplor 쿠버네티스 자동 배포 가이드
|
||
|
|
|
||
|
|
## 개요
|
||
|
|
|
||
|
|
이 문서는 vexplor 프로젝트를 Gitea Actions를 통해 쿠버네티스 클러스터에 자동 배포하는 방법을 설명합니다.
|
||
|
|
|
||
|
|
**작성일**: 2024년 12월 22일
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 아키텍처
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Gitea Repository │
|
||
|
|
│ g.wace.me/chpark/vexplor │
|
||
|
|
└─────────────────────┬───────────────────────────────────────────┘
|
||
|
|
│ push to main
|
||
|
|
▼
|
||
|
|
┌─────────────────────────────────────────────────────────────────┐
|
||
|
|
│ Gitea Actions Runner │
|
||
|
|
│ 1. Checkout code │
|
||
|
|
│ 2. Build Docker images (frontend, backend) │
|
||
|
|
│ 3. Push to Harbor Registry │
|
||
|
|
│ 4. Deploy to Kubernetes │
|
||
|
|
└─────────────────────┬───────────────────────────────────────────┘
|
||
|
|
│
|
||
|
|
┌──────────┴──────────┐
|
||
|
|
▼ ▼
|
||
|
|
┌──────────────────┐ ┌──────────────────┐
|
||
|
|
│ Harbor Registry │ │ Kubernetes (K8s) │
|
||
|
|
│ harbor.wace.me │ │ 112.168.212.142 │
|
||
|
|
└──────────────────┘ └──────────────────┘
|
||
|
|
│
|
||
|
|
┌────────────────┼────────────────┐
|
||
|
|
▼ ▼ ▼
|
||
|
|
┌──────────┐ ┌──────────┐ ┌──────────┐
|
||
|
|
│ Frontend │ │ Backend │ │ Ingress │
|
||
|
|
│ :3000 │ │ :3001 │ │ Nginx │
|
||
|
|
└──────────┘ └──────────┘ └──────────┘
|
||
|
|
│ │ │
|
||
|
|
└────────────────┴────────────────┘
|
||
|
|
│
|
||
|
|
▼
|
||
|
|
┌─────────────────────┐
|
||
|
|
│ External Access │
|
||
|
|
│ v1.vexplor.com │
|
||
|
|
│ api.vexplor.com │
|
||
|
|
└─────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 사전 요구사항
|
||
|
|
|
||
|
|
### 1. 쿠버네티스 클러스터
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 서버 정보
|
||
|
|
IP: 112.168.212.142
|
||
|
|
SSH: ssh -p 22 wace@112.168.212.142
|
||
|
|
K8s 버전: v1.28.15
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Harbor 레지스트리 접근 권한
|
||
|
|
|
||
|
|
Harbor에 `vexplor` 프로젝트가 생성되어 있어야 합니다.
|
||
|
|
|
||
|
|
### 3. Gitea Repository Secrets
|
||
|
|
|
||
|
|
Gitea 저장소에 다음 Secrets를 설정해야 합니다:
|
||
|
|
|
||
|
|
| Secret 이름 | 설명 |
|
||
|
|
|------------|------|
|
||
|
|
| `HARBOR_USERNAME` | Harbor 사용자명 |
|
||
|
|
| `HARBOR_PASSWORD` | Harbor 비밀번호 |
|
||
|
|
| `KUBECONFIG` | base64 인코딩된 Kubernetes config |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 초기 설정
|
||
|
|
|
||
|
|
### 1단계: 쿠버네티스 클러스터 접속
|
||
|
|
|
||
|
|
```bash
|
||
|
|
ssh -p 22 wace@112.168.212.142
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2단계: Nginx Ingress Controller 설치
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Nginx Ingress Controller 설치 (baremetal용)
|
||
|
|
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.5/deploy/static/provider/baremetal/deploy.yaml
|
||
|
|
|
||
|
|
# 설치 확인
|
||
|
|
kubectl get pods -n ingress-nginx
|
||
|
|
kubectl get svc -n ingress-nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3단계: Local Path Provisioner 설치 (PVC용)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Local Path Provisioner 설치
|
||
|
|
kubectl apply -f k8s/local-path-provisioner.yaml
|
||
|
|
|
||
|
|
# 설치 확인
|
||
|
|
kubectl get pods -n local-path-storage
|
||
|
|
kubectl get storageclass
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4단계: Cert-Manager 설치 (SSL 인증서용)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Cert-Manager 설치
|
||
|
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.yaml
|
||
|
|
|
||
|
|
# 설치 확인
|
||
|
|
kubectl get pods -n cert-manager
|
||
|
|
|
||
|
|
# ClusterIssuer 생성 (Let's Encrypt)
|
||
|
|
cat <<EOF | kubectl apply -f -
|
||
|
|
apiVersion: cert-manager.io/v1
|
||
|
|
kind: ClusterIssuer
|
||
|
|
metadata:
|
||
|
|
name: letsencrypt-prod
|
||
|
|
spec:
|
||
|
|
acme:
|
||
|
|
server: https://acme-v02.api.letsencrypt.org/directory
|
||
|
|
email: admin@vexplor.com
|
||
|
|
privateKeySecretRef:
|
||
|
|
name: letsencrypt-prod
|
||
|
|
solvers:
|
||
|
|
- http01:
|
||
|
|
ingress:
|
||
|
|
class: nginx
|
||
|
|
EOF
|
||
|
|
```
|
||
|
|
|
||
|
|
### 5단계: vexplor Secret 생성
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Secret 템플릿을 복사하여 실제 값으로 수정
|
||
|
|
cp k8s/vexplor-secret.yaml.template k8s/vexplor-secret.yaml
|
||
|
|
|
||
|
|
# 값 수정 후 적용
|
||
|
|
kubectl apply -f k8s/vexplor-secret.yaml
|
||
|
|
```
|
||
|
|
|
||
|
|
### 6단계: Gitea Secrets 설정
|
||
|
|
|
||
|
|
1. Gitea 저장소로 이동: https://g.wace.me/chpark/vexplor
|
||
|
|
2. Settings > Secrets > Actions 메뉴로 이동
|
||
|
|
3. 다음 Secrets 추가:
|
||
|
|
|
||
|
|
#### HARBOR_USERNAME
|
||
|
|
Harbor 로그인 사용자명
|
||
|
|
|
||
|
|
#### HARBOR_PASSWORD
|
||
|
|
Harbor 로그인 비밀번호
|
||
|
|
|
||
|
|
#### KUBECONFIG
|
||
|
|
```bash
|
||
|
|
# 쿠버네티스 서버에서 실행
|
||
|
|
cat ~/.kube/config | base64 -w 0
|
||
|
|
```
|
||
|
|
출력된 값을 KUBECONFIG secret으로 등록
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 배포 트리거
|
||
|
|
|
||
|
|
### 자동 배포 (Push)
|
||
|
|
|
||
|
|
다음 경로의 파일이 변경되어 `main` 브랜치에 push되면 자동으로 배포됩니다:
|
||
|
|
|
||
|
|
- `backend-node/**`
|
||
|
|
- `frontend/**`
|
||
|
|
- `docker/**`
|
||
|
|
- `k8s/**`
|
||
|
|
- `.gitea/workflows/deploy.yml`
|
||
|
|
|
||
|
|
### 수동 배포
|
||
|
|
|
||
|
|
1. Gitea 저장소 > Actions 탭으로 이동
|
||
|
|
2. "Deploy vexplor" 워크플로우 선택
|
||
|
|
3. "Run workflow" 버튼 클릭
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 파일 구조
|
||
|
|
|
||
|
|
```
|
||
|
|
vexplor/
|
||
|
|
├── .gitea/
|
||
|
|
│ └── workflows/
|
||
|
|
│ └── deploy.yml # Gitea Actions 워크플로우
|
||
|
|
├── docker/
|
||
|
|
│ └── deploy/
|
||
|
|
│ ├── backend.Dockerfile # 백엔드 배포용 Dockerfile
|
||
|
|
│ └── frontend.Dockerfile # 프론트엔드 배포용 Dockerfile
|
||
|
|
├── k8s/
|
||
|
|
│ ├── namespace.yaml # 네임스페이스 정의
|
||
|
|
│ ├── vexplor-config.yaml # ConfigMap
|
||
|
|
│ ├── vexplor-secret.yaml.template # Secret 템플릿
|
||
|
|
│ ├── vexplor-backend-deployment.yaml # 백엔드 Deployment/Service/PVC
|
||
|
|
│ ├── vexplor-frontend-deployment.yaml # 프론트엔드 Deployment/Service
|
||
|
|
│ ├── vexplor-ingress.yaml # Ingress 설정
|
||
|
|
│ ├── local-path-provisioner.yaml # 스토리지 프로비저너
|
||
|
|
│ └── ingress-nginx.yaml # Ingress 컨트롤러 패치
|
||
|
|
└── docs/
|
||
|
|
└── KUBERNETES_DEPLOYMENT_GUIDE.md # 이 문서
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 운영 명령어
|
||
|
|
|
||
|
|
### 상태 확인
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 전체 리소스 확인
|
||
|
|
kubectl get all -n vexplor
|
||
|
|
|
||
|
|
# Pod 상태 확인
|
||
|
|
kubectl get pods -n vexplor -o wide
|
||
|
|
|
||
|
|
# 로그 확인
|
||
|
|
kubectl logs -f deployment/vexplor-backend -n vexplor
|
||
|
|
kubectl logs -f deployment/vexplor-frontend -n vexplor
|
||
|
|
|
||
|
|
# Pod 상세 정보
|
||
|
|
kubectl describe pod <pod-name> -n vexplor
|
||
|
|
```
|
||
|
|
|
||
|
|
### 수동 배포/롤백
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 이미지 업데이트
|
||
|
|
kubectl set image deployment/vexplor-backend \
|
||
|
|
vexplor-backend=harbor.wace.me/vexplor/vexplor-backend:v20241222-120000-abc1234 \
|
||
|
|
-n vexplor
|
||
|
|
|
||
|
|
# 롤아웃 상태 확인
|
||
|
|
kubectl rollout status deployment/vexplor-backend -n vexplor
|
||
|
|
|
||
|
|
# 롤백
|
||
|
|
kubectl rollout undo deployment/vexplor-backend -n vexplor
|
||
|
|
kubectl rollout undo deployment/vexplor-frontend -n vexplor
|
||
|
|
|
||
|
|
# 히스토리 확인
|
||
|
|
kubectl rollout history deployment/vexplor-backend -n vexplor
|
||
|
|
```
|
||
|
|
|
||
|
|
### 스케일링
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 레플리카 수 조정
|
||
|
|
kubectl scale deployment/vexplor-backend --replicas=3 -n vexplor
|
||
|
|
kubectl scale deployment/vexplor-frontend --replicas=3 -n vexplor
|
||
|
|
```
|
||
|
|
|
||
|
|
### Pod 재시작
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Deployment 재시작 (롤링 업데이트)
|
||
|
|
kubectl rollout restart deployment/vexplor-backend -n vexplor
|
||
|
|
kubectl rollout restart deployment/vexplor-frontend -n vexplor
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 문제 해결
|
||
|
|
|
||
|
|
### Pod이 Pending 상태일 때
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Pod 이벤트 확인
|
||
|
|
kubectl describe pod <pod-name> -n vexplor
|
||
|
|
|
||
|
|
# 노드 리소스 확인
|
||
|
|
kubectl describe node
|
||
|
|
kubectl top nodes
|
||
|
|
```
|
||
|
|
|
||
|
|
### ImagePullBackOff 오류
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Harbor Secret 확인
|
||
|
|
kubectl get secret harbor-registry -n vexplor -o yaml
|
||
|
|
|
||
|
|
# Secret 재생성
|
||
|
|
kubectl delete secret harbor-registry -n vexplor
|
||
|
|
kubectl create secret docker-registry harbor-registry \
|
||
|
|
--docker-server=192.168.1.100:5001 \
|
||
|
|
--docker-username=<username> \
|
||
|
|
--docker-password=<password> \
|
||
|
|
-n vexplor
|
||
|
|
```
|
||
|
|
|
||
|
|
### Ingress가 작동하지 않을 때
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Ingress 상태 확인
|
||
|
|
kubectl get ingress -n vexplor
|
||
|
|
kubectl describe ingress vexplor-ingress -n vexplor
|
||
|
|
|
||
|
|
# Ingress Controller 로그
|
||
|
|
kubectl logs -f deployment/ingress-nginx-controller -n ingress-nginx
|
||
|
|
```
|
||
|
|
|
||
|
|
### SSL 인증서 문제
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Certificate 상태 확인
|
||
|
|
kubectl get certificate -n vexplor
|
||
|
|
kubectl describe certificate vexplor-tls -n vexplor
|
||
|
|
|
||
|
|
# Cert-Manager 로그
|
||
|
|
kubectl logs -f deployment/cert-manager -n cert-manager
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 네트워크 설정
|
||
|
|
|
||
|
|
### 방화벽 포트 개방
|
||
|
|
|
||
|
|
쿠버네티스 서버에서 다음 포트가 개방되어야 합니다:
|
||
|
|
|
||
|
|
| 포트 | 용도 |
|
||
|
|
|-----|------|
|
||
|
|
| 30080 | HTTP (Ingress NodePort) |
|
||
|
|
| 30443 | HTTPS (Ingress NodePort) |
|
||
|
|
| 6443 | Kubernetes API |
|
||
|
|
|
||
|
|
### DNS 설정
|
||
|
|
|
||
|
|
다음 도메인이 쿠버네티스 서버 IP를 가리키도록 설정:
|
||
|
|
|
||
|
|
- `v1.vexplor.com` → 112.168.212.142
|
||
|
|
- `api.vexplor.com` → 112.168.212.142
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 환경 변수
|
||
|
|
|
||
|
|
### Backend 환경 변수
|
||
|
|
|
||
|
|
| 변수 | 설명 | 소스 |
|
||
|
|
|-----|------|-----|
|
||
|
|
| `NODE_ENV` | 환경 (production) | ConfigMap |
|
||
|
|
| `PORT` | 서버 포트 (3001) | ConfigMap |
|
||
|
|
| `DATABASE_URL` | PostgreSQL 연결 문자열 | Secret |
|
||
|
|
| `JWT_SECRET` | JWT 서명 키 | Secret |
|
||
|
|
| `JWT_EXPIRES_IN` | JWT 만료 시간 | ConfigMap |
|
||
|
|
| `CORS_ORIGIN` | CORS 허용 도메인 | ConfigMap |
|
||
|
|
|
||
|
|
### Frontend 환경 변수
|
||
|
|
|
||
|
|
| 변수 | 설명 | 소스 |
|
||
|
|
|-----|------|-----|
|
||
|
|
| `NODE_ENV` | 환경 (production) | ConfigMap |
|
||
|
|
| `NEXT_PUBLIC_API_URL` | 클라이언트 API URL | ConfigMap |
|
||
|
|
| `SERVER_API_URL` | SSR용 내부 API URL | Deployment |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 참고 자료
|
||
|
|
|
||
|
|
- [Kubernetes 공식 문서](https://kubernetes.io/docs/)
|
||
|
|
- [Gitea Actions 문서](https://docs.gitea.com/usage/actions/overview)
|
||
|
|
- [Nginx Ingress Controller](https://kubernetes.github.io/ingress-nginx/)
|
||
|
|
- [Cert-Manager](https://cert-manager.io/docs/)
|
||
|
|
- [Harbor Registry](https://goharbor.io/docs/)
|
||
|
|
|