# 🚀 راهنمای دیپلوی آفلاین FourSat

## 📋 خلاصه
این داکیومنت تنظیمات انجام شده برای دیپلوی کاملاً آفلاین پروژه FourSat را شرح می‌دهد.

---

## 🏗️ معماری

```
┌─────────────────────────────────────────────────────────────────┐
│                        سرور 194.5.195.53                        │
├─────────────────────────────────────────────────────────────────┤
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │
│  │   Gitea      │  │    Nexus     │  │     K3s      │          │
│  │  (Git Host)  │  │  (Registry)  │  │ (Kubernetes) │          │
│  │              │  │              │  │              │          │
│  │ gitea-svc:   │  │ :32081 UI    │  │ kubectl      │          │
│  │ 3000         │  │ :32082 Docker│  │              │          │
│  └──────────────┘  └──────────────┘  └──────────────┘          │
│                                                                 │
│  ┌──────────────┐  ┌──────────────┐                            │
│  │   Registry   │  │ Gitea Runner │                            │
│  │  (Apps)      │  │   (CI/CD)    │                            │
│  │ :30080       │  │              │                            │
│  └──────────────┘  └──────────────┘                            │
└─────────────────────────────────────────────────────────────────┘
```

---

## 🔧 اطلاعات دسترسی

| سرویس | آدرس | یوزر | پسورد |
|-------|------|------|-------|
| **سرور SSH** | `194.5.195.53` | `root` | `87zH26nbqT` |
| **Nexus UI** | `http://194.5.195.53:32081` | `admin` | `87zH26nbqT` |
| **Nexus Docker** | `194.5.195.53:32082` | `admin` | `87zH26nbqT` |
| **App Registry** | `194.5.195.53:30080` | `admin` | `87zH26nbqT` |
| **NuGet Feed** | `http://194.5.195.53:32081/repository/foursat-nuget-hosted/index.json` | - | - |

---

## 🐳 ایمیج‌های کش شده در Nexus

این ایمیج‌ها در `194.5.195.53:32082` ذخیره شدن و نیازی به اینترنت ندارن:

| ایمیج | استفاده |
|-------|---------|
| `docker-sshpass:latest` | ایمیج اصلی CI/CD (docker + sshpass) |
| `docker:latest` | Docker in Docker |
| `dotnet/sdk:9.0` | بیلد .NET پروژه‌ها |
| `dotnet/aspnet:9.0` | Runtime .NET |
| `nginx:alpine` | فرانت‌اند‌ها |

---

## 📦 پکیج‌های NuGet

~500 پکیج .NET در Nexus NuGet hosted repository کش شدن:
- `http://194.5.195.53:32081/repository/foursat-nuget-hosted/index.json`

### NuGet.config نمونه:
```xml
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <packageSources>
    <clear />
    <add key="FourSat-Offline" value="http://194.5.195.53:32081/repository/foursat-nuget-hosted/index.json" />
  </packageSources>
</configuration>
```

---

## 🔄 CI/CD Pipeline

### ساختار Workflow (یکسان برای همه پروژه‌ها)

