update docker

This commit is contained in:
Phuoc Nguyen
2025-10-10 17:13:45 +07:00
parent 87c12b9927
commit 8c34460889
5 changed files with 478 additions and 50 deletions

350
DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,350 @@
# Docker Deployment Guide
## Overview
This project can be deployed using Docker in two ways:
1. **Build and Push to Registry** (Recommended for production)
2. **Build from Source** (Good for development/testing)
---
## Option 1: Using Pre-built Image (Recommended)
### Step 1: Build and Push Image
On your **local machine or CI/CD**:
```bash
# 1. Login to Docker Hub (or your registry)
docker login
# 2. Build the image
docker build -t retail-pos-api:latest .
# 3. Tag for your registry
docker tag retail-pos-api:latest your-username/retail-pos-api:latest
# 4. Push to registry
docker push your-username/retail-pos-api:latest
```
Or use the automated script:
```bash
# Edit the script first to set your registry username
nano build-and-push.sh
# Run the script
./build-and-push.sh
```
### Step 2: Deploy on Target Server
On your **deployment server**:
```bash
# 1. Copy docker-compose.prod.yml to server
scp docker-compose.prod.yml user@server:/path/to/deployment/
# 2. SSH into server
ssh user@server
# 3. Edit docker-compose.prod.yml to update image name and env vars
nano docker-compose.prod.yml
# 4. Pull and start services
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d
# 5. Check status
docker-compose -f docker-compose.prod.yml ps
docker-compose -f docker-compose.prod.yml logs -f api
```
---
## Option 2: Build from Source
### On Target Server
```bash
# 1. Clone repository (or copy files)
git clone your-repo-url
cd retail-nest
# 2. Create/edit .env file if needed
cp .env.example .env
nano .env
# 3. Build and start
docker-compose up -d --build
# 4. Check status
docker-compose ps
docker-compose logs -f api
```
---
## File Structure
```
retail-nest/
├── Dockerfile # Multi-stage build configuration
├── docker-compose.yml # For local development (builds from source)
├── docker-compose.prod.yml # For production (uses pre-built image)
├── build-and-push.sh # Automated build and push script
└── .dockerignore # Files to exclude from Docker build
```
---
## Environment Variables
All environment variables can be configured in `docker-compose.prod.yml`:
### Database (Aiven PostgreSQL)
- `DB_HOST`: Your Aiven database host
- `DB_PORT`: Database port (usually 20912 for Aiven)
- `DB_USERNAME`: Database username
- `DB_PASSWORD`: Database password
- `DB_DATABASE`: Database name
- `DB_SSL`: "true" (required for Aiven)
### Application
- `NODE_ENV`: production
- `PORT`: 3000
- `API_PREFIX`: api
- `JWT_SECRET`: Your JWT secret key
- `CORS_ORIGIN`: Allowed origins
### Redis
- `REDIS_HOST`: redis (container name)
- `REDIS_PORT`: 6379
- `CACHE_TTL`: 300
---
## Useful Commands
### Development (docker-compose.yml)
```bash
# Start services (builds from source)
docker-compose up -d
# View logs
docker-compose logs -f api
# Restart API
docker-compose restart api
# Stop services
docker-compose down
# Rebuild
docker-compose up -d --build
```
### Production (docker-compose.prod.yml)
```bash
# Pull latest image and start
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d
# View logs
docker-compose -f docker-compose.prod.yml logs -f api
# Restart API
docker-compose -f docker-compose.prod.yml restart api
# Stop services
docker-compose -f docker-compose.prod.yml down
# Update to new version
docker-compose -f docker-compose.prod.yml pull
docker-compose -f docker-compose.prod.yml up -d
```
### Docker Commands
```bash
# View running containers
docker ps
# View images
docker images
# Remove unused images
docker image prune -a
# View logs of specific container
docker logs retail-pos-api -f
# Execute command in container
docker exec -it retail-pos-api sh
# Check health
docker inspect retail-pos-api --format='{{.State.Health.Status}}'
```
---
## Registry Options
### Docker Hub (Public/Private)
```bash
# Login
docker login
# Build and push
docker build -t your-username/retail-pos-api:latest .
docker push your-username/retail-pos-api:latest
```
### GitHub Container Registry
```bash
# Login
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
# Build and push
docker build -t ghcr.io/username/retail-pos-api:latest .
docker push ghcr.io/username/retail-pos-api:latest
```
### Private Registry
```bash
# Login
docker login registry.your-domain.com
# Build and push
docker build -t registry.your-domain.com/retail-pos-api:latest .
docker push registry.your-domain.com/retail-pos-api:latest
```
---
## Health Checks
The API includes health check endpoints:
- **Application Health**: `http://localhost:3000/api/health`
- **Root Health**: `http://localhost:3000/api`
Docker automatically monitors these endpoints and will restart the container if unhealthy.
---
## Troubleshooting
### Container won't start
```bash
# Check logs
docker-compose logs api
# Check environment variables
docker exec retail-pos-api env
# Verify database connection
docker exec retail-pos-api wget -qO- http://localhost:3000/api/health
```
### Database connection issues
- Verify `DB_SSL` is set to "true" for Aiven
- Check database credentials in docker-compose.prod.yml
- Ensure firewall allows connections to Aiven
### Redis connection issues
```bash
# Check Redis is running
docker ps | grep redis
# Test Redis connection
docker exec retail-pos-redis redis-cli ping
```
### Image pull fails
```bash
# Re-login to registry
docker login
# Check image name is correct
docker pull your-username/retail-pos-api:latest
```
---
## Security Best Practices
1. **Never commit secrets**: Keep sensitive data in environment variables
2. **Use private registry**: For production deployments
3. **Regular updates**: Keep base images updated
4. **Scan images**: Use `docker scan` to check for vulnerabilities
5. **Use secrets management**: Consider Docker secrets or external vaults
6. **Limit resources**: Add resource limits in docker-compose.yml
---
## CI/CD Integration
### GitHub Actions Example
```yaml
name: Build and Push Docker Image
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Login to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: your-username/retail-pos-api:latest
```
---
## Monitoring
### Check service status
```bash
docker-compose ps
```
### View resource usage
```bash
docker stats retail-pos-api retail-pos-redis
```
### Access API documentation
```
http://localhost:3000/api/docs
```
---
## Backup and Restore
### Redis Data
```bash
# Backup
docker exec retail-pos-redis redis-cli SAVE
docker cp retail-pos-redis:/data/dump.rdb ./backup/
# Restore
docker cp ./backup/dump.rdb retail-pos-redis:/data/
docker-compose restart redis
```
### Database (Aiven handles backups automatically)
Check your Aiven console for backup options.

