docs: update TECH-03 — CI/CD pipeline details, fix namespace default, add PVC health check commands, add K8s commit history

This commit is contained in:
masoodafar-web
2026-02-23 21:40:55 +03:30
parent f5173a4def
commit 52e6e1530c
+184 -99
View File
@@ -1,7 +1,7 @@
# 🚀 استقرار، CI/CD و زیرساخت # 🚀 استقرار، CI/CD و زیرساخت
> **منابع ادغام‌شده:** `CICD-PIPELINE-GUIDE.md`, `DEPLOYMENT-README.md`, `INFRASTRUCTURE-GUIDE.md`, `INGRESS-NGINX-WARNING.md`, `OFFLINE-DEPLOYMENT-GUIDE.md`, `SERVER-MIRRORS-CONFIG.md` > **منابع ادغام‌شده:** `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)
--- ---
@@ -77,31 +77,94 @@ ENTRYPOINT ["dotnet", "CMSMicroservice.dll"]
### ۳.۱ Manifests ساختار ### ۳.۱ Manifests ساختار
مانیفست‌های K8s **داخل ریپوی CMS** نگهداری می‌شن و توسط CI/CD اعمال می‌شن:
``` ```
deployment/k8s-manifests/ CMS/
├── cms-deployment.yaml k8s/
├── cms-service.yaml staging/
├── backoffice-deployment.yaml cms-deployment.yaml ← PVC + Deployment + Service + Ingress
├── backoffice-service.yaml production/
├── frontoffice-deployment.yaml cms-deployment.yaml ← PVC + Deployment + Service + Ingress
├── frontoffice-service.yaml
├── db-statefulset.yaml
├── db-service.yaml
├── ingress.yaml
├── configmap.yaml
└── secrets.yaml
``` ```
### ۳.۲ مثال Deployment > ⚠️ **هر دو محیط از namespace `default` استفاده می‌کنن.**
### ۳.۲ PersistentVolume برای آپلود فایل
فایل‌های آپلود‌شده (عکس محصولات، بلاگ، آواتار و ...) در `/app/Uploads` ذخیره می‌شن.
برای جلوگیری از حذف فایل‌ها با ریستارت Pod، یک **PersistentVolumeClaim** مونت شده:
```yaml
# PVC — 20Gi ذخیره‌سازی دائمی
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: cms-uploads-pvc
namespace: default
spec:
accessModes: [ReadWriteOnce]
resources:
requests:
storage: 20Gi
```
```yaml
# Volume Mount در Deployment
volumeMounts:
- name: cms-uploads
mountPath: /app/Uploads
volumes:
- name: cms-uploads
persistentVolumeClaim:
claimName: cms-uploads-pvc
```
| تنظیم | مقدار |
|--------|-------|
| **PVC Name** | `cms-uploads-pvc` |
| **Mount Path** | `/app/Uploads` |
| **Access Mode** | `ReadWriteOnce` |
| **حجم** | `20Gi` |
| **StorageClass** | `local-path` (K3s default) |
| **Replicas** | `1` (محدودیت RWO) |
> 💡 **نکته مهم:** چون `ReadWriteOnce` هست، فقط **1 replica** می‌تونه بنویسه. برای 2+ replica نیاز به NFS/CephFS با `ReadWriteMany` هست.
### ۳.۳ تنظیمات محیطی (Environment Variables)
تنظیمات حساس (ConnectionString, Email, SMS, ZarinPal) **داخل `appsettings.{Environment}.json`** در ایمیج Docker قرار دارن.
**هیچ K8s Secret استفاده نمی‌شه** — .NET خودش فایل config مربوط به environment رو می‌خونه.
| محیط | `ASPNETCORE_ENVIRONMENT` | فایل Config |
|------|---------------------------|-------------|
| **Staging** | `Staging` | `appsettings.Staging.json` |
| **Production** | `Production` | `appsettings.Production.json` |
env var‌های K8s manifest:
```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"
```
### ۳.۴ مثال Deployment (واقعی)
```yaml ```yaml
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: cms name: cms
namespace: foursat namespace: default
spec: spec:
replicas: 2 replicas: 1
selector: selector:
matchLabels: matchLabels:
app: cms app: cms
@@ -109,104 +172,109 @@ spec:
spec: spec:
containers: containers:
- name: cms - name: cms
image: foursat/cms:latest image: 194.5.195.53:30080/admin/cms:latest
imagePullPolicy: Always
ports: ports:
- containerPort: 5001 - containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Staging"
- name: FileStorage__UploadPath
value: "/app/Uploads"
volumeMounts:
- name: cms-uploads
mountPath: /app/Uploads
resources: resources:
requests: requests: { memory: "512Mi", cpu: "500m" }
memory: "256Mi" limits: { memory: "1Gi", cpu: "1000m" }
cpu: "250m" volumes:
limits: - name: cms-uploads
memory: "512Mi" persistentVolumeClaim:
cpu: "500m" claimName: cms-uploads-pvc
livenessProbe:
grpc:
port: 5001
initialDelaySeconds: 15
readinessProbe:
grpc:
port: 5001
``` ```
### ۳.۳ Ingress ### ۳.۵ Ingress
**Staging:**
```yaml ```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foursat-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
spec: spec:
ingressClassName: nginx
rules: rules:
- host: foursat.ir - host: cms.se.kbs1.ir
http:
paths:
- path: /
backend:
service:
name: frontoffice
port: { number: 5003 }
- path: /admin
backend:
service:
name: backoffice
port: { number: 80 }
``` ```
> ⚠️ **هشدار:** Ingress-nginx نسخه‌های قبل از 1.9.0 مشکل امنیتی CVE-2023-5044 دارند. حتماً بروزرسانی کنید. **Production:**
```yaml
spec:
ingressClassName: nginx
tls:
- hosts: [cms.kbs1.ir, cms.kbs2.ir]
secretName: cms-tls
rules:
- host: cms.kbs2.ir
- host: cms.kbs1.ir
```
> ⚠️ **هشدار:** از `spec.ingressClassName: nginx` استفاده کنید، نه `kubernetes.io/ingress.class` annotation (deprecated).
--- ---
## ۴. CI/CD Pipeline ## ۴. CI/CD Pipeline
### ۴.۱ Gitea Actions Workflow ### ۴.۱ Gitea Actions Workflows (CMS)
```yaml فایل‌های پایپلاین:
name: Build and Deploy ```
on: CMS/.gitea/workflows/
push: ├── kub-deploy.yml ← Staging (branch: kub-stage)
branches: [kub-stage, production] ├── prod-deploy.yml ← Production (branch: production)
└── cms-stage.yml ← قدیمی (IIS روی Windows — غیرفعال)
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '9.0.x'
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --no-restore -c Release
- name: Test
run: dotnet test --no-build -c Release
- name: Docker Build & Push
run: |
docker build -t $REGISTRY/foursat/cms:${{ github.sha }} .
docker push $REGISTRY/foursat/cms:${{ github.sha }}
- name: Deploy to K8s
if: github.ref == 'refs/heads/production'
run: |
kubectl set image deployment/cms cms=$REGISTRY/foursat/cms:${{ github.sha }}
``` ```
### ۴.۲ شاخه‌ها ### ۴.۲ فلوی Staging (`kub-deploy.yml`)
| شاخه | محیط | Deploy | ```mermaid
|------|------|--------| flowchart TD
| `kub-stage` | Staging (194.5.195.53) | Auto | A["Push to kub-stage"] --> B["Start Docker daemon"]
| `production` | Production (45.149.79.127) | Manual trigger | B --> C["Clone repo"]
| `main` | — | Development only | 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"]
```
### ۴.۳ فلوی Production (`prod-deploy.yml`)
```mermaid
flowchart TD
A["Push to production"] --> B["Start Docker daemon"]
B --> C["Clone repo"]
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"]
```
### ۴.۴ شاخه‌ها و محیط‌ها
| شاخه | محیط | سرور | Image Tag | Deploy |
|------|------|------|-----------|--------|
| `kub-stage` | Staging | 194.5.195.53 | `:latest` | Auto |
| `production` | Production | 45.149.79.127 | `:sha` + `:prod` | Auto |
### ۴.۵ نکات مهم CI/CD
- **Proto NuGet:** هر deploy ابتدا proto packages رو build و به Nexus push می‌کنه
- **Manifest apply:** پایپلاین مانیفست K8s رو SCP به سرور و `kubectl apply` می‌زنه
→ 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 می‌شه
--- ---
@@ -328,6 +396,19 @@ flowchart TD
| **FrontOffice** | `kub-stage``production` | `f02d082` | 21 فایل، 400 insertion + فیکس GwUrl به `cms.kbs2.ir` | | **FrontOffice** | `kub-stage``production` | `f02d082` | 21 فایل، 400 insertion + فیکس GwUrl به `cms.kbs2.ir` |
| **BackOffice** | `kub-stage``production` | `bdea2e8` | 36 فایل، بدون conflict | | **BackOffice** | `kub-stage``production` | `bdea2e8` | 36 فایل، بدون conflict |
### ۹.۲ کامیت‌های PVC و اصلاحات K8s (تیر ۱۴۰۴)
| commit | شرح |
|--------|------|
| `3153fd8` | feat: add PersistentVolume for CMS uploads + apply manifests in CI/CD |
| `68da3f4` | fix: staging uses namespace default, not foursat |
| `e41747a` | fix: production ingress — add cms.kbs2.ir, use ingressClassName |
| `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 |
> همه کامیت‌ها به هر دو شاخه `kub-stage` و `production` push شده‌اند.
**تنظیمات محیطی Production (`appsettings.Production.json`):** **تنظیمات محیطی Production (`appsettings.Production.json`):**
| تنظیم | مقدار | | تنظیم | مقدار |
@@ -340,10 +421,14 @@ flowchart TD
| `ConnectionStrings.Default` | `Server=mssql-svc;Database=KBS` | | `ConnectionStrings.Default` | `Server=mssql-svc;Database=KBS` |
```bash ```bash
# k8s-health-check.sh # k8s-health-check.sh (namespace = default)
kubectl get pods -n foursat kubectl get pods
kubectl top pods -n foursat kubectl top pods
kubectl logs deployment/cms -n foursat --tail=50 kubectl logs deployment/cms --tail=50
# بررسی PVC
kubectl get pvc cms-uploads-pvc
kubectl exec deployment/cms -- ls /app/Uploads | wc -l
# تست سرویس‌ها # تست سرویس‌ها
grpcurl -plaintext localhost:5001 list # لیست سرویس‌ها grpcurl -plaintext localhost:5001 list # لیست سرویس‌ها