Inspector de Docker Compose
Analiza archivos docker-compose.yml para problemas de seguridad, puertos expuestos y contenedores privilegiados
Docker Compose Structure Inspector
Docker Compose files define multi-container application architectures as declarative YAML documents.
A single docker-compose.yml (or compose.yaml following the Compose Specification)
describes services, networks, volumes, configs, and secrets β everything needed to run a distributed
application locally or in production. As projects grow, these files become complex dependency graphs
where services depend on other services, share networks, mount overlapping volumes, and expose ports
that must not collide. This inspector analyzes the structural topology of your Compose files, revealing
how services connect, what their startup order looks like, and where architectural issues may hide.
Unlike security-focused scanners that check for privilege escalation or exposed secrets, this tool examines the architectural blueprint itself: service relationships, network segmentation, volume ownership, port allocation conflicts, and dependency chains. It answers structural questions such as "which services start before the database?" or "do any services share a named volume without explicit intent?" β questions that matter when debugging startup failures, planning horizontal scaling, or onboarding new team members to a complex microservices stack.
Service Dependency Graphs and Startup Order
The depends_on key in Docker Compose establishes directed edges in a service
dependency graph. When service A depends on service B, Compose guarantees that B starts before A.
However, "starts before" does not mean "is ready" β a common source of production failures. The
Compose Specification introduced condition-based dependencies to address this:
- service_started β The default condition. Compose starts the dependency container but does not wait for it to be healthy or fully initialized.
-
service_healthy β Compose waits until the dependency passes its
healthcheckbefore starting the dependent service. This requires a validhealthcheckblock on the dependency. - service_completed_successfully β Compose waits until the dependency container exits with code 0. Useful for migration or seed containers that must finish before the application starts.
This inspector builds the complete dependency graph and detects potential issues: circular
dependencies (which Compose rejects), missing healthchecks on services referenced with
service_healthy, orphan services with no dependents or dependencies, and
excessively deep dependency chains that slow startup. It visualizes the topological sort order
that Compose uses internally, helping you understand exactly which containers launch in parallel
and which block others.
Network Topology and Service Communication
Every Compose project creates a default bridge network that all services join automatically. While convenient for small projects, relying solely on the default network means every service can reach every other service by its container name β no isolation boundaries exist. Custom networks let you segment services into logical tiers:
- Bridge networks β The standard single-host network driver. Services on the same bridge can communicate via DNS names. Services on different bridges are isolated unless they share a network.
- Overlay networks β Span multiple Docker hosts in a Swarm cluster. Required for multi-node deployments where services run on different machines.
-
Custom named networks β Defined in the top-level
networkskey and attached to services via thenetworkslist in each service block. A service can join multiple networks simultaneously.
The inspector maps which services share networks, identifies services that are unreachable from
others (disconnected subgraphs), detects services attached to networks that no other service
uses, and highlights services exposed to multiple network segments. It also checks for port
conflicts: two services publishing the same host port will fail at runtime, but Compose only
reports this at docker compose up time. Catching it during inspection saves
debugging time.
Volume Mappings and Bind Mount Analysis
Volumes in Docker Compose come in two forms: named volumes managed by Docker and bind mounts that map host directories into containers. Each has distinct implications for data persistence, portability, and potential conflicts:
-
Named volumes β Declared in the top-level
volumeskey and referenced by services. Docker manages their lifecycle. Multiple services can mount the same named volume, enabling shared data patterns (but also introducing concurrent write risks). -
Bind mounts β Use host paths directly (e.g.,
./src:/app/src). Common in development for live code reloading. The inspector flags relative paths, missing host directories, and mounts that overlap with named volumes. -
tmpfs mounts β In-memory filesystems that do not persist data. Useful for
sensitive temporary files. Declared with
tmpfs:in the service block.
The inspector identifies services sharing the same named volume (potential data races), bind mounts pointing to the same host path from different services, volumes declared but never referenced (dead declarations), and read-only vs read-write mount permissions. Understanding volume topology is critical when migrating from development to production, where bind mounts must be replaced with persistent storage solutions.
Port Exposure and Environment Configuration
Docker Compose distinguishes between expose (internal container-to-container ports)
and ports (host-mapped ports accessible from outside Docker). The short syntax
"8080:80" maps host port 8080 to container port 80. The long syntax provides
additional control over protocol, host IP binding, and port ranges.
Common structural issues the inspector detects in port configuration:
-
Host port collisions β Two services mapping to the same host port
(e.g., both claiming
0.0.0.0:3000). This fails silently until runtime. - Unnecessary host exposure β Services that only need inter-container communication but publish ports to the host, expanding the attack surface.
- Missing expose declarations β Services that other services depend on but that neither expose nor publish the expected port, causing connection refused errors.
For environment variables, the inspector maps which services use environment
inline keys versus env_file references, checks for duplicate variable definitions
across services, and identifies variables referenced via interpolation
(${VARIABLE}) that may not be defined in any .env file.
Code Examples
Multi-service Compose file with dependency graph and network segmentation
services:
postgres:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
networks:
- backend
environment:
POSTGRES_DB: appdb
POSTGRES_USER: admin
POSTGRES_PASSWORD: ${DB_PASSWORD}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U admin -d appdb"]
interval: 5s
timeout: 3s
retries: 5
redis:
image: redis:7-alpine
networks:
- backend
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
api:
build: ./api
ports:
- "3000:3000"
networks:
- backend
- frontend
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
environment:
DATABASE_URL: postgresql://admin:${DB_PASSWORD}@postgres:5432/appdb
REDIS_URL: redis://redis:6379
worker:
build: ./worker
networks:
- backend
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
networks:
- frontend
depends_on:
- api
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
volumes:
pgdata:
networks:
backend:
driver: bridge
frontend:
driver: bridgeOutput:
Service Dependency Graph:
postgres (no dependencies) β starts first
redis (no dependencies) β starts first
api β waits for postgres (healthy), redis (healthy)
worker β waits for postgres (healthy), redis (healthy)
nginx β waits for api (started)
Startup Order (topological): [postgres, redis] β [api, worker] β [nginx]
Network Segmentation:
backend: postgres, redis, api, worker
frontend: api, nginx
Port Mappings:
api: 3000 β host:3000
nginx: 80 β host:80, 443 β host:443
Volumes:
pgdata (named): mounted by postgres
./nginx/nginx.conf (bind, read-only): mounted by nginxStandards & Specifications
- Compose Specification β The official Compose Specification defining the schema for compose.yaml files, service configuration, networking, and volume declarations
- Docker Compose File Reference β Docker documentation covering all top-level keys, service options, network drivers, and volume configuration in Compose files
- Compose Specification GitHub β The canonical source for the Compose Specification including service dependencies, healthcheck integration, and extension fields