-
Notifications
You must be signed in to change notification settings - Fork 0
Container Management API ‐ Proof of Concept
Warning
This page is legacy / archived and may be outdated. It is preserved for historical context only and is not the source of truth for current operations.
Use current documentation instead:
You can also start from Archive / Legacy Index.
This PoC extends our current FastAPI implementation with asynchronous container lifecycle management capabilities.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ FastAPI App │────│ Docker Daemon │────│ Containers │
│ + Rate Limiter │ │ │ │ │
│ (SlowAPI) │ │ │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
│
┌─────────────────┐
│ Database │
│ (SQLAlchemy) │
└─────────────────┘
Description
- FastAPI Application: Web framework serving as the API layer
-
Docker Integration: Direct communication with Docker daemon via
docker-pylibrary - Database Layer: SQLAlchemy-based async persistence for container metadata
- Container Layer: Docker containers running monitoring services that subscribe to and process MQTT topics in real-time (🚧 WIP)
To prevent blocking the main event loop, all Docker daemon interactions are wrapped using asyncio.to_thread() (or similar async wrapper).
This approach ensures that:
- ✅ Docker API calls don't block the FastAPI event loop
- ✅ Multiple container operations can be processed concurrently
- ✅ The application remains responsive under load
# Example implementation pattern
async def create_container_async(container_config):
return await asyncio.to_thread(docker_client.containers.run, **container_config)The service (container) management endpoints are located in api/v1/services.py:
-
GET /api/v1/services/all/- List all monitoring services (with optionalactive_onlyfilter) -
POST /api/v1/services/start/- Create and start a new monitoring service container -
GET /api/v1/services/- Get details for a specific monitoring service by container name or ID -
DELETE /api/v1/services/stop/- Stop and remove a monitoring service container
The rate limiting system is implemented at the FastAPI application layer using SlowAPI, which provides in-memory rate limiting without requiring database persistence.
Rate limits are enforced directly within the FastAPI middleware stack, allowing for immediate request filtering before any business logic execution kicks in. This early intervention prevents unnecessary resource consumption and protects the inner stack from propagating potential abuse.
Since the rate limiting operates in-memory rather than persisting limits to the database, it delivers faster response times and significantly reduces database load. This also bypasses any database connectivity issues that may arise under heavy load, thus providing an additional layer of system resilience.
Time windows and request quotas can be configured "on-the-fly" based on system capacity and usage patterns, ensuring fair resource allocation across clients while protecting both the FastAPI application and the underlying Docker daemon from overload conditions.
- ✅ Current implementation uses decorators like
@shared_limit_fetchand@shared_limit_execute, capable of enforcing different rate limit policies based on operation impact.
# Example SlowAPI configuration
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
limiter = Limiter(
key_func=get_remote_address,
default_limits=["100/hour"],
storage_uri="memory://"
)
# Per-endpoint rate limits
@limiter.limit("10/minute")
async def create_service():
pass- ✅ Limits the number of concurrent Docker API calls (~5, can be configured manually or through env variables)
- Prevents overwhelming the Docker daemon
- ✅ Configurable semaphore count based on system resources
# Example semaphore usage
docker_semaphore = asyncio.Semaphore(10) # Max 10 concurrent Docker operations
async def docker_operation():
async with docker_semaphore:
# Docker API call here
passCurrently the MonitoringService database model tracks all container operations with the following metadata:
- ID: Primary key string identifier for each monitoring service record
- Container ID: Docker-assigned container identifier (unique, nullable for flexibility)
- Container Name: Human-readable name of the monitoring service container (unique, required)
- Stateful Set Name: Kubernetes StatefulSet identifier (unique, nullable for future K8s integration)
- MQTT Topic: JSON field containing the MQTT topics being monitored by the service
- Created At: Timestamp recording when the monitoring service was created
- Status: Boolean flag indicating whether the service is active (True) or stopped (False)
Potential properties that should be considered include:
- Image: Docker image used for the container
- Updated Timestamp: Last modification time
- Ports: Port mappings and network configuration
- Labels: Custom labels and tags
✅ All database operations use SQLAlchemy's async drivers to maintain non-blocking behavior:
# Example async database operation
async def create_service_record(session: AsyncSession, service_data: dict):
service = AsyncMonitoringService(**service_data)
session.add(service)
await session.commit()
return service# Docker configuration
DOCKER_HOST=unix:///var/run/docker.sock
# Rate limiting
RATE_LIMIT_REQUESTS=100
RATE_LIMIT_WINDOW=3600
# Concurrency
MAX_CONCURRENT_DOCKER_OPS=10There are three basic requirements to be met:
- The application MUST handle communication with the Docker API in order to perform CRUD operations
- The application MUST prevent abuse and overload of the Docker API
- The application MUST maintain comprehensive logging across all user-facing operations
✅ Non-blocking I/O: All Docker and database operations are asynchronous
✅ Concurrent Processing: Multiple requests can be handled simultaneously
✅ Resource Efficiency: Optimal use of system resources through semaphores
✅ Data Persistence: All container operations are logged to the database
✅ State Management: Container states are tracked and maintained
✅ Rate Limiting: Prevents abuse and resource exhaustion
✅ Concurrency Control: Protects Docker daemon from overload
🔴 Audit Trail: Complete history of container operations
-
⚠️ The current implementation runs all components on a single host -
🔴
docker-pybinds directly with the docker system socket in the host
- Multi-host Support: Extend to manage containers across multiple Docker hosts
- Load Balancing: Distribute container workloads across hosts
- Clustering: Implement Docker Swarm or Kubernetes integration
- Metrics Collection: Integrate Prometheus for container metrics
- Health Checks: Automated container health monitoring
- Alerting: Notification system for container failures
- Authentication: User-based access control
- Authorization: Role-based permissions for container operations
- Network Isolation: Enhanced container networking security