# Dockerfile - Peikarband Landing Application # Optimized multi-stage build using base image # Build arguments ARG BASE_IMAGE=hub.peikarband.ir/peikarband/landing:base ARG VERSION=latest ARG BUILD_DATE # ============================================ # Stage 1: Builder (using base image) # ============================================ FROM ${BASE_IMAGE} AS builder LABEL stage=builder LABEL maintainer="Peikarband DevOps " 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 to /build/peikarband/ to preserve package structure # This ensures peikarband.peikarband module can be found by Reflex COPY peikarband/ /build/peikarband/ # Set PYTHONPATH to include /build (for peikarband package) and /build/peikarband (for src imports) # This allows both peikarband.peikarband and src.* imports to work ENV PYTHONPATH=/build:/build/peikarband # Verify that peikarband.peikarband can be imported before running reflex # This helps catch import errors early # RUN cd /build && \ # python3 -c "from peikarband.peikarband import app; print('✅ peikarband.peikarband.app imported successfully')" && \ # echo "Import test passed" # Initialize Reflex and build frontend from peikarband directory # Reflex needs to run from the directory containing rxconfig.py RUN cd /build/peikarband && \ reflex init --loglevel debug || true && \ reflex export --frontend-only --no-zip --loglevel debug || echo "Export completed with warnings" # Note: reflex export already builds and installs everything needed # No additional npm install is required RUN echo "Frontend built by reflex export" # ============================================ # Stage 2: Runtime (using base image for Node.js) # ============================================ FROM ${BASE_IMAGE} AS runtime # Re-declare build arguments for this stage ARG BASE_IMAGE=hub.peikarband.ir/peikarband/landing:base ARG VERSION=latest ARG BUILD_DATE ARG GIT_COMMIT ARG GIT_BRANCH ARG BUILD_NUMBER 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 # Note: We keep WORKDIR=/app (not /app/peikarband) to avoid Python importing # /app/peikarband/peikarband/ as the peikarband package incorrectly # The entrypoint script will cd to /app/peikarband before running reflex # 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 to /app/peikarband/ to create peikarband.peikarband structure # With app_name="peikarband", Reflex expects to find peikarband.peikarband module COPY --from=builder --chown=peikarband:peikarband /build/peikarband /app/peikarband # Copy entrypoint script COPY docker/entrypoint.sh /usr/local/bin/entrypoint.sh RUN chmod +x /usr/local/bin/entrypoint.sh # 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 # PYTHONPATH includes both /app and /app/peikarband # - /app: allows importing peikarband from /app/peikarband/ # - /app/peikarband: allows importing src from /app/peikarband/src/ # This makes both peikarband.peikarband and src.* imports work correctly # REFLEX_DIR points to the directory containing rxconfig.py ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONPATH=/app:/app/peikarband \ PATH="/app/.venv/bin:$PATH" \ REFLEX_DIR=/app/peikarband \ 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", "--", "/usr/local/bin/entrypoint.sh"] # Start application # entrypoint.sh will cd to /app/peikarband and run reflex # PYTHONPATH=/app:/app/peikarband allows Python to find both peikarband and peikarband.peikarband CMD ["run", "--env", "prod", "--loglevel", "info", "--frontend-port", "3000", "--backend-port", "8000"] # ============================================ # Build Information # ============================================ # ARG declarations are already done above in runtime stage 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 .