learntodeploy / Learn / Docker Deployment

Practice Docker Deployment

Learn containers, Dockerfiles, and container deployment — Last updated: September 2026

Docker is a container platform that packages an application with everything it needs to run — the runtime, the dependencies, the configuration — into a single image that runs the same way on any machine with a container runtime. Docker deployment is the process of building that image, pushing it somewhere accessible, and running it as a container on a target environment.

Containers are the standard unit of deployment for a reason: they make the deployment environment explicit. The same image that you build and test locally is the image that runs in production. There is no “it works on my machine” because the machine is part of the image.

The deployment simulator at LearnToDeploy includes Docker-based projects where you write and debug Dockerfiles, build images, and figure out why a container fails to start or fails its health check.

What a Dockerfile Does

A Dockerfile is a recipe for building a container image. Each instruction in the Dockerfile becomes a layer in the image. The final image is the result of running those instructions in order — a base image, plus your application code, plus your dependencies, plus the command that starts the application.

The Dockerfile is what makes a container build reproducible. Given the same Dockerfile and the same source code, you get the same image every time. That is what makes container deployment reliable: the thing you tested is the thing you deploy.

A basic Dockerfile

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]

This Dockerfile does the following: starts from a Python base image, sets a working directory, copies the dependency file, installs dependencies, copies the application source, documents the port the application listens on, and declares the command that starts the application.

Building Images

Building a Docker image runs the Dockerfile instructions and produces a layered image. Each instruction creates a new layer, and Docker caches layers so that rebuilds are fast when only later instructions change.

docker build -t myapp:1.2.0 .
docker images
docker tag myapp:1.2.0 myapp:latest

The build command takes a context — the directory whose contents Docker can access during the build. The . at the end means the current directory. The build reads the Dockerfile in that directory and runs its instructions.

Layer caching and build order

Docker caches each layer. If an instruction has not changed, Docker reuses the cached layer instead of running it again. This is why the order of instructions in a Dockerfile matters for build speed.

A common optimization is to copy the dependency file first, install dependencies, and then copy the source code. If only the source code changes, Docker reuses the cached dependency layer and only re-runs the later instructions. If you copy all the source first, every change invalidates the cache from that point onward.

# Slower: copying everything before installing deps
COPY . .
RUN pip install -r requirements.txt

# Faster: install deps first, then copy source
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .

Running Containers

A container is a running instance of an image. You start a container from an image, and the image's startup command runs inside the container. The container is isolated from the host — its own filesystem, its own network, its own process space.

docker run -d -p 8000:8000 --name myapp myapp:1.2.0
docker ps
docker logs myapp
docker stop myapp

What to configure when running a container

Container Ports and Networking

A container listens on a port inside the container. For anything outside the container to reach it, the port must be mapped to the host. If the application listens on port 8000 inside the container and you map -p 8000:8000, you can reach it at localhost:8000 on the host.

A common deployment failure is a port mismatch: the application listens on one port, but the platform — or the port mapping — expects another. The container is running, but nothing can reach the application, and the health check returns 502 Bad Gateway.

# The app listens on 8080, but the platform expects 8000
# This container starts successfully but is unreachable
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8080"]

# The platform routes traffic to 8000, the container exposes 8000,
# but the app is not listening there — connection refused
curl http://localhost:8000/health
# curl: (7) Failed to connect to localhost port 8000
A container can be healthy — running, not crashed — and still be unreachable if it is listening on the wrong port. Container status and application health are not the same thing.

Debugging Container Failures

Container failures fall into a few categories, and each has a different diagnostic path.

Container exits immediately

If a container exits as soon as it starts, the startup command is the first thing to check. The command might be wrong — a typo, a missing executable, a path that does not exist. The application might be crashing on startup because of a missing environment variable or a configuration error.

docker run --rm myapp:1.2.0
# If the container exits immediately, check the logs
docker run --rm myapp:1.2.0 2>&1 | head -20
# Or run interactively to see the error
docker run --rm -it myapp:1.2.0 /bin/bash

Container runs but is unreachable

If the container is running but the health check fails or the port does not respond, check what the application is actually listening on. The application might be listening on a different port than the one the platform expects, or on 127.0.0.1 instead of 0.0.0.0.

# Inside the container, check what is listening
ss -tlnp
# Or check the application logs for the bind address
docker logs myapp | grep -i bind

Health check fails

If the container is reachable but the health check fails, the application might be running but not healthy — the database is not connected, a dependency is unavailable, or the health endpoint itself is misconfigured. Check the application logs and the health endpoint directly.

curl http://localhost:8000/health
# Compare the response against what the health check expects

Docker Deployment Best Practices

Practice Docker Deployment in the Simulator

The LearnToDeploy deployment simulator includes Docker-based projects where you practice writing and debugging Dockerfiles. The simulator responds with real Docker build output, container logs, and health check results — so you can practice reading Docker output and diagnosing container failures.

The simulator includes intentionally broken Dockerfiles — wrong base image tags, missing startup commands, port mismatches, missing dependencies — so you can practice diagnosing the most common container deployment problems in a safe environment.

For the underlying concepts, see the deployment concepts library, including entries on Docker and containers, ports and networking, and health checks.

← Back to Learn