optimize for rpi
This commit is contained in:
@@ -17,27 +17,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
# Set working directory
|
# Set working directory
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Create minimal requirements inline to ensure we use Pydantic v1
|
# Install Python dependencies directly
|
||||||
# which doesn't require Rust compilation
|
# Using Pydantic v1 which doesn't require Rust compilation
|
||||||
RUN cat > requirements.txt << 'EOF'
|
RUN pip install --no-cache-dir \
|
||||||
# Minimal requirements - no compilation needed
|
fastapi==0.95.2 \
|
||||||
# Using Pydantic v1 which is pure Python (no Rust required)
|
pydantic==1.10.9 \
|
||||||
fastapi==0.95.2
|
uvicorn==0.22.0 \
|
||||||
pydantic==1.10.9
|
httpx==0.24.1 \
|
||||||
uvicorn==0.22.0
|
icalendar==5.0.7 \
|
||||||
httpx==0.24.1
|
jinja2==3.1.2 \
|
||||||
icalendar==5.0.7
|
apscheduler==3.10.1 \
|
||||||
jinja2==3.1.2
|
pytz==2023.3 \
|
||||||
apscheduler==3.10.1
|
python-multipart==0.0.6 \
|
||||||
pytz==2023.3
|
starlette==0.27.0 \
|
||||||
python-multipart==0.0.6
|
typing-extensions==4.6.3 \
|
||||||
starlette==0.27.0
|
python-dateutil==2.8.2
|
||||||
typing-extensions==4.6.3
|
|
||||||
python-dateutil==2.8.2
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Install Python dependencies - all pure Python or pre-built wheels
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
|
||||||
|
|
||||||
# Copy application files
|
# Copy application files
|
||||||
COPY main.py .
|
COPY main.py .
|
||||||
|
|||||||
46
Dockerfile.pizero
Normal file
46
Dockerfile.pizero
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
# Optimized Dockerfile for Raspberry Pi Zero (ARMv6)
|
||||||
|
# Minimal memory footprint and no compilation required
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
# Set environment variables
|
||||||
|
ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
TZ=Europe/Berlin \
|
||||||
|
PIP_NO_CACHE_DIR=1 \
|
||||||
|
PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||||
|
|
||||||
|
# Install only essential runtime dependencies
|
||||||
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
|
tzdata \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& ln -snf /usr/share/zoneinfo/$TZ /etc/localtime \
|
||||||
|
&& echo $TZ > /etc/timezone
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install Python dependencies one by one for better memory management on Pi Zero
|
||||||
|
# Using older stable versions that are known to work on ARMv6
|
||||||
|
RUN pip install --no-cache-dir fastapi==0.95.2
|
||||||
|
RUN pip install --no-cache-dir pydantic==1.10.9
|
||||||
|
RUN pip install --no-cache-dir uvicorn==0.22.0
|
||||||
|
RUN pip install --no-cache-dir httpx==0.24.1
|
||||||
|
RUN pip install --no-cache-dir icalendar==5.0.7
|
||||||
|
RUN pip install --no-cache-dir jinja2==3.1.2
|
||||||
|
RUN pip install --no-cache-dir apscheduler==3.10.1
|
||||||
|
RUN pip install --no-cache-dir pytz==2023.3
|
||||||
|
RUN pip install --no-cache-dir python-multipart==0.0.6
|
||||||
|
|
||||||
|
# Copy application files
|
||||||
|
COPY main.py .
|
||||||
|
COPY Vektor-Logo.svg ./
|
||||||
|
|
||||||
|
# Create static directory and copy logo
|
||||||
|
RUN mkdir -p static && \
|
||||||
|
cp Vektor-Logo.svg static/logo.svg
|
||||||
|
|
||||||
|
# Expose port
|
||||||
|
EXPOSE 8000
|
||||||
|
|
||||||
|
# Run with limited workers and basic asyncio loop for Pi Zero
|
||||||
|
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1", "--loop", "asyncio"]
|
||||||
257
build-pi.sh
Executable file
257
build-pi.sh
Executable file
@@ -0,0 +1,257 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Build script for Raspberry Pi Zero/ARM devices
|
||||||
|
# Optimized for low memory and no compilation
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
IMAGE_NAME="turmli-calendar"
|
||||||
|
CONTAINER_NAME="turmli-calendar"
|
||||||
|
|
||||||
|
# Print functions
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}❌ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_success() {
|
||||||
|
echo -e "${GREEN}✅ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_info() {
|
||||||
|
echo -e "${BLUE}ℹ️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}⚠️ $1${NC}"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect system
|
||||||
|
detect_system() {
|
||||||
|
ARCH=$(uname -m)
|
||||||
|
OS=$(cat /etc/os-release | grep "^ID=" | cut -d= -f2 | tr -d '"')
|
||||||
|
VERSION=$(cat /etc/os-release | grep "^VERSION_CODENAME=" | cut -d= -f2 | tr -d '"')
|
||||||
|
|
||||||
|
print_info "System: ${OS} ${VERSION} on ${ARCH}"
|
||||||
|
|
||||||
|
# Check if we're on a Raspberry Pi
|
||||||
|
if [ -f /proc/device-tree/model ]; then
|
||||||
|
MODEL=$(tr -d '\0' < /proc/device-tree/model)
|
||||||
|
print_info "Raspberry Pi detected: ${MODEL}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check available memory
|
||||||
|
if [ -f /proc/meminfo ]; then
|
||||||
|
TOTAL_MEM=$(grep MemTotal /proc/meminfo | awk '{print $2}')
|
||||||
|
TOTAL_MEM_MB=$((TOTAL_MEM / 1024))
|
||||||
|
print_info "Available RAM: ${TOTAL_MEM_MB}MB"
|
||||||
|
|
||||||
|
if [ $TOTAL_MEM_MB -lt 512 ]; then
|
||||||
|
print_warning "Low memory detected! Build may be slow."
|
||||||
|
print_info "Tip: Consider adding swap space if build fails"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for container runtime
|
||||||
|
check_runtime() {
|
||||||
|
if command -v podman &> /dev/null; then
|
||||||
|
RUNTIME="podman"
|
||||||
|
print_success "Using Podman"
|
||||||
|
elif command -v docker &> /dev/null; then
|
||||||
|
RUNTIME="docker"
|
||||||
|
print_success "Using Docker"
|
||||||
|
else
|
||||||
|
print_error "No container runtime found!"
|
||||||
|
print_info "Install Podman (recommended) or Docker:"
|
||||||
|
echo " sudo apt-get update"
|
||||||
|
echo " sudo apt-get install podman"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build the container
|
||||||
|
build_container() {
|
||||||
|
print_info "Building container image..."
|
||||||
|
|
||||||
|
# Choose the right Dockerfile
|
||||||
|
if [ -f "Dockerfile.pizero" ] && [[ "$ARCH" == "armv6l" ]]; then
|
||||||
|
DOCKERFILE="Dockerfile.pizero"
|
||||||
|
print_info "Using Pi Zero optimized Dockerfile"
|
||||||
|
elif [ -f "Dockerfile.minimal" ]; then
|
||||||
|
DOCKERFILE="Dockerfile.minimal"
|
||||||
|
print_info "Using minimal Dockerfile (no compilation)"
|
||||||
|
elif [ -f "Dockerfile" ]; then
|
||||||
|
DOCKERFILE="Dockerfile"
|
||||||
|
print_warning "Using standard Dockerfile (may require compilation)"
|
||||||
|
else
|
||||||
|
print_error "No Dockerfile found!"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build with memory limits for Pi Zero
|
||||||
|
if [[ "$ARCH" == "armv6l" ]] && [ $TOTAL_MEM_MB -lt 512 ]; then
|
||||||
|
print_warning "Building with memory constraints..."
|
||||||
|
${RUNTIME} build \
|
||||||
|
--memory-swap -1 \
|
||||||
|
--file "${DOCKERFILE}" \
|
||||||
|
--tag "${IMAGE_NAME}" \
|
||||||
|
. || {
|
||||||
|
print_error "Build failed!"
|
||||||
|
print_info "Try these solutions:"
|
||||||
|
echo " 1. Add swap space:"
|
||||||
|
echo " sudo dd if=/dev/zero of=/swapfile bs=1M count=1024"
|
||||||
|
echo " sudo mkswap /swapfile"
|
||||||
|
echo " sudo swapon /swapfile"
|
||||||
|
echo " 2. Use pre-built image:"
|
||||||
|
echo " ${RUNTIME} pull docker.io/yourusername/turmli-calendar:armv6"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
${RUNTIME} build \
|
||||||
|
--file "${DOCKERFILE}" \
|
||||||
|
--tag "${IMAGE_NAME}" \
|
||||||
|
. || {
|
||||||
|
print_error "Build failed!"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Container image built successfully!"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run the container
|
||||||
|
run_container() {
|
||||||
|
print_info "Starting container..."
|
||||||
|
|
||||||
|
# Check if container already exists
|
||||||
|
if ${RUNTIME} ps -a --format '{{.Names}}' | grep -q "^${CONTAINER_NAME}$"; then
|
||||||
|
print_info "Container already exists, removing it..."
|
||||||
|
${RUNTIME} stop ${CONTAINER_NAME} 2>/dev/null || true
|
||||||
|
${RUNTIME} rm ${CONTAINER_NAME} 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create cache file if it doesn't exist
|
||||||
|
if [ ! -f "calendar_cache.json" ]; then
|
||||||
|
echo "{}" > calendar_cache.json
|
||||||
|
print_info "Created cache file"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run with appropriate resource limits for Pi
|
||||||
|
if [[ "$ARCH" == "armv6l" ]] && [ $TOTAL_MEM_MB -lt 512 ]; then
|
||||||
|
print_info "Running with memory constraints..."
|
||||||
|
${RUNTIME} run -d \
|
||||||
|
--name ${CONTAINER_NAME} \
|
||||||
|
--memory 256m \
|
||||||
|
--memory-swap -1 \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-v $(pwd)/calendar_cache.json:/app/calendar_cache.json:Z \
|
||||||
|
-e TZ=Europe/Berlin \
|
||||||
|
--restart unless-stopped \
|
||||||
|
${IMAGE_NAME}
|
||||||
|
else
|
||||||
|
${RUNTIME} run -d \
|
||||||
|
--name ${CONTAINER_NAME} \
|
||||||
|
-p 8000:8000 \
|
||||||
|
-v $(pwd)/calendar_cache.json:/app/calendar_cache.json:Z \
|
||||||
|
-e TZ=Europe/Berlin \
|
||||||
|
--restart unless-stopped \
|
||||||
|
${IMAGE_NAME}
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_success "Container started!"
|
||||||
|
print_info "Access the calendar at: http://$(hostname -I | awk '{print $1}'):8000"
|
||||||
|
print_info "or http://localhost:8000"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check container status
|
||||||
|
check_status() {
|
||||||
|
print_info "Checking container status..."
|
||||||
|
|
||||||
|
if ${RUNTIME} ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -q ${CONTAINER_NAME}; then
|
||||||
|
${RUNTIME} ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "NAMES|${CONTAINER_NAME}"
|
||||||
|
|
||||||
|
# Test if the app is responding
|
||||||
|
print_info "Testing application..."
|
||||||
|
sleep 3
|
||||||
|
if curl -s -f http://localhost:8000/api/events > /dev/null 2>&1; then
|
||||||
|
print_success "Application is running and healthy!"
|
||||||
|
else
|
||||||
|
print_warning "Application not responding yet, checking logs..."
|
||||||
|
${RUNTIME} logs --tail 20 ${CONTAINER_NAME}
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "Container is not running"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show logs
|
||||||
|
show_logs() {
|
||||||
|
${RUNTIME} logs -f ${CONTAINER_NAME}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main script
|
||||||
|
case "${1:-build}" in
|
||||||
|
build)
|
||||||
|
detect_system
|
||||||
|
check_runtime
|
||||||
|
build_container
|
||||||
|
;;
|
||||||
|
run)
|
||||||
|
detect_system
|
||||||
|
check_runtime
|
||||||
|
run_container
|
||||||
|
check_status
|
||||||
|
;;
|
||||||
|
start)
|
||||||
|
detect_system
|
||||||
|
check_runtime
|
||||||
|
build_container
|
||||||
|
run_container
|
||||||
|
check_status
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
check_runtime
|
||||||
|
check_status
|
||||||
|
;;
|
||||||
|
logs)
|
||||||
|
check_runtime
|
||||||
|
show_logs
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
check_runtime
|
||||||
|
print_info "Stopping container..."
|
||||||
|
${RUNTIME} stop ${CONTAINER_NAME}
|
||||||
|
print_success "Container stopped"
|
||||||
|
;;
|
||||||
|
help)
|
||||||
|
echo "Raspberry Pi Build Script for Turmli Calendar"
|
||||||
|
echo ""
|
||||||
|
echo "Usage: $0 [COMMAND]"
|
||||||
|
echo ""
|
||||||
|
echo "Commands:"
|
||||||
|
echo " build - Build the container image (default)"
|
||||||
|
echo " run - Run the container"
|
||||||
|
echo " start - Build and run"
|
||||||
|
echo " status - Check container status"
|
||||||
|
echo " logs - Show container logs"
|
||||||
|
echo " stop - Stop the container"
|
||||||
|
echo " help - Show this help"
|
||||||
|
echo ""
|
||||||
|
echo "This script is optimized for Raspberry Pi Zero and other"
|
||||||
|
echo "low-resource ARM devices. It uses Pydantic v1 to avoid"
|
||||||
|
echo "Rust compilation requirements."
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown command: $1"
|
||||||
|
echo "Run '$0 help' for usage"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
25
requirements-pizero.txt
Normal file
25
requirements-pizero.txt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# Requirements for Raspberry Pi Zero (ARMv6)
|
||||||
|
# All pure Python packages - NO compilation required
|
||||||
|
# Uses Pydantic v1 to avoid Rust dependency
|
||||||
|
|
||||||
|
fastapi==0.95.2
|
||||||
|
pydantic==1.10.9
|
||||||
|
uvicorn==0.22.0
|
||||||
|
httpx==0.24.1
|
||||||
|
icalendar==5.0.7
|
||||||
|
jinja2==3.1.2
|
||||||
|
apscheduler==3.10.1
|
||||||
|
pytz==2023.3
|
||||||
|
python-multipart==0.0.6
|
||||||
|
|
||||||
|
# These will be installed as dependencies but listing for clarity:
|
||||||
|
# starlette==0.27.0
|
||||||
|
# typing-extensions==4.6.3
|
||||||
|
# python-dateutil==2.8.2
|
||||||
|
# six==1.16.0
|
||||||
|
# h11==0.14.0
|
||||||
|
# click==8.1.3
|
||||||
|
# anyio==3.7.0
|
||||||
|
# sniffio==1.3.0
|
||||||
|
# certifi
|
||||||
|
# idna
|
||||||
Reference in New Issue
Block a user