From f46bdc978e7caf36bae9c892b6ffdb8eee8b64ec Mon Sep 17 00:00:00 2001 From: Ryan Malloy Date: Tue, 9 Sep 2025 20:13:37 -0600 Subject: [PATCH] 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 --- Dockerfile | 68 +++++++++++++ Makefile | 236 +++++++++++++++++---------------------------- docker-compose.yml | 53 ++++++++++ 3 files changed, 210 insertions(+), 147 deletions(-) create mode 100644 Dockerfile create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..bcae70d --- /dev/null +++ b/Dockerfile @@ -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"] \ No newline at end of file diff --git a/Makefile b/Makefile index 096af6b..4a52c64 100644 --- a/Makefile +++ b/Makefile @@ -1,176 +1,118 @@ # RentCache Makefile - -.PHONY: help install dev test lint format clean server docs +.PHONY: help dev prod build up down logs shell test clean # Default target -help: - @echo "RentCache Development Commands" - @echo "==============================" +help: ## Show this help message + @echo "RentCache - Intelligent Rentcast API caching proxy" @echo "" - @echo "Setup:" - @echo " install Install dependencies" - @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)" + @echo "Available targets:" + @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) -# Installation -install: - uv sync +# Development +dev: ## Start development environment with hot reload + @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: - uv sync --all-extras +prod: ## Start production environment + @echo "๐Ÿญ Starting RentCache in production mode..." + @MODE=production DEBUG=false docker compose up --build -d + @echo "โœ… RentCache running in production mode" -# Development server -server: - uv run rentcache server --reload +# Docker management +build: ## Build Docker images + @docker compose build -# Testing -test: - uv run pytest -v +up: ## Start services + @docker compose up -d -test-cov: - uv run pytest --cov=src/rentcache --cov-report=html --cov-report=term +down: ## Stop services + @docker compose down -test-watch: - uv run pytest-watch --runner "uv run pytest" +logs: ## View logs + @docker compose logs -f rentcache -# Code quality -lint: - uv run ruff check src tests - uv run mypy src +shell: ## Open shell in running container + @docker compose exec rentcache /bin/bash -format: - uv run black src tests - uv run ruff check src tests --fix +# Testing and development +test: ## Run tests + @echo "๐Ÿงช Running tests..." + @uv run pytest tests/ -v -check: lint test - @echo "โœ… All checks passed!" +test-cov: ## Run tests with coverage + @echo "๐Ÿงช Running tests with coverage..." + @uv run pytest tests/ --cov=src/rentcache --cov-report=html -# Database management -db-init: - 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))" +lint: ## Run linting + @echo "๐Ÿ” Running linting..." + @uv run ruff check src/ tests/ + @uv run mypy src/ -db-reset: - rm -f rentcache.db - $(MAKE) db-init +format: ## Format code + @echo "โœจ Formatting code..." + @uv run black src/ tests/ + @uv run ruff --fix src/ tests/ -# CLI shortcuts -create-key: - @read -p "Key name: " name; \ - read -p "Rentcast API key: " key; \ - uv run rentcache create-key "$$name" "$$key" +# Database and cache +db-shell: ## Open database shell + @echo "๐Ÿ—„๏ธ Opening database shell..." + @docker compose exec rentcache uv run python -c "from rentcache.database import engine; import sqlite3; sqlite3.connect('data/rentcache.db').execute('.tables')" -list-keys: - uv run rentcache list-keys +cache-clear: ## Clear all cache + @echo "๐Ÿงน Clearing cache..." + @docker compose exec rentcache uv run rentcache clear-cache --all -stats: - uv run rentcache stats +health: ## Check system health + @echo "โค๏ธ Checking health..." + @docker compose exec rentcache uv run rentcache health -health: - uv run rentcache health +stats: ## Show usage statistics + @echo "๐Ÿ“Š Usage statistics..." + @docker compose exec rentcache uv run rentcache stats # Cleanup -clean: - find . -type d -name __pycache__ -delete - find . -type f -name "*.pyc" -delete - find . -type d -name "*.egg-info" -exec rm -rf {} + - rm -rf .coverage - rm -rf htmlcov/ - rm -rf reports/ - rm -rf build/ - rm -rf dist/ +clean: ## Clean up containers, volumes, and images + @echo "๐Ÿงน Cleaning up..." + @docker compose down -v --remove-orphans + @docker system prune -f -# Documentation -docs: - @echo "๐Ÿ“š API documentation available at:" - @echo " http://localhost:8000/docs (when server is running)" - @echo " http://localhost:8000/redoc (alternative docs)" +clean-all: clean ## Clean everything including images + @docker compose down -v --rmi all --remove-orphans + @docker system prune -af -# Docker commands -docker-build: - docker build -t rentcache . +# API key management +create-key: ## Create API key (usage: make create-key NAME=myapp KEY=your_key) + @docker compose exec rentcache uv run rentcache create-key $(NAME) $(KEY) --daily-limit 1000 -docker-run: - docker run -p 8000:8000 --env-file .env rentcache +list-keys: ## List all API keys + @docker compose exec rentcache uv run rentcache list-keys -docker-dev: - docker-compose up -d +# Install local development +install: ## Install for local development + @echo "๐Ÿ“ฆ Installing dependencies..." + @uv sync + @echo "โœ… Ready for development" -docker-logs: - docker-compose logs -f rentcache +local-dev: install ## Run locally for development + @echo "๐Ÿ–ฅ๏ธ Starting local development server..." + @uv run rentcache server --reload -docker-stop: - docker-compose down +# URL helpers +url: ## Show the service URL + @echo "๐ŸŒ RentCache URL: https://rentcache.l.supported.systems" -# Production deployment helpers -deploy-check: - @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" +docs: ## Open API documentation + @echo "๐Ÿ“š API Documentation: https://rentcache.l.supported.systems/docs" -# Performance testing -perf-test: - @echo "โšก Running performance tests..." - uv run python -m pytest tests/ -m performance -v - -benchmark: - @echo "๐Ÿ“Š Running benchmarks..." - # Add your benchmark commands here - -# 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 \ No newline at end of file +# Quick setup +setup: ## Complete setup (build, create network if needed, start) + @echo "๐Ÿš€ Setting up RentCache..." + @docker network create caddy 2>/dev/null || true + @make build + @make dev + @echo "" + @echo "๐ŸŽ‰ RentCache is ready!" + @make url \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..1c485fd --- /dev/null +++ b/docker-compose.yml @@ -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 \ No newline at end of file