Files
docs/technical/TECH-03-DEPLOYMENT-INFRA.md
T

439 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🚀 استقرار، 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)
---
## ۱. سرورها
| سرور | IP | نقش | منابع |
|------|-----|------|--------|
| **Staging** | 194.5.195.53 | توسعه + تست | 4 CPU, 8GB RAM |
| **Production** | 45.149.79.127 | محیط نهایی | 4 CPU, 16GB RAM |
| **Git** | git.se.kbs1.ir | Gitea (مخازن کد) | — |
| **Registry** | داخلی | Docker Registry / Nexus | — |
---
## ۲. Docker و Container
### ۲.۱ سرویس‌ها
```yaml
# docker-compose.yml (production)
services:
cms:
image: foursat/cms:latest
ports: ["5001:5001"] # gRPC
environment:
- ConnectionStrings__Default=Server=db;Database=FourSatCMS
- ASPNETCORE_ENVIRONMENT=Production
depends_on: [db]
backoffice:
image: foursat/backoffice:latest
ports: ["5002:80"] # Static Blazor WASM
frontoffice:
image: foursat/frontoffice:latest
ports: ["5003:5003"] # Blazor Server
db:
image: mcr.microsoft.com/mssql/server:2022-CU16-ubuntu-22.04
ports: ["1433:1433"]
volumes: ["sqldata:/var/opt/mssql"]
nexus: # NuGet + Docker registry
image: sonatype/nexus3
ports: ["8081:8081"]
volumes:
sqldata:
```
### ۲.۲ Dockerfile (CMS)
```dockerfile
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
WORKDIR /app
EXPOSE 5001
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
COPY ["CMSMicroservice/CMSMicroservice.csproj", "CMSMicroservice/"]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
FROM base AS final
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "CMSMicroservice.dll"]
```
---
## ۳. Kubernetes
### ۳.۱ Manifests ساختار
مانیفست‌های K8s **داخل ریپوی CMS** نگهداری می‌شن و توسط CI/CD اعمال می‌شن:
```
CMS/
k8s/
staging/
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
production/
cms-deployment.yaml ← PVC + Deployment + Service + Ingress
```
> ⚠️ **هر دو محیط از 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
apiVersion: apps/v1
kind: Deployment
metadata:
name: cms
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: cms
template:
spec:
containers:
- name: cms
image: 194.5.195.53:30080/admin/cms:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: ASPNETCORE_ENVIRONMENT
value: "Staging"
- name: FileStorage__UploadPath
value: "/app/Uploads"
volumeMounts:
- name: cms-uploads
mountPath: /app/Uploads
resources:
requests: { memory: "512Mi", cpu: "500m" }
limits: { memory: "1Gi", cpu: "1000m" }
volumes:
- name: cms-uploads
persistentVolumeClaim:
claimName: cms-uploads-pvc
```
### ۳.۵ Ingress
**Staging:**
```yaml
spec:
ingressClassName: nginx
rules:
- host: cms.se.kbs1.ir
```
**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
### ۴.۱ Gitea Actions Workflows (CMS)
فایل‌های پایپلاین:
```
CMS/.gitea/workflows/
├── kub-deploy.yml ← Staging (branch: kub-stage)
├── prod-deploy.yml ← Production (branch: production)
└── cms-stage.yml ← قدیمی (IIS روی Windows — غیرفعال)
```
### ۴.۲ فلوی Staging (`kub-deploy.yml`)
```mermaid
flowchart TD
A["Push to kub-stage"] --> B["Start Docker daemon"]
B --> C["Clone repo"]
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 می‌شه
---
## ۵. استقرار آفلاین (Offline Deployment)
### ۵.۱ فلوی آماده‌سازی
```mermaid
flowchart TD
subgraph ONLINE["🌐 سرور اینترنت‌دار"]
A1["pull-base-images.sh\nدانلود Docker images"] --> A2["cache-nuget-packages.sh\nدانلود NuGet packages"]
A2 --> A3["save-images.sh\nذخیره تصاویر به tar"]
A3 --> A4["بسته‌بندی"]
end
A4 -->|"💾 انتقال فیزیکی\nUSB / HDD"| B1
subgraph OFFLINE["🔒 سرور آفلاین"]
B1["load-images.sh\nبارگذاری تصاویر"] --> B2["setup-nexus-complete.sh\nراه‌اندازی Nexus"]
B2 --> B3["build-all-offline.sh\nبیلد با Nexus محلی"]
B3 --> B4["k8s-deploy.sh\nاستقرار در K8s"]
end
```
### ۵.۲ اسکریپت‌های کلیدی
| اسکریپت | کاربرد |
|----------|--------|
| `pull-base-images.sh` | دانلود ۱۵+ Docker image پایه |
| `save-images.sh` | Export به tar (4-8 GB) |
| `load-images.sh` | Import از tar به Docker |
| `cache-nuget-packages.sh` | دانلود NuGet offline |
| `setup-nexus-complete.sh` | راه‌اندازی NuGet proxy |
| `build-all-offline.sh` | بیلد بدون اینترنت |
| `k8s-deploy.sh` | Deploy تمام سرویس‌ها |
| `k8s-health-check.sh` | بررسی سلامت سرویس‌ها |
---
## ۶. Nexus Repository Manager
### ۶.۱ نقش
```mermaid
graph TD
NEXUS["Nexus داخلی"] --> NP["NuGet proxy\ncache nuget.org"]
NEXUS --> NH["NuGet hosted\nبسته‌های proto داخلی"]
NEXUS --> DP["Docker proxy\ncache Docker Hub"]
NEXUS --> DH["Docker hosted\nتصاویر داخلی FourSat"]
```
### ۶.۲ NuGet.config
```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="nexus" value="http://localhost:8081/repository/nuget-group/index.json" />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
</configuration>
```
---
## ۷. Mirror و Cache
### ۷.۱ Docker Mirror
```json
// /etc/docker/daemon.json
{
"registry-mirrors": [
"https://mirror.gcr.io",
"https://docker.arvancloud.ir"
],
"insecure-registries": [
"localhost:8082"
]
}
```
### ۷.۲ NuGet Mirror
```
Primary: nuget.org
Fallback: Nexus local proxy
Proto packages: BaGet (internal) at http://localhost:5555
```
---
## ۸. Proto Packages (NuGet)
### ۸.۱ فلوی بسته‌بندی
```mermaid
flowchart TD
A["CMS/src/Protos/*.proto"] --> B["pack-protos.sh\ndotnet pack → .nupkg"]
B --> C["Push to BaGet / Nexus"]
C --> D["BackOffice + FrontOffice\ndotnet restore → مصرف proto"]
```
### ۸.۲ نام بسته
```xml
<PackageReference Include="Foursat.CMSMicroservice.Protobuf" Version="1.0.x" />
```
---
## ۹. مانیتورینگ و Health Check
### ۹.۱ مرج پروداکشن (اسفند ۱۴۰۴)
| ریپو | شاخه مبدأ | commit | نکات |
|------|------------|--------|------|
| **CMS** | `kub-stage``production` | `eb1b249` | حل conflict در `appsettings.Production.json` + حذف migration تکراری `u21` |
| **FrontOffice** | `kub-stage``production` | `f02d082` | 21 فایل، 400 insertion + فیکس GwUrl به `cms.kbs2.ir` |
| **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`):**
| تنظیم | مقدار |
|--------|-------|
| `ZarinPal.MerchantId` | `4225d555-5fa9-4df0-9b61-1ce152cbbba8` |
| `ZarinPal.UseSandbox` | `false` |
| `SeedWorkers.MagicWalletCycleSeed.Enabled` | `true` |
| `Kestrel.Endpoints.Grpc.Protocols` | `Http2` |
| `Seq.ServerUrl` | `http://seq-svc:5341` |
| `ConnectionStrings.Default` | `Server=mssql-svc;Database=KBS` |
```bash
# k8s-health-check.sh (namespace = default)
kubectl get pods
kubectl top pods
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 grpc.health.v1.Health/Check # Health
curl http://localhost:5002/index.html # BackOffice
curl http://localhost:5003/ # FrontOffice
```