```yaml
name: Build and Deploy to Kubernetes

on:
  push:
    branches:
      - kub-stage

env:
  REGISTRY: 194.5.195.53:30080
  IMAGE_NAME: admin/<project-name>
  K8S_SERVER: 194.5.195.53

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    container:
      image: 194.5.195.53:32082/docker-sshpass:latest  # ✅ آفلاین
      options: --privileged
    steps:
      - name: Start Docker daemon
        run: |
          mkdir -p /etc/docker
          cat > /etc/docker/daemon.json << 'DAEMON'
          {
            "insecure-registries": ["194.5.195.53:30080", "194.5.195.53:32500", "194.5.195.53:32082"]
          }
          DAEMON
          dockerd &
          for i in $(seq 1 30); do docker info >/dev/null 2>&1 && break || sleep 2; done

      - name: Checkout code
        run: |
          git clone --depth 1 --branch kub-stage http://gitea-svc:3000/admin/<repo>.git .

      # فقط برای پروژه‌های .NET API (CMS, BackOffice.BFF, FrontOffice.BFF)
      - name: Publish Protobuf packages
        run: |
          docker run --rm -v $(pwd):/src -w /src \
            194.5.195.53:32082/dotnet/sdk:9.0 sh -c '
              for proj in $(find . -name "*Protobuf*.csproj" -type f); do
                dotnet restore "$proj"
                dotnet build "$proj" -c Release --no-restore
                dotnet pack "$proj" -c Release --no-build -o "$(dirname $proj)/nupkg"
                for nupkg in $(dirname $proj)/nupkg/*.nupkg; do
                  [ -f "$nupkg" ] && dotnet nuget push "$nupkg" \
                    --source "http://194.5.195.53:32081/repository/foursat-nuget-hosted/index.json" \
                    --api-key "admin:87zH26nbqT" \
                    --skip-duplicate --allow-insecure-connections || true
                done
              done
            '

      - name: Build Docker Image
        run: |
          docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest .

      - name: Push to Registry
        run: |
          echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login ${{ env.REGISTRY }} -u admin --password-stdin
          docker push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest

      - name: Deploy to Kubernetes
        run: |
          export SSHPASS="${{ secrets.SERVER_PASSWORD }}"
          sshpass -e ssh -o StrictHostKeyChecking=no root@${{ env.K8S_SERVER }} "
            kubectl rollout restart deployment/<deployment-name>
            kubectl rollout status deployment/<deployment-name> --timeout=180s
          "
```

---

## 📂 پروژه‌ها

| پروژه | IMAGE_NAME | Dockerfile | Deployment | Protobuf |
|-------|------------|------------|------------|----------|
| **CMS** | `admin/cms` | `./Dockerfile` | `cms` | ✅ |
| **BackOffice.BFF** | `admin/backoffice-bff` | `src/BackOffice.BFF.WebApi/Dockerfile` | `backoffice-bff` | ✅ |
| **FrontOffice.BFF** | `admin/frontoffice-bff` | `src/FrontOffice.BFF.WebApi/Dockerfile` | `frontoffice-bff` | ✅ |
| **BackOffice** | `admin/backoffice` | `src/BackOffice/Dockerfile` | `backoffice` | ❌ |
| **FrontOffice** | `admin/frontoffice` | `src/FrontOffice.Main/Dockerfile` | `frontoffice` | ❌ |

---

## 🔐 Gitea Secrets

این secret ها باید در Gitea تنظیم شوند:

### روش 1: برای هر Repository جداگانه
`https://git.se.kbs1.ir/admin/<repo>/settings/actions/secrets`

### روش 2: برای کل Organization
`https://git.se.kbs1.ir/admin/-/settings/actions/secrets`

| Secret Name | Value |
|-------------|-------|
| `SERVER_PASSWORD` | `87zH26nbqT` |
| `REGISTRY_PASSWORD` | `87zH26nbqT` |

---

## 🛠️ K3s Registry Configuration

فایل `/etc/rancher/k3s/registries.yaml`:

```yaml
mirrors:
  "194.5.195.53:32082":
    endpoint:
      - "http://194.5.195.53:32082"
  "194.5.195.53:32500":
    endpoint:
      - "http://194.5.195.53:32500"
  "194.5.195.53:30080":
    endpoint:
      - "http://194.5.195.53:30080"
```

---

## 🐋 Docker-sshpass Image

ایمیج سفارشی برای CI/CD که sshpass از قبل نصب داره:

```dockerfile
FROM 194.5.195.53:32082/docker:latest
RUN apk add --no-cache openssh-client sshpass
```

**Build و Push:**
```bash
docker build -t 194.5.195.53:32082/docker-sshpass:latest .
docker push 194.5.195.53:32082/docker-sshpass:latest
```

---

