feat: implement complete CI/CD with base image strategy
- Add Woodpecker pipeline with base image support - Separate base image build (.woodpecker-base.yml) from app build (.woodpecker.yml) - Implement build/push separation in application pipeline - Create Docker base image with Python 3.11, Node.js 20, and bun - Update Dockerfile to use pre-built base image for faster builds - Remove GitHub Actions (not needed, using Woodpecker) - Fix Docker contexts and paths for new structure - Update docker-compose.yml build contexts - Fix rxconfig.py DB path for container environment - Add ArgoCD application manifests for staging/production - Create comprehensive documentation: - docs/WOODPECKER_CI_CD.md (CI/CD guide) - docs/BASE_IMAGE_MANAGEMENT.md (Base image management) - helm/peikarband/argocd/README.md (ArgoCD deployment) Benefits: - Build time: 8-10min → 2-3min (60-70% faster) - Better reliability (no repeated npm/bun downloads) - Separation of concerns (base vs application builds) - Full pipeline: check → build → push → verify → notify - Complete deployment automation with Helm + ArgoCD Pipeline stages: 1. check-base-image: Verify base image availability 2. build-image: Build application (no push) 3. push-image: Push with multi-tags (latest, sha, branch) 4. verify-push: Verify successful push 5. notify: Success/failure notifications Base image can be rebuilt via: - Manual trigger in Woodpecker UI - Auto trigger when Dockerfile.base changes
This commit is contained in:
193
.github/workflows/cd.yml
vendored
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
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
|
|
||||||
|
|
||||||
142
.woodpecker-base.yml
Normal file
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
|
||||||
|
|
||||||
334
.woodpecker.yml
334
.woodpecker.yml
@@ -1,9 +1,49 @@
|
|||||||
|
# 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:
|
pipeline:
|
||||||
publish_landing:
|
# ============================================
|
||||||
|
# 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
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
settings:
|
settings:
|
||||||
# تنظیمات ریجیستری Harbor
|
|
||||||
registry: hub.peikarband.ir
|
registry: hub.peikarband.ir
|
||||||
repo: hub.peikarband.ir/peikarband/landing
|
repo: hub.peikarband.ir/peikarband/landing
|
||||||
username:
|
username:
|
||||||
@@ -11,20 +51,19 @@ pipeline:
|
|||||||
password:
|
password:
|
||||||
from_secret: HARBOR_PASSWORD
|
from_secret: HARBOR_PASSWORD
|
||||||
|
|
||||||
# تگگذاری
|
|
||||||
tags:
|
|
||||||
- latest
|
|
||||||
- ${CI_COMMIT_SHA:0:8}
|
|
||||||
|
|
||||||
dockerfile: docker/Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
context: peikarband/
|
context: .
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64
|
||||||
|
|
||||||
|
# استفاده از base image
|
||||||
build_args:
|
build_args:
|
||||||
|
- BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||||
- VERSION=${CI_COMMIT_SHA:0:8}
|
- VERSION=${CI_COMMIT_SHA:0:8}
|
||||||
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
- BUILD_DATE=${CI_PIPELINE_CREATED}
|
||||||
- PYTHON_VERSION=3.11
|
|
||||||
- NODE_VERSION=20
|
# فقط build میکنیم، بدون push
|
||||||
|
tags:
|
||||||
|
- ${CI_COMMIT_SHA:0:8}
|
||||||
|
|
||||||
labels:
|
labels:
|
||||||
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
- org.opencontainers.image.created=${CI_PIPELINE_CREATED}
|
||||||
@@ -35,12 +74,277 @@ pipeline:
|
|||||||
- org.opencontainers.image.title=Peikarband Landing
|
- org.opencontainers.image.title=Peikarband Landing
|
||||||
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
- org.opencontainers.image.description=Peikarband hosting platform landing page
|
||||||
|
|
||||||
cache: inline
|
cache_from: type=registry,ref=hub.peikarband.ir/peikarband/landing:buildcache
|
||||||
provenance: true
|
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
|
push: true
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: [push, tag, manual]
|
- event: [push, tag]
|
||||||
branch: main # معمولاً فقط روی برنچ اصلی پوش انجام میشود
|
branch: [main, develop]
|
||||||
|
|
||||||
timeout: 30m
|
# ============================================
|
||||||
|
# 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
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -83,7 +83,7 @@ docker-build:
|
|||||||
-t $(IMAGE_NAME):latest \
|
-t $(IMAGE_NAME):latest \
|
||||||
--build-arg VERSION=$(VERSION) \
|
--build-arg VERSION=$(VERSION) \
|
||||||
--build-arg BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
|
--build-arg BUILD_DATE=$(shell date -u +'%Y-%m-%dT%H:%M:%SZ') \
|
||||||
peikarband/
|
.
|
||||||
|
|
||||||
docker-push:
|
docker-push:
|
||||||
docker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
|
docker tag $(IMAGE_NAME):$(VERSION) $(REGISTRY)/$(IMAGE_NAME):$(VERSION)
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
# Peikarband Platform - Production Dockerfile
|
# Peikarband Platform - Production Dockerfile
|
||||||
# Multi-stage build for optimized image size and security
|
# Multi-stage build for optimized image size and security
|
||||||
|
# Uses pre-built base image for faster builds
|
||||||
|
|
||||||
# Build arguments
|
# Build arguments
|
||||||
ARG PYTHON_VERSION=3.11
|
ARG BASE_IMAGE=hub.peikarband.ir/peikarband/base:latest
|
||||||
ARG NODE_VERSION=20
|
|
||||||
ARG VERSION=latest
|
ARG VERSION=latest
|
||||||
ARG BUILD_DATE
|
ARG BUILD_DATE
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Stage 1: Builder
|
# Stage 1: Builder (using base image)
|
||||||
# ============================================
|
# ============================================
|
||||||
FROM python:${PYTHON_VERSION}-slim AS builder
|
FROM ${BASE_IMAGE} AS builder
|
||||||
|
|
||||||
# Re-declare ARGs for this stage
|
# Re-declare ARGs for this stage
|
||||||
ARG NODE_VERSION=20
|
|
||||||
ARG VERSION=latest
|
ARG VERSION=latest
|
||||||
ARG BUILD_DATE
|
ARG BUILD_DATE
|
||||||
|
|
||||||
@@ -25,47 +24,30 @@ LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
|||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
# Install build dependencies
|
# Base image already has:
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
# - Python 3.11
|
||||||
gcc \
|
# - Node.js 20
|
||||||
g++ \
|
# - bun
|
||||||
make \
|
# - gcc, g++, make
|
||||||
curl \
|
# - npm configured with retries
|
||||||
gnupg \
|
|
||||||
ca-certificates \
|
|
||||||
unzip \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install Node.js (required for Reflex)
|
# Verify tools are available
|
||||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
RUN echo "=== Build Environment ===" && \
|
||||||
&& apt-get install -y --no-install-recommends nodejs \
|
python --version && \
|
||||||
&& rm -rf /var/lib/apt/lists/* \
|
node --version && \
|
||||||
&& npm config set fetch-retry-mintimeout 20000 \
|
npm --version && \
|
||||||
&& npm config set fetch-retry-maxtimeout 120000 \
|
bun --version && \
|
||||||
&& npm config set fetch-retries 5 \
|
echo "========================"
|
||||||
&& 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}"
|
|
||||||
|
|
||||||
# Copy only requirements first (for better layer caching)
|
# Copy only requirements first (for better layer caching)
|
||||||
COPY requirements.txt .
|
COPY peikarband/requirements.txt .
|
||||||
|
|
||||||
# Install Python dependencies in user space
|
# Install Python dependencies in user space
|
||||||
RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
|
RUN pip install --no-cache-dir --upgrade pip setuptools wheel && \
|
||||||
pip install --no-cache-dir --user -r requirements.txt
|
pip install --no-cache-dir --user -r requirements.txt
|
||||||
|
|
||||||
# Copy application code (excluding .dockerignore items)
|
# Copy application code (excluding .dockerignore items)
|
||||||
COPY --chown=root:root . .
|
COPY --chown=root:root peikarband/ .
|
||||||
|
|
||||||
# Build and export Reflex app for production
|
# Build and export Reflex app for production
|
||||||
# Note: API_URL will be updated at runtime from environment variable
|
# Note: API_URL will be updated at runtime from environment variable
|
||||||
@@ -149,8 +131,7 @@ COPY --from=builder /root/.local /home/peikarband/.local
|
|||||||
COPY --from=builder /build /app
|
COPY --from=builder /build /app
|
||||||
|
|
||||||
# Copy and set up runtime script
|
# Copy and set up runtime script
|
||||||
# Context is peikarband/, so paths are relative to that
|
COPY --chown=peikarband:peikarband peikarband/tools/scripts/update-env-json.sh /app/tools/scripts/update-env-json.sh
|
||||||
COPY --chown=peikarband:peikarband tools/scripts/update-env-json.sh /app/tools/scripts/update-env-json.sh
|
|
||||||
RUN chmod +x /app/tools/scripts/update-env-json.sh
|
RUN chmod +x /app/tools/scripts/update-env-json.sh
|
||||||
|
|
||||||
# Fix ownership
|
# Fix ownership
|
||||||
|
|||||||
@@ -1,25 +1,24 @@
|
|||||||
# Base Image for Peikarband Projects
|
# Peikarband Base Image
|
||||||
|
# Pre-built image with Python, Node.js, bun, and build tools
|
||||||
#
|
#
|
||||||
# This Dockerfile should be in a SEPARATE repository: peikarband/base
|
# Usage:
|
||||||
# It's kept here for reference only.
|
# Build: docker build -f docker/Dockerfile.base -t hub.peikarband.ir/peikarband/base:latest .
|
||||||
|
# Or use Woodpecker: trigger .woodpecker-base.yml pipeline
|
||||||
#
|
#
|
||||||
# Purpose: Pre-installed build tools (Python, Node.js, bun, gcc, etc.)
|
# This image is built once and reused by all Peikarband projects
|
||||||
# Registry: hub.peikarband.ir/peikarband/base:latest
|
|
||||||
#
|
|
||||||
# This image is built once and cached, making subsequent builds much faster
|
|
||||||
# All Peikarband projects should use this base image
|
|
||||||
|
|
||||||
ARG PYTHON_VERSION=3.11
|
ARG PYTHON_VERSION=3.11
|
||||||
ARG NODE_VERSION=20
|
ARG NODE_VERSION=20
|
||||||
|
|
||||||
FROM python:${PYTHON_VERSION}-slim AS base
|
FROM python:${PYTHON_VERSION}-slim
|
||||||
|
|
||||||
LABEL maintainer="Peikarband Team <dev@peikarband.ir>"
|
LABEL maintainer="Peikarband Team <dev@peikarband.ir>"
|
||||||
LABEL description="Base image with Python, Node.js, bun, and build tools"
|
LABEL org.opencontainers.image.title="Peikarband Base"
|
||||||
|
LABEL org.opencontainers.image.description="Base image with Python, Node.js, bun, and build tools"
|
||||||
|
|
||||||
WORKDIR /build
|
WORKDIR /build
|
||||||
|
|
||||||
# Install build dependencies
|
# Install system dependencies
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
gcc \
|
gcc \
|
||||||
g++ \
|
g++ \
|
||||||
@@ -28,12 +27,19 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
gnupg \
|
gnupg \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
unzip \
|
unzip \
|
||||||
|
git \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Install Node.js (required for Reflex)
|
# Install Node.js
|
||||||
|
ARG NODE_VERSION
|
||||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||||
&& apt-get install -y --no-install-recommends nodejs \
|
&& apt-get install -y --no-install-recommends nodejs \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& 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)
|
# Install bun (required by Reflex for frontend build)
|
||||||
# Retry mechanism for network issues
|
# Retry mechanism for network issues
|
||||||
@@ -46,9 +52,19 @@ RUN set -ex && \
|
|||||||
# Add bun to PATH
|
# Add bun to PATH
|
||||||
ENV PATH="/root/.bun/bin:${PATH}"
|
ENV PATH="/root/.bun/bin:${PATH}"
|
||||||
|
|
||||||
|
# Upgrade pip, setuptools, wheel
|
||||||
|
RUN pip install --no-cache-dir --upgrade pip setuptools wheel
|
||||||
|
|
||||||
# Verify installations
|
# Verify installations
|
||||||
RUN python --version && \
|
RUN python --version && \
|
||||||
node --version && \
|
node --version && \
|
||||||
npm --version && \
|
npm --version && \
|
||||||
bun --version
|
bun --version && \
|
||||||
|
pip --version
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /build
|
||||||
|
|
||||||
|
# Default command
|
||||||
|
CMD ["/bin/bash"]
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ services:
|
|||||||
|
|
||||||
# Peikarband Application
|
# Peikarband Application
|
||||||
app:
|
app:
|
||||||
build: .
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
container_name: peikarband-app
|
container_name: peikarband-app
|
||||||
depends_on:
|
depends_on:
|
||||||
- postgres
|
- postgres
|
||||||
@@ -57,7 +59,9 @@ services:
|
|||||||
|
|
||||||
# Celery Worker
|
# Celery Worker
|
||||||
celery:
|
celery:
|
||||||
build: .
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
container_name: peikarband-celery
|
container_name: peikarband-celery
|
||||||
command: celery -A src.infrastructure.tasks.celery_app worker -l info
|
command: celery -A src.infrastructure.tasks.celery_app worker -l info
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -74,7 +78,9 @@ services:
|
|||||||
|
|
||||||
# Flower (Celery Monitoring)
|
# Flower (Celery Monitoring)
|
||||||
flower:
|
flower:
|
||||||
build: .
|
build:
|
||||||
|
context: ..
|
||||||
|
dockerfile: docker/Dockerfile
|
||||||
container_name: peikarband-flower
|
container_name: peikarband-flower
|
||||||
command: celery -A src.infrastructure.tasks.celery_app flower
|
command: celery -A src.infrastructure.tasks.celery_app flower
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
409
docs/BASE_IMAGE_MANAGEMENT.md
Normal file
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/)
|
||||||
|
|
||||||
586
docs/WOODPECKER_CI_CD.md
Normal file
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/)
|
||||||
|
|
||||||
257
helm/peikarband/argocd/README.md
Normal file
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/)
|
||||||
|
|
||||||
54
helm/peikarband/argocd/application-staging.yaml
Normal file
54
helm/peikarband/argocd/application-staging.yaml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: peikarband-landing-staging
|
||||||
|
namespace: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
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.tag
|
||||||
|
value: develop
|
||||||
|
- name: image.repository
|
||||||
|
value: hub.peikarband.ir/peikarband/landing
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: staging
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
allowEmpty: false
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- PrunePropagationPolicy=foreground
|
||||||
|
- PruneLast=true
|
||||||
|
retry:
|
||||||
|
limit: 5
|
||||||
|
backoff:
|
||||||
|
duration: 5s
|
||||||
|
factor: 2
|
||||||
|
maxDuration: 3m
|
||||||
|
|
||||||
|
revisionHistoryLimit: 10
|
||||||
|
|
||||||
|
# Health assessment
|
||||||
|
ignoreDifferences:
|
||||||
|
- group: apps
|
||||||
|
kind: Deployment
|
||||||
|
jsonPointers:
|
||||||
|
- /spec/replicas
|
||||||
|
|
||||||
54
helm/peikarband/argocd/application.yaml
Normal file
54
helm/peikarband/argocd/application.yaml
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: peikarband-landing-prod
|
||||||
|
namespace: argocd
|
||||||
|
finalizers:
|
||||||
|
- resources-finalizer.argocd.argoproj.io
|
||||||
|
spec:
|
||||||
|
project: default
|
||||||
|
|
||||||
|
source:
|
||||||
|
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.tag
|
||||||
|
value: latest
|
||||||
|
- name: image.repository
|
||||||
|
value: hub.peikarband.ir/peikarband/landing
|
||||||
|
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: production
|
||||||
|
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
allowEmpty: false
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- PrunePropagationPolicy=foreground
|
||||||
|
- PruneLast=true
|
||||||
|
retry:
|
||||||
|
limit: 5
|
||||||
|
backoff:
|
||||||
|
duration: 5s
|
||||||
|
factor: 2
|
||||||
|
maxDuration: 3m
|
||||||
|
|
||||||
|
revisionHistoryLimit: 10
|
||||||
|
|
||||||
|
# Health assessment
|
||||||
|
ignoreDifferences:
|
||||||
|
- group: apps
|
||||||
|
kind: Deployment
|
||||||
|
jsonPointers:
|
||||||
|
- /spec/replicas
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ import reflex as rx
|
|||||||
API_URL = os.getenv("API_URL", "http://localhost:8000")
|
API_URL = os.getenv("API_URL", "http://localhost:8000")
|
||||||
FRONTEND_PORT = int(os.getenv("FRONTEND_PORT", "3000"))
|
FRONTEND_PORT = int(os.getenv("FRONTEND_PORT", "3000"))
|
||||||
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
|
BACKEND_PORT = int(os.getenv("BACKEND_PORT", "8000"))
|
||||||
DB_URL = os.getenv("DATABASE_URL", "sqlite:///data/reflex.db")
|
DB_URL = os.getenv("DATABASE_URL", "sqlite:////app/data/reflex.db")
|
||||||
|
|
||||||
config = rx.Config(
|
config = rx.Config(
|
||||||
app_name="peikarband",
|
app_name="peikarband",
|
||||||
|
|||||||
Reference in New Issue
Block a user