Working on AI models locally gives you a ton of control and lets you iterate way faster than waiting on cloud instances for many projects. The problem is that managing all the dependencies, environments, and hardware acceleration across different machines can grind you to a halt, especially with something as specific as a Surface Laptop Ultra. This is where getting Docker AI integrated into your workflow stops being a “nice to have” and becomes essential for creating a portable, reproducible dev environment. But how do you actually get it running at peak performance on a high-end laptop?
Key Takeaways
- Set up a dedicated WSL 2 distribution just for Docker Desktop. This walls off your AI dev environments and stops them from messing with your main Windows system.
- Give Docker Desktop at least 16GB of RAM and 8 CPU cores in its settings. If you don’t, you’re just hamstringing the Surface Laptop Ultra and your model training will crawl.
- Mount your Windows directories as Docker volumes with the right permissions. It’s the only sane way to share huge datasets and model checkpoints between your host and the Linux containers.
- Use Docker Compose to map out your entire multi-service AI app, letting you spin up containers for preprocessing, training, and inference with one command.
- If you’re using an external GPU enclosure with an NVIDIA card, get GPU passthrough working by configuring Docker to use the host’s CUDA cores for massively accelerated training.
Setting Up Your Foundation: WSL 2 and Docker Desktop
The first step toward a sane local AI workflow on a Surface Laptop Ultra is getting your foundation right with Windows Subsystem for Linux 2 (WSL 2) and Docker Desktop. Sure, Docker can run on Windows natively, but using the WSL 2 backend gives you a full Linux kernel, and the performance boost is massive, especially for the I/O-heavy data loading you’re always doing in AI. I’ve seen projects get a 2x data-loading speedup just by switching from native Windows Docker to the WSL 2 engine.
First, get WSL 2 installed and updated. Open PowerShell as an administrator and run wsl, install. Once it’s done, I highly recommend setting a specific Linux distribution like Ubuntu 24.04 LTS as your default using wsl, set-default Ubuntu-24.04. Having this dedicated Linux box isolates your project dependencies from your main Windows setup, which saves you from a world of pain with conflicting libraries. Next, install Docker Desktop. It’s smart enough to detect WSL 2 and will ask to enable its integration during setup, and you absolutely want to say yes, because you’re throwing away performance if you don’t. Go into Docker Desktop’s settings to “Resources” > “WSL Integration” and make sure your Ubuntu distro is toggled on. While you’re there, give it enough power. For any serious AI work on a machine like the Surface Laptop Ultra, I’d assign it at least 16GB of RAM and 8 CPU cores. Trying to save resources here is a mistake that you’ll pay for with painfully long training times.
Crafting Your AI Environment with Dockerfiles
The Dockerfile is your environment’s blueprint. It’s a script where you define every single dependency, setting, and command your project needs to run. A good Dockerfile means your environment will be identical everywhere, which finally kills the “but it works on my machine” problem for good. For AI work, this file is where you’ll install specific versions of Python, frameworks like PyTorch or TensorFlow, maybe CUDA drivers for GPU work, and all the usual data science libraries.
Most of my AI Dockerfiles start with an official base image, like nvidia/cuda:12.3.0-cudnn9-devel-ubuntu24.04 if I’m planning to use a GPU, or something simple like python:3.10-slim-bookworm for a CPU-only job. Then you just add commands to install what you need: apt-get update && apt-get install -y git build-essential for system tools, then copy over your requirements.txt file and run pip install, no-cache-dir -r requirements.txt. A common mistake I see all the time is people trying to COPY their massive datasets right into the Docker image. Don’t do this. It makes your images gigantic, your builds take forever, and updating data is a mess. The right way is to use Docker volumes to mount the data directory from your host machine right into the container, keeping your images small and letting you swap out data without a rebuild. You should also set a working directory (WORKDIR /app) and expose ports (like EXPOSE 8888 for a Jupyter notebook).
Here’s a simple, solid example for a PyTorch project:
# Use an official NVIDIA CUDA runtime image as a parent image
FROM nvidia/cuda:12.3.0-cudnn9-devel-ubuntu24.04 # Set the working directory in the container
WORKDIR /app # Install system dependencies
RUN apt-get update && apt-get install -y \ git \ build-essential \ python3-pip \ && rm -rf /var/lib/apt/lists/* # Install Python dependencies
COPY requirements.txt .
RUN pip install, no-cache-dir -r requirements.txt # Copy the rest of your application code
COPY . . # Expose a port (e.g., for JupyterLab)
EXPOSE 8888 # Define environment variables
ENV PYTHONPATH=/app # Command to run when the container starts
CMD ["jupyter", "lab", ", ip=0.0.0.0", ", port=8888", ", allow-root", ", no-browser"]
This approach gives you a repeatable environment. Just run docker build -t my-ai-project . and you’re off to the races.
Orchestrating Complex AI Workflows with Docker Compose
A real-world AI project is rarely just one script. You’ll likely have a service for data ingestion, another for preprocessing, one for training, an API for inference, and maybe something for monitoring. Trying to juggle all those separate Docker containers with long terminal commands is a fast track to insanity. This is exactly what Docker Compose was made for. It lets you define a whole multi-container application in a single YAML file, turning complex network and volume configurations into a simple, readable setup.
In a docker-compose.yml file, you lay out each service, what image it uses, ports, volumes, and environment variables. For example, you could define a `data-processor` container that feeds its output to a `trainer` container, which in turn saves a model that an `api` container loads to serve predictions. Docker Compose handles the networking between them so they can talk to each other. This kind of modular setup is great for development, since you can rebuild and restart just one part of your application stack without taking the whole thing down. I often use it to spin up a local S3-compatible object storage server like MinIO alongside my training containers, which lets me test code that’s meant for a cloud environment right on my laptop.
Imagine a pipeline with a data ingestor, a model trainer, and a Flask API:
version: '3.8' services: data-ingestor: build: context: ./data_ingestor dockerfile: Dockerfile volumes:
- ./data:/app/data
environment:
- RAW_DATA_PATH=/app/data/raw
- PROCESSED_DATA_PATH=/app/data/processed
model-trainer: build: context: ./model_trainer dockerfile: Dockerfile volumes:
- ./data:/app/data
- ./models:/app/models
environment:
- PROCESSED_DATA_PATH=/app/data/processed
- MODEL_SAVE_PATH=/app/models/my_model.pth
depends_on:
- data-ingestor
deploy: resources: reservations: devices:
- driver: nvidia
count: all capabilities: [gpu] # Only if using GPU passthrough inference-api: build: context: ./inference_api dockerfile: Dockerfile ports:
- "8000:8000"
volumes:
- ./models:/app/models
environment:
- MODEL_LOAD_PATH=/app/models/my_model.pth
depends_on:
- model-trainer
With a file like this, a single docker compose up, build command launches your entire AI pipeline. This orchestration saves a huge amount of time and makes getting your project running much less painful.
Optimizing Performance for Surface Laptop Ultra: GPU and Resource Management
The Surface Laptop Ultra, with its powerful CPU and integrated GPU (usually an Intel Arc or something similar), creates some interesting possibilities and headaches. While the integrated GPU might give you a small boost on lightweight models, you’ll need an external GPU enclosure (eGPU) with an NVIDIA card for any serious deep learning. If you have that kind of setup, getting GPU passthrough working correctly in Docker is the top priority. Docker Desktop on Windows with the WSL 2 backend has solid support for NVIDIA CUDA. You just need to install the right NVIDIA drivers on Windows, and Docker Desktop usually handles the rest, passing the GPU into your Linux containers automatically.
To check if your GPU is visible inside a container, just start one up using a GPU-enabled image (like `nvidia/cuda`) and run nvidia-smi from the container’s shell. If you see your GPU’s stats, you’re in business. If not, go back to Docker Desktop’s “Resources” > “GPU” settings and make sure it’s enabled. For non-NVIDIA GPUs, things get tricky. Frameworks like Intel oneAPI and AMD ROCm exist, but Docker’s direct support is heavily skewed toward NVIDIA. For an Intel Arc GPU, you’ll probably have to dig through Intel’s official guides for WSL 2, which can involve hunting for specific driver versions and kernel modules. It’s a lot more work than the plug-and-play experience with NVIDIA.
GPU aside, good resource management is just as important. Always mount your datasets as volumes (e.g., `-v /path/on/host:/path/in/container`). Never COPY them into the image. Using volumes keeps container sizes down and lets Windows manage disk caching, which is much more efficient. When you’re running a heavy training job, keep an eye on your system with Task Manager on the Windows side or by running `htop` in your WSL terminal. If you’re constantly maxing out your CPU or RAM, bump up the resources you’ve allocated in Docker Desktop’s settings. The Surface Laptop Ultra is a beast, but it can still be brought to its knees by thermal throttling if you push it too hard. You’ll often get better performance from a single, well-resourced container than trying to run several that are all starved for resources.
Simplifying Development with VS Code and Docker Extensions
Plugging your code editor directly into Docker is where you really start to see productivity gains. Visual Studio Code has a couple of extensions that make working with containers feel completely native. The “Docker” extension gives you a GUI for managing your containers, images, and volumes right inside the editor, so you can check logs or open a shell in a running container with a couple of clicks. It’s a small thing, but it stops you from having to constantly jump over to a terminal.
What’s even more powerful for AI work is the “Remote – Containers” extension. This extension lets you open a project folder *inside* a running Docker container, effectively turning that container into your full-time development environment. The VS Code server runs inside the container, so your linter, debugger, and autocomplete all have access to the exact library versions defined in your Dockerfile. If your container has PyTorch 2.1.0 and Python 3.10, that’s exactly what your editor uses, which prevents a whole class of version mismatch bugs. For data scientists and ML engineers, this kind of consistent environment is invaluable. You can take it a step further by creating a .devcontainer/devcontainer.json file to automatically configure build settings, run commands after the container is built, and even install specific VS Code extensions for anyone on your team who uses the environment. This is how you get collaborative projects to run smoothly.
Getting a handle on Docker for local AI work on a machine like the Surface Laptop Ultra turns your workflow from a mess of dependency conflicts into a simple, repeatable process. When you combine WSL 2, good Dockerfiles, and Docker Compose for your service pipelines, you get far more control and speed. The ability to spin up and tear down complex, shareable environments means you spend your time actually iterating on models instead of fighting with your configuration.
Why should I bother with Docker for AI on my Surface Laptop Ultra?
Docker packages your AI project’s specific dependencies (like Python 3.9, PyTorch 2.0, a certain CUDA version) into an isolated, portable box. This stops libraries from conflicting with your main OS or other projects and makes it so anyone can run your code without a week of setup.
How much RAM/CPU does Docker need for AI work on this laptop?
For actual model training, give Docker’s WSL 2 engine at least 16GB of RAM and 8 CPU cores. The Surface Laptop Ultra can spare it, and giving it enough resources is necessary to avoid performance bottlenecks that will slow your training to a crawl.
Can I use the Surface Laptop Ultra’s integrated GPU in Docker?
An integrated GPU like the Intel Arc might offer a little bit of acceleration, but Docker’s GPU support is built for NVIDIA CUDA. You’ll get the best, most straightforward results with an external NVIDIA GPU. Making an Intel GPU work requires digging into special drivers and WSL 2 configurations, so it’s not a simple plug-and-play option.
What’s Docker Compose for and why use it for an AI project?
Docker Compose is a tool for running applications that have multiple containers. Since AI projects often have separate services for data processing, training, and an API, Compose lets you define and launch that whole pipeline with one command from a simple YAML file.
What’s the best way to get large datasets from Windows into a Docker container?
Use Docker volumes to mount the directory from your host machine that contains the data directly into the container. This method avoids embedding huge files in your container image, which keeps image sizes small, makes builds faster, and lets you access the data in real-time.