Containerize a Python API with Docker

Build a Python API container and connect replicas on a Docker network.

Introduction

30 Second Summary

A small service can work on one computer but fail on another because each machine has different software. Repeating the setup by hand makes that gap harder to diagnose.

In this project, you will package a tiny JSON API as a reusable Docker image. Your Windows computer will run it inside a Linux container that peer containers can reach by name.

What You'll Build

From Windows PowerShell, your finished demo returns versioned JSON at http://localhost:8000 while a peer container reaches the same API as docker-api:8000.

By the end of this project, you'll have:

  • A visible API response: Send a request from Windows. See Hello from Docker v1 in the returned JSON. See version 1 beside it.
  • A repeatable deployment workflow: Rebuild source changes into docker-api-lab:2.0. Confirm both versioned images appear in Docker.
  • Service-name networking: Call the API from a peer container at http://docker-api:8000 on api-lab-net.
  • Secret Mission: An optional challenge to push your container skills further.

Are there any prerequisites?

You need a supported Windows 10 or Windows 11 computer with at least 8 GB of RAM.

Hardware virtualization, internet access, and administrator access for the one-time WSL 2 setup are also required.

Docker Desktop is free for personal use, education, non-commercial open source, and qualifying small businesses.

Before We Start

This opening checkpoint locks in your goal of packaging a Python JSON API inside a Docker container. A user-defined Docker network will later give a gateway container-name DNS for reaching the API.

Set Up Your Windows Docker Workspace

Your API build depends on a Linux container engine that Windows can reach. Docker Desktop supplies that engine for this project.

This step checks your host before you create any project files. You'll prepare Windows Subsystem for Linux version 2. You'll also install Visual Studio Code for editing. Windows PowerShell provides the terminal for every Docker command.

In this step, get ready to:
  • Confirm that Windows meets the Docker Desktop host requirements.
  • Install Visual Studio Code 1.144.0 plus Docker Desktop 4.97.0 for your processor architecture.
  • Prove that Windows PowerShell can reach the Linux container engine.
Check your Windows host and WSL

Docker Desktop needs a supported Windows client with at least 8 GB of RAM. Its Linux engine also depends on hardware virtualization plus WSL version 2.1.5 or later.

  • Press the Windows key to open Windows search.
  • Type Settings into the search field.
  • Press Enter to open Settings.
  • Select System.
  • Select About.
  • Confirm that Windows specifications shows a supported Windows 10 or Windows 11 client edition.
  • Record the matching installer architecture from System type here: x64 or Arm64.
  • Confirm that Installed RAM shows at least 8 GB.

Why check these details?

Your processor architecture decides whether you need the x64 or Arm64 installers. The RAM check confirms that Docker Desktop has enough host memory to run its Linux environment.

  • Right-click the Start button.
  • Select Task Manager.
  • Select Performance.
  • Select CPU.
  • Confirm that Virtualization shows Enabled.

Does Virtualization Show Disabled?

A disabled status means Docker Desktop cannot start its Linux environment yet. The virtualization control lives in your computer's firmware.

  • Follow Microsoft's Windows virtualization guide for your computer manufacturer.
  • Return to Task Manager after Windows restarts.
  • Confirm that Virtualization now shows Enabled.

Help me enable hardware virtualization for Docker Desktop on my Windows computer.

  • Press the Windows key to open Windows search.
  • Type Windows PowerShell into the search field.
  • Press Enter to open Windows PowerShell.
  • Check the installed WSL version by running this command:
wsl --version

What Does This Command Show?

The command prints the installed WSL component versions. Docker Desktop requires WSL version 2.1.5 or later for this setup.

✔️ WSL Meets the Requirement

Your WSL version is 2.1.5 or later. The Linux foundation for Docker Desktop is ready.

ⓧ I See an Older WSL Version

  • Update WSL by running this command:
wsl --update

What Does This Command Do?

The command downloads the current supported WSL update. This brings the WSL components up to the level required by Docker Desktop.

  • Check the updated WSL version by running this command:
wsl --version

What Should You See?

The WSL version now shows 2.1.5 or later. Your host can support the Docker Desktop WSL backend.

ⓧ WSL Is Not Installed

