# 🚀 استقرار، CI/CD و زیرساخت
> **منابع ادغامشده:** `CICD-PIPELINE-GUIDE.md`, `DEPLOYMENT-README.md`, `INFRASTRUCTURE-GUIDE.md`, `INGRESS-NGINX-WARNING.md`, `OFFLINE-DEPLOYMENT-GUIDE.md`, `SERVER-MIRRORS-CONFIG.md`
> **آخرین بروزرسانی:** اسفند ۱۴۰۴
---
## ۱. سرورها
| سرور | 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 ساختار
```
deployment/k8s-manifests/
├── cms-deployment.yaml
├── cms-service.yaml
├── backoffice-deployment.yaml
├── backoffice-service.yaml
├── frontoffice-deployment.yaml
├── frontoffice-service.yaml
├── db-statefulset.yaml
├── db-service.yaml
├── ingress.yaml
├── configmap.yaml
└── secrets.yaml
```
### ۳.۲ مثال Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: cms
namespace: foursat
spec:
replicas: 2
selector:
matchLabels:
app: cms
template:
spec:
containers:
- name: cms
image: foursat/cms:latest
ports:
- containerPort: 5001
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
grpc:
port: 5001
initialDelaySeconds: 15
readinessProbe:
grpc:
port: 5001
```
### ۳.۳ Ingress
```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:
rules:
- host: foursat.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 دارند. حتماً بروزرسانی کنید.
---
## ۴. CI/CD Pipeline
### ۴.۱ Gitea Actions Workflow
```yaml
name: Build and Deploy
on:
push:
branches: [kub-stage, production]
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 }}
```
### ۴.۲ شاخهها
| شاخه | محیط | Deploy |
|------|------|--------|
| `kub-stage` | Staging (194.5.195.53) | Auto |
| `production` | Production (45.149.79.127) | Manual trigger |
| `main` | — | Development only |
---
## ۵. استقرار آفلاین (Offline Deployment)
### ۵.۱ فلوی آمادهسازی
```
سرور اینترنتدار:
1. pull-base-images.sh → دانلود Docker images
2. cache-nuget-packages.sh → دانلود NuGet packages
3. save-images.sh → ذخیره تصاویر به tar
4. بستهبندی همه فایلها
انتقال فیزیکی (USB/HDD):
tar files + nuget packages + k8s manifests
سرور آفلاین:
1. load-images.sh → بارگذاری تصاویر
2. setup-nexus-complete.sh → راهاندازی Nexus (NuGet proxy)
3. build-all-offline.sh → بیلد با Nexus محلی
4. k8s-deploy.sh → استقرار در Kubernetes
```
### ۵.۲ اسکریپتهای کلیدی
| اسکریپت | کاربرد |
|----------|--------|
| `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
### ۶.۱ نقش
```
Nexus (داخلی):
├── NuGet proxy → cache.nuget.org packages
├── NuGet hosted → بستههای proto داخلی
├── Docker proxy → cache Docker Hub images
└── Docker hosted → تصاویر داخلی FourSat
```
### ۶.۲ NuGet.config
```xml
```
---
## ۷. 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)
### ۸.۱ فلوی بستهبندی
```
CMS/src/Protos/*.proto
│
▼
pack-protos.sh → dotnet pack → .nupkg
│
▼
push to BaGet/Nexus
│
▼
BackOffice + FrontOffice → dotnet restore → مصرف proto
```
### ۸.۲ نام بسته
```xml
```
---
## ۹. مانیتورینگ و Health Check
```bash
# k8s-health-check.sh
kubectl get pods -n foursat
kubectl top pods -n foursat
kubectl logs deployment/cms -n foursat --tail=50
# تست سرویسها
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
```