Course Wiki
Docker Compose — LLM Zoomcamp Module 5
By now we have three pieces running - PostgreSQL, Grafana, and the Streamlit app. Starting each by hand works, but it adds up. You have to remember the network and type out long commands. Next time around, Docker complains that a container...
Related Pages
LLM Zoomcamp › Module 5: Monitoring › Docker Compose
Notes
Docker Compose
This lesson has no video.
By now we have three pieces running - PostgreSQL, Grafana, and the Streamlit app. Starting each by hand works, but it adds up. You have to remember the network and type out long commands. Next time around, Docker complains that a container with that name already exists, and you have to go remove it.
Docker Compose describes all three services in one file and starts them together on a shared network. You run one command instead.
Project structure
The project layout:
code/
├── docker-compose.yaml
├── Dockerfile
├── .env
├── pyproject.toml
├── uv.lock
├── .python-version
├── app.py # Streamlit app
├── assistant.py # RAG pipeline + LLM
├── db_init.py # Database init
├── db_save.py # Save conversations
└── dashboard.py # Streamlit dashboard
Dockerfile
The Streamlit app needs its own container:
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
WORKDIR /app
ENV PATH="/app/.venv/bin:$PATH"
COPY pyproject.toml uv.lock .python-version ./
RUN uv sync --locked
COPY . .
CMD ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
Environment variables
The .env file stores configuration:
POSTGRES_DB=course_assistant
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_HOST=postgres
OPENAI_API_KEY=your-key-here
Docker Compose
The Compose file defines all three services on the same network:
version: '3.8'
services:
postgres:
image: postgres:17
environment:
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
grafana:
image: grafana/grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
depends_on:
- postgres
The Streamlit service is built from the Dockerfile:
streamlit:
build:
context: .
dockerfile: Dockerfile
environment:
- POSTGRES_HOST=postgres
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- OPENAI_API_KEY=${OPENAI_API_KEY}
ports:
- "8501:8501"
depends_on:
- postgres
volumes:
postgres_data:
grafana_data:
Starting everything
Start all services:
docker-compose up
Initialize the database:
uv run python db_init.py
Access the app at http://localhost:8501 and Grafana at
http://localhost:3000 (login: admin / admin).
To stop:
docker-compose down
The data in PostgreSQL and Grafana persists across restarts thanks to Docker volumes.
Key concepts
Related notes
- llmz-m01-agents
- llmz-m01-data-ingestion
- llmz-m01-environment
- llmz-m01-function-calling
- llmz-m01-introduction
- llmz-m01-other-frameworks
- llmz-m01-quick-rag-revision-optional
- llmz-m01-rag
- llmz-m01-rag-helper
- llmz-m01-search
- llmz-m01-the-course-faq-dataset
- llmz-m01-the-llm
- llmz-m01-wrap-up-of-part-1
- llmz-m02-embeddings
- llmz-m02-next-steps
- llmz-m02-rag-with-vector-search
- llmz-m02-using-onnx-runtime-instead-of-pytorch
- llmz-m02-vector-search
- llmz-m02-vector-search-with-minsearch
- llmz-m02-vector-search-with-pgvector
- llmz-m02-vector-search-with-sqlitesearch
- llmz-m03-ai-agents
- llmz-m03-ai-copilot
- llmz-m03-ai-orchestration
- llmz-m03-best-practices
- llmz-m03-next-steps
- llmz-m03-retrieval-augmented-generation
- llmz-m03-setting-up-kestra
- llmz-m04-agent-evaluation
- llmz-m04-evaluation
- llmz-m04-generating-rag-answers
- llmz-m04-llm-as-a-judge
- llmz-m04-next-steps
- llmz-m04-rag-and-agent-evaluation
- llmz-m04-search-evaluation
- llmz-m04-search-parameter-tuning
- llmz-m05-assistant
- llmz-m05-built-in-judge
- llmz-m05-capturing-metrics
- llmz-m05-chat-app
- llmz-m05-feedback-dashboard
- llmz-m05-grafana-dashboards
- llmz-m05-monitoring
- llmz-m05-next-steps
- llmz-m05-querying-data
- llmz-m05-storing-data-in-postgresql
- llmz-m05-streamlit-dashboard
- llmz-m05-synthetic-data-generation
- llmz-m05-user-feedback
- llmz-m06-best-practices-for-rag
- llmz-m06-next-steps
- llmz-m07-chunking-for-longer-texts
- llmz-m07-content-processing-cases-and-steps
- llmz-m07-end-to-end-project-example
- llmz-m07-evaluating-rag
- llmz-m07-evaluating-retrieval
- llmz-m07-interface-and-ingestion-pipeline
- llmz-m07-monitoring-and-containerization
- llmz-m07-summary-and-closing-remarks