Installing WSL changes Windows features. Administrator access is only needed for this one-time setup.

  • Press the Windows key to open Windows search.
  • Type Windows PowerShell into the search field.
  • Right-click Windows PowerShell in the search results.
  • Select Run as administrator.
  • Approve the Windows permission request.
  • Install WSL by running this command:
wsl --install

What Does This Command Do?

The command enables the Windows features required by WSL. It also installs WSL so Docker Desktop can use a Linux environment.

  • Restart Windows after the installation completes.
  • Press the Windows key after signing back in.
  • Type Windows PowerShell into the search field.
  • Press Enter to open a normal Windows PowerShell terminal.
  • Check the installed WSL version by running this command:
wsl --version

What Should You See?

The output now reports a WSL version. Confirm that it is 2.1.5 or later before continuing.

Is the WSL Check Still Failing?

Confirm that Windows restarted after the installation. An organization-managed computer may also restrict optional Windows features.

Help me diagnose my WSL installation or update.

Install the editor and container engine

The editor and container engine must match the processor architecture you recorded. The pinned releases keep the project instructions consistent with the tools on your screen.

Choose the Visual Studio Code tab that describes your computer's current state.

✔️ Visual Studio Code Is Current

  • Keep your existing Visual Studio Code 1.144.0 installation.

Your editor already matches the release used in this project.

ⓧ I Have an Older Release

  • Open the official Visual Studio Code release page.
  • Select the Windows User Installer matching x64 or Arm64.
  • Run the downloaded User Installer.
  • Complete the update with the recommended User Setup options.
  • Press the Windows key after installation.
  • Type Visual Studio Code into the search field.
  • Press Enter to start the updated editor.

You'll see the Visual Studio Code window open with version 1.144.0 installed.

ⓧ Visual Studio Code Is Not Installed

  • Open the official Visual Studio Code release page.
  • Select the Windows User Installer matching x64 or Arm64.
  • Run the downloaded User Installer.
  • Complete the installation with the recommended User Setup options.
  • Press the Windows key after installation.
  • Type Visual Studio Code into the search field.
  • Press Enter to start the editor.

You'll see the Visual Studio Code window. The final terminal check confirms version 1.144.0 plus command-line access.

Choose the Docker Desktop tab that describes your computer's current state.

✔️ Docker Desktop Is Current

  • Keep your existing Docker Desktop 4.97.0 installation.

Your Docker Desktop release matches this project.

ⓧ I Have an Older Release

  • Open the official Docker Desktop Windows installation page.
  • Download Docker Desktop 4.97.0 for x64 or Arm64.
  • Run the downloaded Docker Desktop installer.
  • Complete the update in the recommended per-user installation mode.

The update keeps Docker Desktop in the per-user location. The WSL backend configuration follows below.

ⓧ Docker Desktop Is Not Installed

  • Open the official Docker Desktop Windows installation page.
  • Download Docker Desktop 4.97.0 for x64 or Arm64.
  • Run the downloaded Docker Desktop installer.
  • Complete the installation in the recommended per-user mode.

The per-user mode supports Linux containers through WSL. It also avoids requiring administrator rights for normal Docker Desktop updates.

Confirm Your Docker Desktop Entitlement

Docker Desktop is free for personal use. It is also free for education or non-commercial open source use.

Qualifying small businesses must have fewer than 250 employees. They must also have less than $10 million USD in annual revenue. Confirm your organization's entitlement before accepting the terms for professional use.

  • Press the Windows key to open Windows search.
  • Type Docker Desktop into the search field.
  • Press Enter to start Docker Desktop.
  • Review the Docker Desktop terms if prompted.
  • Accept the terms only if they fit your use.
  • Allow Docker Desktop to use WSL version 2 if prompted.
  • Select Settings in Docker Desktop.
  • Select General.
  • Select Use WSL 2 based engine if the option is visible.
  • Select Apply if you changed the engine setting.
  • Open the Docker Desktop menu from the Windows taskbar notification area.
  • Select Switch to Linux containers if that option is shown.

How Do You Confirm Linux Container Mode?

Docker Desktop uses WSL version 2 as its Linux backend. The WSL engine option can be hidden when it is already active.

A menu option named Switch to Windows containers confirms that Linux containers are currently active.

Is Docker Desktop Failing to Start?

