> ## Documentation Index
> Fetch the complete documentation index at: https://aegean.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Docker Containers

> Building and running the course Docker environments for GPU and CPU workloads.

A container-based environment is the best way to work on AI/ML projects. The [eng-ai-agents](https://github.com/pantelis/eng-ai-agents) repository provides pre-configured Docker containers with PyTorch, common ML libraries, and a `uv`-managed virtual environment.

<iframe width="560" height="315" src="https://www.youtube.com/embed/pTFZFxd4hOI" frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen />

## Installing Docker

We recommend [VS Code](https://code.visualstudio.com/) as your IDE due to its support for [Dev Containers](https://code.visualstudio.com/docs/remote/remote-overview). Install Docker for your operating system:

### Windows.

Install WSL and follow the instructions below to install Docker natively in WSL. Do **not** install Docker Desktop - all development must happen in the Ubuntu terminal.

```bash theme={null}
# 1. Drop the snap
  sudo snap stop docker
  sudo snap remove --purge docker

  # 2. Install Docker CE (official repo)
  sudo apt-get update
  sudo apt-get install -y ca-certificates curl
  sudo install -m 0755 -d /etc/apt/keyrings
  sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
  sudo chmod a+r /etc/apt/keyrings/docker.asc
  echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
    | sudo tee /etc/apt/sources.list.d/docker.list >/dev/null
  sudo apt-get update
  sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

  # 3. Group + start
  sudo usermod -aG docker "$USER"
  sudo service docker start

  # 4. Re-open WSL shell (group change), then verify the root dir moves off snap
  docker info | grep -iE 'root dir|storage|server version'
  # Expect: Docker Root Dir: /var/lib/docker
```

### Ubuntu

Follow the [Docker Engine instructions](https://docs.docker.com/engine/install/ubuntu/). Never install Docker as a snap package. The snap version runs under strict AppArmor confinement that only permits bind mounts from a small allow-list.

### Apple Silicon (M1/M2/M3/M4)

Install [Docker Desktop](https://docs.docker.com/docker-for-mac/install/). Macs with Apple Silicon can run course containers using Docker Desktop's built-in ARM emulation. For most ML notebooks the CPU container (`torch.dev.cpu`) works well. For GPU-accelerated training, PyTorch supports Apple's [Metal Performance Shaders (MPS)](https://developer.apple.com/metal/pytorch/) backend, which uses the unified memory architecture of the M-series chips.

#### PyTorch with MPS acceleration

MPS acceleration is available when running PyTorch **natively on macOS** (outside Docker). To use it:

```python theme={null}
import torch

# Check MPS availability
if torch.backends.mps.is_available():
    device = torch.device("mps")
else:
    device = torch.device("cpu")

model = model.to(device)
tensor = tensor.to(device)
```

If a specific operation is not yet implemented in MPS, set this environment variable to fall back to CPU automatically:

```bash theme={null}
export PYTORCH_ENABLE_MPS_FALLBACK=1
```

<Note>
  MPS support is maturing but not all PyTorch operations are implemented yet. For operations that fail on MPS, the fallback variable ensures training continues on CPU without errors. Check the [MPS backend documentation](https://docs.pytorch.org/docs/stable/notes/mps.html) for the latest compatibility.
</Note>

### ROS on Mac

ROS2 does not run natively on macOS. Mac users must use the **`ros.dev.gpu` Docker container** for all robotics coursework. The container provides a full ROS2 Jazzy environment with GUI support via X11 forwarding or VNC.

To enable GUI applications (RViz, Gazebo) on macOS, install [XQuartz](https://www.xquartz.org/):

```bash theme={null}
brew install --cask xquartz
```

After installing, open XQuartz, go to **Preferences > Security**, and enable **Allow connections from network clients**. Then allow connections:

```bash theme={null}
xhost +localhost
```

## Course environment setup

1. [Import the repository](https://docs.github.com/en/migrations/importing-source-code/using-github-importer/importing-a-repository-with-github-importer) to your own GitHub account
2. Clone it locally and copy `.env.example` to `.env`
3. Build and run the Docker container (`make docker-build-gpu` or `make docker-build-cpu`)
4. Submit your work to **Canvas/Brightspace** via GitHub

## Configuration

All Docker services read their configuration from a `.env` file in the repository root. Copy the example to get started:

```bash theme={null}
cp .env.example .env
```

Key variables:

```bash theme={null}
# .env
UV_EXTRA=gpu                    # PyTorch variant: gpu or cpu
WORKSPACE_DIR=/workspaces/eng-ai-agents
WORKSPACE_USER=vscode
WANDB_API_KEY=your_api_key_here # For experiment tracking (optional)
```

The `docker-compose.yml` loads `.env` via `env_file`, making all variables available inside every container.

<Warning>
  Never commit your `.env` file to git. It contains your API keys. The repository's `.gitignore` already excludes it.
</Warning>

## Docker Compose services

Three services are defined in `docker-compose.yml`:

| Service         | Container           | GPU          | Use case                                     |
| --------------- | ------------------- | ------------ | -------------------------------------------- |
| `torch.dev.gpu` | `eng-ai-agents-dev` | NVIDIA (all) | PyTorch notebooks requiring GPU acceleration |
| `torch.dev.cpu` | `eng-ai-agents-cpu` | None         | Lightweight notebooks, CI, non-GPU workloads |
| `ros.dev.gpu`   | `eng-ai-agents-ros` | NVIDIA (all) | ROS2 robotics notebooks with GPU support     |

All services mount the repository as a workspace volume, so edits on the host are immediately reflected inside the container.

## Build targets

Build containers using `make` from the repository root:

| Command                 | Description                                        |
| ----------------------- | -------------------------------------------------- |
| `make docker-build-gpu` | Build the GPU container (`Dockerfile.nvidia.dgpu`) |
| `make docker-build-cpu` | Build the CPU container (`Dockerfile.cpu.amd64`)   |
| `make docker-build`     | Build both GPU and CPU containers                  |

## Run targets

| Command               | Description                                                   |
| --------------------- | ------------------------------------------------------------- |
| `make docker-run-gpu` | Start an interactive GPU container with the workspace mounted |
| `make docker-run-cpu` | Start an interactive CPU container with the workspace mounted |

## Development setup

Once inside a container (or on the host with Python 3.11+), use these targets to set up the development environment:

| Command                  | Description                                                                    |
| ------------------------ | ------------------------------------------------------------------------------ |
| `make start`             | Recreate venv, sync dependencies, install package, and register Jupyter kernel |
| `make install`           | Install the package in the virtual environment                                 |
| `make install-dev`       | Install with development extras (linting, testing)                             |
| `make install-notebooks` | Install notebook extras and register the Jupyter kernel                        |
| `make setup-dev`         | Install dev dependencies and set up pre-commit hooks                           |

## Port mappings

Each service exposes ports for development tools:

| Service         | Quarto | Jupyter | Dev  |
| --------------- | ------ | ------- | ---- |
| `torch.dev.gpu` | 4100   | 8888    | 8000 |
| `torch.dev.cpu` | 4101   | 8889    | 8001 |
| `ros.dev.gpu`   | 4180   | 8880    | 8078 |

<Note>
  Port mappings can be customized through environment variables in `.env` (e.g., `DEV_JUPYTER_PORT=8888`).
</Note>

***

<Callout icon="pen-to-square" iconType="regular">
  [Edit this page on GitHub](https://github.com/aegean-ai/eaia/edit/main/src/aiml-common/resources/environment/docker-containers.mdx) or [file an issue](https://github.com/aegean-ai/eaia/issues/new/choose).
</Callout>