View File

@@ -1,7 +1,7 @@
# Multi-stage build for optimized production image
# Stage 1: Build
FROM node:18-alpine AS builder
FROM node:22-alpine AS builder
WORKDIR /app

27
build-and-push.sh Executable file
View File

@@ -0,0 +1,27 @@
#!/bin/bash
# Build and Push Docker Image Script
# This script builds the Docker image and pushes it to a registry
set -e # Exit on error
# Configuration
IMAGE_NAME="retail-backend"
REGISTRY="renolation" # Change this to your Docker Hub username or registry URL
VERSION="latest"
FULL_IMAGE="${REGISTRY}/${IMAGE_NAME}:${VERSION}"
echo "🏗️ Building Docker image..."
docker build -t ${IMAGE_NAME}:${VERSION} .
echo "🏷️ Tagging image for registry..."
docker tag ${IMAGE_NAME}:${VERSION} ${FULL_IMAGE}
echo "📤 Pushing image to registry..."
docker push ${FULL_IMAGE}
echo "✅ Successfully built and pushed: ${FULL_IMAGE}"
echo ""
echo "To use this image on another server, run:"
echo " docker pull ${FULL_IMAGE}"
echo " docker-compose -f docker-compose.prod.yml up -d"

78
docker-compose.prod.yml Normal file
View File