Confirm that hardware virtualization remains enabled. Confirm that WSL meets version 2.1.5 or later.

Help me diagnose why Docker Desktop cannot start its Linux engine.

Verify the Windows Docker toolchain

A new terminal reloads the command paths added by the installers. These checks prove that Windows PowerShell can reach the editor command plus the Docker client and engine.

  • Close the Windows PowerShell window from the WSL check.
  • Press the Windows key to open Windows search.
  • Type Windows PowerShell into the search field.
  • Press Enter to open a new Windows PowerShell terminal.

Before you run the checks, do you expect the new terminal to recognize every installed tool?

  • Check the PowerShell session by running this command:
$PSVersionTable

What Should PowerShell Show?

The table includes PSVersion with Windows PowerShell version 5.1. This confirms that you opened the terminal used throughout the project.

  • Check the Visual Studio Code command by running this command:
code --version

What Should Visual Studio Code Show?

The first output line reports 1.144.0. The remaining lines identify the build plus your processor architecture.

Is the Code Command Missing?

Confirm that you used the Visual Studio Code User Installer. Close every PowerShell window before opening another terminal so Windows reloads its command path.

Help me restore the Visual Studio Code command in Windows PowerShell.

Docker Desktop's first startup can take a few minutes while the Linux engine becomes ready. A quiet dashboard during that startup does not mean the installation failed.

Before the final check, do you expect PowerShell to reach only the Docker client or both the client and server?

  • Verify the Docker client and Linux container engine by running this command:
docker version

What Should Docker Show?

The output contains both Client and Server sections. The server section proves that the Docker client can reach the running Linux container engine.

Is the Server Section Missing?

Confirm that Docker Desktop is still running. Wait for its startup to finish before repeating the command.

Confirm that Docker Desktop uses the WSL version 2 backend. Confirm that Linux container mode is active.

Help me connect the Docker client to the Docker Desktop Linux engine.

You have cleared the host setup hurdle. Windows PowerShell can now reach the editor and the Linux container engine.

Your Windows Docker workspace is ready. Next, you'll package the Python JSON API into its first reusable image.

Build and Run Your First API Container

Your Windows PowerShell terminal can already reach Docker. The next risk is whether that engine can turn source code into a working API response.

You'll write a small JSON API in Visual Studio Code. Docker will package the API as an image that runs in a container on port 8000.

In this step, get ready to:
  • Create the API project files.
  • Build docker-api-lab:1.0.
  • Serve version 1 JSON from docker-api.
Create the API project files

A build context is the folder Docker reads while building an image. Keeping app.py beside Dockerfile gives the build access to your application source.

  • Switch back to the Windows PowerShell terminal from the previous step.
  • Prepare the docker-api-lab workspace by running these commands:
New-Item -ItemType Directory -Path "docker-api-lab"
Set-Location -Path "docker-api-lab"
code .

What do these commands do?

  • New-Item creates the docker-api-lab directory.
  • Set-Location moves PowerShell into that directory.
  • code . opens the current directory in Visual Studio Code.
  • Confirm that Visual Studio Code shows docker-api-lab as the opened folder.

Did the folder fail to open?

Confirm that PowerShell is inside docker-api-lab. A new terminal may be required after installing Visual Studio Code so the code command is available.

Help me fix the project folder or Visual Studio Code command.

The API uses the built-in Python HTTP server. This keeps the project focused on Docker without adding package installation.

  • Select Explorer in the Visual Studio Code Activity Bar.
  • Select New File in the Explorer view.
  • Enter app.py as the file name.
  • Press Enter to create the file.
  • Fill app.py by pasting this code:
import json
from http.server import BaseHTTPRequestHandler, HTTPServer


class ApiHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = json.dumps(
            {
                "message": "Hello from Docker v1",
                "version": 1,
            }
        ).encode("utf-8")

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8000), ApiHandler)
    print("API listening on port 8000", flush=True)
    server.serve_forever()

What does this code do?

  • ApiHandler handles each incoming GET request.
  • json.dumps() turns the message and version into a JSON response body.
  • The HTTP headers describe the response format and size.
  • HTTPServer listens on every container network interface through port 8000.
  • serve_forever() keeps the API process ready for requests.
  • Save app.py by pressing Ctrl+S.
  • Confirm that the Explorer view lists app.py inside docker-api-lab.

