-
Notifications
You must be signed in to change notification settings - Fork 0
Deployment
백엔드는 OCI 위의 k3s 클러스터에 GitOps 방식으로 배포한다.
k3s는 경량 Kubernetes 배포판이다. 따라서
Deployment,Service,Ingress, Kustomize 같은 표준 Kubernetes API를 쓰지만, 실제 운영 클러스터와 네트워크 운영 주체는 k3s이다.
| 위치 | 담당 |
|---|---|
dnd-15th-3-backend |
Dockerfile, GHCR 이미지, deploy/k8s 매니페스트, 환경별 이미지 태그 |
| ArgoCD | 이 레포의 배포 매니페스트 감시 및 k3s 반영 |
| 인프라 관리자 전용 레포 | k3s namespace, ArgoCD Project/RBAC, Cloudflare Tunnel/Access 설정 |
팀원은 이 백엔드 레포만 수정한다. 인프라 관리자 레포나 운영 클러스터에 직접 kubectl apply하지 않는다.
| Git branch | k3s namespace | Kustomize overlay | API hostname | 용도 |
|---|---|---|---|---|
develop |
dnd-15th-3-dev |
deploy/k8s/overlays/develop |
momo-dev.jinmu.me |
팀 통합 개발 환경 |
main |
dnd-15th-3-prod |
deploy/k8s/overlays/main |
momo.jinmu.me |
안정 배포 환경 |
기능 브랜치는 develop으로 PR을 보내고, 검증된 develop은 main으로 PR을 보낸다.
flowchart LR
infra["atlas-infra<br/>main"]
backend["dnd-15th-3-backend<br/>develop / main"]
appConfig["deploy/argocd<br/>Application definitions"]
devOverlay["deploy/k8s/overlays/develop"]
prodOverlay["deploy/k8s/overlays/main"]
ghcr["GHCR<br/>linux/arm64 image"]
root["Argo CD Application: apps"]
pointer["Argo CD Application: dnd-15th-3"]
devApp["Application: dnd-15th-3-dev"]
prodApp["Application: dnd-15th-3-prod"]
updater["Image Updater<br/>develop only"]
devNamespace["Namespace: dnd-15th-3-dev<br/>momo-dev.jinmu.me"]
prodNamespace["Namespace: dnd-15th-3-prod<br/>momo.jinmu.me"]
infra -->|root App of Apps| root
root -->|creates| pointer
pointer -->|reads deploy/argocd| appConfig
appConfig -->|defines| devApp
appConfig -->|defines| prodApp
devApp -->|reads| devOverlay
prodApp -->|reads| prodOverlay
devOverlay -->|sync and selfHeal| devNamespace
prodOverlay -->|sync and selfHeal| prodNamespace
backend -->|push and workflow| ghcr
ghcr -->|new develop tag| updater
updater -->|live image parameter| devApp
flowchart TB
client["Client"]
cloudflare["Cloudflare Edge<br/>momo-dev.jinmu.me / momo.jinmu.me"]
tunnel["Cloudflare Tunnel<br/>cloudflared"]
traefik["Traefik<br/>NodePort 30080"]
ingress["Ingress: momo-api<br/>path /"]
apiService["Service: momo-api<br/>port 80 → 3000"]
api["Deployment: momo-api<br/>1 replica per environment<br/>dnd-15th-3-dev / dnd-15th-3-prod"]
dbService["Service: momo-postgres<br/>port 5432"]
postgres["StatefulSet: momo-postgres<br/>1 replica"]
pvc["local-path PVC<br/>dev 5Gi / prod 10Gi"]
backup["CronJob: momo-postgres-backup<br/>04:00 KST"]
objectStorage["OCI Object Storage<br/>PostgreSQL dump"]
client --> cloudflare
cloudflare -->|public hostname route| tunnel
tunnel -->|HTTP to node port| traefik
traefik --> ingress
ingress --> apiService
apiService --> api
api --> dbService
dbService --> postgres
postgres --> pvc
backup --> dbService
backup --> objectStorage
현재 API와 PostgreSQL은 각 환경에서 1 replica로 실행된다. API replica를 늘려도 PostgreSQL은 단일 인스턴스이므로 전체 구조가 고가용성이 되는 것은 아니다.
feature branch PR → develop merge
→ GitHub Actions: linux/arm64 이미지 build
→ GHCR: develop-<commit-sha> push
→ deploy/k8s/overlays/develop 이미지 태그 commit
→ ArgoCD가 변경 감지
→ k3s dnd-15th-3-dev namespace rollout
develop → main PR도 같은 흐름으로 main 환경에 배포
이미지 태그는 develop-<sha> 또는 main-<sha>의 불변 태그다. latest를 사용하지 않으므로,
어느 코드가 실행 중인지 Git과 ArgoCD에서 추적하고 이전 SHA로 롤백할 수 있다.
Dockerfile # 애플리케이션 컨테이너
.github/workflows/image.yml # ARM build + 배포 태그 갱신
deploy/k8s/base/ # 공통 Deployment, Service, Ingress
deploy/k8s/overlays/develop/ # develop 환경 차이
deploy/k8s/overlays/main/ # main 환경 차이
deploy/sealed-secrets.pub.pem # Secret 암호화용 공개 인증서
배포된 앱은 /api/docs에서 Swagger UI를 제공한다. API 명세는 배포 후 해당 경로에서 확인한다.
현재 readiness/liveness/startup probe는 다음 health endpoint를 사용한다.
| 엔드포인트 | 용도 | 확인 항목 |
|---|---|---|
GET /health (dev) |
App level 종합 상태 | Startup/readiness probe, DB + PostGIS + OCI Storage |
GET /health (prod) |
App level 종합 상태 | Startup/readiness probe, DB + OCI Storage |
GET /health/live |
Liveness probe | 프로세스 생존 |
Kubernetes의 startup과 readiness probe는 /health, liveness probe는 /health/live를
사용한다. 현재 dev /health는 database, postgis, storage를 함께 확인한다. 정상일 때
info.postgis와 details.postgis에는 status: "up"과 설치 버전이 포함되며, PostGIS extension이
없거나 버전 쿼리가 실패하면 503을 반환한다. prod는 PostGIS 승격 전이므로 기존
database·storage 계약을 유지한다. /health/live는 두 환경 모두 외부 의존성과 무관하게
프로세스 생존 여부만 확인한다.
새 기능이 시작 의존성(DB 등)을 추가하면 readiness와 /health 기준도 함께 갱신한다.
평문 .env, API 키, DB 비밀번호는 commit/PR/채팅에 올리지 않는다. 필요한 값은 공개 인증서로
SealedSecret을 만들고 암호화된 파일만 환경 overlay에 추가한다.
kubeseal --format=yaml --cert deploy/sealed-secrets.pub.pem \
< secret.plain.yaml > deploy/k8s/overlays/develop/secret.sealed.yaml
rm secret.plain.yaml공개 인증서는 암호화만 가능하고 복호화는 불가하다. 실제 Secret 값은 k3s의 sealed-secrets controller만 복호화한다.
cluster-admin kubeconfig는 인프라 관리자만 보유한다. 개발자가 dev 클러스터 DB에 붙어야 할 때는 네임스페이스 한정 최소 권한 kubeconfig를 발급한다.
| 환경 | 정책 |
|---|---|
| dev | 제한 kubeconfig 발급 — DB 자격증명 Secret 읽기 + port-forward만 허용 |
| prod | 직접 접근 불가 — 필요 시 인프라 관리자가 쿼리 대행 |
dev RBAC(db-developer)은 deploy/k8s/overlays/develop/db-access.yaml에 정의되어
있고, 허용 범위는 정확히 다음뿐이다.
-
momo-postgres-auth/momo-statistics-postgres-authSecret 읽기 -
pods/portforward생성 (port-forward 대상 해석에 필요한 조회 포함)
발급 플로우(인프라 관리자):
# 1. db-access.yaml이 develop에 머지되어 ArgoCD가 sync한 뒤
bash scripts/make-db-kubeconfig.sh # kubeconfig.db-developer.yaml 생성
# 2. 생성된 파일을 안전한 채널로 전달 (commit/채팅 붙여넣기 금지)개발자 사용법:
export KUBECONFIG=$HOME/.kube/db-developer.yaml
mise run cluster-check # 접속 확인
mise run dev-api # 또는 mise run db-forward-dev토큰 유출이 의심되면 db-developer-token Secret을 삭제·재생성해 전체 발급분을
일괄 폐기할 수 있다. 구성원별 개별 발급이 필요하면 ServiceAccount를 분리한다.
- PostgreSQL/PostGIS 이미지 pull, migration, backup, 노드 DNS와 DB 복구는 PostGIS K3s Operations 런북을 따른다.
- ArgoCD
dnd-viewer계정은 DND 앱과 로그만 read-only로 볼 수 있다. - dev 배포에서는 Sync operation의
PreSync단계에서momo-api-migrationHook이 성공했는지 확인한다. 성공한 Hook Job은 자동 삭제될 수 있으므로 Pod/Job 목록에 없으면 ArgoCD operation history에서 실행 결과와 로그를 확인한다. - dev 배포 후
/health가200 OK이고database,postgis,storage가 모두status: "up"인지 확인한다. prod는 PostGIS 승격 전까지database,storage를 확인한다. -
ImagePullBackOff,CrashLoopBackOff, PVC Pending, Secret 누락은 ArgoCD 상태와 이벤트를 첨부해 인프라 관리자에게 전달한다. - 앱을 멈추려면 Deployment replica 또는 CronJob suspend를 Git PR로 변경한다. UI에서 Delete/Sync하지 않는다.
- 영구 삭제는 PVC까지 지울 수 있으므로 팀원이 단독으로 진행하지 않는다.
- GitHub Actions의 GHCR package write 권한과 public package visibility 확인
- ArgoCD Application이
develop/mainoverlay를 각각 감시하도록 등록 - Cloudflare Tunnel에
momo-dev.jinmu.me,momo.jinmu.mehostname 추가 - ArgoCD
dnd-viewer계정과 Cloudflare Access 이메일 allowlist 설정