add docker compose
This commit is contained in:
parent
6f9defe29a
commit
c62af10b02
55
.dockerignore
Normal file
55
.dockerignore
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Dependencies
|
||||||
|
node_modules
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
dist
|
||||||
|
build
|
||||||
|
.vite
|
||||||
|
|
||||||
|
# Environment files
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
|
||||||
|
# IDE and editor files
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# Git
|
||||||
|
.git
|
||||||
|
.gitignore
|
||||||
|
.gitattributes
|
||||||
|
|
||||||
|
# Docker
|
||||||
|
Dockerfile*
|
||||||
|
docker-compose*.yml
|
||||||
|
.dockerignore
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
README.md
|
||||||
|
STYLE_GUIDE.md
|
||||||
|
*.md
|
||||||
|
|
||||||
|
# Testing
|
||||||
|
coverage
|
||||||
|
.nyc_output
|
||||||
|
*.test.ts
|
||||||
|
*.test.tsx
|
||||||
|
*.spec.ts
|
||||||
|
*.spec.tsx
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
.cache
|
||||||
|
*.log
|
||||||
|
tmp
|
||||||
|
temp
|
||||||
6
.env.example
Normal file
6
.env.example
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Gemini API Key
|
||||||
|
# Get your API key from: https://aistudio.google.com/app/apikey
|
||||||
|
GEMINI_API_KEY=your_gemini_api_key_here
|
||||||
|
|
||||||
|
# Node Environment (development | production)
|
||||||
|
NODE_ENV=development
|
||||||
353
DOCKER_README.md
Normal file
353
DOCKER_README.md
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
# Docker Deployment Guide
|
||||||
|
|
||||||
|
This guide explains how to deploy the Pradit application using Docker and Docker Compose.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Docker Engine 20.10+
|
||||||
|
- Docker Compose 2.0+
|
||||||
|
- Gemini API Key (get from https://aistudio.google.com/app/apikey)
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Setup Environment Variables
|
||||||
|
|
||||||
|
Copy the example environment file and add your Gemini API key:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
Edit `.env` and set your `GEMINI_API_KEY`:
|
||||||
|
|
||||||
|
```
|
||||||
|
GEMINI_API_KEY=your_actual_api_key_here
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Run Development Mode
|
||||||
|
|
||||||
|
Development mode includes hot reload for rapid iteration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose --profile dev up
|
||||||
|
```
|
||||||
|
|
||||||
|
Access the app at: http://localhost:3000
|
||||||
|
|
||||||
|
### 3. Run Production Mode
|
||||||
|
|
||||||
|
Production mode uses optimized build with nginx:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose --profile prod up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Access the app at: http://localhost:80
|
||||||
|
|
||||||
|
## Docker Compose Profiles
|
||||||
|
|
||||||
|
This project uses Docker Compose profiles to separate dev and prod environments.
|
||||||
|
|
||||||
|
### Development Profile (`dev`)
|
||||||
|
|
||||||
|
- **Port**: 3000
|
||||||
|
- **Hot Reload**: Enabled
|
||||||
|
- **Volume Mounts**: Source code mounted for live changes
|
||||||
|
- **Server**: Vite dev server
|
||||||
|
- **Optimizations**: None (fast rebuild)
|
||||||
|
|
||||||
|
**Commands**:
|
||||||
|
```bash
|
||||||
|
# Start dev server
|
||||||
|
docker-compose --profile dev up
|
||||||
|
|
||||||
|
# Start in background
|
||||||
|
docker-compose --profile dev up -d
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose --profile dev logs -f
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
docker-compose --profile dev down
|
||||||
|
```
|
||||||
|
|
||||||
|
### Production Profile (`prod`)
|
||||||
|
|
||||||
|
- **Port**: 80
|
||||||
|
- **Hot Reload**: Disabled
|
||||||
|
- **Build**: Optimized static build
|
||||||
|
- **Server**: Nginx with compression and caching
|
||||||
|
- **Health Check**: Enabled on /health endpoint
|
||||||
|
|
||||||
|
**Commands**:
|
||||||
|
```bash
|
||||||
|
# Build and start production
|
||||||
|
docker-compose --profile prod up -d
|
||||||
|
|
||||||
|
# Rebuild after code changes
|
||||||
|
docker-compose --profile prod up -d --build
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose --profile prod logs -f
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
docker-compose --profile prod down
|
||||||
|
```
|
||||||
|
|
||||||
|
## Manual Docker Commands
|
||||||
|
|
||||||
|
### Build Images
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development image
|
||||||
|
docker build -f Dockerfile.dev -t pradit:dev .
|
||||||
|
|
||||||
|
# Production image
|
||||||
|
docker build -f Dockerfile -t pradit:prod .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run Containers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Development
|
||||||
|
docker run -p 3000:3000 -v $(pwd):/app -v /app/node_modules \
|
||||||
|
-e GEMINI_API_KEY=your_key pradit:dev
|
||||||
|
|
||||||
|
# Production
|
||||||
|
docker run -p 80:80 pradit:prod
|
||||||
|
```
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Development Container
|
||||||
|
|
||||||
|
- **Base**: node:20-alpine
|
||||||
|
- **Package Manager**: pnpm
|
||||||
|
- **Volumes**: Source code mounted for hot reload
|
||||||
|
- **Port**: 3000
|
||||||
|
- **Command**: `pnpm run dev`
|
||||||
|
|
||||||
|
### Production Container
|
||||||
|
|
||||||
|
Multi-stage build for minimal image size:
|
||||||
|
|
||||||
|
1. **Builder Stage**:
|
||||||
|
- Installs dependencies with pnpm
|
||||||
|
- Builds optimized production bundle
|
||||||
|
- Uses node:20-alpine
|
||||||
|
|
||||||
|
2. **Runtime Stage**:
|
||||||
|
- Serves static files with nginx:alpine
|
||||||
|
- Configured for SPA routing
|
||||||
|
- Gzip compression enabled
|
||||||
|
- Security headers added
|
||||||
|
- Health check endpoint at `/health`
|
||||||
|
|
||||||
|
## Configuration Files
|
||||||
|
|
||||||
|
### Dockerfile
|
||||||
|
Production multi-stage build configuration.
|
||||||
|
|
||||||
|
### Dockerfile.dev
|
||||||
|
Development container with hot reload support.
|
||||||
|
|
||||||
|
### docker-compose.yml
|
||||||
|
Orchestration for both dev and prod profiles.
|
||||||
|
|
||||||
|
### nginx.conf
|
||||||
|
Nginx configuration for production:
|
||||||
|
- SPA routing (serves index.html for all routes)
|
||||||
|
- Gzip compression
|
||||||
|
- Static asset caching (1 year)
|
||||||
|
- Security headers
|
||||||
|
- Health check endpoint
|
||||||
|
|
||||||
|
### .dockerignore
|
||||||
|
Excludes unnecessary files from Docker build context:
|
||||||
|
- node_modules
|
||||||
|
- Build artifacts
|
||||||
|
- Environment files
|
||||||
|
- IDE configurations
|
||||||
|
- Documentation
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Description |
|
||||||
|
|----------|----------|-------------|
|
||||||
|
| `GEMINI_API_KEY` | Yes | API key for Gemini AI |
|
||||||
|
| `NODE_ENV` | No | Environment mode (development/production) |
|
||||||
|
|
||||||
|
**Security Note**: Never commit `.env` file. Use `.env.example` as template.
|
||||||
|
|
||||||
|
## Port Configuration
|
||||||
|
|
||||||
|
| Service | Port | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| Development | 3000 | Vite dev server |
|
||||||
|
| Production | 80 | Nginx web server |
|
||||||
|
|
||||||
|
To use different ports, edit `docker-compose.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ports:
|
||||||
|
- "8080:80" # Host:Container
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Port Already in Use
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find process using port 3000
|
||||||
|
netstat -ano | findstr :3000 # Windows
|
||||||
|
lsof -i :3000 # Linux/Mac
|
||||||
|
|
||||||
|
# Change port in docker-compose.yml
|
||||||
|
ports:
|
||||||
|
- "3001:3000"
|
||||||
|
```
|
||||||
|
|
||||||
|
### API Key Not Working
|
||||||
|
|
||||||
|
Ensure `.env` file exists and contains valid key:
|
||||||
|
```bash
|
||||||
|
cat .env # Linux/Mac
|
||||||
|
type .env # Windows
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart containers after changing `.env`:
|
||||||
|
```bash
|
||||||
|
docker-compose --profile dev down
|
||||||
|
docker-compose --profile dev up
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container Won't Start
|
||||||
|
|
||||||
|
Check logs for errors:
|
||||||
|
```bash
|
||||||
|
docker-compose --profile dev logs
|
||||||
|
docker-compose --profile prod logs
|
||||||
|
```
|
||||||
|
|
||||||
|
Remove containers and rebuild:
|
||||||
|
```bash
|
||||||
|
docker-compose down -v
|
||||||
|
docker-compose --profile prod up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
### Volume Permission Issues (Linux)
|
||||||
|
|
||||||
|
If encountering permission issues with mounted volumes:
|
||||||
|
```bash
|
||||||
|
# Add user ID to docker-compose.yml
|
||||||
|
user: "${UID}:${GID}"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Cache Issues
|
||||||
|
|
||||||
|
Clear Docker build cache:
|
||||||
|
```bash
|
||||||
|
docker builder prune -a
|
||||||
|
docker-compose build --no-cache
|
||||||
|
```
|
||||||
|
|
||||||
|
## Health Checks
|
||||||
|
|
||||||
|
Production container includes health check:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check container health
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# Manual health check
|
||||||
|
curl http://localhost/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logs and Debugging
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Follow logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Specific service logs
|
||||||
|
docker-compose --profile dev logs pradit-dev
|
||||||
|
docker-compose --profile prod logs pradit-prod
|
||||||
|
|
||||||
|
# Enter running container
|
||||||
|
docker exec -it pradit-dev sh
|
||||||
|
docker exec -it pradit-prod sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cleaning Up
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stop and remove containers
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Remove containers and volumes
|
||||||
|
docker-compose down -v
|
||||||
|
|
||||||
|
# Remove images
|
||||||
|
docker rmi pradit:dev pradit:prod
|
||||||
|
|
||||||
|
# Full cleanup (all unused Docker resources)
|
||||||
|
docker system prune -a
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Deployment
|
||||||
|
|
||||||
|
For cloud deployment (AWS, GCP, Azure, etc.):
|
||||||
|
|
||||||
|
1. Build and tag image:
|
||||||
|
```bash
|
||||||
|
docker build -t your-registry/pradit:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Push to registry:
|
||||||
|
```bash
|
||||||
|
docker push your-registry/pradit:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Deploy to orchestration platform (Kubernetes, ECS, etc.)
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Production Build
|
||||||
|
|
||||||
|
- Tree shaking removes unused code
|
||||||
|
- Minification reduces bundle size
|
||||||
|
- Gzip compression (nginx)
|
||||||
|
- Static asset caching (1 year)
|
||||||
|
- Multi-stage build minimizes image size
|
||||||
|
|
||||||
|
### Development Build
|
||||||
|
|
||||||
|
- Fast rebuild with hot module replacement
|
||||||
|
- Source maps for debugging
|
||||||
|
- No minification for faster builds
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Never commit API keys** - Use environment variables
|
||||||
|
2. **Use multi-stage builds** - Minimize attack surface
|
||||||
|
3. **Run as non-root** - Production nginx runs as nginx user
|
||||||
|
4. **Keep images updated** - Regularly update base images
|
||||||
|
5. **Scan for vulnerabilities** - Use `docker scan pradit:prod`
|
||||||
|
6. **Use secrets management** - For production, use Docker secrets or cloud provider solutions
|
||||||
|
|
||||||
|
## Additional Resources
|
||||||
|
|
||||||
|
- [Docker Documentation](https://docs.docker.com/)
|
||||||
|
- [Docker Compose Documentation](https://docs.docker.com/compose/)
|
||||||
|
- [Vite Documentation](https://vitejs.dev/)
|
||||||
|
- [Nginx Documentation](https://nginx.org/en/docs/)
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
For issues specific to Docker setup, check:
|
||||||
|
1. Docker daemon is running
|
||||||
|
2. Environment variables are set correctly
|
||||||
|
3. Ports are not already in use
|
||||||
|
4. Sufficient disk space for images and containers
|
||||||
|
|
||||||
|
For application issues, refer to main [README.md](README.md).
|
||||||
35
Dockerfile
Normal file
35
Dockerfile
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Build stage
|
||||||
|
FROM node:20-alpine AS builder
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install pnpm
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build the application
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
|
# Production stage
|
||||||
|
FROM nginx:alpine
|
||||||
|
|
||||||
|
# Copy built assets from builder stage
|
||||||
|
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||||
|
|
||||||
|
# Copy nginx configuration
|
||||||
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Start nginx
|
||||||
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
23
Dockerfile.dev
Normal file
23
Dockerfile.dev
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Development Dockerfile
|
||||||
|
FROM node:20-alpine
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Install pnpm globally
|
||||||
|
RUN npm install -g pnpm
|
||||||
|
|
||||||
|
# Copy package files
|
||||||
|
COPY package.json pnpm-lock.yaml ./
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
# Copy source code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose development port
|
||||||
|
EXPOSE 3000
|
||||||
|
|
||||||
|
# Start development server with hot reload
|
||||||
|
CMD ["pnpm", "run", "dev"]
|
||||||
51
docker-compose.yml
Normal file
51
docker-compose.yml
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
# Development service
|
||||||
|
pradit-dev:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile.dev
|
||||||
|
container_name: pradit-dev
|
||||||
|
profiles:
|
||||||
|
- dev
|
||||||
|
ports:
|
||||||
|
- "3000:3000"
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
- /app/node_modules
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=development
|
||||||
|
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||||
|
command: pnpm run dev
|
||||||
|
networks:
|
||||||
|
- pradit-network
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Production service
|
||||||
|
pradit-prod:
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- GEMINI_API_KEY=${GEMINI_API_KEY}
|
||||||
|
container_name: pradit-prod
|
||||||
|
profiles:
|
||||||
|
- prod
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
networks:
|
||||||
|
- pradit-network
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
pradit-network:
|
||||||
|
driver: bridge
|
||||||
35
nginx.conf
Normal file
35
nginx.conf
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html;
|
||||||
|
|
||||||
|
# Gzip compression
|
||||||
|
gzip on;
|
||||||
|
gzip_vary on;
|
||||||
|
gzip_min_length 1024;
|
||||||
|
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml+rss application/javascript application/json;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||||
|
add_header X-Content-Type-Options "nosniff" always;
|
||||||
|
add_header X-XSS-Protection "1; mode=block" always;
|
||||||
|
|
||||||
|
# Cache static assets
|
||||||
|
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||||
|
expires 1y;
|
||||||
|
add_header Cache-Control "public, immutable";
|
||||||
|
}
|
||||||
|
|
||||||
|
# SPA routing - serve index.html for all routes
|
||||||
|
location / {
|
||||||
|
try_files $uri $uri/ /index.html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint
|
||||||
|
location /health {
|
||||||
|
access_log off;
|
||||||
|
return 200 "healthy\n";
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user