Does the API code look different?

Confirm that the file is named app.py. Compare the indentation inside ApiHandler if Visual Studio Code underlines the code.

Help me compare my API source with the required file.

A Dockerfile records how Docker assembles the image. Its instructions choose the runtime, copy the source, document the port, and define the startup process.

  • Select New File in the Explorer view.
  • Enter Dockerfile as the file name.
  • Press Enter to create the file.
  • Fill Dockerfile by pasting these instructions:
FROM python:3.15.2-slim-bookworm

WORKDIR /app
COPY app.py .

EXPOSE 8000

CMD ["python", "app.py"]

How does the image definition work?

  • FROM selects the pinned python:3.15.2-slim-bookworm runtime image.
  • WORKDIR creates /app as the location for later instructions.
  • COPY places app.py inside the image.
  • EXPOSE documents that the application listens on port 8000.
  • CMD starts the API when a container runs from the image.
  • Save Dockerfile by pressing Ctrl+S.
  • Confirm that the Explorer view lists Dockerfile beside app.py.

Is Dockerfile missing or renamed?

Confirm that the file name is exactly Dockerfile with no file extension. Capitalization matters when Docker searches the build context.

Help me check my Dockerfile name and contents.

✔️ Awesome, I've got everything!

Both project files are saved in docker-api-lab. Your build context is ready.

ⓧ I'd like to double check the full code

The complete app.py file should match this reference:

import json
from http.server import BaseHTTPRequestHandler, HTTPServer


class ApiHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = json.dumps(
            {
                "message": "Hello from Docker v1",
                "version": 1,
            }
        ).encode("utf-8")

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8000), ApiHandler)
    print("API listening on port 8000", flush=True)
    server.serve_forever()

What should match in app.py?

Check the imports, handler class, response values, server address, and startup loop. The response must contain Hello from Docker v1 with version 1.

The complete Dockerfile should match this reference:

FROM python:3.15.2-slim-bookworm

WORKDIR /app
COPY app.py .

EXPOSE 8000

CMD ["python", "app.py"]

What should match in Dockerfile?

Check the pinned base image, working directory, copied source file, exposed port, and startup command. Each instruction becomes part of the repeatable image build.

Build the first image

The image turns the two project files into a reusable package. The tag docker-api-lab:1.0 gives this first build a specific identity.

The first build downloads the base image, so it can take longer than later builds. PowerShell prints each completed build stage while Docker works.

  • Switch back to PowerShell in the docker-api-lab folder.
  • Build the first API image by running this command:
docker build -t docker-api-lab:1.0 .

What does this build command do?

  • docker build reads the Dockerfile and assembles the image.
  • -t docker-api-lab:1.0 assigns the repository name and version tag.
  • . supplies the current docker-api-lab folder as the build context.
  • Confirm that the tagged image exists by running this command:
docker image ls docker-api-lab:1.0

What should the image list show?

The output includes repository docker-api-lab with tag 1.0. This confirms that Docker completed the build.

That's the first reusable image built. Docker can now create containers from the packaged API.

Did the image build fail?

Confirm that PowerShell is inside docker-api-lab. Check that app.py and Dockerfile both appear in that folder.

Help me diagnose my Docker image build.

Run the container and call the API

Port publishing connects a port on Windows to a port inside the container. Mapping 8000:8000 lets PowerShell reach the API through http://localhost:8000.

  • Create the running docker-api container by running this command:
docker run --name docker-api -d -p 8000:8000 docker-api-lab:1.0

How does the container start?

  • --name docker-api assigns a stable name to the container.
  • -d runs the API in the background.
  • -p 8000:8000 publishes the container's API port on Windows.
  • docker-api-lab:1.0 selects the image used to create the container.

PowerShell prints the new container identifier. That output confirms that Docker created the background container.

Did the container fail to start?

Confirm that Docker Desktop is still running. A naming conflict or occupied host port can also prevent the container from starting.

Help me diagnose why the API container did not start.

Before you send the request, which message and version do you expect the container to return?

  • Send the verification request from PowerShell by running this command:
Invoke-RestMethod -Uri "http://localhost:8000"

What does this request prove?

Invoke-RestMethod sends a request to the published host port. PowerShell parses the JSON response into visible message and version fields.

