π§ Day 2-3: FastAPI 3-Tier Application
π§ Day 2-3: FastAPI 3-Tier Application
FastAPI + MySQLμ μ¬μ©ν 3-Tier μν€ν μ² + GitLab/GitHub CI/CD
π μν€ν μ² λ€μ΄μ΄κ·Έλ¨ 보기 - Mermaid λ€μ΄μ΄κ·Έλ¨μΌλ‘ μ 체 κ΅¬μ± νμΈ
λͺ©μ°¨β
- π GitHub β GitLab λ―Έλ¬λ§
- π¦ GitLab CI/CD
- π Kubernetes λ°°ν¬
- ποΈ 3-Tier μν€ν μ²
- π API μλν¬μΈνΈ
- π§ νκ²½λ³μ μ€μ
- π₯ νΈλ¬λΈμν
π GitHub β GitLab μλ λ―Έλ¬λ§ μ€μ β
GitHub Actionsλ₯Ό ν΅ν΄ μλμΌλ‘ GitLabμ λκΈ°ν
μ€μ λ¨κ³β
| Step | μμ | μμΈ |
|---|---|---|
| 1 | GitLab λΉ νλ‘μ νΈ μμ± | GitLab > New project > Create blank project |
| 2 | Access Token λ°κΈ | Settings > Access Tokens (write_repository 체ν¬) |
| 3 | GitHub Secrets μ€μ | Settings > Secrets and variables > Actions |
π GitHub Secretsβ
| Secret μ΄λ¦ | κ° |
|---|---|
GITLAB_URL | gitlab.com/username/pista-megazoncloud.git |
GITLAB_TOKEN | Step 2μμ λ°κΈν ν ν° |
μν¬νλ‘μ° νμΌ:
.github/workflows/mirror-to-gitlab.ymlmain,feat/**,kubernetesλΈλμΉ νΈμ μ μλ λ―Έλ¬λ§
π¦ GitLab CI/CDβ
.gitlab-ci.ymlμ΄ ν¬ν¨λμ΄ μμ΄ main λλ feat/On-premise-ICT λΈλμΉμ νΈμνλ©΄ μλμΌλ‘:
| μμ | μμ | κ²°κ³Όλ¬Ό |
|---|---|---|
| 1 | Docker μ΄λ―Έμ§ λΉλ | - |
| 2 | GitLab Container Registry νΈμ | $CI_REGISTRY_IMAGE/fastapi:latest |
| 3 | - | $CI_REGISTRY_IMAGE/nginx:latest |
| 4 | - | $CI_REGISTRY_IMAGE/mysql:latest |
π λ‘컬μμ GitLab Registry λ‘κ·ΈμΈβ
docker login registry.gitlab.com
# Username: GitLab μ¬μ©μλͺ
# Password: Personal Access Token (λΉλ°λ²νΈ μλ!)
Personal Access Token λ°κΈ:
- GitLab β μ°μΈ‘ μλ¨ νλ‘ν β Edit profile
- Access Tokens λ©λ΄
- Scopes:
read_registry,write_registryμ²΄ν¬ - Create personal access token β ν ν° λ³΅μ¬
π Kubernetes λ°°ν¬β
1οΈβ£ GitLab Registry Secret μμ±β
kubectl create secret docker-registry gitlab-registry-secret \
--docker-server=registry.gitlab.com \
--docker-username=pyh5523 \
--docker-password=<Personal Access Token>
[!WARNING] ImagePullBackOff μλ¬ λ°μ μ:
- Secret νμΈ:
kubectl get secrets- Pod μ¬μμ±:
kubectl delete pod -l app=fastapi-podimagePullSecretsμ€μ νμΈ
2οΈβ£ μ ν리μΌμ΄μ λ°°ν¬β
# FastAPI λ°°ν¬
kubectl apply -f fastapi-deploy.yaml
kubectl apply -f fastapi-service.yaml
# Nginx λ°°ν¬
kubectl apply -f ../nginx/nginx-deploy.yaml
kubectl apply -f ../nginx/nginx-service.yaml
3οΈβ£ MySQL λ°°ν¬β
# ConfigMap (μ΄κΈ°ν μ€ν¬λ¦½νΈ)
kubectl apply -f mysql/mysql-configmap.yaml
# Secret/PV/PVC (β οΈ Secret κ°μ μ§μ μμ ν μ μ©!)
kubectl apply -f mysql/mysql-secret.yaml
kubectl apply -f mysql/mysql-pv.yaml
kubectl apply -f mysql/mysql-pvc.yaml
kubectl apply -f mysql/mysql-deploy.yaml
kubectl apply -f mysql/mysql-service.yaml
4οΈβ£ λ°°ν¬ νμΈβ
kubectl get pods
kubectl get svc
kubectl get pv,pvc
ποΈ 3-Tier μν€ν μ²β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
β Nginx ββββββΆβ FastAPI ββββββΆβ MySQL β
β (Web) β β (WAS) β β (DB) β
β Port 80 β β Port 8000 β β Port 3306 β
βββββββββββββββ βββββββββββββββ βββββββββββββββ
/member proxy /member pymysql
π API μλν¬μΈνΈβ
| Method | Path | μ€λͺ |
|---|---|---|
| GET | / | Hello World μλ΅ |
| GET | /member | MySQL μ°κ²° ν μ€νΈ |
π§ νκ²½λ³μ μ€μ β
| λ³μλͺ | κΈ°λ³Έκ° | μ€λͺ |
|---|---|---|
MYSQL_HOST | mysql | MySQL νΈμ€νΈ |
MYSQL_USER | root | MySQL μ¬μ©μ |
MYSQL_PASSWORD | root | MySQL λΉλ°λ²νΈ |
MYSQL_DB | test | λ°μ΄ν°λ² μ΄μ€λͺ |
Kubernetesμμ νκ²½λ³μ μ€μ :
env:
- name: MYSQL_HOST
value: "mysql-service"
- name: MYSQL_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: username
βοΈ νκ²½ μ€μ β
| νλͺ© | κ° |
|---|---|
| Port | 8000 |
| CORS | localhost:8000, example.com |
| Python | 3.12-slim |
π₯ νΈλ¬λΈμν β
MySQL ConfigMap init.sqlμ΄ μ€νλμ§ μμβ
μ¦μ:
{"message":"fail","error":"(1146, \"Table 'pista-db.tmember' doesn't exist\")"}
μμΈ:
- MySQL μ΄κΈ°ν μ€ν¬λ¦½νΈλ λ°μ΄ν° λλ ν λ¦¬κ° λΉμ΄μμ λλ§ μ€νλ¨
- PVCμ μ΄μ λ°μ΄ν°κ° λ¨μμμΌλ©΄ init.sqlμ΄ λ¬΄μλ¨
ν΄κ²°:
# 1. λͺ¨λ λ
Έλμμ λ°μ΄ν° μμ
ssh k8s-n1 "sudo rm -rf /data/mysql/*"
ssh k8s-n2 "sudo rm -rf /data/mysql/*"
ssh k8s-n3 "sudo rm -rf /data/mysql/*"
kubectl delete -f mysql/
# 2. MySQL 리μμ€ μ¬λ°°ν¬
kubectl apply -f mysql/
κ²μ¦:
curl 192.168.5.101:8000/member
# {"message":"success","data":[...]}