ming commited on
Commit
2043365
Β·
1 Parent(s): cff42a2

feat: add Docker containerization with Ollama integration

Browse files

- Add multi-stage Dockerfile with security best practices
- Add docker-compose.yml for full stack deployment
- Add docker-compose.dev.yml for development with hot reload
- Add nginx.conf for production reverse proxy with rate limiting
- Add .dockerignore for optimized builds
- Add setup-ollama.sh script for model management
- Add run-tests.sh script for Docker-based testing
- Update README with comprehensive Docker deployment guide

Dockerfile ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Use Python 3.7 slim image for compatibility
2
+ FROM python:3.7-slim
3
+
4
+ # Set environment variables
5
+ ENV PYTHONDONTWRITEBYTECODE=1 \
6
+ PYTHONUNBUFFERED=1 \
7
+ PYTHONPATH=/app
8
+
9
+ # Set work directory
10
+ WORKDIR /app
11
+
12
+ # Install system dependencies
13
+ RUN apt-get update \
14
+ && apt-get install -y --no-install-recommends \
15
+ curl \
16
+ ca-certificates \
17
+ && rm -rf /var/lib/apt/lists/*
18
+
19
+ # Copy requirements first for better caching
20
+ COPY requirements.txt .
21
+
22
+ # Install Python dependencies
23
+ RUN pip install --no-cache-dir --upgrade pip \
24
+ && pip install --no-cache-dir -r requirements.txt
25
+
26
+ # Copy application code
27
+ COPY app/ ./app/
28
+ COPY pytest.ini .
29
+
30
+ # Create non-root user for security
31
+ RUN groupadd -r appuser && useradd -r -g appuser appuser \
32
+ && chown -R appuser:appuser /app
33
+ USER appuser
34
+
35
+ # Expose port
36
+ EXPOSE 8000
37
+
38
+ # Health check
39
+ HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
40
+ CMD curl -f http://localhost:8000/health || exit 1
41
+
42
+ # Run the application
43
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
README.md CHANGED
@@ -202,12 +202,15 @@ client.newCall(request).execute().use { response ->
202
  ### Running Tests
203
 
204
  ```bash
205
- # Run all tests
206
  pytest
207
 
208
  # Run with coverage
209
  pytest --cov=app --cov-report=html --cov-report=term
210
 
 
 
 
211
  # Run specific test file
212
  pytest tests/test_api.py -v
213
 
@@ -255,15 +258,46 @@ tests/
255
 
256
  ## Docker Deployment
257
 
258
- ### Local Development with Docker
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
259
 
260
  ```bash
261
- # Build and run with docker-compose
262
- docker-compose up --build
 
 
 
 
 
 
 
 
 
 
263
 
264
- # Or build manually
 
265
  docker build -t summarizer-backend .
266
- docker run -p 8000:8000 summarizer-backend
 
 
 
 
267
  ```
268
 
269
  ### Production Deployment
 
202
  ### Running Tests
203
 
204
  ```bash
205
+ # Run all tests locally
206
  pytest
207
 
208
  # Run with coverage
209
  pytest --cov=app --cov-report=html --cov-report=term
210
 
211
+ # Run tests in Docker
212
+ ./scripts/run-tests.sh
213
+
214
  # Run specific test file
215
  pytest tests/test_api.py -v
216
 
 
258
 
259
  ## Docker Deployment
260
 
261
+ ### Quick Start with Docker
262
+
263
+ ```bash
264
+ # 1. Start Ollama service
265
+ docker-compose up ollama -d
266
+
267
+ # 2. Download a model (first time only)
268
+ ./scripts/setup-ollama.sh llama3.1:8b
269
+
270
+ # 3. Start the API
271
+ docker-compose up api -d
272
+
273
+ # 4. Test the setup
274
+ curl http://localhost:8000/health
275
+ ```
276
+
277
+ ### Development with Hot Reload
278
 
279
  ```bash
280
+ # Use development compose file
281
+ docker-compose -f docker-compose.dev.yml up --build
282
+ ```
283
+
284
+ ### Production with Nginx
285
+
286
+ ```bash
287
+ # Start with Nginx reverse proxy
288
+ docker-compose --profile production up --build
289
+ ```
290
+
291
+ ### Manual Build
292
 
293
+ ```bash
294
+ # Build the image
295
  docker build -t summarizer-backend .
296
+
297
+ # Run with Ollama
298
+ docker run -p 8000:8000 \
299
+ -e OLLAMA_HOST=http://host.docker.internal:11434 \
300
+ summarizer-backend
301
  ```
302
 
303
  ### Production Deployment
docker-compose.dev.yml ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ # Development version with hot reload
5
+ api-dev:
6
+ build: .
7
+ container_name: summarizer-api-dev
8
+ ports:
9
+ - "8000:8000"
10
+ environment:
11
+ - OLLAMA_HOST=http://ollama:11434
12
+ - OLLAMA_MODEL=llama3.1:8b
13
+ - OLLAMA_TIMEOUT=30
14
+ - SERVER_HOST=0.0.0.0
15
+ - SERVER_PORT=8000
16
+ - LOG_LEVEL=DEBUG
17
+ volumes:
18
+ - ./app:/app/app:ro
19
+ command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
20
+ depends_on:
21
+ - ollama
22
+ restart: unless-stopped
23
+
24
+ # Ollama service (same as production)
25
+ ollama:
26
+ image: ollama/ollama:latest
27
+ container_name: summarizer-ollama-dev
28
+ ports:
29
+ - "11434:11434"
30
+ volumes:
31
+ - ollama_data_dev:/root/.ollama
32
+ environment:
33
+ - OLLAMA_HOST=0.0.0.0
34
+ restart: unless-stopped
35
+
36
+ volumes:
37
+ ollama_data_dev:
38
+ driver: local
docker-compose.yml ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ # Ollama service for local LLM inference
5
+ ollama:
6
+ image: ollama/ollama:latest
7
+ container_name: summarizer-ollama
8
+ ports:
9
+ - "11434:11434"
10
+ volumes:
11
+ - ollama_data:/root/.ollama
12
+ environment:
13
+ - OLLAMA_HOST=0.0.0.0
14
+ restart: unless-stopped
15
+ healthcheck:
16
+ test: ["CMD", "curl", "-f", "http://localhost:11434/api/tags"]
17
+ interval: 30s
18
+ timeout: 10s
19
+ retries: 3
20
+ start_period: 40s
21
+
22
+ # FastAPI backend service
23
+ api:
24
+ build: .
25
+ container_name: summarizer-api
26
+ ports:
27
+ - "8000:8000"
28
+ environment:
29
+ - OLLAMA_HOST=http://ollama:11434
30
+ - OLLAMA_MODEL=llama3.1:8b
31
+ - OLLAMA_TIMEOUT=30
32
+ - SERVER_HOST=0.0.0.0
33
+ - SERVER_PORT=8000
34
+ - LOG_LEVEL=INFO
35
+ depends_on:
36
+ ollama:
37
+ condition: service_healthy
38
+ restart: unless-stopped
39
+ healthcheck:
40
+ test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
41
+ interval: 30s
42
+ timeout: 10s
43
+ retries: 3
44
+ start_period: 10s
45
+
46
+ # Optional: Nginx reverse proxy for production
47
+ nginx:
48
+ image: nginx:alpine
49
+ container_name: summarizer-nginx
50
+ ports:
51
+ - "80:80"
52
+ - "443:443"
53
+ volumes:
54
+ - ./nginx.conf:/etc/nginx/nginx.conf:ro
55
+ depends_on:
56
+ - api
57
+ restart: unless-stopped
58
+ profiles:
59
+ - production
60
+
61
+ volumes:
62
+ ollama_data:
63
+ driver: local
64
+
65
+ networks:
66
+ default:
67
+ name: summarizer-network
nginx.conf ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ events {
2
+ worker_connections 1024;
3
+ }
4
+
5
+ http {
6
+ upstream api {
7
+ server api:8000;
8
+ }
9
+
10
+ # Rate limiting
11
+ limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
12
+
13
+ server {
14
+ listen 80;
15
+ server_name localhost;
16
+
17
+ # Security headers
18
+ add_header X-Frame-Options DENY;
19
+ add_header X-Content-Type-Options nosniff;
20
+ add_header X-XSS-Protection "1; mode=block";
21
+
22
+ # API routes
23
+ location / {
24
+ limit_req zone=api burst=20 nodelay;
25
+
26
+ proxy_pass http://api;
27
+ proxy_set_header Host $host;
28
+ proxy_set_header X-Real-IP $remote_addr;
29
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
30
+ proxy_set_header X-Forwarded-Proto $scheme;
31
+
32
+ # Timeouts
33
+ proxy_connect_timeout 30s;
34
+ proxy_send_timeout 30s;
35
+ proxy_read_timeout 30s;
36
+ }
37
+
38
+ # Health check endpoint (no rate limiting)
39
+ location /health {
40
+ proxy_pass http://api;
41
+ proxy_set_header Host $host;
42
+ proxy_set_header X-Real-IP $remote_addr;
43
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
44
+ proxy_set_header X-Forwarded-Proto $scheme;
45
+ }
46
+ }
47
+ }
scripts/run-tests.sh ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Test runner script for Docker environment
4
+ set -e
5
+
6
+ echo "πŸ§ͺ Running tests in Docker environment..."
7
+
8
+ # Build test image
9
+ echo "πŸ“¦ Building test image..."
10
+ docker build -t summarizer-backend-test .
11
+
12
+ # Run tests
13
+ echo "πŸš€ Running tests..."
14
+ docker run --rm \
15
+ -v "$(pwd)/tests:/app/tests:ro" \
16
+ -v "$(pwd)/app:/app/app:ro" \
17
+ -v "$(pwd)/pytest.ini:/app/pytest.ini:ro" \
18
+ summarizer-backend-test \
19
+ pytest tests/ -v --cov=app --cov-report=term-missing
20
+
21
+ echo "βœ… Tests completed!"
scripts/setup-ollama.sh ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ # Setup script for Ollama model download
4
+ set -e
5
+
6
+ echo "πŸš€ Setting up Ollama for Text Summarizer Backend..."
7
+
8
+ # Check if Ollama is running
9
+ if ! curl -s http://localhost:11434/api/tags > /dev/null; then
10
+ echo "❌ Ollama is not running. Please start Ollama first:"
11
+ echo " docker-compose up ollama -d"
12
+ echo " or"
13
+ echo " ollama serve"
14
+ exit 1
15
+ fi
16
+
17
+ # Default model
18
+ MODEL=${1:-"llama3.1:8b"}
19
+
20
+ echo "πŸ“₯ Downloading model: $MODEL"
21
+ echo "This may take several minutes depending on your internet connection..."
22
+
23
+ # Pull the model
24
+ ollama pull "$MODEL"
25
+
26
+ echo "βœ… Model $MODEL downloaded successfully!"
27
+
28
+ # Test the model
29
+ echo "πŸ§ͺ Testing model..."
30
+ TEST_RESPONSE=$(curl -s -X POST http://localhost:11434/api/generate \
31
+ -H "Content-Type: application/json" \
32
+ -d '{
33
+ "model": "'"$MODEL"'",
34
+ "prompt": "Summarize this: Hello world",
35
+ "stream": false
36
+ }')
37
+
38
+ if echo "$TEST_RESPONSE" | grep -q "response"; then
39
+ echo "βœ… Model test successful!"
40
+ else
41
+ echo "❌ Model test failed. Response:"
42
+ echo "$TEST_RESPONSE"
43
+ exit 1
44
+ fi
45
+
46
+ echo ""
47
+ echo "πŸŽ‰ Setup complete! Your text summarizer backend is ready to use."
48
+ echo ""
49
+ echo "Next steps:"
50
+ echo "1. Start the API: docker-compose up api -d"
51
+ echo "2. Test the API: curl http://localhost:8000/health"
52
+ echo "3. Try summarization: curl -X POST http://localhost:8000/api/v1/summarize/ \\"
53
+ echo " -H 'Content-Type: application/json' \\"
54
+ echo " -d '{\"text\": \"Your text to summarize here...\"}'"