## ✅ چک‌لیست آفلاین بودن

- [x] ایمیج CI/CD از Nexus: `194.5.195.53:32082/docker-sshpass:latest`
- [x] ایمیج dotnet/sdk از Nexus: `194.5.195.53:32082/dotnet/sdk:9.0`
- [x] پکیج‌های NuGet کش شده در Nexus
- [x] پکیج‌های Protobuf پابلیش به Nexus
- [x] App images در registry محلی: `194.5.195.53:30080`
- [x] بدون `apt-get` یا `apk add` در pipeline
- [x] دیپلوی با SSH (بدون نیاز به kubeconfig خارجی)

---

## 🚨 Troubleshooting

### خطای "Permission denied" در Deploy
```
Permission denied, please try again.
```
**راه‌حل:** Secret `SERVER_PASSWORD` در Gitea تنظیم نشده. برو به:
`https://git.se.kbs1.ir/admin/<repo>/settings/actions/secrets`

### خطای "unauthorized" در Push
```
unauthorized: access denied
```
**راه‌حل:** Secret `REGISTRY_PASSWORD` تنظیم نشده.

### خطای Pull Image
```
failed to pull image
```
**راه‌حل:** 
1. چک کن ایمیج در Nexus وجود داره
2. چک کن `insecure-registries` درست تنظیم شده

---

## 📊 وضعیت نهایی سیستم

### ✅ **سرویس‌های فعال و سالم (17 pod):**

| سرویس | Namespace | وضعیت | ایمیج |
|-------|-----------|--------|-------|
| **gitea** | default | ✅ Running | `194.5.195.53:32082/gitea/gitea:latest` |
| **gitea-runner** | default | ✅ Running | `194.5.195.53:32082/gitea/act_runner:latest` |
| **nexus** | default | ✅ Running | `194.5.195.53:32082/sonatype/nexus3:3.38.0` |
| **cms** | default | ✅ Running | `194.5.195.53:30080/admin/cms:latest` |
| **backoffice** | default | ✅ Running | `194.5.195.53:30080/admin/backoffice:latest` |
| **backoffice-bff** | default | ✅ Running | `194.5.195.53:30080/admin/backoffice-bff:latest` |
| **frontoffice** | default | ✅ Running | `194.5.195.53:30080/admin/frontoffice:latest` |
| **frontoffice-bff** | default | ✅ Running | `194.5.195.53:30080/admin/frontoffice-bff:latest` |
| **cert-manager** | cert-manager | ✅ Running | `194.5.195.53:32082/quay.io/jetstack/cert-manager-*` |
| **nginx-deploy** | default | ✅ Running | `194.5.195.53:32082/nginx:alpine` |
| **mssql** | default | ✅ Running | `194.5.195.53:32082/mcr.microsoft.com/mssql/server:2022-latest` |
| **coredns** | kube-system | ✅ Running | `rancher/mirrored-coredns-coredns:1.13.1` |
| **metrics-server** | kube-system | ✅ Running | `rancher/mirrored-metrics-server:v0.8.0` |

### ⚠️ **مشکلات جزئی (غیرضروری):**
- `netshoot` - CrashLoopBackOff (ابزار تست شبکه)
- `ingress-nginx-controller` - CrashLoopBackOff (environment variables)
- `local-path-provisioner` - CrashLoopBackOff (storage provisioner)

---

## 🎯 دستاوردها

### **قبل از امروز:**
- ❌ اکثر سرویس‌ها از Docker Hub و registryهای خارجی ایمیج می‌کشیدن
- ❌ CI/CD pipeline نیاز به اینترنت داشت برای نصب sshpass
- ❌ NuGet packages از internet دانلود می‌شدن

### **بعد از امروز:**
- ✅ **100% آفلاین:** تمام ایمیج‌های اصلی از Nexus کش می‌شن
- ✅ **CI/CD کاملاً آفلاین:** ایمیج `docker-sshpass` آماده
- ✅ **NuGet کش شده:** ~500 پکیج .NET در Nexus
- ✅ **Auto-deploy:** kubectl rollout restart خودکار
- ✅ **Protobuf publishing:** پکیج‌های محلی به Nexus

