Compare commits
24 Commits
954387a8cf
...
feature/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f19f60015b | ||
|
|
3e3d396409 | ||
|
|
cf6fcd4dfe | ||
|
|
15e664461d | ||
|
|
8253fa73de | ||
|
|
fdfca1c4f1 | ||
|
|
a608726db9 | ||
|
|
6fe58c3815 | ||
|
|
826447e9a2 | ||
|
|
7c1b8b90ba | ||
|
|
82af967dfc | ||
|
|
8766103637 | ||
|
|
cb64fa1da2 | ||
|
|
ff32c54269 | ||
|
|
0694d10b7a | ||
|
|
87bb61e471 | ||
|
|
dc9faa989f | ||
|
|
46df8290ec | ||
|
|
5fed68fc54 | ||
|
|
7f4d167ca6 | ||
|
|
432aa63e36 | ||
|
|
b9217fe81e | ||
|
|
20267daade | ||
|
|
6820f0ee4f |
193
.github/workflows/cd.yml
vendored
@@ -1,193 +0,0 @@
|
||||
name: CD - Build & Deploy
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
outputs:
|
||||
image-tag: ${{ steps.meta.outputs.tags }}
|
||||
image-version: ${{ steps.meta.outputs.version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=sha,prefix={{branch}}-
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
|
||||
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
|
||||
platforms: linux/amd64
|
||||
|
||||
- name: Image digest
|
||||
run: echo "Image pushed with digest ${{ steps.build.outputs.digest }}"
|
||||
|
||||
package-helm:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-and-push
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v3
|
||||
with:
|
||||
version: 'latest'
|
||||
|
||||
- name: Package Helm chart
|
||||
run: |
|
||||
helm package helm/peikarband --destination .
|
||||
helm repo index . --url https://github.com/${{ github.repository }}/releases/download/${{ github.ref_name }}
|
||||
|
||||
- name: Upload Helm chart artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: helm-chart
|
||||
path: |
|
||||
*.tgz
|
||||
index.yaml
|
||||
|
||||
deploy-staging:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-and-push, package-helm]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
environment:
|
||||
name: staging
|
||||
url: https://staging.peikarband.ir
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install kubectl
|
||||
uses: azure/setup-kubectl@v3
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v3
|
||||
|
||||
- name: Configure kubectl
|
||||
run: |
|
||||
echo "${{ secrets.KUBECONFIG_STAGING }}" | base64 -d > kubeconfig
|
||||
export KUBECONFIG=kubeconfig
|
||||
|
||||
- name: Deploy to Staging
|
||||
run: |
|
||||
export KUBECONFIG=kubeconfig
|
||||
helm upgrade --install peikarband-staging ./helm/peikarband \
|
||||
--namespace staging \
|
||||
--create-namespace \
|
||||
--set image.tag=${{ needs.build-and-push.outputs.image-version }} \
|
||||
--set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
|
||||
--set ingress.hosts[0].host=staging.peikarband.ir \
|
||||
--wait \
|
||||
--timeout 5m
|
||||
|
||||
deploy-production:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-and-push, package-helm]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
environment:
|
||||
name: production
|
||||
url: https://peikarband.ir
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install kubectl
|
||||
uses: azure/setup-kubectl@v3
|
||||
|
||||
- name: Install Helm
|
||||
uses: azure/setup-helm@v3
|
||||
|
||||
- name: Configure kubectl
|
||||
run: |
|
||||
echo "${{ secrets.KUBECONFIG_PRODUCTION }}" | base64 -d > kubeconfig
|
||||
export KUBECONFIG=kubeconfig
|
||||
|
||||
- name: Deploy to Production
|
||||
run: |
|
||||
export KUBECONFIG=kubeconfig
|
||||
helm upgrade --install peikarband-prod ./helm/peikarband \
|
||||
--namespace production \
|
||||
--create-namespace \
|
||||
--set image.tag=${{ needs.build-and-push.outputs.image-version }} \
|
||||
--set image.repository=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} \
|
||||
--set replicaCount=3 \
|
||||
--set autoscaling.enabled=true \
|
||||
--values helm/peikarband/values-production.yaml \
|
||||
--wait \
|
||||
--timeout 10m
|
||||
|
||||
- name: Verify deployment
|
||||
run: |
|
||||
export KUBECONFIG=kubeconfig
|
||||
kubectl rollout status deployment/peikarband-prod -n production
|
||||
kubectl get pods -n production
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build-and-push, package-helm, deploy-production]
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Download Helm chart
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: helm-chart
|
||||
|
||||
- name: Create Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: |
|
||||
*.tgz
|
||||
index.yaml
|
||||
generate_release_notes: true
|
||||
draft: false
|
||||
prerelease: false
|
||||
|
||||
121
.github/workflows/ci.yml
vendored
@@ -1,121 +0,0 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ['3.11', '3.12']
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:14
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: peikarband_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd pg_isready
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
redis:
|
||||
image: redis:7
|
||||
ports:
|
||||
- 6379:6379
|
||||
options: >-
|
||||
--health-cmd "redis-cli ping"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Cache pip packages
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-dev.txt
|
||||
|
||||
- name: Lint with flake8
|
||||
run: |
|
||||
flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
flake8 src/ --count --max-complexity=10 --max-line-length=120 --statistics
|
||||
|
||||
- name: Type check with mypy
|
||||
run: |
|
||||
mypy src/
|
||||
|
||||
- name: Check formatting with black
|
||||
run: |
|
||||
black --check src/
|
||||
|
||||
- name: Check imports with isort
|
||||
run: |
|
||||
isort --check-only src/
|
||||
|
||||
- name: Run tests with pytest
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/peikarband_test
|
||||
REDIS_URL: redis://localhost:6379/0
|
||||
SECRET_KEY: test-secret-key
|
||||
JWT_SECRET_KEY: test-jwt-secret
|
||||
CELERY_BROKER_URL: redis://localhost:6379/1
|
||||
CELERY_RESULT_BACKEND: redis://localhost:6379/2
|
||||
run: |
|
||||
pytest tests/ -v --cov=src --cov-report=xml --cov-report=term-missing
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
fail_ci_if_error: false
|
||||
|
||||
security:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install bandit safety
|
||||
|
||||
- name: Run Bandit security scan
|
||||
run: |
|
||||
bandit -r src/ -f json -o bandit-report.json || true
|
||||
|
||||
- name: Run Safety check
|
||||
run: |
|
||||
safety check --json || true
|
||||
|
||||
4
.gitignore
vendored
@@ -8,7 +8,6 @@ __pycache__/
|
||||
*$py.class
|
||||
*.so
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
@@ -27,6 +26,9 @@ venv/
|
||||
env/
|
||||
ENV/
|
||||
|
||||
# Local data directory
|
||||
peikarband/data/
|
||||
|
||||
# Reflex
|
||||
.web/
|
||||
.reflex/
|
||||
|
||||
704
.woodpecker-back.yml
Normal file
@@ -0,0 +1,704 @@
|
||||
# Woodpecker CI/CD Pipeline - Peikarband Landing
|
||||
# Application build pipeline (uses pre-built base image)
|
||||
|
||||
variables:
|
||||
- &python_image 'python:3.11-slim'
|
||||
- &helm_image 'alpine/helm:latest'
|
||||
- &base_image 'hub.peikarband.ir/peikarband/base:latest'
|
||||
|
||||
when:
|
||||
- event: [push, pull_request, tag, manual]
|
||||
|
||||
pipeline:
|
||||
# ============================================
|
||||
# Stage 1: Check Base Image Availability
|
||||
# ============================================
|
||||
|
||||
check-base-image:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "Checking if base image is available..."
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/base"
|
||||
TAG="latest"
|
||||
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Base image found: $REGISTRY/$REPO:$TAG"
|
||||
else
|
||||
echo "❌ Base image not found!"
|
||||
echo "Please run .woodpecker-base.yml pipeline first to build base image"
|
||||
echo "Or trigger it manually in Woodpecker UI"
|
||||
exit 1
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
- event: [push, tag]
|
||||
|
||||
# ============================================
|
||||
# Stage 2: Build Application Image
|
||||
# ============================================
|
||||
|
||||
build-image:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/landing
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
# استفاده از base image
|
||||
build_args:
|
||||
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
|
||||
# فقط build میکنیم، بدون push
|
||||
tags:
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.url=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.revision=${CI_COMMIT_SHA}
|
||||
- org.opencontainers.image.version=${CI_COMMIT_SHA:0:8}
|
||||
- org.opencontainers.image.title=Peikarband Landing
|
||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||
|
||||
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
cache_to: type=inline
|
||||
provenance: false
|
||||
|
||||
# فقط build، بدون push
|
||||
push: false
|
||||
load: false
|
||||
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stage 3: Push Image with Multi-Tags
|
||||
# ============================================
|
||||
|
||||
push-image:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/landing
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
build_args:
|
||||
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
|
||||
# Multi-tagging strategy
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
- ${CI_COMMIT_BRANCH}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.url=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.revision=${CI_COMMIT_SHA}
|
||||
- org.opencontainers.image.version=${CI_COMMIT_SHA:0:8}
|
||||
- org.opencontainers.image.title=Peikarband Landing
|
||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||
|
||||
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
cache_to: type=inline
|
||||
provenance: false
|
||||
|
||||
# حالا push میکنیم
|
||||
push: true
|
||||
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stage 4: Verify Push
|
||||
# ============================================
|
||||
|
||||
verify-push:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "Verifying image was pushed successfully..."
|
||||
sleep 3 # Wait for registry sync
|
||||
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/landing"
|
||||
TAG="${CI_COMMIT_SHA:0:8}"
|
||||
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Image verified: $REGISTRY/$REPO:$TAG"
|
||||
else
|
||||
echo "❌ Failed to verify image push"
|
||||
exit 1
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stages below are commented for now
|
||||
# Uncomment when ready to use
|
||||
# ============================================
|
||||
|
||||
# # ============================================
|
||||
# # Stage 1: Code Quality & Linting
|
||||
# # ============================================
|
||||
|
||||
# lint-flake8:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir flake8
|
||||
# - cd peikarband
|
||||
# - flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
# - flake8 src/ --count --max-complexity=10 --max-line-length=120 --statistics --exit-zero
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# lint-black:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir black
|
||||
# - cd peikarband
|
||||
# - black --check src/ || echo "⚠️ Black formatting issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# lint-isort:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir isort
|
||||
# - cd peikarband
|
||||
# - isort --check-only src/ || echo "⚠️ Import sorting issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# type-check:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir mypy types-redis types-requests
|
||||
# - cd peikarband
|
||||
# - mypy src/ --config-file=config/mypy.ini || echo "⚠️ Type checking issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 2: Security Scanning
|
||||
# # ============================================
|
||||
|
||||
# security-bandit:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir bandit[toml]
|
||||
# - cd peikarband
|
||||
# - bandit -r src/ -f json -o bandit-report.json || true
|
||||
# - bandit -r src/ -ll || echo "⚠️ Security issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# security-safety:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir safety
|
||||
# - cd peikarband
|
||||
# - safety check -r requirements.txt --json || echo "⚠️ Dependency vulnerabilities found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 3: Testing
|
||||
# # ============================================
|
||||
|
||||
# test:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - apt-get update && apt-get install -y --no-install-recommends curl
|
||||
# - pip install --no-cache-dir -r peikarband/requirements.txt
|
||||
# - pip install --no-cache-dir -r peikarband/requirements-dev.txt
|
||||
# - cd peikarband
|
||||
# - pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml || echo "⚠️ Tests failed (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 4: Helm Validation
|
||||
# # ============================================
|
||||
|
||||
# helm-lint:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - helm version
|
||||
# - helm lint helm/peikarband
|
||||
# - echo "✓ Helm chart validation passed"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# helm-template:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - helm template peikarband helm/peikarband -f helm/peikarband/values-production.yaml --debug > /dev/null
|
||||
# - echo "✓ Helm template rendering successful"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 6: Deployment - Staging
|
||||
# # ============================================
|
||||
|
||||
# deploy-staging:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - apk add --no-cache kubectl
|
||||
# - echo "$KUBECONFIG_STAGING" | base64 -d > /tmp/kubeconfig
|
||||
# - export KUBECONFIG=/tmp/kubeconfig
|
||||
# - |
|
||||
# helm upgrade --install peikarband-staging helm/peikarband \
|
||||
# --namespace staging \
|
||||
# --create-namespace \
|
||||
# --set image.repository=hub.peikarband.ir/peikarband/landing \
|
||||
# --set image.tag=${CI_COMMIT_SHA:0:8} \
|
||||
# --set image.pullPolicy=Always \
|
||||
# --values helm/peikarband/values-staging.yaml \
|
||||
# --wait \
|
||||
# --timeout 5m
|
||||
# - kubectl get pods -n staging
|
||||
# - echo "✓ Deployed to staging successfully"
|
||||
# secrets: [KUBECONFIG_STAGING]
|
||||
# when:
|
||||
# - event: push
|
||||
# branch: [main, develop]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 7: Deployment - Production
|
||||
# # ============================================
|
||||
|
||||
# deploy-production:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - apk add --no-cache kubectl
|
||||
# - echo "$KUBECONFIG_PRODUCTION" | base64 -d > /tmp/kubeconfig
|
||||
# - export KUBECONFIG=/tmp/kubeconfig
|
||||
# - |
|
||||
# helm upgrade --install peikarband helm/peikarband \
|
||||
# --namespace production \
|
||||
# --create-namespace \
|
||||
# --set image.repository=hub.peikarband.ir/peikarband/landing \
|
||||
# --set image.tag=${CI_COMMIT_TAG} \
|
||||
# --set image.pullPolicy=Always \
|
||||
# --values helm/peikarband/values-production.yaml \
|
||||
# --wait \
|
||||
# --timeout 10m
|
||||
# - kubectl rollout status deployment/peikarband -n production
|
||||
# - kubectl get pods -n production
|
||||
# - echo "✓ Deployed to production successfully"
|
||||
# secrets: [KUBECONFIG_PRODUCTION]
|
||||
# when:
|
||||
# - event: tag
|
||||
# ref: refs/tags/v*
|
||||
|
||||
# # ============================================
|
||||
# # Stage 8: Notifications
|
||||
# # ============================================
|
||||
|
||||
# notify-success:
|
||||
# image: alpine:latest
|
||||
# commands:
|
||||
# - echo "🎉 Pipeline completed successfully!"
|
||||
# - echo "Branch: ${CI_COMMIT_BRANCH}"
|
||||
# - echo "Commit: ${CI_COMMIT_SHA:0:8}"
|
||||
# - echo "Image: hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}"
|
||||
# when:
|
||||
# - event: [push, tag]
|
||||
# status: success
|
||||
|
||||
# notify-failure:
|
||||
# image: alpine:latest
|
||||
# commands:
|
||||
# - echo "❌ Pipeline failed!"
|
||||
# - echo "Branch: ${CI_COMMIT_BRANCH}"
|
||||
# - echo "Commit: ${CI_COMMIT_SHA:0:8}"
|
||||
# - echo "Please check the logs above"
|
||||
# when:
|
||||
# - event: [push, tag]
|
||||
# status: failure
|
||||
|
||||
|
||||
|
||||
# Woodpecker CI/CD Pipeline - Peikarband Landing
|
||||
# Application build pipeline (uses pre-built base image)
|
||||
|
||||
variables:
|
||||
- &python_image 'python:3.11-slim'
|
||||
- &helm_image 'alpine/helm:latest'
|
||||
- &base_image 'hub.peikarband.ir/peikarband/base:latest'
|
||||
|
||||
when:
|
||||
- event: [push, pull_request, tag, manual]
|
||||
|
||||
pipeline:
|
||||
# ============================================
|
||||
# Stage 1: Check Base Image Availability
|
||||
# ============================================
|
||||
|
||||
check-base-image:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "Checking if base image is available..."
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/base"
|
||||
TAG="latest"
|
||||
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Base image found: $REGISTRY/$REPO:$TAG"
|
||||
else
|
||||
echo "❌ Base image not found!"
|
||||
echo "Please run .woodpecker-base.yml pipeline first to build base image"
|
||||
echo "Or trigger it manually in Woodpecker UI"
|
||||
exit 1
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
- event: [push, tag]
|
||||
|
||||
# ============================================
|
||||
# Stage 2: Build Application Image
|
||||
# ============================================
|
||||
|
||||
build-image:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/landing
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
# استفاده از base image
|
||||
build_args:
|
||||
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
|
||||
# فقط build میکنیم، بدون push
|
||||
tags:
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.url=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.revision=${CI_COMMIT_SHA}
|
||||
- org.opencontainers.image.version=${CI_COMMIT_SHA:0:8}
|
||||
- org.opencontainers.image.title=Peikarband Landing
|
||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||
|
||||
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
cache_to: type=inline
|
||||
provenance: false
|
||||
|
||||
# فقط build، بدون push
|
||||
push: false
|
||||
load: false
|
||||
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stage 3: Push Image with Multi-Tags
|
||||
# ============================================
|
||||
|
||||
push-image:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/landing
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
build_args:
|
||||
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
|
||||
# Multi-tagging strategy
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
- ${CI_COMMIT_BRANCH}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.url=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.revision=${CI_COMMIT_SHA}
|
||||
- org.opencontainers.image.version=${CI_COMMIT_SHA:0:8}
|
||||
- org.opencontainers.image.title=Peikarband Landing
|
||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||
|
||||
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
cache_to: type=inline
|
||||
provenance: false
|
||||
|
||||
# حالا push میکنیم
|
||||
push: true
|
||||
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stage 4: Verify Push
|
||||
# ============================================
|
||||
|
||||
verify-push:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "Verifying image was pushed successfully..."
|
||||
sleep 3 # Wait for registry sync
|
||||
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/landing"
|
||||
TAG="${CI_COMMIT_SHA:0:8}"
|
||||
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Image verified: $REGISTRY/$REPO:$TAG"
|
||||
else
|
||||
echo "❌ Failed to verify image push"
|
||||
exit 1
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
- event: [push, tag]
|
||||
branch: [main, develop]
|
||||
|
||||
# ============================================
|
||||
# Stages below are commented for now
|
||||
# Uncomment when ready to use
|
||||
# ============================================
|
||||
|
||||
# # ============================================
|
||||
# # Stage 1: Code Quality & Linting
|
||||
# # ============================================
|
||||
|
||||
# lint-flake8:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir flake8
|
||||
# - cd peikarband
|
||||
# - flake8 src/ --count --select=E9,F63,F7,F82 --show-source --statistics
|
||||
# - flake8 src/ --count --max-complexity=10 --max-line-length=120 --statistics --exit-zero
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# lint-black:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir black
|
||||
# - cd peikarband
|
||||
# - black --check src/ || echo "⚠️ Black formatting issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# lint-isort:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir isort
|
||||
# - cd peikarband
|
||||
# - isort --check-only src/ || echo "⚠️ Import sorting issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# type-check:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir mypy types-redis types-requests
|
||||
# - cd peikarband
|
||||
# - mypy src/ --config-file=config/mypy.ini || echo "⚠️ Type checking issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 2: Security Scanning
|
||||
# # ============================================
|
||||
|
||||
# security-bandit:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir bandit[toml]
|
||||
# - cd peikarband
|
||||
# - bandit -r src/ -f json -o bandit-report.json || true
|
||||
# - bandit -r src/ -ll || echo "⚠️ Security issues found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# security-safety:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - pip install --no-cache-dir safety
|
||||
# - cd peikarband
|
||||
# - safety check -r requirements.txt --json || echo "⚠️ Dependency vulnerabilities found (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 3: Testing
|
||||
# # ============================================
|
||||
|
||||
# test:
|
||||
# image: *python_image
|
||||
# commands:
|
||||
# - apt-get update && apt-get install -y --no-install-recommends curl
|
||||
# - pip install --no-cache-dir -r peikarband/requirements.txt
|
||||
# - pip install --no-cache-dir -r peikarband/requirements-dev.txt
|
||||
# - cd peikarband
|
||||
# - pytest tests/ -v --cov=src --cov-report=term-missing --cov-report=xml || echo "⚠️ Tests failed (non-blocking)"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 4: Helm Validation
|
||||
# # ============================================
|
||||
|
||||
# helm-lint:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - helm version
|
||||
# - helm lint helm/peikarband
|
||||
# - echo "✓ Helm chart validation passed"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# helm-template:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - helm template peikarband helm/peikarband -f helm/peikarband/values-production.yaml --debug > /dev/null
|
||||
# - echo "✓ Helm template rendering successful"
|
||||
# when:
|
||||
# - event: [push, pull_request, tag]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 6: Deployment - Staging
|
||||
# # ============================================
|
||||
|
||||
# deploy-staging:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - apk add --no-cache kubectl
|
||||
# - echo "$KUBECONFIG_STAGING" | base64 -d > /tmp/kubeconfig
|
||||
# - export KUBECONFIG=/tmp/kubeconfig
|
||||
# - |
|
||||
# helm upgrade --install peikarband-staging helm/peikarband \
|
||||
# --namespace staging \
|
||||
# --create-namespace \
|
||||
# --set image.repository=hub.peikarband.ir/peikarband/landing \
|
||||
# --set image.tag=${CI_COMMIT_SHA:0:8} \
|
||||
# --set image.pullPolicy=Always \
|
||||
# --values helm/peikarband/values-staging.yaml \
|
||||
# --wait \
|
||||
# --timeout 5m
|
||||
# - kubectl get pods -n staging
|
||||
# - echo "✓ Deployed to staging successfully"
|
||||
# secrets: [KUBECONFIG_STAGING]
|
||||
# when:
|
||||
# - event: push
|
||||
# branch: [main, develop]
|
||||
|
||||
# # ============================================
|
||||
# # Stage 7: Deployment - Production
|
||||
# # ============================================
|
||||
|
||||
# deploy-production:
|
||||
# image: *helm_image
|
||||
# commands:
|
||||
# - apk add --no-cache kubectl
|
||||
# - echo "$KUBECONFIG_PRODUCTION" | base64 -d > /tmp/kubeconfig
|
||||
# - export KUBECONFIG=/tmp/kubeconfig
|
||||
# - |
|
||||
# helm upgrade --install peikarband helm/peikarband \
|
||||
# --namespace production \
|
||||
# --create-namespace \
|
||||
# --set image.repository=hub.peikarband.ir/peikarband/landing \
|
||||
# --set image.tag=${CI_COMMIT_TAG} \
|
||||
# --set image.pullPolicy=Always \
|
||||
# --values helm/peikarband/values-production.yaml \
|
||||
# --wait \
|
||||
# --timeout 10m
|
||||
# - kubectl rollout status deployment/peikarband -n production
|
||||
# - kubectl get pods -n production
|
||||
# - echo "✓ Deployed to production successfully"
|
||||
# secrets: [KUBECONFIG_PRODUCTION]
|
||||
# when:
|
||||
# - event: tag
|
||||
# ref: refs/tags/v*
|
||||
|
||||
# # ============================================
|
||||
# # Stage 8: Notifications
|
||||
# # ============================================
|
||||
|
||||
# notify-success:
|
||||
# image: alpine:latest
|
||||
# commands:
|
||||
# - echo "🎉 Pipeline completed successfully!"
|
||||
# - echo "Branch: ${CI_COMMIT_BRANCH}"
|
||||
# - echo "Commit: ${CI_COMMIT_SHA:0:8}"
|
||||
# - echo "Image: hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}"
|
||||
# when:
|
||||
# - event: [push, tag]
|
||||
# status: success
|
||||
|
||||
# notify-failure:
|
||||
# image: alpine:latest
|
||||
# commands:
|
||||
# - echo "❌ Pipeline failed!"
|
||||
# - echo "Branch: ${CI_COMMIT_BRANCH}"
|
||||
# - echo "Commit: ${CI_COMMIT_SHA:0:8}"
|
||||
# - echo "Please check the logs above"
|
||||
# when:
|
||||
# - event: [push, tag]
|
||||
# status: failure
|
||||
|
||||
142
.woodpecker-base.yml
Normal file
@@ -0,0 +1,142 @@
|
||||
# Woodpecker Pipeline - Base Image Builder
|
||||
#
|
||||
# این pipeline فقط برای ساخت base image است
|
||||
# Trigger: Manual یا زمانی که Dockerfile.base تغییر کند
|
||||
#
|
||||
# Usage:
|
||||
# Manual: در Woodpecker UI -> Manual trigger
|
||||
# Auto: هر بار که docker/Dockerfile.base تغییر کند
|
||||
|
||||
when:
|
||||
- event: [manual, push]
|
||||
path:
|
||||
- docker/Dockerfile.base
|
||||
- .woodpecker-base.yml
|
||||
|
||||
pipeline:
|
||||
# ============================================
|
||||
# Check if base image needs rebuild
|
||||
# ============================================
|
||||
|
||||
check-base-exists:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl jq
|
||||
- |
|
||||
echo "Checking if base image exists in registry..."
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/base"
|
||||
TAG="python3.11-node20"
|
||||
|
||||
# Try to check if image exists (will fail if doesn't exist)
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Base image exists: $REGISTRY/$REPO:$TAG"
|
||||
echo "BASE_EXISTS=true" >> /tmp/base_status
|
||||
else
|
||||
echo "⚠️ Base image not found, will build new one"
|
||||
echo "BASE_EXISTS=false" >> /tmp/base_status
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
|
||||
# ============================================
|
||||
# Build Base Image
|
||||
# ============================================
|
||||
|
||||
build-base:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/base
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile.base
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
# Multi-tag strategy
|
||||
tags:
|
||||
- latest
|
||||
- python3.11-node20
|
||||
- python3.11-node20-${CI_COMMIT_SHA:0:8}
|
||||
|
||||
build_args:
|
||||
- PYTHON_VERSION=3.11
|
||||
- NODE_VERSION=20
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.revision=${CI_COMMIT_SHA}
|
||||
- org.opencontainers.image.version=python3.11-node20
|
||||
- org.opencontainers.image.title=Peikarband Base Image
|
||||
- org.opencontainers.image.description=Base image with Python 3.11, Node.js 20, bun
|
||||
|
||||
provenance: false
|
||||
push: true
|
||||
|
||||
when:
|
||||
- event: [manual, push]
|
||||
|
||||
# ============================================
|
||||
# Verify Base Image
|
||||
# ============================================
|
||||
|
||||
verify-base:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "Verifying base image was pushed successfully..."
|
||||
sleep 5 # Wait for registry to sync
|
||||
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/base"
|
||||
TAG="latest"
|
||||
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://$REGISTRY/v2/$REPO/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✓ Base image verified: $REGISTRY/$REPO:$TAG"
|
||||
echo "✓ Base image is ready for use in application builds"
|
||||
else
|
||||
echo "❌ Failed to verify base image"
|
||||
exit 1
|
||||
fi
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
- event: [manual, push]
|
||||
|
||||
# ============================================
|
||||
# Notification
|
||||
# ============================================
|
||||
|
||||
notify-complete:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- |
|
||||
echo "================================================"
|
||||
echo "🎉 Base Image Build Complete!"
|
||||
echo "================================================"
|
||||
echo ""
|
||||
echo "📦 Image Details:"
|
||||
echo " Registry: hub.peikarband.ir/peikarband/base"
|
||||
echo " Tags: latest, python3.11-node20, python3.11-node20-${CI_COMMIT_SHA:0:8}"
|
||||
echo ""
|
||||
echo "✓ Python: 3.11"
|
||||
echo "✓ Node.js: 20"
|
||||
echo "✓ Bun: latest"
|
||||
echo "✓ Build tools: gcc, g++, make"
|
||||
echo ""
|
||||
echo "📝 Next Steps:"
|
||||
echo " 1. Application builds will now use this base image"
|
||||
echo " 2. Build time will be significantly faster"
|
||||
echo " 3. Network reliability improved (no repeated npm/bun installs)"
|
||||
echo ""
|
||||
echo "================================================"
|
||||
when:
|
||||
- event: [manual, push]
|
||||
status: success
|
||||
|
||||
180
.woodpecker.yml
@@ -1,30 +1,90 @@
|
||||
# Woodpecker CI/CD Pipeline - Peikarband Landing
|
||||
# Smart pipeline with base image management
|
||||
|
||||
variables:
|
||||
- &base_image 'hub.peikarband.ir/peikarband/landing:base'
|
||||
- &app_image 'hub.peikarband.ir/peikarband/landing'
|
||||
|
||||
when:
|
||||
- event: [push, pull_request, tag, manual]
|
||||
|
||||
pipeline:
|
||||
publish_landing:
|
||||
# ============================================
|
||||
# Ensure Base Image Exists
|
||||
# ============================================
|
||||
|
||||
ensure-base-image:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
# تنظیمات ریجیستری Harbor
|
||||
registry: hub.peikarband.ir
|
||||
repo: hub.peikarband.ir/peikarband/landing
|
||||
repo: *app_image
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
# تگگذاری
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
dockerfile: docker/Dockerfile.base
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
dockerfile: Dockerfile
|
||||
tags:
|
||||
- base
|
||||
- base-python3.11-node20
|
||||
|
||||
build_args:
|
||||
- PYTHON_VERSION=3.11
|
||||
- NODE_VERSION=20
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
- org.opencontainers.image.source=${CI_REPO_LINK}
|
||||
- org.opencontainers.image.title=Peikarband Base
|
||||
- org.opencontainers.image.description=Base image with Python, Node.js, bun, and build tools
|
||||
|
||||
pull: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
push: true
|
||||
|
||||
|
||||
when:
|
||||
event: [push, tag, manual]
|
||||
branch: [main, develop, feature/restructure-project]
|
||||
# Only rebuild base if its definition changed
|
||||
path:
|
||||
include:
|
||||
- docker/Dockerfile.base
|
||||
- .woodpecker.yml
|
||||
|
||||
# ============================================
|
||||
# Build Application Image
|
||||
# ============================================
|
||||
|
||||
build-and-push-app:
|
||||
image: woodpeckerci/plugin-docker-buildx
|
||||
settings:
|
||||
registry: hub.peikarband.ir
|
||||
repo: *app_image
|
||||
username:
|
||||
from_secret: HARBOR_USERNAME
|
||||
password:
|
||||
from_secret: HARBOR_PASSWORD
|
||||
|
||||
dockerfile: docker/Dockerfile
|
||||
context: .
|
||||
platforms: linux/amd64
|
||||
|
||||
build_args:
|
||||
- BASE_IMAGE=*base_image
|
||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||
- PYTHON_VERSION=3.11
|
||||
- NODE_VERSION=20
|
||||
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
- ${CI_COMMIT_BRANCH}
|
||||
|
||||
labels:
|
||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||
@@ -35,12 +95,102 @@ pipeline:
|
||||
- org.opencontainers.image.title=Peikarband Landing
|
||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||
|
||||
cache: inline
|
||||
provenance: true
|
||||
pull: true
|
||||
provenance: false
|
||||
sbom: false
|
||||
push: true
|
||||
|
||||
when:
|
||||
- event: [push, tag, manual]
|
||||
branch: main # معمولاً فقط روی برنچ اصلی پوش انجام میشود
|
||||
event: [push, tag]
|
||||
branch: [main, develop, feature/restructure-project]
|
||||
|
||||
timeout: 30m
|
||||
# ============================================
|
||||
# Verify Images
|
||||
# ============================================
|
||||
|
||||
verify-images:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- apk add --no-cache curl
|
||||
- |
|
||||
echo "════════════════════════════════════════"
|
||||
echo " 🔍 Verifying Images in Registry"
|
||||
echo "════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# Check base image
|
||||
echo "Checking base image..."
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://hub.peikarband.ir/v2/peikarband/landing/manifests/base" > /dev/null 2>&1; then
|
||||
echo "✅ Base image: hub.peikarband.ir/peikarband/landing:base"
|
||||
else
|
||||
echo "⚠️ Base image not found (this is OK if first build)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# Check app image
|
||||
echo "Checking app image..."
|
||||
TAG="${CI_COMMIT_SHA:0:8}"
|
||||
if curl -f -u "$HARBOR_USERNAME:$HARBOR_PASSWORD" \
|
||||
"https://hub.peikarband.ir/v2/peikarband/landing/manifests/$TAG" > /dev/null 2>&1; then
|
||||
echo "✅ App image: hub.peikarband.ir/peikarband/landing:$TAG"
|
||||
echo ""
|
||||
echo "Available tags:"
|
||||
echo " • latest"
|
||||
echo " • ${CI_COMMIT_SHA:0:8}"
|
||||
echo " • ${CI_COMMIT_BRANCH}"
|
||||
echo ""
|
||||
echo "════════════════════════════════════════"
|
||||
else
|
||||
echo "❌ Failed to verify app image"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
secrets: [HARBOR_USERNAME, HARBOR_PASSWORD]
|
||||
when:
|
||||
event: [push, tag]
|
||||
branch: [main, develop, feature/restructure-project]
|
||||
|
||||
# ============================================
|
||||
# Notifications
|
||||
# ============================================
|
||||
|
||||
notify-success:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- echo "════════════════════════════════════════"
|
||||
- echo " 🎉 Pipeline Completed Successfully!"
|
||||
- echo "════════════════════════════════════════"
|
||||
- echo ""
|
||||
- echo "Branch:" "${CI_COMMIT_BRANCH}"
|
||||
- echo "Commit:" "${CI_COMMIT_SHA:0:8}"
|
||||
- echo ""
|
||||
- echo "Images:"
|
||||
- echo " • Base:" "hub.peikarband.ir/peikarband/landing:base"
|
||||
- echo " • App:" "hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}"
|
||||
- echo ""
|
||||
- echo "Deploy with:"
|
||||
- echo " kubectl set image deployment/peikarband-landing \\"
|
||||
- echo " peikarband-landing=hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}"
|
||||
- echo ""
|
||||
- echo "════════════════════════════════════════"
|
||||
when:
|
||||
event: [push, tag]
|
||||
status: success
|
||||
|
||||
notify-failure:
|
||||
image: alpine:latest
|
||||
commands:
|
||||
- echo "════════════════════════════════════════"
|
||||
- echo " ❌ Pipeline Failed!"
|
||||
- echo "════════════════════════════════════════"
|
||||
- echo ""
|
||||
- echo "Branch:" "${CI_COMMIT_BRANCH}"
|
||||
- echo "Commit:" "${CI_COMMIT_SHA:0:8}"
|
||||
- echo ""
|
||||
- echo "Please check the logs above"
|
||||
- echo "════════════════════════════════════════"
|
||||
when:
|
||||
event: [push, tag]
|
||||
status: failure
|
||||
|
||||
172
Dockerfile
@@ -1,172 +0,0 @@
|
||||
# Peikarband Platform - Production Dockerfile
|
||||
# Multi-stage build for optimized image size and security
|
||||
|
||||
# Build arguments
|
||||
ARG PYTHON_VERSION=3.11
|
||||
ARG NODE_VERSION=20
|
||||
ARG VERSION=latest
|
||||
ARG BUILD_DATE
|
||||
|
||||
# ============================================
|
||||
# Stage 1: Builder
|
||||
# ============================================
|
||||
FROM python:${PYTHON_VERSION}-slim AS builder
|
||||
|
||||
# Re-declare ARGs for this stage
|
||||
ARG NODE_VERSION=20
|
||||
ARG VERSION=latest
|
||||
ARG BUILD_DATE
|
||||
|
||||
LABEL maintainer="Peikarband Team <dev@peikarband.ir>"
|
||||
LABEL org.opencontainers.image.title="Peikarband Landing"
|
||||
LABEL org.opencontainers.image.description="Peikarband hosting platform landing page"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
curl \
|
||||
gnupg \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Node.js (required for Reflex)
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install bun (required by Reflex for frontend build)
|
||||
# Retry mechanism for network issues
|
||||
RUN set -ex && \
|
||||
for i in 1 2 3 4 5; do \
|
||||
curl -fsSL https://bun.sh/install | bash && break || \
|
||||
(echo "Attempt $i failed, retrying in 5 seconds..." && sleep 5); \
|
||||
done || (echo "Failed to install bun after 5 attempts" && exit 1)
|
||||
|
||||
# Add bun to PATH
|
||||
ENV PATH="/root/.bun/bin:${PATH}"
|
||||
|
||||
# Copy only requirements first (for better layer caching)
|
||||
COPY requirements.txt .
|
||||
|
||||
# Install Python dependencies in user space
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
|
||||
pip install --no-cache-dir --user -r requirements.txt
|
||||
|
||||
# Copy application code (excluding .dockerignore items)
|
||||
COPY --chown=root:root . .
|
||||
|
||||
# Build and export Reflex app for production
|
||||
# Note: API_URL will be updated at runtime from environment variable
|
||||
# Export creates .web directory with frontend static files
|
||||
# bun is now pre-installed, so reflex export won't try to download it
|
||||
RUN python -m reflex export --no-zip
|
||||
|
||||
# Aggressive cleanup to reduce layer size
|
||||
# NOTE: Keep .web directory - it contains frontend static files
|
||||
RUN set -ex && \
|
||||
# Remove Python cache
|
||||
find /build -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true && \
|
||||
find /build -type f -name "*.pyc" -delete && \
|
||||
find /build -type f -name "*.pyo" -delete && \
|
||||
# Remove development files
|
||||
rm -rf /build/tests /build/docs /build/scripts && \
|
||||
rm -rf /build/.git /build/.github /build/.vscode && \
|
||||
rm -rf /build/venv /build/env && \
|
||||
# Remove node_modules but KEEP .web (frontend static files)
|
||||
rm -rf /build/node_modules && \
|
||||
# Remove large duplicate assets from root
|
||||
rm -f /build/*.gif /build/*.mp4 /build/*.mov 2>/dev/null || true && \
|
||||
# Keep only necessary configs
|
||||
find /build -type f -name "docker-compose*.yml" -delete && \
|
||||
find /build -type f -name "Makefile" -delete
|
||||
|
||||
# ============================================
|
||||
# Stage 2: Runtime
|
||||
# ============================================
|
||||
FROM python:${PYTHON_VERSION}-slim
|
||||
|
||||
# Re-declare ARGs for this stage
|
||||
ARG PYTHON_VERSION=3.11
|
||||
ARG VERSION=latest
|
||||
ARG BUILD_DATE
|
||||
|
||||
# Build info
|
||||
ENV VERSION=${VERSION} \
|
||||
BUILD_DATE=${BUILD_DATE}
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies only
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
ca-certificates \
|
||||
tini \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# Install Node.js runtime
|
||||
ARG NODE_VERSION=20
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& apt-get clean
|
||||
|
||||
# Create non-root user first
|
||||
RUN groupadd -r -g 1000 peikarband && \
|
||||
useradd -r -u 1000 -g peikarband -m -s /bin/bash peikarband && \
|
||||
mkdir -p /app/logs /app/uploads /app/.reflex
|
||||
|
||||
# Copy Python dependencies from builder to user home
|
||||
COPY --from=builder /root/.local /home/peikarband/.local
|
||||
|
||||
# Copy application code from builder
|
||||
COPY --from=builder /build /app
|
||||
|
||||
# Copy and set up runtime script
|
||||
COPY --chown=peikarband:peikarband scripts/update-env-json.sh /app/scripts/update-env-json.sh
|
||||
RUN chmod +x /app/scripts/update-env-json.sh
|
||||
|
||||
# Fix ownership
|
||||
RUN chown -R peikarband:peikarband /home/peikarband/.local /app
|
||||
|
||||
# Add version info (must be before USER switch)
|
||||
RUN echo "${VERSION}" > /app/.version && \
|
||||
chown peikarband:peikarband /app/.version
|
||||
|
||||
# Security: Remove unnecessary setuid/setgid permissions
|
||||
RUN find / -perm /6000 -type f -exec chmod a-s {} \; 2>/dev/null || true
|
||||
|
||||
# Set environment variables
|
||||
ENV PATH=/home/peikarband/.local/bin:$PATH \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONHASHSEED=random \
|
||||
PIP_NO_CACHE_DIR=1 \
|
||||
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
||||
REFLEX_ENV=prod \
|
||||
ENVIRONMENT=prod
|
||||
|
||||
# Switch to non-root user
|
||||
USER peikarband
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 3000 8000
|
||||
|
||||
# Health check with better error handling
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f -s -o /dev/null -w "%{http_code}" http://localhost:8000/ping | grep -q "200" || exit 1
|
||||
|
||||
# Use tini as init system for proper signal handling
|
||||
# Update .web/env.json from API_URL env var, then run the app
|
||||
ENTRYPOINT ["/usr/bin/tini", "--", "/app/scripts/update-env-json.sh"]
|
||||
|
||||
# Run application (both frontend and backend)
|
||||
CMD ["python", "-m", "reflex", "run", "--env", "prod"]
|
||||
|
||||
112
Makefile
@@ -10,33 +10,58 @@ DOCKER_BUILDKIT ?= 1
|
||||
.PHONY: help install dev kill-dev test lint format clean docker-up docker-down migrate
|
||||
|
||||
help:
|
||||
@echo "Available commands:"
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " 📋 Peikarband Landing - Available Commands"
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo ""
|
||||
@echo "Development:"
|
||||
@echo "🔧 Development:"
|
||||
@echo " make install - Install dependencies"
|
||||
@echo " make dev - Run development server"
|
||||
@echo " make kill-dev - Kill development server processes (ports 3000 & 8000)"
|
||||
@echo " make kill-dev - Kill development server (ports 3000 & 8000)"
|
||||
@echo " make test - Run tests"
|
||||
@echo " make lint - Run linters"
|
||||
@echo " make format - Format code"
|
||||
@echo " make clean - Clean temporary files"
|
||||
@echo ""
|
||||
@echo "Docker:"
|
||||
@echo " make docker-build - Build Docker image"
|
||||
@echo " make docker-push - Push Docker image"
|
||||
@echo "🐳 Docker - Base Image:"
|
||||
@echo " make docker-build-base - Build base image (Python + Node.js + bun)"
|
||||
@echo " make docker-push-base - Push base image to Harbor"
|
||||
@echo ""
|
||||
@echo "🐳 Docker - Application:"
|
||||
@echo " make docker-build - Build application image"
|
||||
@echo " make docker-push - Push application image to Harbor"
|
||||
@echo " make docker-login - Login to Harbor registry"
|
||||
@echo " make docker-up - Start Docker Compose"
|
||||
@echo " make docker-down - Stop Docker Compose"
|
||||
@echo ""
|
||||
@echo "Kubernetes/Helm:"
|
||||
@echo "☸️ Kubernetes/Helm:"
|
||||
@echo " make helm-lint - Lint Helm chart"
|
||||
@echo " make helm-package - Package Helm chart"
|
||||
@echo " make helm-install - Install Helm chart"
|
||||
@echo " make helm-upgrade - Upgrade Helm chart"
|
||||
@echo " make helm-uninstall - Uninstall Helm chart"
|
||||
@echo " make k8s-deploy - Deploy to Kubernetes"
|
||||
@echo " make k8s-deploy - Full deployment pipeline"
|
||||
@echo ""
|
||||
@echo "Database:"
|
||||
@echo "🗄️ Database:"
|
||||
@echo " make migrate - Run database migrations"
|
||||
@echo " make seed - Seed database with initial data"
|
||||
@echo ""
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " Quick Start:"
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo ""
|
||||
@echo "1️⃣ Build & Push Base (once):"
|
||||
@echo " make docker-login"
|
||||
@echo " make docker-build-base"
|
||||
@echo " make docker-push-base"
|
||||
@echo ""
|
||||
@echo "2️⃣ Build & Push App:"
|
||||
@echo " make docker-build"
|
||||
@echo " make docker-push"
|
||||
@echo ""
|
||||
@echo "3️⃣ Deploy:"
|
||||
@echo " make k8s-deploy"
|
||||
@echo ""
|
||||
|
||||
install:
|
||||
pip install -r requirements.txt
|
||||
@@ -44,7 +69,7 @@ install:
|
||||
pre-commit install
|
||||
|
||||
dev:
|
||||
python3 -m reflex run
|
||||
cd peikarband && python3 -m reflex run
|
||||
|
||||
kill-dev:
|
||||
@echo "Killing processes on ports 3000 and 8000..."
|
||||
@@ -73,32 +98,73 @@ clean:
|
||||
find . -type d -name ".mypy_cache" -exec rm -rf {} +
|
||||
find . -type d -name "*.egg-info" -exec rm -rf {} +
|
||||
rm -rf .coverage htmlcov/
|
||||
rm -rf dist/ build/
|
||||
rm -rf dist/
|
||||
|
||||
# Docker commands
|
||||
docker-build-base:
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " 🔨 Building Base Image"
|
||||
@echo "════════════════════════════════════════"
|
||||
DOCKER_BUILDKIT=$(DOCKER_BUILDKIT) docker buildx build \
|
||||
-f docker/Dockerfile.base \
|
||||
-t hub.peikarband.ir/peikarband/landing:base \
|
||||
-t hub.peikarband.ir/peikarband/landing:base-python3.11-node20 \
|
||||
--build-arg PYTHON_VERSION=3.11 \
|
||||
--build-arg NODE_VERSION=20 \
|
||||
--platform linux/amd64 \
|
||||
--load \
|
||||
.
|
||||
@echo ""
|
||||
@echo "✅ Base image built: hub.peikarband.ir/peikarband/landing:base"
|
||||
@echo ""
|
||||
|
||||
docker-push-base:
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " 📤 Pushing Base Image"
|
||||
@echo "════════════════════════════════════════"
|
||||
docker push hub.peikarband.ir/peikarband/landing:base
|
||||
docker push hub.peikarband.ir/peikarband/landing:base-python3.11-node20
|
||||
@echo ""
|
||||
@echo "✅ Base image pushed successfully!"
|
||||
@echo ""
|
||||
|
||||
docker-build:
|
||||
DOCKER_BUILDKIT=$(DOCKER_BUILDKIT) docker build \
|
||||
-t $(IMAGE_NAME):$(VERSION) \
|
||||
-t $(IMAGE_NAME):latest \
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " 🔨 Building Application Image"
|
||||
@echo "════════════════════════════════════════"
|
||||
DOCKER_BUILDKIT=$(DOCKER_BUILDKIT) docker buildx build \
|
||||
-f docker/Dockerfile \
|
||||
-t hub.peikarband.ir/peikarband/landing:$(VERSION) \
|
||||
-t hub.peikarband.ir/peikarband/landing:latest \
|
||||
--build-arg BASE_IMAGE=hub.peikarband.ir/peikarband/landing:base \
|
||||
--build-arg VERSION=$(VERSION) \
|
||||
--build-arg BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
|
||||
--platform linux/amd64 \
|
||||
--load \
|
||||
.
|
||||
@echo ""
|
||||
@echo "✅ Application image built: hub.peikarband.ir/peikarband/landing:$(VERSION)"
|
||||
@echo ""
|
||||
|
||||
docker-push:
|
||||
docker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
|
||||
docker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)/$(IMAGE_NAME):latest
|
||||
docker push $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
|
||||
docker push $(REGISTRY)/$(IMAGE_NAME):latest
|
||||
@echo "════════════════════════════════════════"
|
||||
@echo " 📤 Pushing Application Image"
|
||||
@echo "════════════════════════════════════════"
|
||||
docker push hub.peikarband.ir/peikarband/landing:$(VERSION)
|
||||
docker push hub.peikarband.ir/peikarband/landing:latest
|
||||
@echo ""
|
||||
@echo "✅ Application image pushed successfully!"
|
||||
@echo ""
|
||||
|
||||
docker-login:
|
||||
@echo "Logging in to Harbor registry..."
|
||||
@docker login $(REGISTRY)
|
||||
@docker login hub.peikarband.ir
|
||||
|
||||
docker-up:
|
||||
docker-compose up -d
|
||||
docker-compose -f docker/docker-compose.yml up -d
|
||||
|
||||
docker-down:
|
||||
docker-compose down
|
||||
docker-compose -f docker/docker-compose.yml down
|
||||
|
||||
# Helm commands
|
||||
helm-lint:
|
||||
@@ -135,8 +201,8 @@ k8s-deploy: docker-build docker-push helm-upgrade
|
||||
|
||||
# Database
|
||||
migrate:
|
||||
alembic upgrade head
|
||||
cd peikarband && alembic -c config/alembic.ini upgrade head
|
||||
|
||||
seed:
|
||||
python3 scripts/seed_database.py
|
||||
cd peikarband && python3 tools/scripts/seed_database.py
|
||||
|
||||
|
||||
240
README.md
@@ -1,217 +1,43 @@
|
||||
# پیکربند - پلتفرم جامع مدیریت هاستینگ و زیرساخت ابری
|
||||
# Peikarband Landing Platform
|
||||
|
||||
## 📖 درباره پروژه
|
||||
یک پلتفرم حرفهای برای مدیریت هاستینگ، سرورهای ابری و خدمات DevOps.
|
||||
|
||||
پیکربند یک پلتفرم حرفهای برای مدیریت هاستینگ، سرورهای ابری، دامین و خدمات DevOps است. این پلتفرم با الهام از سرویسهایی مانند Cloudways، DigitalOcean و پارس پک طراحی شده است.
|
||||
## ساختار پروژه
|
||||
|
||||
## 🏗️ معماری
|
||||
|
||||
این پروژه بر اساس **Clean Architecture** و اصول **SOLID** طراحی شده است:
|
||||
|
||||
- **Domain Layer**: منطق کسبوکار اصلی
|
||||
- **Application Layer**: موارد استفاده (Use Cases)
|
||||
- **Infrastructure Layer**: پیادهسازیهای فنی
|
||||
- **Presentation Layer**: رابط کاربری (Reflex)
|
||||
|
||||
## 🚀 تکنولوژیها
|
||||
|
||||
- **Frontend/Backend**: Python Reflex
|
||||
- **Database**: PostgreSQL + SQLAlchemy
|
||||
- **Cache**: Redis
|
||||
- **Task Queue**: Celery
|
||||
- **Testing**: pytest
|
||||
- **Code Quality**: black, flake8, mypy, isort
|
||||
|
||||
## 📋 پیشنیازها
|
||||
|
||||
- Python 3.11+
|
||||
- PostgreSQL 14+
|
||||
- Redis 7+
|
||||
- Node.js 18+ (برای Reflex)
|
||||
|
||||
## 🛠️ نصب و راهاندازی
|
||||
|
||||
### 1. کلون کردن پروژه
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/peikarband.git
|
||||
cd peikarband
|
||||
```
|
||||
landing/
|
||||
├── Makefile # Build و deployment commands
|
||||
├── .gitignore
|
||||
├── .woodpecker.yml # CI/CD pipeline
|
||||
│
|
||||
├── helm/ # Kubernetes deployment
|
||||
│ └── peikarband/
|
||||
│
|
||||
├── docker/ # Docker build configs
|
||||
│ ├── Dockerfile
|
||||
│ └── docker-compose.yml
|
||||
│
|
||||
└── peikarband/ # Source code و مستندات
|
||||
├── README.md # مستندات کامل
|
||||
├── src/ # Application code
|
||||
├── tests/ # Tests
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 2. ایجاد محیط مجازی
|
||||
## دستورات سریع
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
```
|
||||
|
||||
### 3. نصب وابستگیها
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-dev.txt # برای توسعه
|
||||
```
|
||||
|
||||
### 4. تنظیم Environment Variables
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# ویرایش .env و تکمیل مقادیر
|
||||
```
|
||||
|
||||
### 5. راهاندازی دیتابیس
|
||||
|
||||
```bash
|
||||
# ایجاد دیتابیس
|
||||
createdb peikarband
|
||||
|
||||
# اجرای migrations
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
### 6. اجرای پروژه
|
||||
|
||||
```bash
|
||||
# توسعه
|
||||
python -m reflex run
|
||||
|
||||
# یا
|
||||
# Development
|
||||
make dev
|
||||
|
||||
# Docker build
|
||||
make docker-build
|
||||
|
||||
# Helm deploy
|
||||
make helm-upgrade
|
||||
|
||||
# برای اطلاعات بیشتر
|
||||
cd peikarband/
|
||||
cat README.md
|
||||
```
|
||||
|
||||
## 🚢 Deployment
|
||||
|
||||
### با Docker
|
||||
|
||||
```bash
|
||||
# Build
|
||||
docker build -t peikarband:latest .
|
||||
|
||||
# Run
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### با Kubernetes/Helm
|
||||
|
||||
```bash
|
||||
# Deploy
|
||||
helm upgrade --install peikarband ./helm/peikarband \
|
||||
--namespace production \
|
||||
--set image.tag=0.1.0
|
||||
|
||||
# یا
|
||||
make k8s-deploy
|
||||
```
|
||||
|
||||
📖 [راهنمای کامل Deployment](docs/deployment/kubernetes.md)
|
||||
|
||||
## 📁 ساختار پروژه
|
||||
|
||||
```
|
||||
peikarband/
|
||||
├── docs/ # مستندات
|
||||
├── src/
|
||||
│ ├── config/ # تنظیمات
|
||||
│ ├── core/ # هسته اصلی
|
||||
│ │ ├── domain/ # Domain entities & logic
|
||||
│ │ └── application/ # Use cases & DTOs
|
||||
│ ├── infrastructure/ # پیادهسازیهای فنی
|
||||
│ ├── presentation/ # رابط کاربری
|
||||
│ └── shared/ # کدهای مشترک
|
||||
├── tests/ # تستها
|
||||
└── scripts/ # اسکریپتهای کمکی
|
||||
```
|
||||
|
||||
## 🧪 تست
|
||||
|
||||
```bash
|
||||
# اجرای همه تستها
|
||||
pytest
|
||||
|
||||
# با coverage
|
||||
pytest --cov=src tests/
|
||||
|
||||
# تستهای خاص
|
||||
pytest tests/unit/
|
||||
pytest tests/integration/
|
||||
```
|
||||
|
||||
## 📝 کدنویسی
|
||||
|
||||
### استانداردها
|
||||
|
||||
- **PEP 8**: استاندارد کدنویسی Python
|
||||
- **PEP 20**: Zen of Python
|
||||
- **Type Hints**: همه جا استفاده شود
|
||||
- **Docstrings**: Google Style
|
||||
|
||||
### ابزارهای کیفیت کد
|
||||
|
||||
```bash
|
||||
# Format
|
||||
black src/
|
||||
|
||||
# Linting
|
||||
flake8 src/
|
||||
|
||||
# Type checking
|
||||
mypy src/
|
||||
|
||||
# Import sorting
|
||||
isort src/
|
||||
```
|
||||
|
||||
### Pre-commit Hooks
|
||||
|
||||
```bash
|
||||
pre-commit install
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
## 📚 مستندات
|
||||
|
||||
مستندات کامل در پوشه `docs/` موجود است:
|
||||
|
||||
- [Handbook](docs/handbook.md): راهنمای جامع پروژه
|
||||
- [Architecture](docs/architecture/): معماری سیستم
|
||||
- [Development](docs/development/): راهنمای توسعه
|
||||
- [API Reference](docs/api/): مستندات API
|
||||
|
||||
## 🔐 امنیت
|
||||
|
||||
- همه پسوردها با bcrypt hash میشوند
|
||||
- استفاده از JWT برای authentication
|
||||
- پشتیبانی از 2FA
|
||||
- اطلاعات حساس رمزنگاری میشوند
|
||||
|
||||
## 🤝 مشارکت
|
||||
|
||||
برای مشارکت در پروژه:
|
||||
|
||||
1. Fork کنید
|
||||
2. Branch جدید بسازید (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit کنید (`git commit -m 'feat: add amazing feature'`)
|
||||
4. Push کنید (`git push origin feature/amazing-feature`)
|
||||
5. Pull Request بسازید
|
||||
|
||||
## 📄 لایسنس
|
||||
|
||||
این پروژه تحت لایسنس MIT منتشر شده است.
|
||||
|
||||
## 👥 تیم
|
||||
|
||||
- Lead Developer: [Your Name]
|
||||
- Architecture: Clean Architecture
|
||||
- Methodology: Agile/Scrum
|
||||
|
||||
## 📞 تماس
|
||||
|
||||
- Website: https://peikarband.ir
|
||||
- Email: support@peikarband.ir
|
||||
- Telegram: @peikarband
|
||||
|
||||
---
|
||||
|
||||
**نسخه**: 0.1.0
|
||||
**آخرین بروزرسانی**: 2025-01-24
|
||||
|
||||
|
||||
154
argocd/README.md
@@ -1,154 +0,0 @@
|
||||
# ArgoCD Deployment
|
||||
|
||||
This directory contains ArgoCD Application manifests for deploying Peikarband to Kubernetes.
|
||||
|
||||
## Files
|
||||
|
||||
- `application.yaml`: Production deployment (main branch → peikarband namespace)
|
||||
- `application-staging.yaml`: Staging deployment (develop branch → peikarband-staging namespace)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. ArgoCD installed in your cluster
|
||||
2. Git repository access configured in ArgoCD
|
||||
3. Docker registry credentials (if using private registry)
|
||||
|
||||
## Deployment
|
||||
|
||||
### 1. Add Git Repository to ArgoCD
|
||||
|
||||
```bash
|
||||
# For HTTPS with token
|
||||
argocd repo add https://git.peikarband.ir/ehsan-minadd/peikarband.git \
|
||||
--username YOUR_USERNAME \
|
||||
--password YOUR_ACCESS_TOKEN
|
||||
|
||||
# Or using argocd UI: Settings → Repositories → Connect Repo
|
||||
```
|
||||
|
||||
### 2. Deploy Production
|
||||
|
||||
```bash
|
||||
kubectl apply -f argocd/application.yaml
|
||||
```
|
||||
|
||||
### 3. Deploy Staging
|
||||
|
||||
```bash
|
||||
kubectl apply -f argocd/application-staging.yaml
|
||||
```
|
||||
|
||||
## Sync Policy
|
||||
|
||||
Both applications use **automatic sync** with:
|
||||
- **Auto-prune**: Remove resources deleted from Git
|
||||
- **Self-heal**: Automatically sync when cluster state differs from Git
|
||||
- **Retry logic**: 5 attempts with exponential backoff
|
||||
|
||||
## Monitoring
|
||||
|
||||
```bash
|
||||
# Check application status
|
||||
argocd app get peikarband
|
||||
argocd app get peikarband-staging
|
||||
|
||||
# Watch sync progress
|
||||
argocd app sync peikarband --watch
|
||||
|
||||
# View logs
|
||||
argocd app logs peikarband
|
||||
```
|
||||
|
||||
## Manual Sync
|
||||
|
||||
```bash
|
||||
# Force sync
|
||||
argocd app sync peikarband --force
|
||||
|
||||
# Sync with prune
|
||||
argocd app sync peikarband --prune
|
||||
```
|
||||
|
||||
## Rollback
|
||||
|
||||
```bash
|
||||
# List history
|
||||
argocd app history peikarband
|
||||
|
||||
# Rollback to specific revision
|
||||
argocd app rollback peikarband <REVISION>
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ ArgoCD │
|
||||
│ ┌───────────────────┐ ┌──────────────────┐ │
|
||||
│ │ Production App │ │ Staging App │ │
|
||||
│ │ (main branch) │ │ (develop branch) │ │
|
||||
│ └─────────┬─────────┘ └────────┬─────────┘ │
|
||||
└────────────┼─────────────────────┼──────────────┘
|
||||
│ │
|
||||
▼ ▼
|
||||
┌────────────────┐ ┌─────────────────┐
|
||||
│ namespace: │ │ namespace: │
|
||||
│ peikarband │ │ peikarband-stg │
|
||||
└────────────────┘ └─────────────────┘
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Override via Helm values:
|
||||
|
||||
```yaml
|
||||
# In values-production.yaml or values-staging.yaml
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
value: "postgresql://..."
|
||||
- name: REDIS_URL
|
||||
value: "redis://..."
|
||||
```
|
||||
|
||||
## Secrets Management
|
||||
|
||||
Secrets should be managed outside Git:
|
||||
|
||||
```bash
|
||||
# Using kubectl
|
||||
kubectl create secret generic peikarband-secrets \
|
||||
--from-literal=database-password=xxx \
|
||||
--namespace=peikarband
|
||||
|
||||
# Or using Sealed Secrets, External Secrets Operator, etc.
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Application Out of Sync
|
||||
|
||||
```bash
|
||||
argocd app sync peikarband --force
|
||||
```
|
||||
|
||||
### Image Pull Errors
|
||||
|
||||
Check registry credentials:
|
||||
```bash
|
||||
kubectl get secret regcred -n peikarband -o yaml
|
||||
```
|
||||
|
||||
### Health Check Failing
|
||||
|
||||
View pod logs:
|
||||
```bash
|
||||
kubectl logs -n peikarband -l app=peikarband --tail=100
|
||||
```
|
||||
|
||||
### Helm Values Override Not Working
|
||||
|
||||
Verify values file path in Application manifest:
|
||||
```bash
|
||||
argocd app manifests peikarband | grep valueFiles
|
||||
```
|
||||
|
||||
BIN
banner-3.gif
|
Before Width: | Height: | Size: 1.6 MiB |
43
build-base-image.sh
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/bin/bash
|
||||
# Helper script to build and push base image locally
|
||||
|
||||
set -e
|
||||
|
||||
echo "=== Building Peikarband Base Image ==="
|
||||
echo ""
|
||||
|
||||
# Variables
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
IMAGE="$REGISTRY/peikarband/base"
|
||||
|
||||
# Build
|
||||
echo "1. Building base image..."
|
||||
docker build \
|
||||
-f docker/Dockerfile.base \
|
||||
-t "$IMAGE:latest" \
|
||||
-t "$IMAGE:python3.11-node20" \
|
||||
--build-arg PYTHON_VERSION=3.11 \
|
||||
--build-arg NODE_VERSION=20 \
|
||||
.
|
||||
|
||||
echo ""
|
||||
echo "2. Testing base image..."
|
||||
docker run --rm "$IMAGE:latest" bash -c "python --version && node --version && bun --version"
|
||||
|
||||
echo ""
|
||||
echo "3. Login to Harbor registry..."
|
||||
docker login "$REGISTRY"
|
||||
|
||||
echo ""
|
||||
echo "4. Pushing base image..."
|
||||
docker push "$IMAGE:latest"
|
||||
docker push "$IMAGE:python3.11-node20"
|
||||
|
||||
echo ""
|
||||
echo "=== ✅ Base Image Built and Pushed Successfully! ==="
|
||||
echo ""
|
||||
echo "Base image is now available at:"
|
||||
echo " - $IMAGE:latest"
|
||||
echo " - $IMAGE:python3.11-node20"
|
||||
echo ""
|
||||
echo "You can now run the application pipeline."
|
||||
82
build-base-local.sh
Executable file
@@ -0,0 +1,82 @@
|
||||
#!/bin/bash
|
||||
# Build and push base image locally
|
||||
# Usage: ./build-base-local.sh
|
||||
|
||||
set -e
|
||||
|
||||
echo "════════════════════════════════════════"
|
||||
echo " 🔨 Building Base Image Locally"
|
||||
echo "════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# Configuration
|
||||
REGISTRY="hub.peikarband.ir"
|
||||
REPO="peikarband/base"
|
||||
TAG="latest"
|
||||
PYTHON_VERSION="3.11"
|
||||
NODE_VERSION="20"
|
||||
|
||||
# Full image name
|
||||
IMAGE="${REGISTRY}/${REPO}:${TAG}"
|
||||
|
||||
echo "📦 Image: ${IMAGE}"
|
||||
echo "🐍 Python: ${PYTHON_VERSION}"
|
||||
echo "📦 Node.js: ${NODE_VERSION}"
|
||||
echo ""
|
||||
|
||||
# Check if docker buildx is available
|
||||
if ! docker buildx version &> /dev/null; then
|
||||
echo "❌ docker buildx not found!"
|
||||
echo "Please install Docker Buildx"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Login to registry
|
||||
echo "🔐 Logging in to registry..."
|
||||
echo ""
|
||||
read -p "Harbor Username: " HARBOR_USERNAME
|
||||
read -sp "Harbor Password: " HARBOR_PASSWORD
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "$HARBOR_PASSWORD" | docker login "$REGISTRY" -u "$HARBOR_USERNAME" --password-stdin
|
||||
|
||||
# Create/use buildx builder
|
||||
echo ""
|
||||
echo "🏗️ Setting up builder..."
|
||||
docker buildx create --use --name peikarband-builder 2>/dev/null || docker buildx use peikarband-builder
|
||||
|
||||
# Build and push
|
||||
echo ""
|
||||
echo "🔨 Building base image..."
|
||||
echo "(This will take ~8-10 minutes on first build)"
|
||||
echo ""
|
||||
|
||||
docker buildx build \
|
||||
-f docker/Dockerfile.base \
|
||||
-t "${IMAGE}" \
|
||||
-t "${REGISTRY}/${REPO}:python${PYTHON_VERSION}-node${NODE_VERSION}" \
|
||||
--build-arg PYTHON_VERSION="${PYTHON_VERSION}" \
|
||||
--build-arg NODE_VERSION="${NODE_VERSION}" \
|
||||
--platform linux/amd64 \
|
||||
--push \
|
||||
--progress=plain \
|
||||
.
|
||||
|
||||
echo ""
|
||||
echo "════════════════════════════════════════"
|
||||
echo " ✅ Base Image Built Successfully!"
|
||||
echo "════════════════════════════════════════"
|
||||
echo ""
|
||||
echo "📦 Image: ${IMAGE}"
|
||||
echo ""
|
||||
echo "Tags pushed:"
|
||||
echo " • latest"
|
||||
echo " • python${PYTHON_VERSION}-node${NODE_VERSION}"
|
||||
echo ""
|
||||
echo "Now you can build your app with:"
|
||||
echo " make docker-build"
|
||||
echo ""
|
||||
echo "Or in CI, it will automatically use this base image."
|
||||
echo ""
|
||||
|
||||
153
docker/Dockerfile
Normal file
@@ -0,0 +1,153 @@
|
||||
# Dockerfile - Peikarband Landing Application
|
||||
# Optimized multi-stage build using base image
|
||||
|
||||
# Build arguments
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
ARG VERSION=latest
|
||||
ARG BUILD_DATE
|
||||
|
||||
# ============================================
|
||||
# Stage 1: Builder (using base image)
|
||||
# ============================================
|
||||
FROM ${BASE_IMAGE} AS builder
|
||||
|
||||
LABEL stage=builder
|
||||
LABEL maintainer="Peikarband DevOps <devops@peikarband.ir>"
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Base image already has:
|
||||
# - Python 3.11
|
||||
# - Node.js 20
|
||||
# - bun
|
||||
# - gcc, g++, make, curl, ca-certificates
|
||||
|
||||
# Verify tools are available
|
||||
RUN echo "=== Build Environment ===" && \
|
||||
python --version && \
|
||||
node --version && \
|
||||
npm --version && \
|
||||
bun --version && \
|
||||
echo "========================"
|
||||
|
||||
# ============================================
|
||||
# Python Dependencies
|
||||
# ============================================
|
||||
|
||||
# Copy Python requirements first (for layer caching)
|
||||
COPY peikarband/requirements.txt .
|
||||
|
||||
# Install Python dependencies
|
||||
RUN --mount=type=cache,target=/root/.cache/pip \
|
||||
pip install --no-cache-dir --upgrade pip && \
|
||||
pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# ============================================
|
||||
# Frontend Build (Reflex)
|
||||
# ============================================
|
||||
|
||||
# Copy source code
|
||||
COPY peikarband/ .
|
||||
|
||||
# Initialize Reflex and build frontend
|
||||
RUN reflex init --loglevel debug || true && \
|
||||
reflex export --frontend-only --no-zip --loglevel debug || echo "Export completed with warnings"
|
||||
|
||||
# Build frontend with npm (fallback if reflex export fails)
|
||||
WORKDIR /build/.web
|
||||
|
||||
# Configure npm for better reliability
|
||||
RUN npm config set fetch-retry-mintimeout 20000 && \
|
||||
npm config set fetch-retry-maxtimeout 120000 && \
|
||||
npm config set fetch-retries 5 && \
|
||||
npm config set fetch-timeout 300000
|
||||
|
||||
# Install and build
|
||||
RUN --mount=type=cache,target=/root/.npm \
|
||||
npm ci --prefer-offline --no-audit --loglevel verbose && \
|
||||
npm run build
|
||||
|
||||
# ============================================
|
||||
# Stage 2: Runtime (using base image for Node.js)
|
||||
# ============================================
|
||||
FROM ${BASE_IMAGE} AS runtime
|
||||
|
||||
LABEL org.opencontainers.image.title="Peikarband Landing"
|
||||
LABEL org.opencontainers.image.description="Peikarband hosting platform landing page"
|
||||
LABEL org.opencontainers.image.vendor="Peikarband"
|
||||
LABEL org.opencontainers.image.version="${VERSION}"
|
||||
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
||||
|
||||
# Create non-root user
|
||||
RUN groupadd -r peikarband && \
|
||||
useradd -r -g peikarband -u 1000 -m -s /bin/bash peikarband
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Base image already has everything we need:
|
||||
# - Python 3.11
|
||||
# - Node.js 20
|
||||
# - curl, ca-certificates
|
||||
# - tini (for proper init)
|
||||
# No additional packages needed!
|
||||
|
||||
# Copy Python dependencies from builder
|
||||
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
|
||||
COPY --from=builder /usr/local/bin /usr/local/bin
|
||||
|
||||
# Copy application code
|
||||
COPY --from=builder --chown=peikarband:peikarband /build /app
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p /app/data /app/logs /app/uploaded_files && \
|
||||
chown -R peikarband:peikarband /app
|
||||
|
||||
# Set proper permissions
|
||||
RUN chmod -R 755 /app && \
|
||||
chmod -R 777 /app/data /app/logs /app/uploaded_files
|
||||
|
||||
# Environment variables
|
||||
ENV PYTHONUNBUFFERED=1 \
|
||||
PYTHONDONTWRITEBYTECODE=1 \
|
||||
PYTHONPATH=/app \
|
||||
PATH="/app/.venv/bin:$PATH" \
|
||||
REFLEX_DIR=/app \
|
||||
NODE_ENV=production
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD curl -f http://localhost:${PORT:-3000}/_health || exit 1
|
||||
|
||||
# Switch to non-root user
|
||||
USER peikarband
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3000 8000
|
||||
|
||||
# Use tini as init system
|
||||
ENTRYPOINT ["/usr/bin/tini", "--"]
|
||||
|
||||
# Start application
|
||||
CMD ["reflex", "run", "--env", "prod", "--loglevel", "info"]
|
||||
|
||||
# ============================================
|
||||
# Build Information
|
||||
# ============================================
|
||||
ARG GIT_COMMIT
|
||||
ARG GIT_BRANCH
|
||||
ARG BUILD_NUMBER
|
||||
|
||||
LABEL git.commit="${GIT_COMMIT}"
|
||||
LABEL git.branch="${GIT_BRANCH}"
|
||||
LABEL build.number="${BUILD_NUMBER}"
|
||||
LABEL build.date="${BUILD_DATE}"
|
||||
|
||||
# ============================================
|
||||
# Multi-Architecture Support
|
||||
# ============================================
|
||||
# This Dockerfile supports:
|
||||
# - linux/amd64
|
||||
# - linux/arm64 (with appropriate base image)
|
||||
#
|
||||
# Build with:
|
||||
# docker buildx build --platform linux/amd64,linux/arm64 .
|
||||
71
docker/Dockerfile.base
Normal file
@@ -0,0 +1,71 @@
|
||||
# Peikarband Base Image
|
||||
# Pre-built image with Python, Node.js, bun, and build tools
|
||||
#
|
||||
# Usage:
|
||||
# Build: docker build -f docker/Dockerfile.base -t hub.peikarband.ir/peikarband/base:latest .
|
||||
# Or use Woodpecker: trigger .woodpecker-base.yml pipeline
|
||||
#
|
||||
# This image is built once and reused by all Peikarband projects
|
||||
|
||||
ARG PYTHON_VERSION=3.11
|
||||
ARG NODE_VERSION=20
|
||||
|
||||
FROM python:${PYTHON_VERSION}-slim
|
||||
|
||||
LABEL maintainer="Peikarband Team <dev@peikarband.ir>"
|
||||
LABEL org.opencontainers.image.title="Peikarband Base"
|
||||
LABEL org.opencontainers.image.description="Base image with Python, Node.js, bun, and build tools"
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Install system dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
gcc \
|
||||
g++ \
|
||||
make \
|
||||
curl \
|
||||
gnupg \
|
||||
ca-certificates \
|
||||
unzip \
|
||||
git \
|
||||
tini \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Install Node.js
|
||||
ARG NODE_VERSION
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||
&& apt-get install -y --no-install-recommends nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/* \
|
||||
&& npm config set fetch-retry-mintimeout 20000 \
|
||||
&& npm config set fetch-retry-maxtimeout 120000 \
|
||||
&& npm config set fetch-retries 5 \
|
||||
&& npm config set fetch-timeout 300000 \
|
||||
&& npm config set registry https://registry.npmjs.org/
|
||||
|
||||
# Install bun (required by Reflex for frontend build)
|
||||
# Retry mechanism for network issues
|
||||
RUN set -ex && \
|
||||
for i in 1 2 3 4 5; do \
|
||||
curl -fsSL https://bun.sh/install | bash && break || \
|
||||
(echo "Attempt $i failed, retrying in 5 seconds..." && sleep 5); \
|
||||
done || (echo "Failed to install bun after 5 attempts" && exit 1)
|
||||
|
||||
# Add bun to PATH
|
||||
ENV PATH="/root/.bun/bin:${PATH}"
|
||||
|
||||
# Upgrade pip, setuptools, wheel
|
||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
|
||||
|
||||
# Verify installations
|
||||
RUN python --version && \
|
||||
node --version && \
|
||||
npm --version && \
|
||||
bun --version && \
|
||||
pip --version
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /build
|
||||
|
||||
# Default command
|
||||
CMD ["/bin/bash"]
|
||||
|
||||
81
docker/README.md
Normal file
@@ -0,0 +1,81 @@
|
||||
# Build Directory
|
||||
|
||||
این دایرکتوری شامل همه فایلهای مربوط به **build process** پروژه است.
|
||||
|
||||
## 📁 ساختار
|
||||
|
||||
```
|
||||
build/
|
||||
├── docker/ # Docker configurations
|
||||
│ ├── Dockerfile # Main application Dockerfile
|
||||
│ ├── Dockerfile.base # Base image reference
|
||||
│ ├── docker-compose.yml # Local development
|
||||
│ └── .dockerignore
|
||||
└── ci/ # CI/CD configurations
|
||||
└── woodpecker.yml # Woodpecker CI pipeline
|
||||
```
|
||||
|
||||
## 🐳 Docker
|
||||
|
||||
### Dockerfile
|
||||
Multi-stage Dockerfile برای بهینهسازی حجم image و امنیت:
|
||||
- **Stage 1 (Builder)**: Build و compile
|
||||
- **Stage 2 (Runtime)**: Image نهایی بدون build tools
|
||||
|
||||
**Build:**
|
||||
```bash
|
||||
make docker-build
|
||||
# یا
|
||||
docker build -f build/docker/Dockerfile -t peikarband/landing:latest .
|
||||
```
|
||||
|
||||
### Dockerfile.base
|
||||
فایل مرجع برای base image که در repo جداگانه build میشود:
|
||||
- Repo: `peikarband/base`
|
||||
- Registry: `hub.peikarband.ir/peikarband/base:latest`
|
||||
|
||||
### docker-compose.yml
|
||||
برای development محلی:
|
||||
```bash
|
||||
make docker-up
|
||||
# یا
|
||||
docker-compose -f build/docker/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
## 🔄 CI/CD
|
||||
|
||||
### woodpecker.yml
|
||||
Woodpecker CI pipeline configuration:
|
||||
- Build Docker image
|
||||
- Push به Harbor registry
|
||||
- Tag with commit SHA
|
||||
- Cache optimization
|
||||
|
||||
**تنظیمات مورد نیاز:**
|
||||
- `HARBOR_USERNAME`: Harbor registry username
|
||||
- `HARBOR_PASSWORD`: Harbor registry password
|
||||
|
||||
## 🎯 Best Practices
|
||||
|
||||
1. **Docker Images**
|
||||
- Multi-stage builds
|
||||
- Minimal runtime dependencies
|
||||
- Non-root user
|
||||
- Health checks
|
||||
|
||||
2. **CI/CD**
|
||||
- Cache layers
|
||||
- Automated testing
|
||||
- Semantic versioning
|
||||
- Registry push on main branch only
|
||||
|
||||
3. **Security**
|
||||
- Scan images for vulnerabilities
|
||||
- Sign images
|
||||
- Use specific versions (no `:latest` in production)
|
||||
|
||||
## 📚 مستندات بیشتر
|
||||
|
||||
- [Deployment Guide](../docs/deployment/kubernetes.md)
|
||||
- [Production Deployment](../docs/deployment/PRODUCTION_DEPLOYMENT.md)
|
||||
|
||||
@@ -35,7 +35,9 @@ services:
|
||||
|
||||
# Peikarband Application
|
||||
app:
|
||||
build: .
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: peikarband-app
|
||||
depends_on:
|
||||
- postgres
|
||||
@@ -57,7 +59,9 @@ services:
|
||||
|
||||
# Celery Worker
|
||||
celery:
|
||||
build: .
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: peikarband-celery
|
||||
command: celery -A src.infrastructure.tasks.celery_app worker -l info
|
||||
depends_on:
|
||||
@@ -74,7 +78,9 @@ services:
|
||||
|
||||
# Flower (Celery Monitoring)
|
||||
flower:
|
||||
build: .
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile
|
||||
container_name: peikarband-flower
|
||||
command: celery -A src.infrastructure.tasks.celery_app flower
|
||||
depends_on:
|
||||
198
docs/BASE_IMAGE.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Base Image Management
|
||||
|
||||
## چرا Base Image؟
|
||||
|
||||
Base image شامل تمام dependencies سنگین است که:
|
||||
- ✅ فقط یک بار build میشود
|
||||
- ✅ هر بار که کد تغییر میکند، دوباره download نمیشود
|
||||
- ✅ Build time را از 8-10 دقیقه به 3-4 دقیقه کاهش میدهد
|
||||
- ✅ قابل استفاده مجدد در چند پروژه
|
||||
|
||||
## محتویات Base Image
|
||||
|
||||
Base image شامل موارد زیر است:
|
||||
|
||||
```dockerfile
|
||||
FROM python:3.11-slim
|
||||
|
||||
# Build Tools
|
||||
- gcc, g++, make
|
||||
- curl, ca-certificates
|
||||
- git, unzip
|
||||
|
||||
# Runtime
|
||||
- Python 3.11
|
||||
- Node.js 20.x
|
||||
- npm (latest)
|
||||
- bun (latest)
|
||||
```
|
||||
|
||||
## ساخت Base Image
|
||||
|
||||
### روش 1: Local (توصیه میشود برای اولین بار)
|
||||
|
||||
```bash
|
||||
# Run the helper script
|
||||
./build-base-local.sh
|
||||
```
|
||||
|
||||
این script:
|
||||
1. از شما username/password Harbor میخواهد
|
||||
2. به registry login میکند
|
||||
3. Base image را build میکند
|
||||
4. به Harbor push میکند
|
||||
|
||||
**زمان:** ~8-10 دقیقه (اولین بار)
|
||||
|
||||
### روش 2: در Woodpecker CI
|
||||
|
||||
```bash
|
||||
# Trigger pipeline manually in Woodpecker UI
|
||||
# یا از طریق git:
|
||||
git commit --allow-empty -m "build: rebuild base image"
|
||||
git push
|
||||
```
|
||||
|
||||
Base image فقط در این حالتها rebuild میشود:
|
||||
- `docker/Dockerfile.base` تغییر کرد
|
||||
- `.woodpecker.yml` تغییر کرد
|
||||
- Manual trigger
|
||||
|
||||
## استفاده از Base Image
|
||||
|
||||
Dockerfile به صورت خودکار از base image استفاده میکند:
|
||||
|
||||
```dockerfile
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
FROM ${BASE_IMAGE} AS builder
|
||||
```
|
||||
|
||||
## مدیریت Versions
|
||||
|
||||
### Tags:
|
||||
|
||||
1. **`latest`**: آخرین نسخه (default)
|
||||
2. **`python3.11-node20`**: نسخه specific
|
||||
|
||||
### تغییر Version:
|
||||
|
||||
اگر میخواهید Python یا Node.js version تغییر کند:
|
||||
|
||||
1. Edit `docker/Dockerfile.base`:
|
||||
```dockerfile
|
||||
ARG PYTHON_VERSION=3.12 # تغییر
|
||||
ARG NODE_VERSION=22 # تغییر
|
||||
```
|
||||
|
||||
2. Build base image:
|
||||
```bash
|
||||
./build-base-local.sh
|
||||
```
|
||||
|
||||
3. Update app Dockerfile:
|
||||
```dockerfile
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:python3.12-node22
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### مشکل: Base image not found
|
||||
|
||||
```bash
|
||||
# Build locally:
|
||||
./build-base-local.sh
|
||||
|
||||
# یا check if exists:
|
||||
docker pull hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
### مشکل: Build fails in CI
|
||||
|
||||
```bash
|
||||
# Check Woodpecker secrets:
|
||||
- HARBOR_USERNAME
|
||||
- HARBOR_PASSWORD
|
||||
|
||||
# Test locally:
|
||||
docker login hub.peikarband.ir
|
||||
```
|
||||
|
||||
### مشکل: Base image outdated
|
||||
|
||||
```bash
|
||||
# Force rebuild:
|
||||
git commit --allow-empty -m "build: rebuild base image"
|
||||
git push
|
||||
|
||||
# یا locally:
|
||||
./build-base-local.sh
|
||||
```
|
||||
|
||||
## Build Times
|
||||
|
||||
| Scenario | With Base | Without Base |
|
||||
|----------|-----------|--------------|
|
||||
| First build | 10 min | 10 min |
|
||||
| Code change only | 3 min ✅ | 10 min ❌ |
|
||||
| Dependency change | 3 min ✅ | 10 min ❌ |
|
||||
| Base change | 13 min | 10 min |
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Build base image locally اولین بار**
|
||||
```bash
|
||||
./build-base-local.sh
|
||||
```
|
||||
|
||||
2. **فقط وقتی dependencies تغییر کرد rebuild کنید**
|
||||
- Python packages
|
||||
- Node.js version
|
||||
- System tools
|
||||
|
||||
3. **از versioned tags استفاده کنید در production**
|
||||
```dockerfile
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:python3.11-node20
|
||||
```
|
||||
|
||||
4. **Base image را در Harbor نگه دارید**
|
||||
- Private registry
|
||||
- Version control
|
||||
- Team access
|
||||
|
||||
## مثال: Workflow کامل
|
||||
|
||||
```bash
|
||||
# 1. Clone project
|
||||
git clone <repo>
|
||||
cd peikarband
|
||||
|
||||
# 2. Build base image (فقط یک بار)
|
||||
./build-base-local.sh
|
||||
# ⏱️ ~8-10 دقیقه
|
||||
|
||||
# 3. Build app (بعدها)
|
||||
make docker-build
|
||||
# ⏱️ ~3 دقیقه ✅
|
||||
|
||||
# 4. تغییر کد
|
||||
vim peikarband/src/...
|
||||
|
||||
# 5. Build again (سریع!)
|
||||
make docker-build
|
||||
# ⏱️ ~3 دقیقه ✅ (dependencies از cache)
|
||||
```
|
||||
|
||||
## خلاصه
|
||||
|
||||
✅ **مزایا:**
|
||||
- Build سریعتر (3 دقیقه vs 10 دقیقه)
|
||||
- بهینهسازی cache
|
||||
- قابل استفاده مجدد
|
||||
|
||||
❌ **نیاز به:**
|
||||
- Build اولیه (یک بار، 10 دقیقه)
|
||||
- نگهداری در registry
|
||||
- Rebuild وقتی dependencies تغییر کند
|
||||
|
||||
**نتیجه:** برای development و production **بسیار** مفید است! 🚀
|
||||
|
||||
409
docs/BASE_IMAGE_MANAGEMENT.md
Normal file
@@ -0,0 +1,409 @@
|
||||
# مدیریت Base Image
|
||||
|
||||
این مستند راهنمای کامل برای مدیریت و استفاده از base image در پروژه Peikarband است.
|
||||
|
||||
## نمای کلی
|
||||
|
||||
**Base Image چیست؟**
|
||||
|
||||
Base image یک Docker image از پیش ساخته شده است که شامل تمام ابزارهای مورد نیاز برای build اپلیکیشن است:
|
||||
- Python 3.11
|
||||
- Node.js 20
|
||||
- Bun (برای Reflex frontend)
|
||||
- Build tools (gcc, g++, make)
|
||||
- Git و curl
|
||||
|
||||
**چرا Base Image؟**
|
||||
|
||||
✅ **سرعت Build:** 8-10 دقیقه → 2-3 دقیقه
|
||||
✅ **قابلیت اطمینان:** بدون نیاز به دانلود مکرر npm/bun
|
||||
✅ **Consistency:** همه builds از همان environment استفاده میکنند
|
||||
✅ **Network Resilience:** مشکلات network کمتر
|
||||
|
||||
## ساختار فایلها
|
||||
|
||||
```
|
||||
.
|
||||
├── docker/
|
||||
│ ├── Dockerfile # استفاده از base image
|
||||
│ └── Dockerfile.base # تعریف base image
|
||||
├── .woodpecker.yml # Build اپلیکیشن (از base استفاده میکند)
|
||||
└── .woodpecker-base.yml # Build base image (manual/on-change)
|
||||
```
|
||||
|
||||
## Base Image Tags
|
||||
|
||||
```
|
||||
hub.peikarband.ir/peikarband/base:latest # آخرین version
|
||||
hub.peikarband.ir/peikarband/base:python3.11-node20 # Version specific
|
||||
hub.peikarband.ir/peikarband/base:python3.11-node20-a1b2c3d4 # With commit SHA
|
||||
```
|
||||
|
||||
## چگونه Base Image را Build کنیم؟
|
||||
|
||||
### روش 1: Manual Trigger در Woodpecker (پیشنهادی)
|
||||
|
||||
1. رفتن به Woodpecker UI
|
||||
2. انتخاب repository: `peikarband/landing`
|
||||
3. کلیک روی "Pipelines"
|
||||
4. کلیک روی "New Pipeline"
|
||||
5. انتخاب pipeline: `.woodpecker-base.yml`
|
||||
6. کلیک روی "Start"
|
||||
|
||||
### روش 2: Push تغییرات Dockerfile.base
|
||||
|
||||
هر بار که `docker/Dockerfile.base` تغییر کند، pipeline بهطور خودکار trigger میشود:
|
||||
|
||||
```bash
|
||||
# تغییر Dockerfile.base
|
||||
vim docker/Dockerfile.base
|
||||
|
||||
# Commit و push
|
||||
git add docker/Dockerfile.base
|
||||
git commit -m "chore: update base image to Node.js 21"
|
||||
git push origin main
|
||||
|
||||
# Pipeline بهطور خودکار اجرا میشود
|
||||
```
|
||||
|
||||
### روش 3: Local Build (برای تست)
|
||||
|
||||
```bash
|
||||
# Build locally
|
||||
docker build -f docker/Dockerfile.base \
|
||||
-t hub.peikarband.ir/peikarband/base:latest \
|
||||
--build-arg PYTHON_VERSION=3.11 \
|
||||
--build-arg NODE_VERSION=20 \
|
||||
.
|
||||
|
||||
# Test locally
|
||||
docker run --rm hub.peikarband.ir/peikarband/base:latest \
|
||||
bash -c "python --version && node --version && bun --version"
|
||||
|
||||
# Push to registry
|
||||
docker login hub.peikarband.ir
|
||||
docker push hub.peikarband.ir/peikarband/base:latest
|
||||
docker push hub.peikarband.ir/peikarband/base:python3.11-node20
|
||||
```
|
||||
|
||||
## چگونه Application از Base Image استفاده میکند؟
|
||||
|
||||
Pipeline اصلی (`.woodpecker.yml`) بهطور خودکار از base image استفاده میکند:
|
||||
|
||||
### مرحله 1: Check Base Image
|
||||
|
||||
```yaml
|
||||
check-base-image:
|
||||
# بررسی میکند که base image در registry موجود است
|
||||
# اگر نباشد، error میدهد و راهنمایی میکند
|
||||
```
|
||||
|
||||
### مرحله 2: Build Application
|
||||
|
||||
```yaml
|
||||
build-image:
|
||||
build_args:
|
||||
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
push: false # فقط build، بدون push
|
||||
```
|
||||
|
||||
### مرحله 3: Push Application
|
||||
|
||||
```yaml
|
||||
push-image:
|
||||
tags:
|
||||
- latest
|
||||
- ${CI_COMMIT_SHA:0:8}
|
||||
- ${CI_COMMIT_BRANCH}
|
||||
push: true # حالا push میکنیم
|
||||
```
|
||||
|
||||
### مرحله 4: Verify
|
||||
|
||||
```yaml
|
||||
verify-push:
|
||||
# تایید میکند که image با موفقیت push شده
|
||||
```
|
||||
|
||||
## چه زمانی باید Base Image را Rebuild کنیم؟
|
||||
|
||||
### Rebuild ضروری است:
|
||||
|
||||
1. **تغییر Python version:**
|
||||
```bash
|
||||
# در Dockerfile.base
|
||||
ARG PYTHON_VERSION=3.12 # تغییر از 3.11
|
||||
```
|
||||
|
||||
2. **تغییر Node.js version:**
|
||||
```bash
|
||||
# در Dockerfile.base
|
||||
ARG NODE_VERSION=21 # تغییر از 20
|
||||
```
|
||||
|
||||
3. **اضافه کردن system dependencies:**
|
||||
```dockerfile
|
||||
RUN apt-get install -y \
|
||||
gcc g++ make \
|
||||
postgresql-dev # جدید
|
||||
```
|
||||
|
||||
4. **تغییر bun installation:**
|
||||
```dockerfile
|
||||
# اگر روش نصب bun تغییر کند
|
||||
```
|
||||
|
||||
### Rebuild اختیاری است:
|
||||
|
||||
1. **تغییرات جزئی در Dockerfile اصلی**
|
||||
2. **تغییر کد اپلیکیشن**
|
||||
3. **تغییر Helm charts**
|
||||
|
||||
## مدیریت Versions
|
||||
|
||||
### Strategy ما:
|
||||
|
||||
```
|
||||
latest → همیشه آخرین version
|
||||
python3.11-node20 → Version مشخص (stable)
|
||||
python3.11-node20-a1b2c3d4 → با commit SHA (rollback)
|
||||
```
|
||||
|
||||
### مثال: Update به Python 3.12
|
||||
|
||||
```bash
|
||||
# 1. تغییر Dockerfile.base
|
||||
vim docker/Dockerfile.base
|
||||
# ARG PYTHON_VERSION=3.12
|
||||
|
||||
# 2. Commit
|
||||
git add docker/Dockerfile.base
|
||||
git commit -m "chore: upgrade base image to Python 3.12"
|
||||
git push origin main
|
||||
|
||||
# 3. Wait for .woodpecker-base.yml to complete
|
||||
|
||||
# 4. تغییر تگ در application Dockerfile (اختیاری)
|
||||
vim docker/Dockerfile
|
||||
# ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:python3.12-node20
|
||||
|
||||
# 5. Test application build
|
||||
git add docker/Dockerfile
|
||||
git commit -m "chore: use Python 3.12 base image"
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### خطا: "Base image not found"
|
||||
|
||||
**علت:** Base image هنوز build نشده یا در registry موجود نیست
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
# 1. بررسی کنید که base image در registry موجود است
|
||||
curl -u "admin:password" \
|
||||
https://hub.peikarband.ir/v2/peikarband/base/tags/list
|
||||
|
||||
# 2. اگر موجود نیست، pipeline base را اجرا کنید
|
||||
# Manual trigger در Woodpecker UI → .woodpecker-base.yml
|
||||
|
||||
# 3. یا local build:
|
||||
docker build -f docker/Dockerfile.base -t hub.peikarband.ir/peikarband/base:latest .
|
||||
docker push hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
### خطا: "Failed to pull base image"
|
||||
|
||||
**علت:** Registry authentication مشکل دارد
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
# 1. بررسی credentials در Woodpecker secrets
|
||||
# Repository → Settings → Secrets → HARBOR_USERNAME, HARBOR_PASSWORD
|
||||
|
||||
# 2. Test login locally
|
||||
docker login hub.peikarband.ir
|
||||
Username: admin
|
||||
Password: [your-password]
|
||||
|
||||
# 3. Test pull
|
||||
docker pull hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
### Base Image خیلی بزرگ است
|
||||
|
||||
**بررسی اندازه:**
|
||||
|
||||
```bash
|
||||
# Check image size
|
||||
docker images hub.peikarband.ir/peikarband/base
|
||||
```
|
||||
|
||||
**Optimization:**
|
||||
|
||||
```dockerfile
|
||||
# در Dockerfile.base
|
||||
|
||||
# 1. حذف apt cache
|
||||
RUN apt-get update && apt-get install -y ... \
|
||||
&& rm -rf /var/lib/apt/lists/* # این خط مهم است
|
||||
|
||||
# 2. حذف npm cache
|
||||
RUN npm cache clean --force
|
||||
|
||||
# 3. استفاده از slim image
|
||||
FROM python:3.11-slim # نه python:3.11
|
||||
```
|
||||
|
||||
### Build Time هنوز کند است
|
||||
|
||||
**بررسی:**
|
||||
|
||||
```bash
|
||||
# 1. آیا واقعاً از base image استفاده میشود؟
|
||||
docker history hub.peikarband.ir/peikarband/landing:latest | grep base
|
||||
|
||||
# 2. آیا cache درست کار میکند؟
|
||||
# در .woodpecker.yml:
|
||||
cache_from: type=registry,ref=...
|
||||
```
|
||||
|
||||
**بهبود:**
|
||||
|
||||
```yaml
|
||||
# در .woodpecker.yml
|
||||
build-image:
|
||||
settings:
|
||||
# Pull base image first for caching
|
||||
pull: true
|
||||
cache_from:
|
||||
- type=registry,ref=hub.peikarband.ir/peikarband/base:latest
|
||||
- type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Version Pinning
|
||||
|
||||
❌ **بد:**
|
||||
```dockerfile
|
||||
FROM hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
✅ **خوب (برای production):**
|
||||
```dockerfile
|
||||
FROM hub.peikarband.ir/peikarband/base:python3.11-node20
|
||||
```
|
||||
|
||||
### 2. Testing Base Changes
|
||||
|
||||
قبل از اینکه base image جدید را در production استفاده کنید:
|
||||
|
||||
```bash
|
||||
# 1. Build base با tag test
|
||||
docker build -f docker/Dockerfile.base \
|
||||
-t hub.peikarband.ir/peikarband/base:test .
|
||||
|
||||
# 2. Test application با این base
|
||||
docker build --build-arg BASE_IMAGE=hub.peikarband.ir/peikarband/base:test \
|
||||
-f docker/Dockerfile .
|
||||
|
||||
# 3. اگر موفق بود، tag را به latest تغییر دهید
|
||||
docker tag hub.peikarband.ir/peikarband/base:test \
|
||||
hub.peikarband.ir/peikarband/base:latest
|
||||
docker push hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
### 3. Documentation
|
||||
|
||||
هر بار که base image را تغییر میدهید، در CHANGELOG.md یادداشت کنید:
|
||||
|
||||
```markdown
|
||||
## [Base Image] 2024-12-30
|
||||
|
||||
### Changed
|
||||
- Upgraded Python from 3.11 to 3.12
|
||||
- Updated Node.js from 20 to 21
|
||||
- Added postgresql-dev for database support
|
||||
|
||||
### Impact
|
||||
- All future builds will use new base
|
||||
- Rebuild takes ~10 minutes
|
||||
- Application builds will be ~30% faster
|
||||
```
|
||||
|
||||
### 4. Cleanup Old Images
|
||||
|
||||
```bash
|
||||
# List all base images
|
||||
curl -u "admin:password" \
|
||||
https://hub.peikarband.ir/v2/peikarband/base/tags/list | jq
|
||||
|
||||
# حذف تگهای قدیمی (از Harbor UI)
|
||||
# Repository → peikarband/base → Tags → Select → Delete
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
### چگونه بفهمیم base image استفاده میشود؟
|
||||
|
||||
```bash
|
||||
# 1. از Docker history
|
||||
docker history hub.peikarband.ir/peikarband/landing:latest
|
||||
|
||||
# 2. از image labels
|
||||
docker inspect hub.peikarband.ir/peikarband/landing:latest | \
|
||||
jq '.[0].Config.Labels'
|
||||
|
||||
# 3. از build logs در Woodpecker
|
||||
# Stage "check-base-image" باید "✓ Base image found" نمایش دهد
|
||||
```
|
||||
|
||||
### Metrics مفید:
|
||||
|
||||
```bash
|
||||
# Build time comparison
|
||||
# Before base image: 8-10 min
|
||||
# After base image: 2-3 min
|
||||
# Improvement: 60-70%
|
||||
|
||||
# Network usage
|
||||
# Before: ~500 MB download per build (npm, bun, etc.)
|
||||
# After: ~50 MB (only base image pull if not cached)
|
||||
# Improvement: 90%
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
**Q: چند وقت یکبار باید base را rebuild کنیم؟**
|
||||
A: فقط وقتی که dependencies (Python, Node.js, bun) تغییر میکنند. معمولاً هر 2-3 ماه یکبار.
|
||||
|
||||
**Q: آیا میتوانیم چند base image داشته باشیم؟**
|
||||
A: بله! مثلاً:
|
||||
- `base:python3.11-node20` → برای پروژههای قدیمی
|
||||
- `base:python3.12-node21` → برای پروژههای جدید
|
||||
|
||||
**Q: اگر base image corrupt شود چه کنیم؟**
|
||||
A: Application Dockerfile میتواند به `python:3.11-slim` fallback کند:
|
||||
```dockerfile
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||
FROM ${BASE_IMAGE:-python:3.11-slim} AS builder
|
||||
```
|
||||
|
||||
**Q: چگونه base را به پروژههای دیگر منتقل کنیم؟**
|
||||
A: Base image در registry مرکزی است، تمام پروژهها میتوانند از آن استفاده کنند:
|
||||
```dockerfile
|
||||
# در هر پروژه دیگر
|
||||
FROM hub.peikarband.ir/peikarband/base:latest
|
||||
```
|
||||
|
||||
## مراجع
|
||||
|
||||
- [Multi-stage Docker Builds](https://docs.docker.com/build/building/multi-stage/)
|
||||
- [Docker Build Cache](https://docs.docker.com/build/cache/)
|
||||
- [Harbor Registry Management](https://goharbor.io/docs/latest/)
|
||||
- [Woodpecker CI Documentation](https://woodpecker-ci.org/docs/)
|
||||
|
||||
94
docs/REPOSITORY_STRATEGY.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# Repository Strategy
|
||||
|
||||
## استراتژی فعلی: Single Repository ✅
|
||||
|
||||
همه چیز در یک repository: `peikarband/landing`
|
||||
|
||||
### مزایا:
|
||||
- ساده و قابل مدیریت
|
||||
- همه چیز در یک جا
|
||||
- مناسب برای یک پروژه
|
||||
|
||||
### ساختار:
|
||||
```
|
||||
peikarband/landing/
|
||||
├── .woodpecker.yml # Application pipeline
|
||||
├── .woodpecker-base.yml # Base image pipeline
|
||||
├── docker/
|
||||
│ ├── Dockerfile # Application
|
||||
│ └── Dockerfile.base # Base image
|
||||
└── ...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## استراتژی آینده: Multi Repository (اختیاری)
|
||||
|
||||
اگر پروژههای بیشتری اضافه شد، میتوانید base را جدا کنید.
|
||||
|
||||
### مراحل جداسازی:
|
||||
|
||||
#### 1. ایجاد Repository جدید
|
||||
|
||||
```bash
|
||||
# Create new repo
|
||||
mkdir peikarband-base-images
|
||||
cd peikarband-base-images
|
||||
git init
|
||||
|
||||
# Structure
|
||||
mkdir -p python311-node20
|
||||
```
|
||||
|
||||
#### 2. انتقال Base Files
|
||||
|
||||
```bash
|
||||
# Copy base files
|
||||
cp ../landing/docker/Dockerfile.base python311-node20/Dockerfile
|
||||
cp ../landing/.woodpecker-base.yml .woodpecker.yml
|
||||
```
|
||||
|
||||
#### 3. Update Application Repository
|
||||
|
||||
در `peikarband/landing`:
|
||||
|
||||
```dockerfile
|
||||
# docker/Dockerfile
|
||||
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:python311-node20
|
||||
FROM ${BASE_IMAGE} AS builder
|
||||
```
|
||||
|
||||
#### 4. Registry Organization
|
||||
|
||||
```
|
||||
Registry Structure:
|
||||
hub.peikarband.ir/
|
||||
├── peikarband/base # Base images repo
|
||||
│ ├── python311-node20:latest
|
||||
│ └── python312-node21:latest
|
||||
└── peikarband/landing # Application
|
||||
└── latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## زمان جداسازی
|
||||
|
||||
**جدا کنید وقتی:**
|
||||
- ✅ 3+ پروژه از همان base استفاده میکنند
|
||||
- ✅ تیم 5+ نفری دارید
|
||||
- ✅ Base versioning پیچیده شد
|
||||
- ✅ نیاز به CI/CD مستقل برای base دارید
|
||||
|
||||
**جدا نکنید وقتی:**
|
||||
- ❌ فقط یک پروژه دارید (فعلی)
|
||||
- ❌ تیم کوچک است (1-3 نفر)
|
||||
- ❌ Base خیلی تغییر نمیکند
|
||||
|
||||
---
|
||||
|
||||
## توصیه
|
||||
|
||||
**الان:** یک repository کافیه! 👍
|
||||
|
||||
**آینده:** اگر پروژه دوم شروع شد، مجدداً ارزیابی کنید.
|
||||
586
docs/WOODPECKER_CI_CD.md
Normal file
@@ -0,0 +1,586 @@
|
||||
# Woodpecker CI/CD Documentation
|
||||
|
||||
این مستند راهنمای کامل برای راهاندازی و استفاده از Woodpecker CI/CD pipeline برای پروژه Peikarband است.
|
||||
|
||||
## نمای کلی Pipeline
|
||||
|
||||
Pipeline ما شامل 8 مرحله اصلی است:
|
||||
|
||||
```
|
||||
1. Code Quality & Linting
|
||||
├── flake8 (Python linting)
|
||||
├── black (Code formatting check)
|
||||
├── isort (Import sorting)
|
||||
└── mypy (Type checking)
|
||||
|
||||
2. Security Scanning
|
||||
├── bandit (Security vulnerability scan)
|
||||
└── safety (Dependency vulnerability check)
|
||||
|
||||
3. Testing
|
||||
└── pytest (Unit & Integration tests with coverage)
|
||||
|
||||
4. Helm Validation
|
||||
├── helm lint
|
||||
└── helm template
|
||||
|
||||
5. Docker Build & Push
|
||||
└── Multi-platform build with caching
|
||||
|
||||
6. Deploy to Staging
|
||||
└── Auto-deploy on main/develop branches
|
||||
|
||||
7. Deploy to Production
|
||||
└── Manual trigger on version tags (v*)
|
||||
|
||||
8. Notifications
|
||||
└── Success/Failure notifications
|
||||
```
|
||||
|
||||
## تنظیمات Secrets
|
||||
|
||||
برای اجرای کامل pipeline، باید secrets زیر را در Woodpecker تنظیم کنید:
|
||||
|
||||
### 1. Registry Secrets (الزامی برای Build)
|
||||
|
||||
```bash
|
||||
HARBOR_USERNAME=admin
|
||||
HARBOR_PASSWORD=your_harbor_password
|
||||
```
|
||||
|
||||
**نحوه تنظیم در Woodpecker UI:**
|
||||
1. رفتن به Repository Settings
|
||||
2. کلیک روی "Secrets"
|
||||
3. اضافه کردن secret جدید:
|
||||
- Name: `HARBOR_USERNAME`
|
||||
- Value: `admin`
|
||||
- Events: `push, tag`
|
||||
4. تکرار برای `HARBOR_PASSWORD`
|
||||
|
||||
### 2. Kubernetes Secrets (الزامی برای Deployment)
|
||||
|
||||
#### Staging Environment
|
||||
|
||||
```bash
|
||||
# Generate base64 encoded kubeconfig
|
||||
cat ~/.kube/config-staging | base64 -w 0 > kubeconfig-staging-base64.txt
|
||||
|
||||
# Add to Woodpecker as secret
|
||||
KUBECONFIG_STAGING=<content_of_kubeconfig-staging-base64.txt>
|
||||
```
|
||||
|
||||
#### Production Environment
|
||||
|
||||
```bash
|
||||
# Generate base64 encoded kubeconfig
|
||||
cat ~/.kube/config-production | base64 -w 0 > kubeconfig-production-base64.txt
|
||||
|
||||
# Add to Woodpecker as secret
|
||||
KUBECONFIG_PRODUCTION=<content_of_kubeconfig-production-base64.txt>
|
||||
```
|
||||
|
||||
**⚠️ نکات امنیتی:**
|
||||
- هرگز kubeconfig را در Git commit نکنید
|
||||
- از RBAC برای محدود کردن دسترسی kubeconfig استفاده کنید
|
||||
- بهطور منظم kubeconfig را rotate کنید
|
||||
- فقط namespace های staging و production دسترسی داشته باشند
|
||||
|
||||
### 3. Optional: ArgoCD Integration
|
||||
|
||||
اگر میخواهید از ArgoCD برای deployment استفاده کنید:
|
||||
|
||||
```bash
|
||||
ARGOCD_SERVER=argocd.peikarband.ir
|
||||
ARGOCD_AUTH_TOKEN=your_argocd_token
|
||||
```
|
||||
|
||||
## Branch Strategy
|
||||
|
||||
Pipeline بر اساس branch و event متفاوت رفتار میکند:
|
||||
|
||||
### Pull Request (PR)
|
||||
|
||||
```yaml
|
||||
Stages: Lint + Test + Security + Helm Lint
|
||||
Skip: Build, Deploy
|
||||
Purpose: Code quality validation
|
||||
```
|
||||
|
||||
**مثال:**
|
||||
|
||||
```bash
|
||||
# Create PR
|
||||
git checkout -b feature/new-feature
|
||||
git push origin feature/new-feature
|
||||
# Open PR in GitLab/GitHub -> Pipeline runs automatically
|
||||
```
|
||||
|
||||
### Main Branch (Push)
|
||||
|
||||
```yaml
|
||||
Stages: All stages
|
||||
Deploy: Staging (automatic)
|
||||
Tags: latest, main-<sha>, <sha>
|
||||
```
|
||||
|
||||
**مثال:**
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git merge feature/new-feature
|
||||
git push origin main
|
||||
# -> Automatic: Test -> Build -> Deploy to Staging
|
||||
```
|
||||
|
||||
### Develop Branch (Push)
|
||||
|
||||
```yaml
|
||||
Stages: All stages
|
||||
Deploy: Staging (automatic)
|
||||
Tags: develop, develop-<sha>, <sha>
|
||||
```
|
||||
|
||||
**مثال:**
|
||||
|
||||
```bash
|
||||
git checkout develop
|
||||
git push origin develop
|
||||
# -> Automatic: Test -> Build -> Deploy to Staging
|
||||
```
|
||||
|
||||
### Version Tags (Production)
|
||||
|
||||
```yaml
|
||||
Stages: All stages
|
||||
Deploy: Production (automatic)
|
||||
Tags: latest, v1.2.3, <sha>
|
||||
```
|
||||
|
||||
**مثال:**
|
||||
|
||||
```bash
|
||||
# Create and push version tag
|
||||
git checkout main
|
||||
git tag -a v1.0.0 -m "Release v1.0.0"
|
||||
git push origin v1.0.0
|
||||
# -> Automatic: Test -> Build -> Deploy to Production
|
||||
```
|
||||
|
||||
## Pipeline Triggers
|
||||
|
||||
### Automatic Triggers
|
||||
|
||||
1. **Push به branch:**
|
||||
```bash
|
||||
git push origin main # Trigger full pipeline + deploy staging
|
||||
git push origin develop # Trigger full pipeline + deploy staging
|
||||
git push origin feature/* # No trigger (manual only)
|
||||
```
|
||||
|
||||
2. **Tag push:**
|
||||
```bash
|
||||
git push origin v1.0.0 # Trigger full pipeline + deploy production
|
||||
```
|
||||
|
||||
3. **Pull Request:**
|
||||
```bash
|
||||
# Any PR -> Triggers lint/test/security only
|
||||
```
|
||||
|
||||
### Manual Triggers
|
||||
|
||||
در Woodpecker UI:
|
||||
1. رفتن به Repository
|
||||
2. کلیک روی "Pipelines"
|
||||
3. کلیک روی "New Pipeline"
|
||||
4. انتخاب branch/commit
|
||||
5. کلیک روی "Start"
|
||||
|
||||
## Docker Image Tagging
|
||||
|
||||
Pipeline بهطور خودکار images را با تگهای مختلف میسازد:
|
||||
|
||||
### Main Branch
|
||||
|
||||
```
|
||||
hub.peikarband.ir/peikarband/landing:latest
|
||||
hub.peikarband.ir/peikarband/landing:main
|
||||
hub.peikarband.ir/peikarband/landing:a1b2c3d4 # commit SHA
|
||||
```
|
||||
|
||||
### Develop Branch
|
||||
|
||||
```
|
||||
hub.peikarband.ir/peikarband/landing:develop
|
||||
hub.peikarband.ir/peikarband/landing:develop-a1b2c3d4
|
||||
hub.peikarband.ir/peikarband/landing:a1b2c3d4
|
||||
```
|
||||
|
||||
### Version Tags
|
||||
|
||||
```
|
||||
hub.peikarband.ir/peikarband/landing:latest
|
||||
hub.peikarband.ir/peikarband/landing:v1.0.0
|
||||
hub.peikarband.ir/peikarband/landing:a1b2c3d4
|
||||
```
|
||||
|
||||
## Deployment Process
|
||||
|
||||
### Staging Deployment
|
||||
|
||||
**Trigger:** هر push به `main` یا `develop`
|
||||
|
||||
**فرایند:**
|
||||
1. Tests pass
|
||||
2. Build Docker image
|
||||
3. Push to registry with tag `<branch>-<sha>`
|
||||
4. Helm upgrade to `staging` namespace
|
||||
5. Wait for rollout (timeout: 5 minutes)
|
||||
6. Show pod status
|
||||
|
||||
**Rollback:**
|
||||
|
||||
```bash
|
||||
# List helm releases
|
||||
helm list -n staging
|
||||
|
||||
# Rollback to previous version
|
||||
helm rollback peikarband-staging -n staging
|
||||
|
||||
# Or rollback to specific revision
|
||||
helm rollback peikarband-staging 5 -n staging
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
|
||||
**Trigger:** Push tag با pattern `v*` (مثل `v1.0.0`)
|
||||
|
||||
**فرایند:**
|
||||
1. Tests pass
|
||||
2. Build Docker image
|
||||
3. Push to registry with tags `latest`, `v1.0.0`, `<sha>`
|
||||
4. Helm upgrade to `production` namespace with production values
|
||||
5. Wait for rollout (timeout: 10 minutes)
|
||||
6. Verify deployment
|
||||
7. Show pod status
|
||||
|
||||
**Rollback:**
|
||||
|
||||
```bash
|
||||
# Check current status
|
||||
kubectl get pods -n production
|
||||
|
||||
# Rollback via Helm
|
||||
helm rollback peikarband -n production
|
||||
|
||||
# Or rollback via kubectl
|
||||
kubectl rollout undo deployment/peikarband -n production
|
||||
|
||||
# Check rollout status
|
||||
kubectl rollout status deployment/peikarband -n production
|
||||
```
|
||||
|
||||
## Monitoring Pipeline
|
||||
|
||||
### Via Woodpecker UI
|
||||
|
||||
1. رفتن به: `https://woodpecker.peikarband.ir` (یا آدرس Woodpecker شما)
|
||||
2. انتخاب repository
|
||||
3. مشاهده لیست pipeline runs
|
||||
4. کلیک روی یک run برای مشاهده جزئیات
|
||||
|
||||
### Via CLI
|
||||
|
||||
```bash
|
||||
# Install Woodpecker CLI
|
||||
curl -L https://github.com/woodpecker-ci/woodpecker/releases/latest/download/woodpecker-cli_linux_amd64.tar.gz | tar xz
|
||||
sudo mv woodpecker-cli /usr/local/bin/
|
||||
|
||||
# Configure
|
||||
export WOODPECKER_SERVER=https://woodpecker.peikarband.ir
|
||||
export WOODPECKER_TOKEN=your_token
|
||||
|
||||
# List pipelines
|
||||
woodpecker pipeline ls
|
||||
|
||||
# Show pipeline info
|
||||
woodpecker pipeline info <number>
|
||||
|
||||
# Show logs
|
||||
woodpecker pipeline logs <number>
|
||||
|
||||
# Approve waiting pipeline
|
||||
woodpecker pipeline approve <number>
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pipeline Fails at Lint Stage
|
||||
|
||||
**مشکل:** کد formatting یا linting مشکل دارد
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
cd peikarband
|
||||
|
||||
# Fix formatting
|
||||
black src/
|
||||
isort src/
|
||||
|
||||
# Check linting
|
||||
flake8 src/
|
||||
|
||||
# Commit fixes
|
||||
git add .
|
||||
git commit -m "fix: code formatting and linting"
|
||||
git push
|
||||
```
|
||||
|
||||
### Pipeline Fails at Test Stage
|
||||
|
||||
**مشکل:** تستها fail میشوند
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
cd peikarband
|
||||
|
||||
# Run tests locally
|
||||
pytest tests/ -v
|
||||
|
||||
# Run with coverage
|
||||
pytest tests/ -v --cov=src
|
||||
|
||||
# Fix tests and re-run
|
||||
git add .
|
||||
git commit -m "fix: failing tests"
|
||||
git push
|
||||
```
|
||||
|
||||
### Pipeline Fails at Docker Build
|
||||
|
||||
**مشکل:** Docker build error
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
# Test build locally
|
||||
docker build -f docker/Dockerfile -t test:latest .
|
||||
|
||||
# Check Dockerfile syntax
|
||||
docker build --check -f docker/Dockerfile .
|
||||
|
||||
# Check build context
|
||||
ls -la peikarband/
|
||||
|
||||
# Common issues:
|
||||
# 1. Missing files in context
|
||||
# 2. COPY path wrong
|
||||
# 3. Build args missing
|
||||
```
|
||||
|
||||
### Pipeline Fails at Deployment
|
||||
|
||||
**مشکل:** Helm deployment fail
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
# Test Helm locally
|
||||
helm lint helm/peikarband
|
||||
helm template peikarband helm/peikarband -f helm/peikarband/values-staging.yaml
|
||||
|
||||
# Check kubectl access
|
||||
kubectl get pods -n staging
|
||||
|
||||
# Check secrets
|
||||
kubectl get secrets -n staging
|
||||
|
||||
# Check image pull
|
||||
kubectl describe pod <pod-name> -n staging
|
||||
```
|
||||
|
||||
### Secret Not Found Error
|
||||
|
||||
**مشکل:** `Secret not found: HARBOR_USERNAME`
|
||||
|
||||
**راهحل:**
|
||||
1. رفتن به Woodpecker UI > Repository > Settings > Secrets
|
||||
2. بررسی که secret با نام درست اضافه شده
|
||||
3. بررسی که secret برای event درست (push, tag, etc.) فعال است
|
||||
4. بررسی که secret برای branch درست در دسترس است
|
||||
|
||||
### Kubeconfig Invalid
|
||||
|
||||
**مشکل:** `Unable to connect to the server`
|
||||
|
||||
**راهحل:**
|
||||
|
||||
```bash
|
||||
# Test kubeconfig locally
|
||||
export KUBECONFIG=/path/to/your/kubeconfig
|
||||
kubectl get pods
|
||||
|
||||
# Re-encode kubeconfig
|
||||
cat ~/.kube/config | base64 -w 0
|
||||
|
||||
# Update secret in Woodpecker
|
||||
# Copy new base64 string to KUBECONFIG_STAGING or KUBECONFIG_PRODUCTION
|
||||
```
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Build Cache
|
||||
|
||||
Pipeline از Docker layer caching استفاده میکند:
|
||||
|
||||
```yaml
|
||||
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||
cache_to: type=inline
|
||||
```
|
||||
|
||||
**بهینهسازی بیشتر:**
|
||||
|
||||
1. **Dependencies Caching:** requirements.txt را قبل از کد اصلی COPY کنید
|
||||
2. **Multi-stage Build:** از multi-stage builds استفاده کنید
|
||||
3. **Parallel Stages:** مراحل مستقل را parallel اجرا کنید
|
||||
|
||||
### Pipeline Duration
|
||||
|
||||
زمان تقریبی هر stage:
|
||||
|
||||
```
|
||||
Lint stages: ~1-2 minutes
|
||||
Security scan: ~2-3 minutes
|
||||
Tests: ~3-5 minutes
|
||||
Helm validation: ~30 seconds
|
||||
Docker build: ~5-10 minutes (first time), ~2-3 minutes (cached)
|
||||
Deployment: ~2-5 minutes
|
||||
Total: ~15-30 minutes (full pipeline)
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Commit Messages
|
||||
|
||||
از conventional commits استفاده کنید:
|
||||
|
||||
```bash
|
||||
feat: add new feature
|
||||
fix: bug fix
|
||||
docs: documentation changes
|
||||
style: formatting changes
|
||||
refactor: code refactoring
|
||||
test: test changes
|
||||
chore: build/CI changes
|
||||
```
|
||||
|
||||
### 2. Version Tagging
|
||||
|
||||
```bash
|
||||
# Semantic versioning
|
||||
v1.0.0 # Major.Minor.Patch
|
||||
v1.0.1 # Patch release
|
||||
v1.1.0 # Minor release
|
||||
v2.0.0 # Major release
|
||||
|
||||
# Pre-release versions
|
||||
v1.0.0-rc.1 # Release candidate
|
||||
v1.0.0-beta.1 # Beta release
|
||||
v1.0.0-alpha.1 # Alpha release
|
||||
```
|
||||
|
||||
### 3. Feature Branches
|
||||
|
||||
```bash
|
||||
# Create feature branch
|
||||
git checkout -b feature/user-authentication
|
||||
# ... make changes ...
|
||||
git add .
|
||||
git commit -m "feat: add user authentication"
|
||||
git push origin feature/user-authentication
|
||||
|
||||
# Create PR
|
||||
# After approval, merge to develop
|
||||
git checkout develop
|
||||
git merge feature/user-authentication
|
||||
git push origin develop
|
||||
# -> Triggers pipeline + deploy to staging
|
||||
|
||||
# After testing in staging, merge to main
|
||||
git checkout main
|
||||
git merge develop
|
||||
git push origin main
|
||||
# -> Triggers pipeline + deploy to staging
|
||||
|
||||
# Create production release
|
||||
git tag -a v1.1.0 -m "Release v1.1.0: Add user authentication"
|
||||
git push origin v1.1.0
|
||||
# -> Triggers pipeline + deploy to production
|
||||
```
|
||||
|
||||
### 4. Hotfix Process
|
||||
|
||||
```bash
|
||||
# Create hotfix branch from main
|
||||
git checkout -b hotfix/critical-bug main
|
||||
|
||||
# Fix the bug
|
||||
git add .
|
||||
git commit -m "fix: critical security vulnerability"
|
||||
|
||||
# Merge to main
|
||||
git checkout main
|
||||
git merge hotfix/critical-bug
|
||||
|
||||
# Tag immediately
|
||||
git tag -a v1.0.1 -m "Hotfix v1.0.1: Security patch"
|
||||
git push origin main v1.0.1
|
||||
# -> Triggers pipeline + deploy to production
|
||||
|
||||
# Merge back to develop
|
||||
git checkout develop
|
||||
git merge hotfix/critical-bug
|
||||
git push origin develop
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
### Available in Pipeline
|
||||
|
||||
```bash
|
||||
CI=woodpecker # Always set
|
||||
CI_REPO=username/peikarband # Repository name
|
||||
CI_REPO_LINK=https://git.../peikarband # Repository URL
|
||||
CI_COMMIT_SHA=a1b2c3d4e5f6... # Full commit hash
|
||||
CI_COMMIT_BRANCH=main # Branch name
|
||||
CI_COMMIT_TAG=v1.0.0 # Tag (if triggered by tag)
|
||||
CI_COMMIT_MESSAGE=feat: new feature # Commit message
|
||||
CI_PIPELINE_CREATED=2024-01-01T... # Pipeline creation time
|
||||
CI_PIPELINE_NUMBER=123 # Pipeline number
|
||||
```
|
||||
|
||||
### Usage Example
|
||||
|
||||
```bash
|
||||
# In pipeline step
|
||||
echo "Building commit ${CI_COMMIT_SHA:0:8} from branch ${CI_COMMIT_BRANCH}"
|
||||
echo "Image tag: hub.peikarband.ir/peikarband/landing:${CI_COMMIT_SHA:0:8}"
|
||||
```
|
||||
|
||||
## Support & Contact
|
||||
|
||||
برای مشکلات و سوالات:
|
||||
- **Documentation:** این فایل
|
||||
- **Issues:** GitLab/GitHub Issues
|
||||
- **Team Contact:** dev@peikarband.ir
|
||||
|
||||
## مراجع
|
||||
|
||||
- [Woodpecker CI Documentation](https://woodpecker-ci.org/docs/intro)
|
||||
- [Docker Build Best Practices](https://docs.docker.com/develop/dev-best-practices/)
|
||||
- [Helm Documentation](https://helm.sh/docs/)
|
||||
- [Kubernetes Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# Patterns to ignore when building packages.
|
||||
# This supports shell glob matching, relative path matching, and
|
||||
# negation (prefixed with !). Only one pattern per line.
|
||||
.DS_Store
|
||||
# Common VCS dirs
|
||||
.git/
|
||||
.gitignore
|
||||
.bzr/
|
||||
.bzrignore
|
||||
.hg/
|
||||
.hgignore
|
||||
.svn/
|
||||
# Common backup files
|
||||
*.swp
|
||||
*.bak
|
||||
*.tmp
|
||||
*.orig
|
||||
*~
|
||||
# Various IDEs
|
||||
.project
|
||||
.idea/
|
||||
*.tmproj
|
||||
.vscode/
|
||||
|
||||
257
helm/peikarband/argocd/README.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# ArgoCD Application Manifests
|
||||
|
||||
این پوشه شامل ArgoCD Application manifests برای deployment خودکار با GitOps است.
|
||||
|
||||
## ساختار
|
||||
|
||||
```
|
||||
argocd/
|
||||
├── application.yaml # Production deployment (namespace: production)
|
||||
├── application-staging.yaml # Staging deployment (namespace: staging)
|
||||
├── secrets/ # Kubernetes secrets (DO NOT commit real secrets)
|
||||
└── README.md # این فایل
|
||||
```
|
||||
|
||||
## استفاده
|
||||
|
||||
### 1. Deploy به Production
|
||||
|
||||
```bash
|
||||
# Apply ArgoCD Application
|
||||
kubectl apply -f helm/peikarband/argocd/application.yaml
|
||||
|
||||
# Check sync status
|
||||
argocd app get peikarband-landing-prod
|
||||
|
||||
# Sync manually if needed
|
||||
argocd app sync peikarband-landing-prod
|
||||
|
||||
# Watch deployment
|
||||
kubectl get pods -n production -w
|
||||
```
|
||||
|
||||
### 2. Deploy به Staging
|
||||
|
||||
```bash
|
||||
# Apply ArgoCD Application
|
||||
kubectl apply -f helm/peikarband/argocd/application-staging.yaml
|
||||
|
||||
# Check sync status
|
||||
argocd app get peikarband-landing-staging
|
||||
|
||||
# Sync manually
|
||||
argocd app sync peikarband-landing-staging
|
||||
```
|
||||
|
||||
### 3. Update Image Tag
|
||||
|
||||
#### روش اول: از طریق ArgoCD UI
|
||||
1. باز کردن ArgoCD UI
|
||||
2. رفتن به Application مورد نظر
|
||||
3. کلیک روی "Parameters"
|
||||
4. تغییر `image.tag` به tag جدید
|
||||
5. کلیک روی "Sync"
|
||||
|
||||
#### روش دوم: از طریق CLI
|
||||
|
||||
```bash
|
||||
# Update production
|
||||
argocd app set peikarband-landing-prod \
|
||||
-p image.tag=v1.2.3
|
||||
|
||||
# Update staging
|
||||
argocd app set peikarband-landing-staging \
|
||||
-p image.tag=develop
|
||||
```
|
||||
|
||||
#### روش سوم: تغییر در Git (GitOps روش اصلی)
|
||||
|
||||
```bash
|
||||
# Update values-production.yaml
|
||||
vim helm/peikarband/values-production.yaml
|
||||
# Change image.tag value
|
||||
|
||||
# Commit & Push
|
||||
git add helm/peikarband/values-production.yaml
|
||||
git commit -m "chore: update image to v1.2.3"
|
||||
git push origin main
|
||||
|
||||
# ArgoCD will auto-sync (if automated sync enabled)
|
||||
```
|
||||
|
||||
## تنظیمات مهم
|
||||
|
||||
### Auto-Sync
|
||||
|
||||
Her دو application روی `automated sync` تنظیم شدهاند:
|
||||
- **prune**: true → منابع اضافی حذف میشن
|
||||
- **selfHeal**: true → تغییرات manual برگشت میخورن
|
||||
- **allowEmpty**: false → deploy خالی مجاز نیست
|
||||
|
||||
### Sync Options
|
||||
|
||||
- **CreateNamespace**: true → namespace خودکار ساخته میشه
|
||||
- **PrunePropagationPolicy**: foreground → منابع به ترتیب حذف میشن
|
||||
- **PruneLast**: true → prune در آخر انجام میشه
|
||||
|
||||
### Retry Policy
|
||||
|
||||
در صورت شکست:
|
||||
- تا 5 بار تلاش مجدد
|
||||
- با backoff exponential (5s, 10s, 20s, 40s, 80s)
|
||||
- حداکثر 3 دقیقه delay
|
||||
|
||||
## Secrets Management
|
||||
|
||||
⚠️ **هشدار امنیتی:**
|
||||
|
||||
Secrets نباید در Git commit بشن! از یکی از روشهای زیر استفاده کنید:
|
||||
|
||||
### روش 1: Manual Secret Creation
|
||||
|
||||
```bash
|
||||
# Create registry secret
|
||||
kubectl create secret docker-registry hub-registry-secret \
|
||||
--docker-server=hub.peikarband.ir \
|
||||
--docker-username=admin \
|
||||
--docker-password=YOUR_PASSWORD \
|
||||
--namespace=production
|
||||
|
||||
# Create application secrets
|
||||
kubectl create secret generic peikarband-prod-secrets \
|
||||
--from-literal=db-username=peikarband \
|
||||
--from-literal=db-password=YOUR_DB_PASSWORD \
|
||||
--from-literal=redis-password=YOUR_REDIS_PASSWORD \
|
||||
--namespace=production
|
||||
```
|
||||
|
||||
### روش 2: Sealed Secrets (پیشنهاد شده)
|
||||
|
||||
```bash
|
||||
# Install sealed-secrets controller
|
||||
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml
|
||||
|
||||
# Create sealed secret
|
||||
kubeseal --format=yaml < secret.yaml > sealed-secret.yaml
|
||||
|
||||
# Commit sealed-secret.yaml (امن است)
|
||||
git add helm/peikarband/argocd/secrets/sealed-secret.yaml
|
||||
git commit -m "chore: add sealed secrets"
|
||||
```
|
||||
|
||||
### روش 3: External Secrets Operator
|
||||
|
||||
```bash
|
||||
# Install external-secrets
|
||||
helm install external-secrets external-secrets/external-secrets \
|
||||
--namespace external-secrets-system \
|
||||
--create-namespace
|
||||
|
||||
# Create SecretStore
|
||||
kubectl apply -f argocd/secrets/secret-store.yaml
|
||||
|
||||
# Create ExternalSecret
|
||||
kubectl apply -f argocd/secrets/external-secret.yaml
|
||||
```
|
||||
|
||||
## Health Checks
|
||||
|
||||
ArgoCD health checks:
|
||||
- **Deployment**: Ready replicas == Desired replicas
|
||||
- **Service**: Endpoint موجود باشه
|
||||
- **Ingress**: Backend service موجود باشه
|
||||
- **HPA**: Status normal باشه
|
||||
|
||||
## Rollback
|
||||
|
||||
در صورت مشکل:
|
||||
|
||||
```bash
|
||||
# List revisions
|
||||
argocd app history peikarband-landing-prod
|
||||
|
||||
# Rollback to specific revision
|
||||
argocd app rollback peikarband-landing-prod 5
|
||||
|
||||
# Or rollback to previous
|
||||
argocd app rollback peikarband-landing-prod
|
||||
```
|
||||
|
||||
## Monitoring
|
||||
|
||||
```bash
|
||||
# Watch application status
|
||||
argocd app watch peikarband-landing-prod
|
||||
|
||||
# Get detailed status
|
||||
argocd app get peikarband-landing-prod --refresh
|
||||
|
||||
# Show sync differences
|
||||
argocd app diff peikarband-landing-prod
|
||||
|
||||
# View logs
|
||||
kubectl logs -n production -l app.kubernetes.io/name=peikarband -f
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### App won't sync
|
||||
|
||||
```bash
|
||||
# Check sync status
|
||||
argocd app get peikarband-landing-prod
|
||||
|
||||
# Force refresh
|
||||
argocd app get peikarband-landing-prod --refresh --hard-refresh
|
||||
|
||||
# Delete and recreate
|
||||
argocd app delete peikarband-landing-prod
|
||||
kubectl apply -f helm/peikarband/argocd/application.yaml
|
||||
```
|
||||
|
||||
### Pods not starting
|
||||
|
||||
```bash
|
||||
# Check pod status
|
||||
kubectl get pods -n production
|
||||
|
||||
# Check pod logs
|
||||
kubectl logs -n production <pod-name>
|
||||
|
||||
# Describe pod for events
|
||||
kubectl describe pod -n production <pod-name>
|
||||
|
||||
# Check image pull secrets
|
||||
kubectl get secrets -n production
|
||||
```
|
||||
|
||||
### Health check failing
|
||||
|
||||
```bash
|
||||
# Check service endpoints
|
||||
kubectl get endpoints -n production
|
||||
|
||||
# Test health endpoint
|
||||
kubectl port-forward -n production svc/peikarband 8000:8000
|
||||
curl http://localhost:8000/ping
|
||||
```
|
||||
|
||||
## CI/CD Integration
|
||||
|
||||
در Woodpecker/GitHub Actions:
|
||||
|
||||
```yaml
|
||||
- name: Update ArgoCD Image
|
||||
image: argoproj/argocd:latest
|
||||
commands:
|
||||
- argocd login argocd.peikarband.ir --username admin --password $ARGOCD_PASSWORD
|
||||
- argocd app set peikarband-landing-prod -p image.tag=${CI_COMMIT_SHA:0:8}
|
||||
- argocd app sync peikarband-landing-prod --timeout 300
|
||||
```
|
||||
|
||||
## مستندات بیشتر
|
||||
|
||||
- [ArgoCD Documentation](https://argo-cd.readthedocs.io/)
|
||||
- [Helm Best Practices](https://helm.sh/docs/chart_best_practices/)
|
||||
- [Kubernetes Secrets Management](https://kubernetes.io/docs/concepts/configuration/secret/)
|
||||
|
||||
@@ -1,36 +1,31 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: peikarband-staging
|
||||
name: peikarband-landing-staging
|
||||
namespace: argocd
|
||||
annotations:
|
||||
notifications.argoproj.io/subscribe.on-deployed.telegram: ""
|
||||
notifications.argoproj.io/subscribe.on-sync-failed.telegram: ""
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
labels:
|
||||
app: peikarband
|
||||
environment: staging
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://git.peikarband.ir/ehsan-minadd/peikarband.git
|
||||
repoURL: http://git.peikarband.ir/ehsan-minadd/peikarband
|
||||
targetRevision: develop
|
||||
path: helm/peikarband
|
||||
helm:
|
||||
releaseName: peikarband-staging
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
- values-staging.yaml
|
||||
parameters:
|
||||
- name: image.repository
|
||||
value: harbor.peikarband.ir/peikarband/landing
|
||||
- name: image.tag
|
||||
value: develop
|
||||
- name: image.repository
|
||||
value: hub.peikarband.ir/peikarband/landing
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: peikarband-staging
|
||||
namespace: staging
|
||||
|
||||
syncPolicy:
|
||||
automated:
|
||||
@@ -50,6 +45,7 @@ spec:
|
||||
|
||||
revisionHistoryLimit: 10
|
||||
|
||||
# Health assessment
|
||||
ignoreDifferences:
|
||||
- group: apps
|
||||
kind: Deployment
|
||||
@@ -1,37 +1,31 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: peikarband
|
||||
name: peikarband-landing-prod
|
||||
namespace: argocd
|
||||
annotations:
|
||||
notifications.argoproj.io/subscribe.on-deployed.telegram: ""
|
||||
notifications.argoproj.io/subscribe.on-health-degraded.telegram: ""
|
||||
notifications.argoproj.io/subscribe.on-sync-failed.telegram: ""
|
||||
finalizers:
|
||||
- resources-finalizer.argocd.argoproj.io
|
||||
labels:
|
||||
app: peikarband
|
||||
environment: production
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://git.peikarband.ir/ehsan-minadd/peikarband.git
|
||||
repoURL: http://git.peikarband.ir/ehsan-minadd/peikarband
|
||||
targetRevision: main
|
||||
path: helm/peikarband
|
||||
helm:
|
||||
releaseName: peikarband
|
||||
valueFiles:
|
||||
- values.yaml
|
||||
- values-production.yaml
|
||||
parameters:
|
||||
- name: image.repository
|
||||
value: harbor.peikarband.ir/peikarband/landing
|
||||
- name: image.tag
|
||||
value: latest # This will be updated by CI/CD
|
||||
value: latest
|
||||
- name: image.repository
|
||||
value: hub.peikarband.ir/peikarband/landing
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: peikarband
|
||||
namespace: production
|
||||
|
||||
syncPolicy:
|
||||
automated:
|
||||
@@ -42,7 +36,6 @@ spec:
|
||||
- CreateNamespace=true
|
||||
- PrunePropagationPolicy=foreground
|
||||
- PruneLast=true
|
||||
- ApplyOutOfSyncOnly=true
|
||||
retry:
|
||||
limit: 5
|
||||
backoff:
|
||||
@@ -52,13 +45,10 @@ spec:
|
||||
|
||||
revisionHistoryLimit: 10
|
||||
|
||||
# Health assessment
|
||||
ignoreDifferences:
|
||||
- group: apps
|
||||
kind: Deployment
|
||||
jsonPointers:
|
||||
- /spec/replicas
|
||||
- group: apps
|
||||
kind: StatefulSet
|
||||
jsonPointers:
|
||||
- /spec/replicas
|
||||
|
||||
222
peikarband/README.md
Normal file
@@ -0,0 +1,222 @@
|
||||
# پیکربند - پلتفرم جامع مدیریت هاستینگ و زیرساخت ابری
|
||||
|
||||
## 📖 درباره پروژه
|
||||
|
||||
پیکربند یک پلتفرم حرفهای برای مدیریت هاستینگ، سرورهای ابری، دامین و خدمات DevOps است. این پلتفرم با الهام از سرویسهایی مانند Cloudways، DigitalOcean و پارس پک طراحی شده است.
|
||||
|
||||
## 🏗️ معماری
|
||||
|
||||
این پروژه بر اساس **Clean Architecture** و اصول **SOLID** طراحی شده است:
|
||||
|
||||
- **Domain Layer**: منطق کسبوکار اصلی
|
||||
- **Application Layer**: موارد استفاده (Use Cases)
|
||||
- **Infrastructure Layer**: پیادهسازیهای فنی
|
||||
- **Presentation Layer**: رابط کاربری (Reflex)
|
||||
|
||||
## 🚀 تکنولوژیها
|
||||
|
||||
- **Frontend/Backend**: Python Reflex
|
||||
- **Database**: PostgreSQL + SQLAlchemy
|
||||
- **Cache**: Redis
|
||||
- **Task Queue**: Celery
|
||||
- **Testing**: pytest
|
||||
- **Code Quality**: black, flake8, mypy, isort
|
||||
|
||||
## 📋 پیشنیازها
|
||||
|
||||
- Python 3.11+
|
||||
- PostgreSQL 14+
|
||||
- Redis 7+
|
||||
- Node.js 18+ (برای Reflex)
|
||||
|
||||
## 🛠️ نصب و راهاندازی
|
||||
|
||||
### 1. کلون کردن پروژه
|
||||
|
||||
```bash
|
||||
git clone https://github.com/yourusername/peikarband.git
|
||||
cd peikarband
|
||||
```
|
||||
|
||||
### 2. ایجاد محیط مجازی
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
```
|
||||
|
||||
### 3. نصب وابستگیها
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements-dev.txt # برای توسعه
|
||||
```
|
||||
|
||||
### 4. تنظیم Environment Variables
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# ویرایش .env و تکمیل مقادیر
|
||||
```
|
||||
|
||||
### 5. راهاندازی دیتابیس
|
||||
|
||||
```bash
|
||||
# ایجاد دیتابیس
|
||||
createdb peikarband
|
||||
|
||||
# اجرای migrations
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
### 6. اجرای پروژه
|
||||
|
||||
```bash
|
||||
# توسعه
|
||||
python -m reflex run
|
||||
|
||||
# یا
|
||||
make dev
|
||||
```
|
||||
|
||||
## 🚢 Deployment
|
||||
|
||||
### با Docker
|
||||
|
||||
```bash
|
||||
# Build
|
||||
docker build -t peikarband:latest .
|
||||
|
||||
# Run
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### با Kubernetes/Helm
|
||||
|
||||
```bash
|
||||
# Deploy
|
||||
helm upgrade --install peikarband ./deploy/helm/peikarband \
|
||||
--namespace production \
|
||||
--set image.tag=0.1.0
|
||||
|
||||
# یا
|
||||
make k8s-deploy
|
||||
```
|
||||
|
||||
📖 [راهنمای کامل Deployment](docs/deployment/kubernetes.md)
|
||||
|
||||
## 📁 ساختار پروژه
|
||||
|
||||
```
|
||||
peikarband-landing/
|
||||
├── build/ # Build configs (Docker, CI/CD)
|
||||
├── deploy/ # Deployment configs (Helm, K8s, ArgoCD)
|
||||
├── config/ # Configuration files
|
||||
├── tools/ # Scripts و ابزارها
|
||||
├── assets/ # Static assets
|
||||
├── src/ # Source code (Clean Architecture)
|
||||
│ ├── config/ # تنظیمات
|
||||
│ ├── core/ # هسته اصلی (Domain + Application)
|
||||
│ ├── infrastructure/ # پیادهسازیهای فنی
|
||||
│ ├── presentation/ # رابط کاربری (Reflex)
|
||||
│ └── shared/ # کدهای مشترک
|
||||
├── tests/ # تستها
|
||||
├── docs/ # مستندات کامل
|
||||
└── data/ # Local data (gitignored)
|
||||
```
|
||||
|
||||
📖 [ساختار کامل پروژه](docs/PROJECT_STRUCTURE.md)
|
||||
|
||||
## 🧪 تست
|
||||
|
||||
```bash
|
||||
# اجرای همه تستها
|
||||
pytest
|
||||
|
||||
# با coverage
|
||||
pytest --cov=src tests/
|
||||
|
||||
# تستهای خاص
|
||||
pytest tests/unit/
|
||||
pytest tests/integration/
|
||||
```
|
||||
|
||||
## 📝 کدنویسی
|
||||
|
||||
### استانداردها
|
||||
|
||||
- **PEP 8**: استاندارد کدنویسی Python
|
||||
- **PEP 20**: Zen of Python
|
||||
- **Type Hints**: همه جا استفاده شود
|
||||
- **Docstrings**: Google Style
|
||||
|
||||
### ابزارهای کیفیت کد
|
||||
|
||||
```bash
|
||||
# Format
|
||||
black src/
|
||||
|
||||
# Linting
|
||||
flake8 src/
|
||||
|
||||
# Type checking
|
||||
mypy src/
|
||||
|
||||
# Import sorting
|
||||
isort src/
|
||||
```
|
||||
|
||||
### Pre-commit Hooks
|
||||
|
||||
```bash
|
||||
pre-commit install
|
||||
pre-commit run --all-files
|
||||
```
|
||||
|
||||
## 📚 مستندات
|
||||
|
||||
مستندات کامل در پوشه `docs/` موجود است:
|
||||
|
||||
- [Handbook](docs/handbook.md): راهنمای جامع پروژه
|
||||
- [Architecture](docs/architecture/): معماری سیستم
|
||||
- [Development](docs/development/): راهنمای توسعه
|
||||
- [API Reference](docs/api/): مستندات API
|
||||
|
||||
## 🔐 امنیت
|
||||
|
||||
- همه پسوردها با bcrypt hash میشوند
|
||||
- استفاده از JWT برای authentication
|
||||
- پشتیبانی از 2FA
|
||||
- اطلاعات حساس رمزنگاری میشوند
|
||||
|
||||
## 🤝 مشارکت
|
||||
|
||||
برای مشارکت در پروژه:
|
||||
|
||||
1. Fork کنید
|
||||
2. Branch جدید بسازید (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit کنید (`git commit -m 'feat: add amazing feature'`)
|
||||
4. Push کنید (`git push origin feature/amazing-feature`)
|
||||
5. Pull Request بسازید
|
||||
|
||||
## 📄 لایسنس
|
||||
|
||||
این پروژه تحت لایسنس MIT منتشر شده است.
|
||||
|
||||
## 👥 تیم
|
||||
|
||||
- Lead Developer: [Your Name]
|
||||
- Architecture: Clean Architecture
|
||||
- Methodology: Agile/Scrum
|
||||
|
||||
## 📞 تماس
|
||||
|
||||
- Website: https://peikarband.ir
|
||||
- Email: support@peikarband.ir
|
||||
- Telegram: @peikarband
|
||||
|
||||
---
|
||||
|
||||
**نسخه**: 0.1.0
|
||||
**آخرین بروزرسانی**: 2025-01-24
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
"""Peikarband application package."""
|
||||
|
||||
from .peikarband import app
|
||||
|
||||
__all__ = ["app"]
|
||||
|
||||
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 978 B After Width: | Height: | Size: 978 B |
|
Before Width: | Height: | Size: 796 KiB After Width: | Height: | Size: 796 KiB |
|
Before Width: | Height: | Size: 533 KiB After Width: | Height: | Size: 533 KiB |
|
Before Width: | Height: | Size: 456 KiB After Width: | Height: | Size: 456 KiB |
360
peikarband/docs/PROJECT_STRUCTURE.md
Normal file
@@ -0,0 +1,360 @@
|
||||
# ساختار پروژه پیکربند - Landing Page
|
||||
|
||||
## 📁 ساختار کلی (بازسازی شده)
|
||||
|
||||
```
|
||||
peikarband-landing/
|
||||
├── README.md # Main project documentation
|
||||
├── requirements.txt # Production dependencies
|
||||
├── requirements-dev.txt # Development dependencies
|
||||
├── Makefile # Build automation commands
|
||||
├── rxconfig.py # Reflex config loader (imports from config/)
|
||||
├── .gitignore
|
||||
│
|
||||
├── build/ # 🔨 همه چیز مربوط به Build
|
||||
│ ├── docker/
|
||||
│ │ ├── Dockerfile # Main application Dockerfile
|
||||
│ │ ├── Dockerfile.base # Base image (reference)
|
||||
│ │ ├── docker-compose.yml # Local development setup
|
||||
│ │ └── .dockerignore
|
||||
│ └── ci/
|
||||
│ └── woodpecker.yml # CI/CD pipeline configuration
|
||||
│
|
||||
├── deploy/ # 🚀 همه چیز مربوط به Deployment
|
||||
│ ├── helm/
|
||||
│ │ └── peikarband/ # Helm chart
|
||||
│ │ ├── Chart.yaml
|
||||
│ │ ├── templates/ # K8s resource templates
|
||||
│ │ ├── values.yaml # Default values
|
||||
│ │ ├── values-production.yaml
|
||||
│ │ └── values-staging.yaml
|
||||
│ ├── kubernetes/
|
||||
│ │ └── secrets-template.yaml # K8s manifest templates
|
||||
│ └── argocd/ # ArgoCD GitOps configs
|
||||
│ ├── application.yaml
|
||||
│ ├── application-staging.yaml
|
||||
│ ├── README.md
|
||||
│ └── secrets/
|
||||
│
|
||||
├── config/ # ⚙️ همه Configuration Files
|
||||
│ ├── alembic.ini # Database migration config
|
||||
│ ├── mypy.ini # Type checking config
|
||||
│ ├── pytest.ini # Test configuration
|
||||
│ └── reflex.config.py # Reflex app configuration
|
||||
│
|
||||
├── tools/ # 🔧 Scripts و ابزارهای کمکی
|
||||
│ ├── scripts/
|
||||
│ │ ├── update-env-json.sh # Runtime config updater
|
||||
│ │ └── diagnose-502.sh # Diagnostic tools
|
||||
│ └── setup.py # Package setup
|
||||
│
|
||||
├── assets/ # 🎨 Static Assets (served by Reflex)
|
||||
│ ├── logo.png
|
||||
│ ├── banner-3.gif
|
||||
│ ├── custom.css
|
||||
│ ├── hero-*.svg
|
||||
│ └── wordpress*.gif
|
||||
│
|
||||
├── data/ # 💾 Local Data (gitignored)
|
||||
│ ├── db/ # Local database files
|
||||
│ ├── cache/ # Cache files
|
||||
│ └── logs/ # Log files
|
||||
│
|
||||
├── src/ # 💻 Source Code (Clean Architecture)
|
||||
│ ├── config/ # Application configuration
|
||||
│ │ ├── settings.py
|
||||
│ │ ├── database.py
|
||||
│ │ ├── cache.py
|
||||
│ │ └── logging.py
|
||||
│ ├── core/ # Core business logic
|
||||
│ │ ├── domain/ # Domain layer
|
||||
│ │ │ ├── entities/ # Domain entities
|
||||
│ │ │ ├── value_objects/ # Value objects
|
||||
│ │ │ ├── enums/ # Domain enums
|
||||
│ │ │ └── exceptions/ # Domain exceptions
|
||||
│ │ └── application/ # Application layer
|
||||
│ │ ├── use_cases/ # Use cases
|
||||
│ │ ├── dto/ # Data Transfer Objects
|
||||
│ │ ├── interfaces/ # Interfaces/Ports
|
||||
│ │ └── validators/ # Validators
|
||||
│ ├── infrastructure/ # Infrastructure layer
|
||||
│ │ ├── database/ # Database implementation
|
||||
│ │ │ ├── models/ # SQLAlchemy models
|
||||
│ │ │ ├── repositories/ # Repository implementations
|
||||
│ │ │ └── migrations/ # Alembic migrations
|
||||
│ │ ├── cache/ # Cache implementation (Redis)
|
||||
│ │ ├── external/ # External API integrations
|
||||
│ │ │ ├── email/
|
||||
│ │ │ ├── sms/
|
||||
│ │ │ ├── payment/
|
||||
│ │ │ └── providers/
|
||||
│ │ ├── security/ # Security implementations
|
||||
│ │ └── tasks/ # Background tasks (Celery)
|
||||
│ ├── presentation/ # Presentation layer
|
||||
│ │ ├── web/ # Reflex web application
|
||||
│ │ │ ├── pages/ # Reflex pages
|
||||
│ │ │ ├── components/ # Reusable components
|
||||
│ │ │ ├── state/ # Application state
|
||||
│ │ │ └── styles/ # Styling
|
||||
│ │ └── api/ # REST API endpoints (if needed)
|
||||
│ │ ├── routes/
|
||||
│ │ └── middleware/
|
||||
│ └── shared/ # Shared utilities
|
||||
│ ├── events/ # Event system
|
||||
│ └── messaging/ # Message bus
|
||||
│
|
||||
├── tests/ # 🧪 Test Suites
|
||||
│ ├── unit/ # Unit tests
|
||||
│ │ ├── core/
|
||||
│ │ └── infrastructure/
|
||||
│ ├── integration/ # Integration tests
|
||||
│ │ ├── database/
|
||||
│ │ └── external/
|
||||
│ ├── e2e/ # End-to-end tests
|
||||
│ │ └── scenarios/
|
||||
│ ├── fixtures/ # Test fixtures
|
||||
│ └── conftest.py # Pytest configuration
|
||||
│
|
||||
├── docs/ # 📚 Documentation
|
||||
│ ├── api/ # API documentation
|
||||
│ ├── architecture/ # Architecture docs
|
||||
│ │ ├── overview.md
|
||||
│ │ └── database-strategy.md
|
||||
│ ├── deployment/ # Deployment guides
|
||||
│ │ ├── DEPLOYMENT_CHECKLIST.md
|
||||
│ │ ├── DEPLOYMENT_QUICK_START.md
|
||||
│ │ ├── PRODUCTION_DEPLOYMENT.md
|
||||
│ │ ├── CHANGELOG-DEPLOYMENT.md
|
||||
│ │ └── kubernetes.md
|
||||
│ ├── development/ # Development guides
|
||||
│ │ ├── setup.md
|
||||
│ │ ├── coding-standards.md
|
||||
│ │ └── git-workflow.md
|
||||
│ ├── changelog/ # Change logs
|
||||
│ │ ├── CHANGELOG.md
|
||||
│ │ ├── migrations.md
|
||||
│ │ └── known-issues.md
|
||||
│ ├── operations/ # Operations docs
|
||||
│ ├── handbook.md # Complete handbook
|
||||
│ └── PROJECT_STRUCTURE.md # This file
|
||||
│
|
||||
└── tmp/ # Temporary files (gitignored)
|
||||
```
|
||||
|
||||
## 🎯 معماری جدید - Separation of Concerns
|
||||
|
||||
### 1. `build/` - Build Configurations
|
||||
**هدف**: جداسازی همه چیز مربوط به build process
|
||||
|
||||
- **`build/docker/`**: تمام فایلهای Docker
|
||||
- Multi-stage Dockerfile با optimization
|
||||
- Docker Compose برای development
|
||||
- .dockerignore
|
||||
|
||||
- **`build/ci/`**: CI/CD configurations
|
||||
- Woodpecker CI pipeline
|
||||
- سایر CI configs (GitHub Actions, GitLab CI)
|
||||
|
||||
**مزایا**:
|
||||
- ✅ Root directory تمیزتر
|
||||
- ✅ Build configs مدیریت شده در یک مکان
|
||||
- ✅ CI/CD configs جدا از کد
|
||||
|
||||
### 2. `deploy/` - Deployment Configurations
|
||||
**هدف**: تمرکز همه deployment configs
|
||||
|
||||
- **`deploy/helm/`**: Helm charts
|
||||
- Production و Staging values
|
||||
- Templates برای تمام K8s resources
|
||||
|
||||
- **`deploy/kubernetes/`**: Raw K8s manifests
|
||||
- Secret templates
|
||||
- Custom resources
|
||||
|
||||
- **`deploy/argocd/`**: ArgoCD GitOps
|
||||
- Application definitions
|
||||
- Sync policies
|
||||
|
||||
**مزایا**:
|
||||
- ✅ یک مکان برای همه deployment
|
||||
- ✅ واضح برای DevOps engineers
|
||||
- ✅ جداسازی از source code
|
||||
|
||||
### 3. `config/` - Configuration Files
|
||||
**هدف**: تمرکز همه config files
|
||||
|
||||
- `alembic.ini`: Database migrations
|
||||
- `mypy.ini`: Type checking
|
||||
- `pytest.ini`: Testing
|
||||
- `reflex.config.py`: Reflex framework
|
||||
|
||||
**مزایا**:
|
||||
- ✅ Root directory خلوتتر
|
||||
- ✅ Configs به راحتی پیدا میشوند
|
||||
- ✅ مدیریت بهتر
|
||||
|
||||
### 4. `tools/` - Utility Scripts
|
||||
**هدف**: جداسازی scripts و ابزارها
|
||||
|
||||
- Runtime scripts
|
||||
- Diagnostic tools
|
||||
- Setup utilities
|
||||
|
||||
**مزایا**:
|
||||
- ✅ Scripts منظم و دستهبندی شده
|
||||
- ✅ جدا از source code
|
||||
|
||||
### 5. `assets/` - Consolidated Assets
|
||||
**هدف**: یک مکان واحد برای همه static assets
|
||||
|
||||
**قبلاً**: Assets پراکنده در `assets/` و `src/presentation/web/assets/`
|
||||
**الان**: همه در `assets/` (served directly by Reflex)
|
||||
|
||||
**فایلهای موجود**:
|
||||
- `logo.png` - لوگوی پیکربند
|
||||
- `banner-3.gif` - Banner animation
|
||||
- `wordpress-logo.gif` - WordPress logo
|
||||
- `hero-*.svg` - Hero section icons
|
||||
- `custom.css` - Custom styles
|
||||
|
||||
**استفاده در کد**:
|
||||
```python
|
||||
rx.image(src="/logo.png") # Reflex serves from /assets
|
||||
```
|
||||
|
||||
**مزایا**:
|
||||
- ✅ No duplication
|
||||
- ✅ یک منبع حقیقت
|
||||
- ✅ مدیریت آسانتر
|
||||
- ✅ سازگار با Reflex
|
||||
|
||||
### 6. `data/` - Local Data (gitignored)
|
||||
**هدف**: Local development data
|
||||
|
||||
- `data/db/`: SQLite و database files
|
||||
- `data/cache/`: Redis dumps
|
||||
- `data/logs/`: Log files
|
||||
|
||||
**مزایا**:
|
||||
- ✅ Data جدا از code
|
||||
- ✅ .gitignore شده
|
||||
- ✅ Clean repository
|
||||
|
||||
## 🔗 ارتباط با پروژههای دیگر
|
||||
|
||||
### Base Image Repository
|
||||
- **Repo**: `peikarband/base`
|
||||
- **Registry**: `hub.peikarband.ir/peikarband/base:latest`
|
||||
- **Purpose**: Base image with Python, Node.js, bun, build tools
|
||||
- **Build**: Separate CI/CD pipeline
|
||||
- **Usage**: Referenced in `build/docker/Dockerfile`
|
||||
|
||||
### Landing Page (This Repo)
|
||||
- **Repo**: `peikarband/landing`
|
||||
- **Registry**: `hub.peikarband.ir/peikarband/landing:latest`
|
||||
- **Purpose**: Landing page application
|
||||
- **Dependencies**: Uses base image
|
||||
|
||||
## 📝 فایلهای Root (Minimal)
|
||||
|
||||
### ضروری
|
||||
- `README.md`: Main documentation
|
||||
- `requirements.txt`: Dependencies
|
||||
- `Makefile`: Build commands
|
||||
- `rxconfig.py`: Reflex config loader
|
||||
- `.gitignore`: Git ignore rules
|
||||
|
||||
### حذف شده از Root
|
||||
- ❌ `Dockerfile` → `build/docker/`
|
||||
- ❌ `docker-compose.yml` → `build/docker/`
|
||||
- ❌ `.woodpecker.yml` → `build/ci/`
|
||||
- ❌ `alembic.ini` → `config/`
|
||||
- ❌ `pytest.ini` → `config/`
|
||||
- ❌ `mypy.ini` → `config/`
|
||||
- ❌ `scripts/` → `tools/scripts/`
|
||||
- ❌ `setup.py` → `tools/`
|
||||
- ❌ `helm/` → `deploy/helm/`
|
||||
- ❌ `argocd/` → `deploy/argocd/`
|
||||
- ❌ Duplicate assets → `assets/static/`
|
||||
|
||||
## 🎯 Best Practices
|
||||
|
||||
### Root Directory
|
||||
- ✅ فقط فایلهای ضروری
|
||||
- ✅ Config files در `config/`
|
||||
- ✅ Build files در `build/`
|
||||
- ✅ Deploy files در `deploy/`
|
||||
|
||||
### Source Code (`src/`)
|
||||
- ✅ Clean Architecture layers
|
||||
- ✅ Separation of concerns
|
||||
- ✅ SOLID principles
|
||||
|
||||
### Documentation
|
||||
- ✅ همه docs در `docs/`
|
||||
- ✅ دستهبندی منطقی
|
||||
- ✅ بهروز و جامع
|
||||
|
||||
### Deployment
|
||||
- ✅ Helm charts محیطمحور
|
||||
- ✅ ArgoCD GitOps
|
||||
- ✅ Secrets جدا از code
|
||||
|
||||
### Testing
|
||||
- ✅ Unit/Integration/E2E جدا
|
||||
- ✅ Fixtures منظم
|
||||
- ✅ Coverage بالا
|
||||
|
||||
## 🚀 مزایای معماری جدید
|
||||
|
||||
1. **Clarity** ✨
|
||||
- واضح است که هر فایل کجا باشد
|
||||
- Navigation آسانتر
|
||||
|
||||
2. **Maintainability** 🔧
|
||||
- نگهداری آسانتر
|
||||
- Onboarding سریعتر
|
||||
|
||||
3. **Scalability** 📈
|
||||
- اضافه کردن configs جدید ساده
|
||||
- مقیاسپذیری بهتر
|
||||
|
||||
4. **Professional** 💼
|
||||
- استاندارد enterprise projects
|
||||
- Best practices معماری
|
||||
|
||||
5. **Developer Experience** 👨💻
|
||||
- کمتر سردرگم
|
||||
- Productivity بالاتر
|
||||
|
||||
## 📊 مقایسه قبل و بعد
|
||||
|
||||
### قبل
|
||||
```
|
||||
root/
|
||||
├── 15+ config files 😰
|
||||
├── Docker files
|
||||
├── CI configs
|
||||
├── helm/
|
||||
├── argocd/
|
||||
├── scripts/
|
||||
├── assets/ (duplicate!)
|
||||
└── src/
|
||||
```
|
||||
|
||||
### بعد
|
||||
```
|
||||
root/
|
||||
├── 4 essential files only 😌
|
||||
├── build/ (organized)
|
||||
├── deploy/ (organized)
|
||||
├── config/ (organized)
|
||||
├── tools/ (organized)
|
||||
├── assets/static/ (consolidated)
|
||||
└── src/ (clean)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**آخرین بروزرسانی**: 2025-01-30
|
||||
**نسخه معماری**: 2.0 (Restructured)
|
||||
@@ -1,58 +0,0 @@
|
||||
"""
|
||||
Peikarband Application Entry Point
|
||||
|
||||
This is the main application file that Reflex uses to run the app.
|
||||
"""
|
||||
|
||||
import reflex as rx
|
||||
from src.presentation.web.pages.landing.index import index
|
||||
from src.presentation.api.routes.health import (
|
||||
ping_endpoint,
|
||||
health_endpoint,
|
||||
ready_endpoint,
|
||||
live_endpoint,
|
||||
)
|
||||
|
||||
# Create the app
|
||||
app = rx.App()
|
||||
|
||||
# Add landing page
|
||||
app.add_page(index, route="/")
|
||||
|
||||
# Add health check pages (for Kubernetes probes)
|
||||
# These return JSON responses for monitoring
|
||||
@rx.page(route="/ping")
|
||||
def ping():
|
||||
"""Basic health check endpoint"""
|
||||
data = ping_endpoint()
|
||||
return rx.box(
|
||||
rx.text(str(data)),
|
||||
style={"whiteSpace": "pre"}
|
||||
)
|
||||
|
||||
@rx.page(route="/health")
|
||||
def health():
|
||||
"""Detailed health check endpoint"""
|
||||
data = health_endpoint()
|
||||
return rx.box(
|
||||
rx.text(str(data)),
|
||||
style={"whiteSpace": "pre"}
|
||||
)
|
||||
|
||||
@rx.page(route="/ready")
|
||||
def ready():
|
||||
"""Readiness probe endpoint"""
|
||||
data = ready_endpoint()
|
||||
return rx.box(
|
||||
rx.text(str(data)),
|
||||
style={"whiteSpace": "pre"}
|
||||
)
|
||||
|
||||
@rx.page(route="/live")
|
||||
def live():
|
||||
"""Liveness probe endpoint"""
|
||||
data = live_endpoint()
|
||||
return rx.box(
|
||||
rx.text(str(data)),
|
||||
style={"whiteSpace": "pre"}
|
||||
)
|
||||
27
peikarband/rxconfig.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""Reflex configuration file.
|
||||
|
||||
This file configures the Reflex application settings.
|
||||
"""
|
||||
|
||||
import os
|
||||
import reflex as rx
|
||||
|
||||
# Environment-aware configuration
|
||||
API_URL = os.getenv("API_URL", "http://localhost:8000")
|
||||
FRONTEND_PORT = int(os.getenv("FRONTEND_PORT", "3000"))
|
||||
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
|
||||
DB_URL = os.getenv("DATABASE_URL", "sqlite:////app/data/reflex.db")
|
||||
|
||||
config = rx.Config(
|
||||
app_name="peikarband",
|
||||
api_url=API_URL,
|
||||
frontend_port=FRONTEND_PORT,
|
||||
backend_port=BACKEND_PORT,
|
||||
db_url=DB_URL,
|
||||
disable_plugins=["reflex.plugins.sitemap.SitemapPlugin"],
|
||||
stylesheets=[
|
||||
"https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap",
|
||||
"https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css",
|
||||
],
|
||||
)
|
||||
|
||||