Add Docker Compose with Caddy reverse proxy integration

- Multi-stage Dockerfile with development and production modes
- Docker Compose with caddy-docker-proxy labels for HTTPS
- Domain configuration: DOMAIN=rentcache.l.supported.systems
- Comprehensive Makefile with development and production targets
- Support for external caddy network and Redis backend
- Health checks and proper volume management
- Environment configuration with .env file

Usage:
- make setup  # Complete setup
- make dev    # Development with hot reload
- make prod   # Production deployment
- URL: https://rentcache.l.supported.systems
This commit is contained in:
Ryan Malloy 2025-09-09 20:13:37 -06:00
parent c0eaecad21
commit f46bdc978e
3 changed files with 210 additions and 147 deletions

68
Dockerfile Normal file
View File

@ -0,0 +1,68 @@
# Multi-stage Dockerfile for RentCache
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim AS base
# Set working directory
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/*
# Copy dependency files
COPY pyproject.toml uv.lock ./
# Install dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-install-project --no-dev
# Copy source code
COPY src/ ./src/
COPY README.md LICENSE ./
# Install the project
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-editable
# Development stage
FROM base AS development
# Install development dependencies
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-editable
# Create non-root user
RUN groupadd -r rentcache && useradd -r -g rentcache rentcache
RUN chown -R rentcache:rentcache /app
USER rentcache
# Create data directories
RUN mkdir -p /app/data /app/logs
EXPOSE 8000
# Development command with hot reload
CMD ["uv", "run", "rentcache", "server", "--host", "0.0.0.0", "--port", "8000", "--reload"]
# Production stage
FROM base AS production
# Create non-root user
RUN groupadd -r rentcache && useradd -r -g rentcache rentcache
RUN chown -R rentcache:rentcache /app
USER rentcache
# Create data directories
RUN mkdir -p /app/data /app/logs
# Compile bytecode for better performance
ENV UV_COMPILE_BYTECODE=1
EXPOSE 8000
# Health check
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
CMD curl -f http://localhost:8000/health || exit 1
# Production command
CMD ["uv", "run", "rentcache", "server", "--host", "0.0.0.0", "--port", "8000"]

236
Makefile
View File

@ -1,176 +1,118 @@
# RentCache Makefile # RentCache Makefile
.PHONY: help dev prod build up down logs shell test clean
.PHONY: help install dev test lint format clean server docs
# Default target # Default target
help: help: ## Show this help message
@echo "RentCache Development Commands" @echo "RentCache - Intelligent Rentcast API caching proxy"
@echo "=============================="
@echo "" @echo ""
@echo "Setup:" @echo "Available targets:"
@echo " install Install dependencies" @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@echo " dev Install dev dependencies"
@echo ""
@echo "Development:"
@echo " server Start development server"
@echo " test Run tests"
@echo " test-cov Run tests with coverage"
@echo " lint Run linting"
@echo " format Format code"
@echo ""
@echo "Database:"
@echo " db-init Initialize database"
@echo " db-reset Reset database"
@echo ""
@echo "Utilities:"
@echo " clean Clean temporary files"
@echo " docs Generate documentation"
@echo " check Run all checks (lint, test, format)"
# Installation # Development
install: dev: ## Start development environment with hot reload
uv sync @echo "🚀 Starting RentCache in development mode..."
@docker compose --profile redis up --build -d
@echo "✅ RentCache available at: https://rentcache.l.supported.systems"
@echo "📚 API docs: https://rentcache.l.supported.systems/docs"
@echo "❤️ Health: https://rentcache.l.supported.systems/health"
dev: prod: ## Start production environment
uv sync --all-extras @echo "🏭 Starting RentCache in production mode..."
@MODE=production DEBUG=false docker compose up --build -d
@echo "✅ RentCache running in production mode"
# Development server # Docker management
server: build: ## Build Docker images
uv run rentcache server --reload @docker compose build
# Testing up: ## Start services
test: @docker compose up -d
uv run pytest -v
test-cov: down: ## Stop services
uv run pytest --cov=src/rentcache --cov-report=html --cov-report=term @docker compose down
test-watch: logs: ## View logs
uv run pytest-watch --runner "uv run pytest" @docker compose logs -f rentcache
# Code quality shell: ## Open shell in running container
lint: @docker compose exec rentcache /bin/bash
uv run ruff check src tests
uv run mypy src
format: # Testing and development
uv run black src tests test: ## Run tests
uv run ruff check src tests --fix @echo "🧪 Running tests..."
@uv run pytest tests/ -v
check: lint test test-cov: ## Run tests with coverage
@echo "✅ All checks passed!" @echo "🧪 Running tests with coverage..."
@uv run pytest tests/ --cov=src/rentcache --cov-report=html
# Database management lint: ## Run linting
db-init: @echo "🔍 Running linting..."
uv run python -c "import asyncio; from rentcache.models import Base; from sqlalchemy.ext.asyncio import create_async_engine; asyncio.run(create_async_engine('sqlite+aiosqlite:///./rentcache.db').begin().__aenter__().run_sync(Base.metadata.create_all))" @uv run ruff check src/ tests/
@uv run mypy src/
db-reset: format: ## Format code
rm -f rentcache.db @echo "✨ Formatting code..."
$(MAKE) db-init @uv run black src/ tests/
@uv run ruff --fix src/ tests/
# CLI shortcuts # Database and cache
create-key: db-shell: ## Open database shell
@read -p "Key name: " name; \ @echo "🗄️ Opening database shell..."
read -p "Rentcast API key: " key; \ @docker compose exec rentcache uv run python -c "from rentcache.database import engine; import sqlite3; sqlite3.connect('data/rentcache.db').execute('.tables')"
uv run rentcache create-key "$$name" "$$key"
list-keys: cache-clear: ## Clear all cache
uv run rentcache list-keys @echo "🧹 Clearing cache..."
@docker compose exec rentcache uv run rentcache clear-cache --all
stats: health: ## Check system health
uv run rentcache stats @echo "❤️ Checking health..."
@docker compose exec rentcache uv run rentcache health
health: stats: ## Show usage statistics
uv run rentcache health @echo "📊 Usage statistics..."
@docker compose exec rentcache uv run rentcache stats
# Cleanup # Cleanup
clean: clean: ## Clean up containers, volumes, and images
find . -type d -name __pycache__ -delete @echo "🧹 Cleaning up..."
find . -type f -name "*.pyc" -delete @docker compose down -v --remove-orphans
find . -type d -name "*.egg-info" -exec rm -rf {} + @docker system prune -f
rm -rf .coverage
rm -rf htmlcov/
rm -rf reports/
rm -rf build/
rm -rf dist/
# Documentation clean-all: clean ## Clean everything including images
docs: @docker compose down -v --rmi all --remove-orphans
@echo "📚 API documentation available at:" @docker system prune -af
@echo " http://localhost:8000/docs (when server is running)"
@echo " http://localhost:8000/redoc (alternative docs)"
# Docker commands # API key management
docker-build: create-key: ## Create API key (usage: make create-key NAME=myapp KEY=your_key)
docker build -t rentcache . @docker compose exec rentcache uv run rentcache create-key $(NAME) $(KEY) --daily-limit 1000
docker-run: list-keys: ## List all API keys
docker run -p 8000:8000 --env-file .env rentcache @docker compose exec rentcache uv run rentcache list-keys
docker-dev: # Install local development
docker-compose up -d install: ## Install for local development
@echo "📦 Installing dependencies..."
@uv sync
@echo "✅ Ready for development"
docker-logs: local-dev: install ## Run locally for development
docker-compose logs -f rentcache @echo "🖥️ Starting local development server..."
@uv run rentcache server --reload
docker-stop: # URL helpers
docker-compose down url: ## Show the service URL
@echo "🌐 RentCache URL: https://rentcache.l.supported.systems"
# Production deployment helpers docs: ## Open API documentation
deploy-check: @echo "📚 API Documentation: https://rentcache.l.supported.systems/docs"
@echo "🚀 Pre-deployment checklist:"
@echo " - [ ] Tests passing"
@echo " - [ ] Environment variables configured"
@echo " - [ ] Database migrations ready"
@echo " - [ ] SSL certificates configured"
@echo " - [ ] Monitoring setup"
@echo " - [ ] Backup strategy in place"
# Performance testing # Quick setup
perf-test: setup: ## Complete setup (build, create network if needed, start)
@echo "⚡ Running performance tests..." @echo "🚀 Setting up RentCache..."
uv run python -m pytest tests/ -m performance -v @docker network create caddy 2>/dev/null || true
@make build
benchmark: @make dev
@echo "📊 Running benchmarks..." @echo ""
# Add your benchmark commands here @echo "🎉 RentCache is ready!"
@make url
# Development environment
env-copy:
cp .env.example .env
@echo "📝 .env file created from example. Please edit with your settings."
setup: install env-copy db-init
@echo "🎉 Setup complete! Run 'make server' to start development."
# Release helpers
version:
@echo "Current version: $$(grep version pyproject.toml | head -1 | cut -d'"' -f2)"
bump-version:
@read -p "New version: " version; \
sed -i "s/version = .*/version = \"$$version\"/" pyproject.toml; \
echo "Version bumped to $$version"
build:
uv build
publish:
uv publish
# Monitoring and debugging
logs:
tail -f rentcache.log
monitor:
watch -n 1 "curl -s http://localhost:8000/metrics | jq '.'"
debug-server:
uv run python -m debugpy --listen 5678 --wait-for-client -m rentcache.server
# Quick shortcuts for common operations
s: server
t: test
f: format
l: lint
c: clean

53
docker-compose.yml Normal file
View File

@ -0,0 +1,53 @@
services:
rentcache:
build:
context: .
dockerfile: Dockerfile
target: ${MODE:-production}
environment:
- HOST=0.0.0.0
- PORT=8000
- DATABASE_URL=sqlite+aiosqlite:///./data/rentcache.db
- DEBUG=${DEBUG:-false}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
volumes:
- ./data:/app/data
- ./logs:/app/logs
# Development hot-reload
- ./src:/app/src:ro
networks:
- caddy
expose:
- "8000"
labels:
caddy: ${DOMAIN:-rentcache.l.supported.systems}
caddy.reverse_proxy: "{{upstreams}}"
caddy.header.X-Forwarded-Proto: https
caddy.header.X-Real-IP: "{remote_host}"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
# Optional Redis for caching
redis:
image: redis:7-alpine
networks:
- caddy
volumes:
- redis_data:/data
command: redis-server --appendonly yes
profiles:
- redis
restart: unless-stopped
networks:
caddy:
external: true
volumes:
redis_data:
driver: local