| # Deployment Guide |
|
|
| This document covers all deployment options for Irminsul, the cost tradeoffs between them, and the architectural decisions behind the live demo setup. |
|
|
| --- |
|
|
| ## Deployment Options |
|
|
| Irminsul supports two LLM backends and multiple hosting targets. Choose based on your infrastructure and budget. |
|
|
| | Backend | Where to Run | GPU Required | Cost | |
| |---|---|---|---| |
| | **Groq** (recommended) | Anywhere β no GPU | No | Free tier available | |
| | **Local Llama** (fine-tuned model) | Local machine / GPU VM | Yes (6GB+ VRAM) | Hardware cost / ~$0.50β1.50/hr on Azure | |
|
|
| --- |
|
|
| ## Live Demo: HuggingFace Spaces + Groq |
|
|
| **Why this is the live demo environment:** |
|
|
| The fine-tuned Llama 3.1 8B model is 16GB on disk and requires a GPU-enabled instance to serve at acceptable latency. On Azure, the minimum viable GPU instance for this model is the **NC4as T4 v3** (~$0.50/hr, ~$360/month). Running this persistently for a portfolio project is not cost-effective. |
|
|
| The live demo instead uses: |
| - **HuggingFace Spaces** β free CPU hosting for the FastAPI container |
| - **Groq API** β runs `llama-3.3-70b-versatile` on Groq's Language Processing Units (LPUs) at ~300 tokens/second, for free under the public tier |
|
|
| This demonstrates the identical RAG architecture β the LLM backend is swapped via a single environment variable (`LLM_BACKEND=groq`). The retrieval pipeline, guardrails, response format, and API contract are unchanged. |
|
|
| ``` |
| Live demo: https://huggingface.co/spaces/MukulRay/Irminsul |
| ``` |
|
|
| --- |
|
|
| ## Option A: Local Development |
|
|
| The full stack including the fine-tuned model runs locally on an RTX 3060 6GB: |
|
|
| ```bash |
| # 1. Clone and install |
| git clone https://github.com/MukulRay1603/Irminsul.git |
| cd Irminsul |
| python -m venv venv && source venv/bin/activate |
| pip install -r requirements.txt |
| |
| # 2. Configure |
| cp .env.example .env |
| # Edit .env β set MODEL_PATH, PINECONE_API_KEY |
| |
| # 3. Ingest corpus |
| python ingest.py --dir ./docs --chunk-size 300 --chunk-overlap 40 |
| |
| # 4. Serve |
| uvicorn main:app --host 0.0.0.0 --port 8000 |
| ``` |
|
|
| **Memory profile:** |
|
|
| | Component | VRAM | |
| |---|---| |
| | Llama 3.1 8B @ 4-bit NF4 | ~4.5 GB | |
| | all-MiniLM-L6-v2 embedder | ~90 MB | |
| | Inference headroom | ~1.2 GB | |
| | **Total** | **~5.8 GB** | |
|
|
| The model loads with `max_memory={0: "5.5GiB", "cpu": "24GiB"}` β layers that don't fit on GPU overflow to RAM automatically via `accelerate`. |
|
|
| --- |
|
|
| ## Option B: Docker (Local or Any Cloud) |
|
|
| The Dockerfile is intentionally slim β the model is **not baked in**. It's injected at runtime via `MODEL_PATH`. |
|
|
| ```bash |
| # Build |
| docker build -t irminsul:latest . |
| |
| # Run with Groq backend (no GPU needed) |
| docker run -p 8000:8000 \ |
| -e PINECONE_API_KEY=your_key \ |
| -e GROQ_API_KEY=your_key \ |
| -e PINECONE_INDEX=llmops-rag \ |
| -e LLM_BACKEND=groq \ |
| irminsul:latest |
| |
| # Run with local model (GPU required) |
| docker run -p 8000:8000 \ |
| --gpus all \ |
| -v /path/to/models:/app/models \ |
| -e PINECONE_API_KEY=your_key \ |
| -e MODEL_PATH=/app/models/merged/exp2_lr2e-4_r16 \ |
| -e LLM_BACKEND=local \ |
| irminsul:latest |
| ``` |
|
|
| --- |
|
|
| ## Option C: Azure Container Apps |
|
|
| Azure Container Apps (ACA) is the production deployment target. The `deploy_azure.sh` script provisions the full stack in one command. |
|
|
| ### Prerequisites |
|
|
| ```bash |
| # Install Azure CLI |
| # macOS: |
| brew install azure-cli |
| |
| # Linux: |
| curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash |
| |
| # Windows: https://aka.ms/installazurecliwindows |
| |
| # Log in |
| az login |
| az account show # confirm your subscription |
| ``` |
|
|
| ### One-shot deploy |
|
|
| ```bash |
| export PINECONE_API_KEY=your_pinecone_key |
| export GROQ_API_KEY=your_groq_key |
| chmod +x deploy_azure.sh |
| ./deploy_azure.sh |
| ``` |
|
|
| The script: |
| 1. Creates resource group `irminsul-rg` in East US |
| 2. Creates Azure Container Registry `irminsulacr` |
| 3. Builds the Docker image via **ACR Tasks** β the source code is uploaded and built in Azure's cloud; no local Docker daemon needed |
| 4. Creates a Container Apps environment |
| 5. Deploys the app with secrets injected as environment variables |
| 6. Outputs the live HTTPS URL |
|
|
| ### Tearing down |
|
|
| ```bash |
| # Delete everything β stops all billing immediately |
| az group delete --name irminsul-rg --yes --no-wait |
| ``` |
|
|
| ### Cost breakdown (Groq backend, no GPU) |
|
|
| | Resource | SKU | Cost | |
| |---|---|---| |
| | Container Apps | Consumption plan | Free (180k vCPU-s/month) | |
| | ACR | Basic | ~$5/month | |
| | Outbound bandwidth | First 100GB | Free | |
| | **Total** | | **~$5/month** | |
|
|
| On Azure for Students ($100 credit), this runs for ~20 months. |
|
|
| ### Why not GPU on Azure? |
|
|
| To serve the fine-tuned Llama model in production, a GPU instance is required: |
|
|
| | Instance | GPU | VRAM | Cost | |
| |---|---|---|---| |
| | NC4as T4 v3 | Tesla T4 | 16 GB | ~$0.50/hr = **~$360/month** | |
| | NC6s v3 | Tesla V100 | 16 GB | ~$0.90/hr = **~$648/month** | |
|
|
| At these prices, a portfolio project running 24/7 would exhaust the $100 student credit in under a week. The Groq backend delivers the same RAG functionality at zero marginal cost, making it the right engineering tradeoff. |
|
|
| ### Serving the fine-tuned model on Azure (production path) |
|
|
| If cost were not a constraint, the correct architecture is: |
|
|
| 1. **Upload model to Azure Blob Storage** (~$0.02/GB/month for 16GB = ~$0.32/month) |
| 2. **Mount as a volume** in Container Apps β the container sees it at `/app/models/` |
| 3. **Switch to GPU SKU** β replace `--cpu 1.0 --memory 2.0Gi` in `deploy_azure.sh` with a GPU-enabled workload profile |
| 4. **Set `LLM_BACKEND=local`** in env vars |
| |
| The Docker image and application code require zero changes for this path. The abstraction was designed for it. |
| |
| --- |
| |
| ## Environment Variables Reference |
| |
| | Variable | Required | Default | Description | |
| |---|---|---|---| |
| | `PINECONE_API_KEY` | Yes | β | Pinecone serverless API key | |
| | `PINECONE_INDEX` | No | `llmops-rag` | Pinecone index name | |
| | `LLM_BACKEND` | No | `groq` | `groq` or `local` | |
| | `GROQ_API_KEY` | If Groq | β | Groq API key | |
| | `GROQ_MODEL` | No | `llama-3.3-70b-versatile` | Groq model name | |
| | `MODEL_PATH` | If local | `./models/merged/exp2_lr2e-4_r16` | Path to merged model | |
| | `EMBED_MODEL` | No | `sentence-transformers/all-MiniLM-L6-v2` | Embedding model | |
| |
| --- |
| |
| ## CI/CD (Planned) |
| |
| The intended CI/CD pipeline: |
| |
| ``` |
| git push main |
| β |
| βΌ |
| GitHub Actions |
| βββ Run tests |
| βββ Build Docker image |
| βββ Push to ACR |
| βββ az containerapp update --image new-tag |
| ``` |
| |
| This would give zero-downtime rolling deploys on every push to main. Currently, re-running `deploy_azure.sh` achieves the same result with a cold start. |
| |