A successful response proves that the source code, Dockerfile, image build, port mapping, and container process work together.

PowerShell displays Hello from Docker v1 with version 1. You now have a Linux container serving your first API response from Windows.

Did the request fail?

Confirm that the container start command printed a container identifier. Check that the request uses port 8000 and that Docker Desktop remains running.

Help me trace why the local API request cannot reach my container.

Your first image now runs as a named container with a published API port. Next, you'll test whether editing the host source changes the container that is already running.

Prove the Container Is a Snapshot

Your version 1 API is already running inside a Docker container. That visible JSON response proves your image, published port, and Python process work as one.

The open question is whether editing app.py on Windows also changes the process that is already running. This step creates a controlled snapshot test to find out.

In this step, get ready to:
  • Inspect the running container, stored image, and request logs.
  • Change the JSON response in the host copy of app.py.
  • Compare the running API response with the saved host source.
Inspect the running deployment

Runtime evidence connects docker-api to the build that serves your request. The container listing, image listing, and logs expose each part of that trail.

  • Collect the deployment evidence by running these commands:
docker ps
docker image ls
docker logs docker-api

What does this evidence show?

  • The container listing includes docker-api as a running container.
  • Its port details connect host port 8000 to container port 8000.
  • The image listing includes docker-api-lab:1.0 as the stored build.
  • The logs include API listening on port 8000 plus entries for the requests you sent.

Missing the container or logs?

  • Confirm Docker Desktop is still running.
  • Confirm the docker-api row is present in the running-container output.

If the expected evidence is still missing, help me diagnose the Docker container inspection results.

That is a useful checkpoint: the live response now has a clear trail back to its container, image, port, and logs.

Change the host source

The next edit creates a controlled difference between the source on Windows and the process already running. Only the two response values need to change.

  • Switch back to app.py in VS Code.
  • Find the message value Hello from Docker v1.
  • Replace it with Hello from Docker v2.
  • Find the version value 1 directly below the message.
  • Replace it with 2.
  • Save app.py.

Do the response values look different?

Confirm the message ends with v2. Confirm the numeric version directly below it is 2.

If the two values still do not match, help me check the version 2 response values in app.py.

✔️ Awesome, I've got everything!

Your saved app.py now contains the version 2 response. The existing image, container, and Dockerfile remain unchanged for the comparison.

ⓧ I'd like to double check the full code

Your Dockerfile remains unchanged. Compare the complete saved app.py with this reference.

import json
from http.server import BaseHTTPRequestHandler, HTTPServer


class ApiHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        body = json.dumps(
            {
                "message": "Hello from Docker v2",
                "version": 2,
            }
        ).encode("utf-8")

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)


if __name__ == "__main__":
    server = HTTPServer(("0.0.0.0", 8000), ApiHandler)
    print("API listening on port 8000", flush=True)
    server.serve_forever()

What should match?

The response object contains Hello from Docker v2 and numeric version 2. Every other line remains unchanged from the working API.

Test the existing container

The same published port still leads to the existing docker-api process. A new request reveals which response that process currently serves.

Before you send the request, predict whether the existing container returns version 1 or version 2.

  • Request the running API by running this command:
Invoke-RestMethod -Uri "http://localhost:8000"

What did the snapshot prove?

  • PowerShell still displays Hello from Docker v1 and version 1.
  • The saved host file contains Hello from Docker v2 and version 2.
  • The running container still executes the filesystem snapshot captured in docker-api-lab:1.0.
  • This demonstrates an immutable deployment. A rebuild and replacement are required before the new source can serve requests.

Seeing version 2 or no response?

  • Confirm the saved app.py file contains the version 2 values.
  • Confirm docker-api-lab:1.0 was not rebuilt after the edit.
  • Confirm docker-api was not removed or recreated after the edit.

If the comparison still differs, help me diagnose why my snapshot test did not return version 1.

You have proved the snapshot boundary: changing the Windows source does not patch a container that already started from an image. Next, you will turn the saved edit into a new image and replace the old container.

Rebuild the API and Test Default Networking

Your earlier snapshot test proved that the running container still serves the version 1 image. Now you need a replacement that serves the version 2 source already saved in app.py.