@@ -0,0 +1,78 @@
version: '3.8'
services:
# Redis Cache
redis:
image: redis:7-alpine
container_name: retail-redis
restart: unless-stopped
ports:
- "6379:6379"
volumes:
- redis-data:/data
networks:
- retail-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
# NestJS API Application (Using pre-built image)
api:
image: renolation/retail-backend:latest # Change this to your Docker Hub or registry URL
container_name: retail-backend
restart: unless-stopped
ports:
- "3000:3000"
environment:
# Application
NODE_ENV: production
PORT: 3000
API_PREFIX: api
# Database (Aiven PostgreSQL)
DB_HOST: pg-30ed1d6a-renolation.b.aivencloud.com
DB_PORT: 20912
DB_USERNAME: avnadmin
DB_PASSWORD: AVNS_b5AVrZdm2M2donLgXXQ
DB_DATABASE: defaultdb
DB_SSL: "true"
# JWT Configuration
JWT_SECRET: retail-pos-super-secret-key-change-in-production-2025
JWT_EXPIRES_IN: 1d
# Redis Cache
REDIS_HOST: redis
REDIS_PORT: 6379
CACHE_TTL: 300
# CORS
CORS_ORIGIN: http://localhost:3000,capacitor://localhost
# Rate Limiting
THROTTLE_TTL: 60
THROTTLE_LIMIT: 100
# Bcrypt
BCRYPT_ROUNDS: 10
depends_on:
redis:
condition: service_healthy
networks:
- retail-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
volumes:
redis-data:
driver: local
networks:
retail-network:
driver: bridge

View File

@@ -1,27 +1,6 @@
version: '3.8'
services:
# PostgreSQL Database
postgres:
image: postgres:15-alpine
container_name: retail-pos-postgres
restart: unless-stopped
environment:
POSTGRES_DB: retail_pos
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- retail-pos-network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# Redis Cache
redis:
image: redis:7-alpine
@@ -39,67 +18,61 @@ services:
timeout: 5s
retries: 5
# NestJS Application
# NestJS API Application
api:
build:
context: .
dockerfile: Dockerfile
target: production
container_name: retail-pos-api
restart: unless-stopped
ports:
- "3000:3000"
environment:
# Application
NODE_ENV: production
PORT: 3000
API_PREFIX: api
DB_HOST: postgres
DB_PORT: 5432
DB_USERNAME: postgres
DB_PASSWORD: postgres
DB_DATABASE: retail_pos
# Database (Aiven PostgreSQL)
DB_HOST: pg-30ed1d6a-renolation.b.aivencloud.com
DB_PORT: 20912
DB_USERNAME: avnadmin
DB_PASSWORD: AVNS_b5AVrZdm2M2donLgXXQ
DB_DATABASE: defaultdb
DB_SSL: "true"
# JWT Configuration
JWT_SECRET: retail-pos-super-secret-key-change-in-production-2025
JWT_EXPIRES_IN: 1d
# Redis Cache
REDIS_HOST: redis
REDIS_PORT: 6379
CACHE_TTL: 300
# CORS
CORS_ORIGIN: http://localhost:3000,capacitor://localhost
# Rate Limiting
THROTTLE_TTL: 60
THROTTLE_LIMIT: 100
# Bcrypt
BCRYPT_ROUNDS: 10
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- retail-pos-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/health"]
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# Optional: pgAdmin for database management
pgadmin:
image: dpage/pgadmin4:latest
container_name: retail-pos-pgadmin
restart: unless-stopped
environment:
PGADMIN_DEFAULT_EMAIL: admin@retailpos.com
PGADMIN_DEFAULT_PASSWORD: admin123
ports:
- "5050:80"
depends_on:
- postgres
networks:
- retail-pos-network
profiles:
- tools
volumes:
postgres-data:
driver: local
redis-data:
driver: local