# ๐ŸŒ Web Portal โ€” Kubernetes + GitOps ํ™ˆ๋žฉ ํ”„๋กœ์ ํŠธ > ์กฐ์ง ๋‚ด๋ถ€ ์›นํŽ˜์ด์ง€๋ฅผ ํ†ตํ•ฉ ๊ด€๋ฆฌํ•˜๋Š” ํฌํ„ธ ์‹œ์Šคํ…œ์„ **์˜จํ”„๋ ˆ๋ฏธ์Šค Kubernetes ํ™˜๊ฒฝ**์—์„œ ์ง์ ‘ ์„ค๊ณ„ยท๊ตฌ์ถ•ยท์šด์˜ํ•œ ํ™ˆ๋žฉ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. [![Kubernetes](https://img.shields.io/badge/Kubernetes-326CE5?style=flat&logo=kubernetes&logoColor=white)](https://kubernetes.io) [![ArgoCD](https://img.shields.io/badge/ArgoCD-EF7B4D?style=flat&logo=argo&logoColor=white)](https://argoproj.github.io/cd) [![FastAPI](https://img.shields.io/badge/FastAPI-009688?style=flat&logo=fastapi&logoColor=white)](https://fastapi.tiangolo.com) [![PostgreSQL](https://img.shields.io/badge/PostgreSQL-4169E1?style=flat&logo=postgresql&logoColor=white)](https://www.postgresql.org) [![Docker](https://img.shields.io/badge/Docker-2496ED?style=flat&logo=docker&logoColor=white)](https://www.docker.com) [![Let's Encrypt](https://img.shields.io/badge/Let's_Encrypt-003A70?style=flat&logo=letsencrypt&logoColor=white)](https://letsencrypt.org) --- ## ๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ๋ชฉ์  ๋‹จ์ˆœํžˆ ๋”ฐ๋ผํ•˜๋Š” ํŠœํ† ๋ฆฌ์–ผ์ด ์•„๋‹Œ, **์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฌธ์ œ๋“ค์„ ์ง์ ‘ ๋งž๋‹ฅ๋œจ๋ฆฌ๊ณ  ํ•ด๊ฒฐ**ํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค. - ์‹ค์ œ ๋„๋ฉ”์ธ(`cyanburu.com`) + HTTPS ์ ์šฉ์œผ๋กœ ์™ธ๋ถ€ ์ธํ„ฐ๋„ท์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์„œ๋น„์Šค ์šด์˜ - GitOps ๋ฐฉ์‹์œผ๋กœ ์ฝ”๋“œ ๋ณ€๊ฒฝ ์‹œ ์ž๋™ ๋ฐฐํฌ๋˜๋Š” CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ - Pod ์ด์ƒ ๊ฐ์ง€, ์ธ์ฆ์„œ ๋งŒ๋ฃŒ ์ž„๋ฐ• ์‹œ DiscordยทGmail ์ž๋™ ์•Œ๋ฆผ ๊ตฌํ˜„ - ๋ฐœ์ƒํ•œ ์žฅ์•  14๊ฑด์„ ๋ชจ๋‘ ๋ฌธ์„œํ™”ํ•˜์—ฌ ์žฌํ˜„ยทํ•ด๊ฒฐ ๊ณผ์ • ๊ธฐ๋ก --- ## ๐Ÿ—๏ธ ์ „์ฒด ์•„ํ‚คํ…์ฒ˜ ``` ์‚ฌ์šฉ์ž (์™ธ๋ถ€ ์ธํ„ฐ๋„ท) โ”œโ”€โ”€ https://cyanburu.com โ†’ Web Portal โ”œโ”€โ”€ https://gitea.cyanburu.com โ†’ Gitea (Self-hosted Git) โ””โ”€โ”€ https://argo.cyanburu.com โ†’ ArgoCD (GitOps) โ†“ MSI ๋ผ์šฐํ„ฐ (ํฌํŠธํฌ์›Œ๋”ฉ 80/443) โ†“ Nginx Ingress Controller โ† TLS ์ข…๋ฃŒ, ๋„๋ฉ”์ธ๋ณ„ ๋ผ์šฐํŒ… โ†“ cert-manager โ† Let's Encrypt ์ธ์ฆ์„œ ์ž๋™ ๋ฐœ๊ธ‰/๊ฐฑ์‹  โ†“ Kubernetes ๋„ค์ž„์ŠคํŽ˜์ด์Šค โ”œโ”€โ”€ web-portal โ”‚ โ”œโ”€โ”€ Nginx Frontend (SPA) โ”‚ โ”œโ”€โ”€ FastAPI Backend (REST API) โ”‚ โ””โ”€โ”€ PostgreSQL DB (PVC ์˜๊ตฌ ์ €์žฅ) โ”œโ”€โ”€ gitea โ†’ Self-hosted Git + Container Registry โ””โ”€โ”€ argocd โ†’ GitOps ์ž๋™ ๋ฐฐํฌ ์—”์ง„ โ†‘ ๊ฐœ๋ฐœ์ž git push โ†’ Gitea โ†’ ArgoCD ์ž๋™ ๊ฐ์ง€ & ๋ฐฐํฌ ``` --- ## ๐Ÿ› ๏ธ ๊ธฐ์ˆ  ์Šคํƒ | ๊ตฌ๋ถ„ | ๊ธฐ์ˆ  | ์„ ํƒ ์ด์œ  | |------|------|-----------| | **Container Orchestration** | Kubernetes (Docker Desktop ๋‚ด์žฅ) | ์˜จํ”„๋ ˆ๋ฏธ์Šค ํ™˜๊ฒฝ์—์„œ ํ”„๋กœ๋•์…˜๊ณผ ๋™์ผํ•œ ๊ตฌ์กฐ ๊ตฌํ˜„ | | **GitOps** | Gitea + ArgoCD | Git์„ ๋‹จ์ผ ์ง„์‹ค ์†Œ์Šค๋กœ, ์„ ์–ธ์  ๋ฐฐํฌ ์ž๋™ํ™” | | **Image Registry** | Gitea Container Registry | ์™ธ๋ถ€ ์˜์กด ์—†์ด ์‚ฌ๋‚ด ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ž์ฒด ์šด์˜ | | **Ingress** | Nginx Ingress Controller | ๋„๋ฉ”์ธ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…, TLS ์ข…๋ฃŒ ์ฒ˜๋ฆฌ | | **TLS** | cert-manager + Let's Encrypt | ์ธ์ฆ์„œ ๋ฐœ๊ธ‰ยท๊ฐฑ์‹  ์™„์ „ ์ž๋™ํ™” | | **Backend** | Python FastAPI | ๋น„๋™๊ธฐ REST API, JWT ์ธ์ฆ | | **Database** | PostgreSQL + PVC | ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘ ํ›„์—๋„ ๋ฐ์ดํ„ฐ ์˜์† | | **Monitoring** | APScheduler (์ปค์Šคํ…€) | Pod ์ƒํƒœ 1๋ถ„ ์ฃผ๊ธฐ, ์ธ์ฆ์„œ ๋งŒ๋ฃŒ 24์‹œ๊ฐ„ ์ฃผ๊ธฐ ์ฒดํฌ | | **Alerting** | Discord Webhook + Gmail | ์žฅ์•  ๋ฐœ์ƒ ์‹œ ์ฆ‰์‹œ ์•Œ๋ฆผ | --- ## โœจ ๊ตฌํ˜„ ๊ธฐ๋Šฅ ### ๋ณด์•ˆ (Security) - JWT ๊ธฐ๋ฐ˜ ์ธ์ฆ / ์„ธ์…˜ ๊ด€๋ฆฌ - **๋น„๋ฐ€๋ฒˆํ˜ธ 5ํšŒ ์˜ค๋ฅ˜ ์‹œ ๊ณ„์ • ์ž๋™ ์ž ๊ธˆ** โ†’ ๊ด€๋ฆฌ์ž ํ•ด์ œ - **์ตœ์ดˆ ๋กœ๊ทธ์ธ ๊ฐ•์ œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ** (์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ฐœ๊ธ‰ ํฌํ•จ) - **Nginx Rate Limiting** โ€” ๋กœ๊ทธ์ธ API ๋ถ„๋‹น 5ํšŒ ์ œํ•œ (Brute Force ๋ฐฉ์–ด) - HTTPS ์ž๋™ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ (`ssl-redirect: "true"`) ### ๋ชจ๋‹ˆํ„ฐ๋ง & ์•Œ๋ฆผ (Observability) - Pod ์ƒํƒœ 1๋ถ„๋งˆ๋‹ค ์ž๋™ ์ฒดํฌ โ†’ ์ด์ƒ/๋ณต๊ตฌ ์‹œ **Discord + Gmail ์•Œ๋ฆผ** - ์ธ์ฆ์„œ ๋งŒ๋ฃŒ 24์‹œ๊ฐ„ ์ฃผ๊ธฐ ์ฒดํฌ โ†’ ๋งŒ๋ฃŒ ์ž„๋ฐ• ์‹œ Gmail ์•Œ๋ฆผ - **์›น UI์—์„œ ์•Œ๋ฆผ ์ฑ„๋„ ๊ด€๋ฆฌ** (Discord/Gmail/ํ˜ผํ•ฉ ์ฑ„๋„ ๋‹ค์ค‘ ๋“ฑ๋ก) - DB ๊ธฐ๋ฐ˜ ์•Œ๋ฆผ ์„ค์ • โ†’ Pod ์žฌ์‹œ์ž‘ ํ›„์—๋„ ์„ค์ • ์œ ์ง€ ### ๊ด€๋ฆฌ์ž ๊ธฐ๋Šฅ - ์‚ฌ์šฉ์ž ๊ณ„์ • ์ƒ์„ฑ/์‚ญ์ œ, ์ ‘๊ทผ ๊ถŒํ•œ ์„ค์ • (์ฒดํฌ๋ฐ•์Šค UI) - ์ž„์‹œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ž๋™ ์ƒ์„ฑ ๋ฐ ๋ฐœ๊ธ‰ - ๊ณต์ง€์‚ฌํ•ญ / ๊ด€๋ฆฌ์ž ์š”์ฒญ ๊ฒŒ์‹œํŒ (๋Œ“๊ธ€ยท๋‹ต๊ธ€ ํฌํ•จ) - ์‚ฌ์šฉ์ž ์ƒํƒœ ํƒœ๊ทธ: `์ •์ƒ` / `๐Ÿ”’์ž ๊น€` / `์ดˆ๊ธฐPW` / `๋ณ€๊ฒฝ์š”์ฒญ` --- ## ๐Ÿ“… ๊ตฌ์ถ• ์ด๋ ฅ | ๋‚ ์งœ | ์ฃผ์š” ์ž‘์—… | |------|-----------| | 2026-04-06 | K8s ์ดˆ๊ธฐ ๊ตฌ์ถ•, FastAPI + Nginx + PostgreSQL ๋ฐฐํฌ, Gitea + ArgoCD GitOps ๊ตฌ์„ฑ | | 2026-04-10 | ๋„๋ฉ”์ธ ์—ฐ๊ฒฐ (HTTPS), cert-manager, CoreDNS ํ—ค์–ดํ•€ NAT ์šฐํšŒ, ๋ณด์•ˆ ๊ธฐ๋Šฅ ๊ฐ•ํ™” | | 2026-04-27 | Discord/Gmail ์•Œ๋ฆผ ์ถ”๊ฐ€, APScheduler ๋ชจ๋‹ˆํ„ฐ๋ง, ์•Œ๋ฆผ ์ฑ„๋„ ๊ด€๋ฆฌ UI | --- ## ๐Ÿ”ฅ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… (14๊ฑด ํ•ด๊ฒฐ) ์‹ค์ œ ๊ตฌ์ถ• ๊ณผ์ •์—์„œ ๊ฒช์€ ์žฅ์• ์™€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ๊ธฐ๋กํ•ฉ๋‹ˆ๋‹ค.
1. NodePort ํฌํŠธ ์ถฉ๋Œ **์ฆ์ƒ** `provided port is already allocated` **์›์ธ** ํ•ด๋‹น NodePort๊ฐ€ ๋‹ค๋ฅธ ์„œ๋น„์Šค์—์„œ ์ด๋ฏธ ์‚ฌ์šฉ ์ค‘ **ํ•ด๊ฒฐ** `k8s/05-frontend.yaml`์—์„œ NodePort ๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ํ›„ ์„œ๋น„์Šค ์žฌ์ ์šฉ
2. Backend CrashLoopBackOff โ€” Liveness Probe ์‹คํŒจ **์ฆ์ƒ** `Liveness probe failed: HTTP probe failed with statuscode: 404` **์›์ธ** DB ์—ฐ๊ฒฐ ๋Œ€๊ธฐ ์ค‘ liveness probe๊ฐ€ ๋จผ์ € ์‹คํŒจํ•ด K8s๊ฐ€ ๊ฐ•์ œ ์žฌ์‹œ์ž‘ **ํ•ด๊ฒฐ** `initialDelaySeconds: 60`, `failureThreshold: 5`๋กœ ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ฆ๊ฐ€
3. Nginx API ํ”„๋ก์‹œ ์‹คํŒจ โ€” JSON ํŒŒ์‹ฑ ์˜ค๋ฅ˜ **์ฆ์ƒ** ๋กœ๊ทธ์ธ ์‹œ `Unexpected token '<', "..." is not valid JSON` **์›์ธ** Nginx๊ฐ€ `/api/` ์š”์ฒญ์„ ๋ฐฑ์—”๋“œ๋กœ ์ „๋‹ฌํ•˜์ง€ ๋ชปํ•˜๊ณ  HTML ๋ฐ˜ํ™˜ **ํ•ด๊ฒฐ** `proxy_pass`๋ฅผ K8s ๋‚ด๋ถ€ FQDN(`backend-service.web-portal.svc.cluster.local`)์œผ๋กœ ๋ณ€๊ฒฝ
4. ArgoCD โ€” authentication required: Unauthorized **์ฆ์ƒ** `failed to list refs: authentication required` **์›์ธ** ArgoCD๊ฐ€ Gitea ์ €์žฅ์†Œ ์ธ์ฆ ์ •๋ณด ์—†์Œ **ํ•ด๊ฒฐ** `argocd.argoproj.io/secret-type=repository` ๋ ˆ์ด๋ธ”์ด ์žˆ๋Š” Secret ์ง์ ‘ ์ƒ์„ฑ
5. RepeatedResourceWarning โ€” ๋ฆฌ์†Œ์Šค ์ค‘๋ณต **์ฆ์ƒ** `Resource appeared 2 times among application resources` **์›์ธ** `k8s/` ํด๋” ๋‚ด ๋™์ผ ๋ฆฌ์†Œ์Šค๋ฅผ ์ •์˜ํ•˜๋Š” YAML ์ค‘๋ณต ์กด์žฌ **ํ•ด๊ฒฐ** ์ค‘๋ณต ํŒŒ์ผ ์‚ญ์ œ ํ›„ push
6. ImagePullBackOff โ€” Gitea Registry HTTP ์ ‘๊ทผ ์˜ค๋ฅ˜ **์ฆ์ƒ** `server gave HTTP response to HTTPS client` **์›์ธ** Gitea Registry๊ฐ€ HTTP์ธ๋ฐ Docker๊ฐ€ HTTPS๋กœ ์ ‘๊ทผ ์‹œ๋„ **ํ•ด๊ฒฐ** Docker Desktop `insecure-registries` ์„ค์ • ์ถ”๊ฐ€
7. Gitea Container Registry ๋กœ๊ทธ์ธ ์‹คํŒจ (context deadline exceeded) **์ฆ์ƒ** `Get "http://...:30000/v2/": context deadline exceeded` **์›์ธ** Gitea ROOT_URL์ด `localhost`๋กœ ์„ค์ •๋˜์–ด token ์š”์ฒญ์ด ์™ธ๋ถ€๋กœ ๋‚˜๊ฐ€์ง€ ๋ชปํ•จ **ํ•ด๊ฒฐ** Helm upgrade๋กœ `ROOT_URL`, `DOMAIN`, Packages ํ™œ์„ฑํ™” ์„ค์ • ๋ณ€๊ฒฝ
8. K8s ๋‚ด๋ถ€ Gitea Registry ์ด๋ฏธ์ง€ Pull ์‹คํŒจ **์ฆ์ƒ** ์™ธ๋ถ€์—์„œ๋Š” push ์„ฑ๊ณต, Pod๋Š” `ImagePullBackOff` **์›์ธ** K8s Pod โ†’ ์™ธ๋ถ€ IP ๊ฒฝ๋กœ ๋ถˆ์•ˆ์ • **ํ•ด๊ฒฐ** image ์ฃผ์†Œ๋ฅผ K8s ๋‚ด๋ถ€ ์„œ๋น„์Šค๋ช…(`gitea-http.gitea.svc.cluster.local:3000`)์œผ๋กœ ๋ณ€๊ฒฝ
9. ๋กœ๊ทธ์ธ ์‹คํŒจ โ€” ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹œ ์˜ค์—ผ **์ฆ์ƒ** ์˜ฌ๋ฐ”๋ฅธ ๊ณ„์ •์œผ๋กœ๋„ ๋กœ๊ทธ์ธ ์‹คํŒจ **์›์ธ** ํ„ฐ๋ฏธ๋„ ์ƒ‰์ƒ ์ฝ”๋“œ(`\x1B[0m`)๊ฐ€ bcrypt ํ•ด์‹œ์— ์„ž์—ฌ DB์— ์ €์žฅ๋จ **ํ•ด๊ฒฐ** Backend Pod์—์„œ Python์œผ๋กœ ํ•ด์‹œ ์žฌ์ƒ์„ฑ ํ›„ DB ์ง์ ‘ ์—…๋ฐ์ดํŠธ
10. git push ๊ฑฐ์ ˆ โ€” non-fast-forward **์ฆ์ƒ** `Updates were rejected because the tip of your current branch is behind` **์›์ธ** Gitea UI์—์„œ ์ง์ ‘ ํŒŒ์ผ ์ˆ˜์ •์œผ๋กœ ๋กœ์ปฌ-์›๊ฒฉ ๋ธŒ๋žœ์น˜ diverge **ํ•ด๊ฒฐ** `git pull origin main --rebase` ํ›„ push
11. cert-manager HTTP01 Challenge Pending โ€” ํ—ค์–ดํ•€ NAT **์ฆ์ƒ** `propagation check failed: context deadline exceeded` **์›์ธ** cert-manager๊ฐ€ K8s ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ๋„๋ฉ”์ธ์œผ๋กœ self-check ์‹œ ํ—ค์–ดํ•€ NAT ๋ฏธ์ง€์›์œผ๋กœ ํƒ€์ž„์•„์›ƒ **ํ•ด๊ฒฐ** CoreDNS์— ๋‚ด๋ถ€ ๋„๋ฉ”์ธ์„ ์ง์ ‘ ๋“ฑ๋ก โ†’ K8s ๋‚ด๋ถ€์—์„œ ๋„๋ฉ”์ธ์„ ๋‚ด๋ถ€ IP๋กœ ํ•ด์„
12. Ingress Controller EXTERNAL-IP๊ฐ€ localhost๋กœ ํ‘œ์‹œ **์ฆ์ƒ** `kubectl get svc -n ingress-nginx` โ†’ EXTERNAL-IP: `localhost` **์›์ธ** Docker Desktop ํ™˜๊ฒฝ์˜ ์ •์ƒ ๋™์ž‘ (`localhost` = ์‹ค์ œ PC) **ํ•ด๊ฒฐ** ํฌํŠธํฌ์›Œ๋”ฉ์„ NodePort๊ฐ€ ์•„๋‹Œ **80/443 โ†’ PC ๋‚ด๋ถ€ IP:80/443**์œผ๋กœ ์ง์ ‘ ์„ค์ •
13. git commit ์‹คํŒจ โ€” Author identity unknown **์ฆ์ƒ** `fatal: unable to auto-detect email address` **์›์ธ** Git ์‚ฌ์šฉ์ž ์ •๋ณด ๋ฏธ์„ค์ • **ํ•ด๊ฒฐ** `git config --global user.email`, `user.name` ์„ค์ •
14. Gitea Registry ImagePullBackOff โ€” ํ† ํฐ ์ธ์ฆ ํ—ค์–ดํ•€ NAT **์ฆ์ƒ** `Get "http://gitea-http...svc.cluster.local:3000/v2/token?...": context deadline exceeded` **์›์ธ** Docker ๋ฐ๋ชฌ์ด K8s ๋‚ด๋ถ€ DNS๋ฅผ ํ•ด์„ํ•˜์ง€ ๋ชปํ•ด ํ† ํฐ ์ธ์ฆ ์‹คํŒจ **ํ•ด๊ฒฐ** image ์ฃผ์†Œ์™€ Registry Secret์„ ์™ธ๋ถ€ IP(`192.168.10.101:30000`)๋กœ ํ†ต์ผ
--- ## ๐Ÿ“ ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ ``` nginx-portal/ โ”œโ”€โ”€ backend/ โ”‚ โ”œโ”€โ”€ main.py # FastAPI ์ „์ฒด API ๋กœ์ง (์ธ์ฆ, ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ, ๊ฒŒ์‹œํŒ) โ”‚ โ”œโ”€โ”€ notifier.py # Discord/Gmail ์•Œ๋ฆผ ๋ชจ๋“ˆ (DB ๊ธฐ๋ฐ˜ ๋‹ค์ค‘ ์ฑ„๋„) โ”‚ โ”œโ”€โ”€ monitor.py # APScheduler ๋ชจ๋‹ˆํ„ฐ๋ง (Pod ์ƒํƒœ, ์ธ์ฆ์„œ ๋งŒ๋ฃŒ) โ”‚ โ”œโ”€โ”€ requirements.txt โ”‚ โ””โ”€โ”€ Dockerfile โ”œโ”€โ”€ frontend/ โ”‚ โ”œโ”€โ”€ index.html # ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์•ฑ (SPA) โ”‚ โ”œโ”€โ”€ nginx.conf # Nginx ์„ค์ • + Rate Limiting + /api/* ํ”„๋ก์‹œ โ”‚ โ””โ”€โ”€ Dockerfile โ”œโ”€โ”€ k8s/ โ”‚ โ”œโ”€โ”€ 01-namespace.yaml โ”‚ โ”œโ”€โ”€ 02-postgres.yaml # PostgreSQL + PVC โ”‚ โ”œโ”€โ”€ 03-secrets.yaml # DB / JWT ์‹œํฌ๋ฆฟ โ”‚ โ”œโ”€โ”€ 04-backend.yaml # FastAPI Deployment โ”‚ โ”œโ”€โ”€ 05-frontend.yaml # Nginx Deployment โ”‚ โ”œโ”€โ”€ 07-clusterissuer.yaml # Let's Encrypt ClusterIssuer โ”‚ โ”œโ”€โ”€ 08-ingress.yaml # cyanburu.com โ”‚ โ”œโ”€โ”€ 09-ingress-gitea.yaml โ”‚ โ””โ”€โ”€ 10-ingress-argocd.yaml โ”œโ”€โ”€ 06-argocd-app.yaml # ArgoCD Application (k8s/ ํด๋” ๋ฐ– โ€” ์ˆœํ™˜ ์ฐธ์กฐ ๋ฐฉ์ง€) โ””โ”€โ”€ README.md ``` --- ## ๐Ÿš€ ๋ฐฐํฌ ๋ฐฉ๋ฒ• ### ์‚ฌ์ „ ์š”๊ตฌ ์‚ฌํ•ญ - Docker Desktop (Kubernetes ํ™œ์„ฑํ™”) - kubectl, helm ์„ค์น˜ - ๊ณต์ธ ๋„๋ฉ”์ธ (A ๋ ˆ์ฝ”๋“œ โ†’ ๊ณต์ธ IP ์—ฐ๊ฒฐ) - ๋ผ์šฐํ„ฐ ํฌํŠธํฌ์›Œ๋”ฉ ์„ค์ • (80, 443) ### ํ•ต์‹ฌ ๋ฐฐํฌ ์ˆœ์„œ ```bash # 1. Nginx Ingress Controller kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.10.0/deploy/static/provider/cloud/deploy.yaml # 2. cert-manager kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.14.4/cert-manager.yaml # 3. CoreDNS ํ—ค์–ดํ•€ NAT ์šฐํšŒ ์„ค์ • kubectl patch configmap coredns -n kube-system --patch-file coredns-patch.yaml kubectl rollout restart deployment/coredns -n kube-system # 4. ์ด๋ฏธ์ง€ ๋นŒ๋“œ & Push docker build -t /portal-backend:latest ./backend/ docker build -t /portal-frontend:latest ./frontend/ docker push /portal-backend:latest docker push /portal-frontend:latest # 5. K8s ๋ฆฌ์†Œ์Šค ๋ฐฐํฌ kubectl apply -f k8s/ # 6. ArgoCD Application ๋“ฑ๋ก kubectl apply -f 06-argocd-app.yaml ``` ์ž์„ธํ•œ ๋ฐฐํฌ ๊ฐ€์ด๋“œ๋Š” [๋ฐฐํฌ ๋ฌธ์„œ](docs/deployment.md)๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”. --- ## ๐Ÿ“Š ๋ฐฐ์šด ์  / ํ•ต์‹ฌ ์ธ์‚ฌ์ดํŠธ | ๋ฌธ์ œ ์œ ํ˜• | ๋ฐฐ์šด ์  | |-----------|---------| | **ํ—ค์–ดํ•€ NAT** | K8s ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ๋„๋ฉ”์ธ์œผ๋กœ self-check ์‹œ ๋ฐœ์ƒํ•˜๋Š” ๋„คํŠธ์›Œํฌ ๋ฃจํ”„ โ†’ CoreDNS ๋‚ด๋ถ€ ์˜ค๋ฒ„๋ผ์ด๋“œ๋กœ ํ•ด๊ฒฐ | | **Docker ๋ฐ๋ชฌ vs kubelet DNS** | kubelet์€ K8s ๋‚ด๋ถ€ DNS ์‚ฌ์šฉ ๊ฐ€๋Šฅ, Docker ๋ฐ๋ชฌ์€ ํ˜ธ์ŠคํŠธ DNS๋งŒ ์‚ฌ์šฉ โ†’ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ์ฃผ์†Œ ํ†ต์ผ ํ•„์š” | | **GitOps ์ˆœํ™˜ ์ฐธ์กฐ** | ArgoCD Application YAML์„ ๊ฐ์‹œ ๋Œ€์ƒ ํด๋” ์•ˆ์— ๋„ฃ์œผ๋ฉด ๋ฌดํ•œ ๋ฃจํ”„ โ†’ ํด๋” ๋ฐ– ๋ณ„๋„ ๊ด€๋ฆฌ | | **์ปจํ…Œ์ด๋„ˆ ์‹œ์ž‘ ์ˆœ์„œ** | DB ์ค€๋น„ ์ „ ๋ฐฑ์—”๋“œ probe ์‹คํ–‰ โ†’ `initialDelaySeconds`๋กœ ์˜์กด์„ฑ ์ˆœ์„œ ์ œ์–ด | | **bcrypt ํ•ด์‹œ ์˜ค์—ผ** | ํ„ฐ๋ฏธ๋„ ANSI ์ƒ‰์ƒ ์ฝ”๋“œ๊ฐ€ ํ•ด์‹œ์— ์„ž์ด๋Š” ์—ฃ์ง€ ์ผ€์ด์Šค โ†’ ์ถœ๋ ฅ๊ฐ’ ์ง์ ‘ ๊ฒ€์ฆ ํ•„์š” | --- ## ๐Ÿ”œ ๊ฐœ์„  ์˜ˆ์ • (Next Steps) - [ ] GitHub Actions CI/CD ํŒŒ์ดํ”„๋ผ์ธ ๊ตฌ์„ฑ (์ž๋™ ๋นŒ๋“œ โ†’ Push โ†’ ArgoCD sync) - [ ] Helm Chart๋กœ ํŒจํ‚ค์ง• (values.yaml ํ™˜๊ฒฝ๋ณ„ ๋ถ„๋ฆฌ) - [ ] Prometheus + Grafana ๋ชจ๋‹ˆํ„ฐ๋ง ์Šคํƒ ๋„์ž… - [ ] Terraform์œผ๋กœ Azure ์ธํ”„๋ผ IaC ๊ด€๋ฆฌ - [ ] Trivy ์ด๋ฏธ์ง€ ์ทจ์•ฝ์  ์Šค์บ” โ†’ GitHub Actions ํ†ตํ•ฉ --- ## ๐Ÿ“„ ๋ผ์ด์„ ์Šค MIT License