The rebuilt API restores the current JSON response. A temporary peer then tests whether docker-api works as a stable service name on Docker's default bridge network.

In this step, get ready to:
  • Replace the version 1 container.
  • Build a version 2 image from the updated source.
  • Test container-name resolution on the default bridge.
Replace the version 1 container

Stopping a container ends its process while preserving the container record. Removing that stopped container releases the name docker-api for the replacement.

  • Stop the version 1 container by running this command:
docker stop docker-api

What does stopping change?

The API process stops inside docker-api. Its container record remains available until you remove it.

  • Remove the stopped container by running this command:
docker rm docker-api

What does removing change?

Docker removes the old container record. The version 1 image remains available as docker-api-lab:1.0.

Could not stop or remove the container?

Confirm Docker Desktop remains connected to the Linux container engine. A missing container means your local state differs from the earlier inspection.

Use this if the lifecycle commands return an unexpected result: Help me check why I cannot stop or remove my docker-api container without deleting my images.

Deploy version 2

A new build captures the saved version 2 source inside another image snapshot. The tag docker-api-lab:2.0 keeps that snapshot distinct from version 1.

  • Build the version 2 image from the current project folder by running this command:
docker build -t docker-api-lab:2.0 .

What does this build create?

  • The -t option assigns the tag docker-api-lab:2.0 to the new image.
  • The final . uses the current docker-api-lab folder as the build context.
  • The unchanged Dockerfile copies the saved version 2 source into the image.

Good progress. The version 2 image now preserves your updated API as a reusable snapshot.

Did the image build fail?

Confirm PowerShell remains in the local docker-api-lab folder. That folder must contain both app.py and Dockerfile.

Use this if the build stops before creating the image: Help me diagnose my docker-api-lab version 2 image build.

  • Create the replacement version 2 container by running this command:
docker run --name docker-api -d -p 8000:8000 docker-api-lab:2.0

What does this command launch?

  • The --name option assigns the reusable name docker-api.
  • The -d option runs the API in the background.
  • The -p 8000:8000 setting uses port publishing to connect Windows port 8000 to the API's container port 8000.
  • The final value selects the docker-api-lab:2.0 image.

Did the replacement container fail to start?

A report about an occupied name usually means the old container still exists. A report about the published port usually means another local process is using port 8000.

Use this if the replacement does not start: Help me diagnose why docker-api-lab:2.0 cannot start as docker-api on port 8000.

Before you send the Windows request, which version do you expect the replacement container to return?

  • Request the replacement API from Windows PowerShell by running this command:
Invoke-RestMethod -Uri "http://localhost:8000"

What should you see?

PowerShell parses the response and displays Hello from Docker v2 for message. It displays 2 for version.

That replacement worked. Your published API now serves the source captured in the version 2 image.

Still seeing version 1?

Confirm the replacement container was created from docker-api-lab:2.0. Building version 2 does not change a container created from version 1.

Use this if the Windows request remains stale: Help me trace why localhost still returns version 1 after I rebuilt and replaced docker-api.

Test container-name resolution

The next request comes from a temporary client container on the default bridge. It addresses the API only as docker-api:8000.

Before you run the peer request, do you expect the name docker-api to resolve from another container?

  • Test the API name from a temporary client container by running this command:
docker run --rm docker-api-lab:2.0 python -c "import urllib.request; print(urllib.request.urlopen('http://docker-api:8000', timeout=3).read().decode())"

Why does the request fail?

  • The temporary client starts on Docker's default bridge because the command does not select another network.
  • The default bridge does not provide container-name DNS.
  • The request ends with a name-resolution error before it reaches the API.
  • The --rm option removes the temporary client after it exits.

That failure is the intended result. It exposes the service-discovery gap that blocks peer containers from reaching docker-api by name.

Seeing a different result?

Confirm the command targets http://docker-api:8000. Confirm it does not include a network option.

Use this if the temporary client produces another result: Help me interpret my default-bridge client test without fixing the networking gap yet.

You now have a working version 2 API plus proof that the default bridge cannot resolve its container name. Next, you'll give peer containers a reliable path to docker-api.

Connect Containers with a Named Network

Your rebuilt API now serves version 2 from a Docker container. The peer request still fails because the default bridge cannot resolve docker-api by name.