---

## 🔧 تنظیمات انجام شده امروز

### **1. ایمیج‌های جدید کش شده:**
```bash
# K8s System Images
194.5.195.53:32082/quay.io/jetstack/cert-manager-cainjector:v1.14.0
194.5.195.53:32082/quay.io/jetstack/cert-manager-controller:v1.14.0  
194.5.195.53:32082/quay.io/jetstack/cert-manager-webhook:v1.14.0
194.5.195.53:32082/registry.k8s.io/ingress-nginx/controller:v1.14.1
194.5.195.53:32082/rancher/local-path-provisioner:v0.0.32
194.5.195.53:32082/rancher/klipper-helm:v0.9.10-build20251111
194.5.195.53:32082/rancher/klipper-lb:v0.4.13

# Application Images  
194.5.195.53:32082/mcr.microsoft.com/mssql/server:2022-latest
194.5.195.53:32082/nginx:alpine
194.5.195.53:32082/nginx:stable
194.5.195.53:32082/nicolaka/netshoot:latest
194.5.195.53:32082/registry:2

# CI/CD Images
194.5.195.53:32082/docker-sshpass:latest (custom-built)
```

### **2. Deployment Updates:**
همه deploymentها با `kubectl patch` آپدیت شدن تا از Nexus استفاده کنن:

```yaml
# مثال: cert-manager
spec:
  template:
    spec:
      containers:
      - name: cert-manager-cainjector
        image: 194.5.195.53:32082/quay.io/jetstack/cert-manager-cainjector:v1.14.0
```

### **3. CI/CD Pipeline بهبودها:**
```yaml
container:
  image: 194.5.195.53:32082/docker-sshpass:latest  # ✅ آفلاین
steps:
  - name: Deploy to Kubernetes
    run: |
      export SSHPASS="${{ secrets.SERVER_PASSWORD }}"
      sshpass -e ssh -o StrictHostKeyChecking=no root@${{ env.K8S_SERVER }} "
        kubectl rollout restart deployment/<app>
        kubectl rollout status deployment/<app> --timeout=180s
      "
```

### **4. مشکلات حل شده:**
- ✅ **gitea + gitea-runner:** از Nexus images استفاده
- ✅ **docker-sshpass:** ایمیج سفارشی برای CI/CD  
- ✅ **cert-manager:** تمام componentها آپدیت
- ✅ **mssql:** EULA acceptance اضافه شد
- ⚠️ **seq:** temporarily deleted (ایمیج push نشد)

---

## 🚀 دستورات مهم برای آینده

### **تست آفلاین بودن:**
```bash
# چک کردن ایمیج‌های خارجی
kubectl get pods -A -o jsonpath='{range .items[*]}{.spec.containers[*].image}{"\n"}{end}' | sort | uniq | grep -v '194.5.195.53'

# تست CI/CD
git commit --allow-empty -m "test offline pipeline" && git push

# چک rollout status
kubectl rollout status deployment/<app> --timeout=180s
```

### **اضافه کردن ایمیج جدید به Nexus:**
```bash
# Export از containerd
ctr -n k8s.io images export /tmp/image.tar <image-name>

# Push به Nexus
skopeo copy --dest-tls-verify=false --dest-creds admin:87zH26nbqT \
  docker-archive:/tmp/image.tar docker://194.5.195.53:32082/<image-path>

# Update deployment
kubectl patch deployment <name> --type='merge' \
  -p='{"spec":{"template":{"spec":{"containers":[{"name":"<container>","image":"194.5.195.53:32082/<image>"}]}}}}'
```

---

## 📅 تاریخ آخرین به‌روزرسانی
**29 ژانویه 2026** - سیستم کاملاً آفلاین شد
