# How Project N.O.M.A.D. Handles Docker Container Orchestration

> Discover how Project N.O.M.A.D. handles Docker container orchestration using Docker Compose for dynamic management and zero-downtime rolling updates.

- Repository: [Crosstalk Solutions/project-nomad](https://github.com/Crosstalk-Solutions/project-nomad)
- Tags: how-to-guide
- Published: 2026-03-16

---

**Project N.O.M.A.D. uses Docker Compose to orchestrate a multi-service stack where the admin container mounts the host Docker socket to dynamically manage containers, supplemented by a dedicated sidecar updater for zero-downtime rolling updates.**

Project N.O.M.A.D. (Network-Orchestrated Media-Asset Delivery) from the `Crosstalk-Solutions/project-nomad` repository implements a sophisticated Docker container orchestration strategy that balances deployment simplicity with powerful runtime control. The entire application stack runs inside Docker containers coordinated through a declarative Compose file, eliminating external orchestration dependencies like Kubernetes while providing enterprise-grade container lifecycle management. This self-contained architecture enables single-command deployments with intelligent update capabilities through a custom sidecar pattern.

## Docker Compose Foundation and Service Architecture

The orchestration layer centers on [`install/management_compose.yaml`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/management_compose.yaml), which defines six tightly-coupled services in a single Compose project:

- **admin** – The main AdonisJS web/API server (`ghcr.io/crosstalk-solutions/project-nomad:latest`) that drives the UI and background workers.
- **disk-collector** – A read-only filesystem metadata scanner (`ghcr.io/crosstalk-solutions/project-nomad-disk-collector:latest`) with host-root bind access.
- **mysql** – Persistent relational database using the official `mysql:8.0` image.
- **redis** – In-memory cache and queue backend running `redis:7-alpine`.
- **dozzle** – Real-time log viewer (`amir20/dozzle:v10.0`) for container monitoring.
- **updater** – Sidecar service built from `install/sidecar-updater/Dockerfile` that manages rolling updates.

Each service mounts specific volumes for persistence, with the admin and updater containers receiving special access to the host Docker socket for runtime orchestration.

## Admin Container as Runtime Orchestrator

By mounting `/var/run/docker.sock` directly into the admin container, Project N.O.M.A.D. grants the AdonisJS application direct Docker CLI capabilities without requiring external orchestration tools. This design allows the admin service to invoke `dockerode` (Node.js Docker library) or native Docker commands to start, stop, or remove background worker containers on demand.

The socket mount configuration in [`install/management_compose.yaml`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/management_compose.yaml) appears as:

```yaml
services:
  admin:
    image: ghcr.io/crosstalk-solutions/project-nomad:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /opt/project-nomad/storage:/app/storage
    depends_on:
      - mysql
      - redis

```

This architecture centralizes control within the admin service while maintaining strict isolation for filesystem-focused containers like the disk-collector, which runs with read-only host root access (`/:/host:ro,rslave`) but no Docker socket privileges.

## Container Bootstrap and Entrypoint Management

When the admin container starts, [`install/entrypoint.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/entrypoint.sh) executes a deterministic boot sequence that ensures dependent services are healthy before accepting traffic:

```bash
#!/bin/sh
set -e
/usr/local/bin/wait-for-it.sh ${DB_HOST}:${DB_PORT} -t 60 -- echo "MySQL is up and running!"
node ace migration:run --force
node ace db:seed
node ace queue:work --all &
exec node bin/server.js

```

This script handles database migrations, seeding, and queue worker initialization, preventing race conditions during stack startup. The `depends_on` directives in the Compose file coordinate container start order, while the entrypoint script handles application-level readiness.

## Zero-Downtime Updates via Sidecar Pattern

Project N.O.M.A.D. implements a unique sidecar updater that achieves zero-downtime deployments without complex orchestration platforms. The updater runs in an isolated Alpine container that watches for update requests and performs sequential service replacements.

### Update Trigger Mechanism

When an operator initiates an update through the UI, the admin service writes a JSON request to a shared volume mounted at `/opt/project-nomad/update-shared/`:

```bash
cat <<EOF > /opt/project-nomad/update-shared/update-request
{
  "target_tag": "v2.3.0"
}
EOF

```

### Rolling Update Execution

The [`install/sidecar-updater/update-watcher.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/sidecar-updater/update-watcher.sh) script detects this file and executes a controlled rolling update:

1. **Patch the Compose file** – Uses `sed` to substitute the image tag:
   ```bash
   sed -i "s|\(image: ghcr\.io/crosstalk-solutions/project-nomad\):.*|\1:${target_tag}|" "$COMPOSE_FILE"
   ```

2. **Pull updated images** – Runs `docker compose pull` to fetch new layers.

3. **Sequential recreation** – Stops, removes, and recreates each service individually (excluding itself), ensuring the application remains available throughout the process.

4. **Status reporting** – Writes progress to a JSON status file in the shared volume for UI feedback.

## Initial Deployment and Lifecycle Commands

Deploying the stack requires only Docker and the Compose file:

```bash
docker compose -p project-nomad -f ./install/management_compose.yaml up -d

```

This command starts all services detached, creates the project network, and establishes volume mounts. For routine management, the repository includes convenience scripts:

- [`install/start_nomad.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/start_nomad.sh) – Wraps the compose up command with project-specific parameters.
- [`install/stop_nomad.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/stop_nomad.sh) – Gracefully stops containers using `docker compose down`.
- [`install/uninstall_nomad.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/uninstall_nomad.sh) – Removes containers and cleans up resources.

## Summary

- **Docker Compose** serves as the declarative orchestration engine, defined entirely in [`install/management_compose.yaml`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/management_compose.yaml).
- **Admin socket access** enables dynamic container management by mounting `/var/run/docker.sock`, allowing runtime control without Kubernetes.
- **Sidecar updater** provides sophisticated rolling updates through [`install/sideside-updater/update-watcher.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/sideside-updater/update-watcher.sh), patching Compose files and sequentially recreating services.
- **Entrypoint orchestration** via [`install/entrypoint.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/entrypoint.sh) ensures database readiness and proper worker initialization before serving traffic.
- **Service isolation** limits security exposure by granting filesystem access only to the disk-collector and Docker socket access only to admin and updater containers.

## Frequently Asked Questions

### Does Project N.O.M.A.D. require Kubernetes for container orchestration?

No, Project N.O.M.A.D. deliberately avoids Kubernetes dependencies, using Docker Compose as its native orchestration layer. The architecture achieves dynamic container management through Docker socket access rather than external orchestrators, making it suitable for single-node or small-scale deployments without the operational complexity of Kubernetes clusters.

### How does the admin container safely manage other containers?

The admin container receives privileged access to the host Docker socket through a volume mount (`/var/run/docker.sock:/var/run/docker.sock`), allowing it to execute Docker API calls as if running on the host. This capability enables the AdonisJS application to spawn background workers and trigger updates while maintaining container isolation for other services like the disk-collector, which lacks socket access.

### What happens during a zero-downtime update process?

The sidecar updater container detects update requests written to a shared volume, then sequentially stops and recreates each service defined in the Compose file while excluding itself from the rotation. It patches the image tags using `sed`, pulls new images via `docker compose pull`, and recreates containers one-by-one, ensuring the admin API remains available throughout the deployment.

### Where are the Docker orchestration files located in the repository?

All orchestration assets reside in the `install/` directory: [`install/management_compose.yaml`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/management_compose.yaml) defines the service topology, [`install/entrypoint.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/entrypoint.sh) handles container bootstrapping, `install/sidecar-updater/Dockerfile` builds the updater image, and [`install/sidecar-updater/update-watcher.sh`](https://github.com/Crosstalk-Solutions/project-nomad/blob/main/install/sidecar-updater/update-watcher.sh) contains the rolling update logic. The main application Dockerfile sits in the repository root for building the `ghcr.io/crosstalk-solutions/project-nomad:latest` image.