A user-defined bridge network provides automatic DNS for container names. This gives a peer container the stable service address a future gateway needs.

In this step, get ready to:
  • Replace the default-bridge API container on api-lab-net.
  • Confirm the API still responds through the published Windows port.
  • Prove a peer container can reach the API by name.
Clear the old network attachment

Network membership belongs to a container's runtime configuration. Replacing docker-api lets its successor join the named network when Docker creates it.

  • Return to the Windows PowerShell terminal from earlier.
  • Stop and remove the default-bridge container by running these commands:
docker stop docker-api
docker rm docker-api

What do these commands change?

  • The first command stops the running API process.
  • The second command removes the stopped container record.
  • Removing that record frees the name docker-api for its replacement.

PowerShell prints docker-api after each command. The old default-bridge container is now gone.

Could not remove the container?

Confirm that the container name is docker-api. A missing container message can mean the previous command already removed it.

Help me troubleshoot the container replacement.

Give the API a shared DNS scope

The named network creates a shared DNS scope for attached containers. The name docker-api becomes a usable hostname inside that scope.

  • Create api-lab-net by running this command:
docker network create api-lab-net

What does this command create?

Docker creates a user-defined bridge named api-lab-net. Containers attached to this network can resolve one another by container name.

PowerShell prints the new network identifier. This confirms that api-lab-net exists.

Network creation failed?

Check whether api-lab-net already exists from an earlier attempt. An existing network can be reused for the next command.

Help me diagnose the named network problem.

  • Launch the version 2 API on api-lab-net by running this command:
docker run --name docker-api -d --network api-lab-net -p 8000:8000 docker-api-lab:2.0

How is the replacement configured?

  • The --name option assigns the reusable hostname docker-api.
  • The -d option starts the API in the background.
  • The --network api-lab-net option attaches the container to the named network.
  • The -p 8000:8000 option keeps the API available through Windows port 8000.

PowerShell prints the new container identifier. The version 2 API is now running on api-lab-net.

Replacement container did not start?

  • Confirm that the earlier removal freed the name docker-api.
  • Confirm that network creation printed an identifier.
  • Confirm that Docker Desktop still shows its Linux container engine as running.

Help me troubleshoot the replacement container.

Test both access paths

Port publishing serves requests from Windows. Network DNS serves requests from peer containers through the name docker-api.

Before you test from Windows, do you expect the network change to affect the published host port?

  • Request the API through the published Windows port by running this command:
Invoke-RestMethod -Uri "http://localhost:8000"

What does the Windows request prove?

  • The published port still carries requests from Windows into the replacement container.
  • PowerShell displays Hello from Docker v2 for the message.
  • PowerShell displays 2 for the version.

Windows request not responding?

Confirm that the replacement command published host port 8000. Confirm that no other local process is using that port.

Help me restore the Windows request.

Before you run the final check, do you expect the peer container to resolve docker-api now?

  • Request the API from a temporary peer container by running this command:
docker run --rm --network api-lab-net docker-api-lab:2.0 python -c "import urllib.request; print(urllib.request.urlopen('http://docker-api:8000', timeout=3).read().decode())"

What does the peer request prove?

  • The --rm option removes the temporary client after the request finishes.
  • The --network api-lab-net option places the temporary client in the API's DNS scope.
  • The address http://docker-api:8000 reaches the API through its container name.
  • You should see {"message": "Hello from Docker v2", "version": 2} in PowerShell.

Peer name still not resolving?

  • Confirm that the replacement container uses api-lab-net.
  • Confirm that the temporary client command uses the same network name.
  • Confirm that the request address uses the container name docker-api.

Help me fix container-name resolution.

You have cleared the networking wall. Peer containers can now reach your API through its stable service name.

Secret mission

Add a Second API Replica

Launch a second API replica from the same image on a separate host port. Prove that Windows and peer containers can reach both replicas independently.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep your local Docker Desktop resources active, stop them for later, or remove them with the project files. This local lab creates no metered cloud charges.

Check Docker Desktop Entitlement

Docker Desktop is free for personal use, education, non-commercial open source, or a small business with fewer than 250 employees and less than $10 million USD in annual revenue.

Other professional use and government use require a paid subscription. Confirm your entitlement before reusing this workspace for work.

