docs: update TECH-03 — K8s Secret for persistent config, branch/appsettings separation, updated CI/CD flow
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# 🚀 استقرار، CI/CD و زیرساخت
|
||||
|
||||
> **منابع ادغامشده:** `CICD-PIPELINE-GUIDE.md`, `DEPLOYMENT-README.md`, `INFRASTRUCTURE-GUIDE.md`, `INGRESS-NGINX-WARNING.md`, `OFFLINE-DEPLOYMENT-GUIDE.md`, `SERVER-MIRRORS-CONFIG.md`
|
||||
> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: PersistentVolume برای آپلود فایل + اصلاح namespace + حذف secretRef)
|
||||
> **آخرین بروزرسانی:** اسفند ۱۴۰۴ (بروزرسانی: PVC آپلود + K8s Secret برای config دائمی + جدا کردن appsettings هر برنچ)
|
||||
|
||||
---
|
||||
|
||||
@@ -83,9 +83,11 @@ ENTRYPOINT ["dotnet", "CMSMicroservice.dll"]
|
||||
CMS/
|
||||
k8s/
|
||||
staging/
|
||||
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
|
||||
cms-config.yaml ← K8s Secret (appsettings.Staging.json)
|
||||
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
|
||||
production/
|
||||
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
|
||||
cms-config.yaml ← K8s Secret (appsettings.Production.json)
|
||||
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
|
||||
```
|
||||
|
||||
> ⚠️ **هر دو محیط از namespace `default` استفاده میکنن.**
|
||||
@@ -131,30 +133,60 @@ volumes:
|
||||
|
||||
> 💡 **نکته مهم:** چون `ReadWriteOnce` هست، فقط **1 replica** میتونه بنویسه. برای 2+ replica نیاز به NFS/CephFS با `ReadWriteMany` هست.
|
||||
|
||||
### ۳.۳ تنظیمات محیطی (Environment Variables)
|
||||
### ۳.۳ تنظیمات محیطی (K8s Secret)
|
||||
|
||||
تنظیمات حساس (ConnectionString, Email, SMS, ZarinPal) **داخل `appsettings.{Environment}.json`** در ایمیج Docker قرار دارن.
|
||||
**هیچ K8s Secret استفاده نمیشه** — .NET خودش فایل config مربوط به environment رو میخونه.
|
||||
تنظیمات حساس (ConnectionString, Email, SMS, ZarinPal) **در K8s Secret** نگهداری میشن — نه داخل Docker image.
|
||||
فایل `appsettings.{Environment}.json` از Secret به `/app/` مونت میشه و .NET اون رو override میخونه.
|
||||
|
||||
| محیط | `ASPNETCORE_ENVIRONMENT` | فایل Config |
|
||||
```mermaid
|
||||
flowchart LR
|
||||
S["K8s Secret<br/>cms-appsettings"] -->|volumeMount| F["/app/appsettings.*.json"]
|
||||
F --> D[".NET reads config"]
|
||||
I["Docker Image<br/>appsettings.json (base)"] --> D
|
||||
```
|
||||
|
||||
| محیط | `ASPNETCORE_ENVIRONMENT` | فایل Config (از Secret) |
|
||||
|------|---------------------------|-------------|
|
||||
| **Staging** | `Staging` | `appsettings.Staging.json` |
|
||||
| **Production** | `Production` | `appsettings.Production.json` |
|
||||
|
||||
env varهای K8s manifest:
|
||||
**Secret manifest** (`cms-config.yaml`):
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: cms-appsettings
|
||||
namespace: default
|
||||
type: Opaque
|
||||
stringData:
|
||||
appsettings.Staging.json: | # یا appsettings.Production.json
|
||||
{ "ConnectionStrings": { ... }, "ZarinPal": { ... }, ... }
|
||||
```
|
||||
|
||||
**Volume mount در Deployment:**
|
||||
```yaml
|
||||
volumeMounts:
|
||||
- name: cms-config
|
||||
mountPath: /app/appsettings.Staging.json
|
||||
subPath: appsettings.Staging.json
|
||||
readOnly: true
|
||||
volumes:
|
||||
- name: cms-config
|
||||
secret:
|
||||
secretName: cms-appsettings
|
||||
```
|
||||
|
||||
env varهای K8s manifest (فقط environment و URL):
|
||||
```yaml
|
||||
env:
|
||||
- name: ASPNETCORE_ENVIRONMENT
|
||||
value: "Staging" # یا "Production"
|
||||
- name: ASPNETCORE_URLS
|
||||
value: "http://+:8080"
|
||||
- name: Kestrel__EndpointDefaults__Protocols
|
||||
value: "Http1AndHttp2"
|
||||
- name: FileStorage__UploadPath
|
||||
value: "/app/Uploads"
|
||||
```
|
||||
|
||||
> 💡 **تغییر config بدون deploy:** `kubectl edit secret cms-appsettings && kubectl rollout restart deployment/cms`
|
||||
|
||||
### ۳.۴ مثال Deployment (واقعی)
|
||||
|
||||
```yaml
|
||||
@@ -179,11 +211,15 @@ spec:
|
||||
env:
|
||||
- name: ASPNETCORE_ENVIRONMENT
|
||||
value: "Staging"
|
||||
- name: FileStorage__UploadPath
|
||||
value: "/app/Uploads"
|
||||
- name: ASPNETCORE_URLS
|
||||
value: "http://+:8080"
|
||||
volumeMounts:
|
||||
- name: cms-uploads
|
||||
mountPath: /app/Uploads
|
||||
- name: cms-config
|
||||
mountPath: /app/appsettings.Staging.json
|
||||
subPath: appsettings.Staging.json
|
||||
readOnly: true
|
||||
resources:
|
||||
requests: { memory: "512Mi", cpu: "500m" }
|
||||
limits: { memory: "1Gi", cpu: "1000m" }
|
||||
@@ -191,6 +227,9 @@ spec:
|
||||
- name: cms-uploads
|
||||
persistentVolumeClaim:
|
||||
claimName: cms-uploads-pvc
|
||||
- name: cms-config
|
||||
secret:
|
||||
secretName: cms-appsettings
|
||||
```
|
||||
|
||||
### ۳.۵ Ingress
|
||||
@@ -217,6 +256,28 @@ spec:
|
||||
|
||||
> ⚠️ **هشدار:** از `spec.ingressClassName: nginx` استفاده کنید، نه `kubernetes.io/ingress.class` annotation (deprecated).
|
||||
|
||||
### ۳.۶ جداسازی appsettings در Git
|
||||
|
||||
هر برنچ فقط فایل config مربوط به محیط خودش رو داره:
|
||||
|
||||
| برنچ | `appsettings.json` | `appsettings.Staging.json` | `appsettings.Production.json` |
|
||||
|------|---|---|---|
|
||||
| `kub-stage` | ✅ | ✅ | ❌ حذف شده |
|
||||
| `production` | ✅ | ❌ حذف شده | ✅ |
|
||||
|
||||
**چرا؟** چون config اصلی از K8s Secret میاد (`cms-config.yaml`)، فایلهای محیط دیگه داخل ایمیج اضافی و گمراهکنندهان.
|
||||
همچنین وقتی merge/cherry-pick میکنید، فایل config محیط دیگه دیگه conflict ایجاد نمیکنه.
|
||||
|
||||
> ⚠️ **کامیتهای حذف فایل config رو هرگز cherry-pick نکنید به برنچ دیگه!**
|
||||
> `e72673c` (حذف Production از staging) و `3ebe0f9` (حذف Staging از production)
|
||||
|
||||
### ۳.۷ خلاصه: چه چیزهایی دائمی هستند (مستقل از ایمیج)
|
||||
|
||||
| چه چیزی | مکانیزم K8s | محل Mount |
|
||||
|---------|-------------|------------|
|
||||
| **فایلهای آپلود** (عکس، آواتار، ...) | `PersistentVolumeClaim` | `/app/Uploads` |
|
||||
| **تنظیمات اپلیکیشن** (DB, SMS, IPG, ...) | `Secret` (`cms-appsettings`) | `/app/appsettings.{Env}.json` |
|
||||
|
||||
---
|
||||
|
||||
## ۴. CI/CD Pipeline
|
||||
@@ -240,10 +301,11 @@ flowchart TD
|
||||
C --> D["Pack & Push Proto NuGet"]
|
||||
D --> E["Docker build → tag :latest"]
|
||||
E --> F["Push to 194.5.195.53:30080"]
|
||||
F --> G["SCP manifest to server"]
|
||||
G --> H["kubectl apply -f cms-deployment.yaml"]
|
||||
H --> I["kubectl rollout restart"]
|
||||
I --> J["✅ Deployed to Staging"]
|
||||
F --> G["SCP cms-config.yaml + cms-deployment.yaml"]
|
||||
G --> H["kubectl apply -f cms-config.yaml (Secret)"]
|
||||
H --> I["kubectl apply -f cms-deployment.yaml"]
|
||||
I --> J["kubectl rollout restart"]
|
||||
J --> K["✅ Deployed to Staging"]
|
||||
```
|
||||
|
||||
### ۴.۳ فلوی Production (`prod-deploy.yml`)
|
||||
@@ -255,10 +317,11 @@ flowchart TD
|
||||
C --> D["Pack & Push Proto NuGet"]
|
||||
D --> E["Docker build → tag :sha + :prod"]
|
||||
E --> F["Push to 194.5.195.53:30080"]
|
||||
F --> G["SCP manifest to server"]
|
||||
G --> H["kubectl apply -f cms-deployment.yaml"]
|
||||
H --> I["kubectl set image → sha"]
|
||||
I --> J["✅ Deployed to Production"]
|
||||
F --> G["SCP cms-config.yaml + cms-deployment.yaml"]
|
||||
G --> H["kubectl apply -f cms-config.yaml (Secret)"]
|
||||
H --> I["kubectl apply -f cms-deployment.yaml"]
|
||||
I --> J["kubectl set image → sha"]
|
||||
J --> K["✅ Deployed to Production"]
|
||||
```
|
||||
|
||||
### ۴.۴ شاخهها و محیطها
|
||||
@@ -271,10 +334,11 @@ flowchart TD
|
||||
### ۴.۵ نکات مهم CI/CD
|
||||
|
||||
- **Proto NuGet:** هر deploy ابتدا proto packages رو build و به Nexus push میکنه
|
||||
- **Manifest apply:** پایپلاین مانیفست K8s رو SCP به سرور و `kubectl apply` میزنه
|
||||
→ PVC، Deployment، Service و Ingress هر بار اعمال میشه
|
||||
- **Manifest apply:** پایپلاین ابتدا `cms-config.yaml` (Secret) رو apply میکنه، بعد `cms-deployment.yaml`
|
||||
→ Secret + PVC + Deployment + Service + Ingress هر بار اعمال میشه
|
||||
- **Image registry:** `194.5.195.53:30080` (داخلی Nexus) — نه `git.se.kbs1.ir`
|
||||
- **appsettings حفاظت:** `.gitattributes` با `merge=ours` مانع overwrite شدن `appsettings.Production.json` موقع merge میشه
|
||||
- **Config دائمی:** تنظیمات در K8s Secret هست، نه داخل Docker image — تغییر config بدون rebuild ایمیج ممکنه
|
||||
- **جداسازی برنچ:** هر برنچ فقط appsettings محیط خودش رو داره (بخش ۳.۶)
|
||||
|
||||
---
|
||||
|
||||
@@ -406,8 +470,12 @@ flowchart TD
|
||||
| `2d6c95e` | fix: use local registry 194.5.195.53:30080 instead of git.se.kbs1.ir |
|
||||
| `f8dc4ab` | fix: staging ASPNETCORE_ENVIRONMENT=Staging, remove secretKeyRef |
|
||||
| `de83c31` | fix: production uses namespace default + remove foursat namespace references |
|
||||
| `9288d06` | feat: externalize appsettings to K8s Secret — config persists independently |
|
||||
| `e72673c` | chore(staging): remove appsettings.Production.json (فقط kub-stage) |
|
||||
| `3ebe0f9` | chore(production): remove appsettings.Staging.json (فقط production) |
|
||||
|
||||
> همه کامیتها به هر دو شاخه `kub-stage` و `production` push شدهاند.
|
||||
> کامیتهای PVC و Secret به هر دو شاخه push شدهاند.
|
||||
> ⚠️ کامیتهای حذف appsettings فقط به برنچ مربوطه push شده — cherry-pick نکنید!
|
||||
|
||||
**تنظیمات محیطی Production (`appsettings.Production.json`):**
|
||||
|
||||
|
||||
Reference in New Issue
Block a user