Deploying a Multi-Service RAG Application to Alibaba Cloud ECS via Docker
Project Overview
This guide documents the process of containerizing and deploying a Retrieval-Augmented Generation (RAG) platform to Alibaba Cloud ECS. The stack consists of three distinct services:
- Client Interface: React PWA served via Nginx.
- API Service: Node.js backend using Koa and MongoDB.
- AI Engine: Python service using FastAPI, MongoDB, and ChromaDB.
Creating Dockerfiles
1. Frontend Configuration (React + Nginx)
The frontend build process uses a multi-stage Dockerfile. The first stage compiles the React application, and the second stage serves the static assets using Nginx.
When configuring Nginx within Docker, note that the configuration file copied into the container typically represents the server block rather than the full http or main context. It is usually placed in /etc/nginx/conf.d/default.conf.
Key Nginx Settings:
- Request Size: Increase the body size limit to allow large file uploads (avoid 413 errors).
- MIME Types: Ensure proper handling of modern assets like JavaScript modules and WOFF2 fonts.
- Caching: Disable caching for
index.htmlto ensure users receive the latest PWA updates.
server {
listen 80;
client_max_body_size 50m;
types {
application/javascript js mjs;
font/woff2 woff2;
# ... other types
}
location / {
root /usr/share/nginx/html;
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}
# Proxy API requests to the Node service
location /koapi/ {
proxy_pass http://node-api:3001/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
Note: The trailing slash in proxy_pass http://node-api:3001/; replaces the /koapi/ path. Omitting it would append the path.
2. Node.js Service
The Koa service Dockerfile should install dependencies and start the application. No complex build steps are required beyond npm install.
3. Python AI Service
For the FastAPI service, we use Poetry for dependency management. Since a container runs a single process, we disable Poetry's virtual environment creation to use the system Python direct.
# Disable virtual environment creation inside the container
ENV POETRY_VIRTUALENVS_CREATE=false \
POETRY_VIRTUALENVS_IN_PROJECT=false
# Install dependencies and run
RUN poetry install --no-interaction --no-ansi
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Defining Services with Docker Compose
We use docker-compose.yml to orchestrate the multi-container setup. This includes the application services and the MongoDB instance.
Critical Configurations:
- Volumes: Map host directoreis to container paths for MongoDB data persistence and shared uploaded files.
- Networks: Create a custom bridge network (e.g.,
app-net) so services can communicate using container names (e.g.,node-api). - Dependencies: Use
depends_onto ensure the database starts before the applications.
version: '3.8'
services:
node-api:
build: ./koa-node
container_name: node-api
restart: always
env_file:
- ./koa-node/.env
volumes:
- uploads_volume:/app/public/uploads
networks:
- app-net
ai-engine:
build: ./python-for-ai
container_name: ai-engine
restart: always
volumes:
- chroma_volume:/app/chroma
- uploads_volume:/app/public/uploads
depends_on:
- mongo-db
networks:
- app-net
mongo-db:
image: mongo:7
container_name: mongo-db
environment:
MONGO_INITDB_ROOT_USERNAME: admin
MONGO_INITDB_ROOT_PASSWORD: secret
volumes:
- mongo_data:/data/db
networks:
- app-net
volumes:
uploads_volume:
chroma_volume:
mongo_data:
networks:
app-net:
driver: bridge
Cross-Platform Builds and Alibaba Cloud Deployment
Handling Architecture Differences
If building on an Apple Silicon (ARM) Mac but deploying to an Alibaba Cloud ECS (x86/AMD64), you must build the images for the correct platform. Use docker buildx to create AMD64 images from an ARM machine.
# Build for x86 architecture and push directly to registry
docker buildx build --platform linux/amd64 \
-t registry.cn-guangzhou.aliyuncs.com/user/rag:backend-latest \
./koa-node --push
ECS Configuration
- Install Docker and Docker Compose on the Alibaba Cloud ECS instance.
- Configure the Security Group to allow inbound traffic on port 22 (SSH) and port 80 (HTTP).
- Transfer the
docker-compose.ymlto the server using SFTP/SCP. - Update
docker-compose.ymlto useimage:instead ofbuild:if the images are already in a registry (like Alibaba Cloud Container Registry). - Run
docker compose pullanddocker compose up -d.
Code Adjustments for Containerization
When moving to a containerized environment, file system operations may behave differently. For example, moving files between mounted volumes and local container storage often fails with rename due to cross-device links.
Solution: Use copy and unlink instead of rename.
try {
// Avoid using rename() when dealing with volume mounts
// await fs.promises.rename(sourcePath, destinationPath);
await fs.promises.copyFile(sourcePath, destinationPath);
await fs.promises.unlink(sourcePath);
console.log('File moved successfully');
} catch (error) {
console.error('File operation failed', error);
ctx.status = 500;
ctx.body = { error: 'Failed to save file' };
}