Resources you used:

  • Two running containers named docker-api and docker-api-2.
  • Two versioned images named docker-api-lab:1.0 and docker-api-lab:2.0.
  • A user-defined bridge network named api-lab-net.
  • A local docker-api-lab folder containing app.py and Dockerfile.

Keep everything running

No cleanup is needed. Choose this if you plan to use both replicas in a follow-on gateway lab.

  • Leave docker-api running on host port 8000.
  • Leave docker-api-2 running on host port 8001.
  • Retain api-lab-net for container-name communication.
  • Keep docker-api-lab:1.0 as the original image snapshot.
  • Keep docker-api-lab:2.0 as the updated image snapshot.
  • Retain the docker-api-lab folder for future source changes.
  • Leave Docker Desktop and Visual Studio Code installed for future projects.

Pause - I'll come back to this later

Stop both replicas to free their running resources while preserving your images, network, and source files. You can restart the same containers later.

  • Stop both API replicas by running these commands:
docker stop docker-api
docker stop docker-api-2

What Do These Commands Do?

These commands stop both container processes while preserving their names and settings. The images and network remain available.

Containers Not Stopping?

Confirm Docker Desktop remains connected to the Linux container engine. A container that already shows a stopped state needs no further action.

Help me stop both Docker containers.

  • Confirm docker-api shows a stopped state in Docker Desktop.
  • Confirm docker-api-2 shows a stopped state in Docker Desktop.
  • Restart both API replicas later by running these commands:
docker start docker-api
docker start docker-api-2

What Happens When You Return?

These commands restart the existing containers with their saved port and network settings. Both version 2 replicas become available again.

Containers Not Restarting?

Confirm Docker Desktop is running before retrying the commands. Check that both container names still appear in its container list.

Help me restart both Docker containers.

Delete - I don't want to use this again

Remove every lab resource if you are finished with this workspace. This clears both replicas, both images, the named network, and the local source folder.

  • Return to Docker Desktop.
  • Use its container list to remove docker-api.
  • Use its container list to remove docker-api-2.
  • Confirm both container names no longer appear in Docker Desktop.
  • Return to the Windows PowerShell terminal from earlier.
  • Remove the user-defined network by running this command:
docker network rm api-lab-net

What Does This Remove?

This command removes the bridge network used for container-name communication. Removing the containers first releases their connections to the network.

Network Still in Use?

Return to Docker Desktop if the network cannot be removed. Remove any remaining container connected to api-lab-net before retrying the command.

Help me remove the Docker network.

PowerShell returns to the prompt after Docker removes the network.

  • Remove both versioned images by running this command:
docker image rm docker-api-lab:1.0 docker-api-lab:2.0

What Does This Remove?

This command removes both local image tags from the Linux container engine. Your source files remain in the docker-api-lab folder.

Images Still in Use?

An image cannot be removed while a remaining container depends on it. Return to Docker Desktop to remove any leftover lab container before retrying the command.

Help me remove the Docker images.

PowerShell returns removal details for both image tags.

  • Close Visual Studio Code if it still has the docker-api-lab folder open.
  • Close the Windows PowerShell terminal after the Docker cleanup completes.
  • Press the Windows key to open Windows search.
  • Enter File Explorer in the search field.
  • Select the matching app.
  • Return to the location where you created the docker-api-lab folder.
  • Delete the docker-api-lab folder.
  • Confirm the folder no longer appears in its parent location.

Folder Still in Use?

Confirm every PowerShell terminal and editor window using docker-api-lab is closed. Retry the folder deletion after those processes release it.

Help me delete the local project folder.

Docker Desktop and Visual Studio Code remain installed for future projects.

Nice Work!

Nice Work!

You made it! Your Python JSON API now runs in two independently addressable Docker containers.

What you learned:

  • Built a containerized API without installing Python on Windows. Packaged app.py with a reusable Dockerfile.
  • Proved image immutability by changing the host source while the running container kept its original response. Rebuilt the image to deploy the updated API.
  • Diagnosed a container-name DNS failure on Docker's default bridge. Restored service discovery with the api-lab-net bridge network.
  • Secret Mission: Launched a second API replica named docker-api-2. Proved both replicas respond independently through separate host ports plus container-name addressing.

Ready to quiz yourself?