The Tool Desk
Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Antihost offers VPS plans with one-click Docker, NVMe storage and a 14-day free trial.
Containerizing a Python web app packages its code, pinned dependencies, configuration, and Python runtime into a portable Docker image. You can build that image once, run it on a laptop or CI runner, and deploy the same artifact to a server with predictable behavior. The reliable workflow is to prepare a clean project directory, install dependencies in a cache-friendly layer, bind the web server to 0.0.0.0, and use a small multi-stage image with non-root execution for production.
What containerizing a Python web app means
A container image is an immutable filesystem and metadata bundle containing an application and everything it needs to start. Docker describes containerizing an application as packaging it with its dependencies, configuration, and runtime into one portable unit. Starting the image creates an isolated process with its own filesystem, network namespace, and resource limits while sharing the host’s kernel.
PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteThat packaging solves a common deployment problem: a developer’s laptop, a CI runner, and a production server may have different Python versions, operating-system libraries, or installed packages. A pinned dependency file and an explicit image tag make those inputs visible and reproducible. Containers do not automatically make an application secure, highly available, or stateful; those concerns still require runtime configuration, storage, monitoring, and an appropriate deployment platform.
Prepare the project before writing a Dockerfile
Keep the build context deliberate
Place the application source, dependency declaration, Dockerfile, Compose file (if used), and .dockerignore in a predictable project directory. A typical layout is:
#1 Best Overall
my-python-app/
├── app.py
├── requirements.txt
├── Dockerfile
├── compose.yaml
└── .dockerignore
If the project uses Poetry, uv, or another package manager, copy its project file and lock file instead of inventing a second dependency list. The important property is that versions are pinned or otherwise locked according to the project’s support policy.
Use a minimal dependency file
For a small FastAPI example, requirements.txt might contain pinned FastAPI and Uvicorn releases selected by the project. Flask applications would list Flask and the production WSGI server they use. Do not install development-only linters, test runners, or documentation tools into the production environment unless the runtime actually needs them.
Exclude local and secret files
Create .dockerignore before the first build so Docker does not send unnecessary data to the build engine:
.git
.gitignore
.venv/
venv/
__pycache__/
*.py[cod]
.pytest_cache/
.mypy_cache/
.coverage
.env
.env.*
Dockerfile*
compose*.yml
compose*.yaml
tests/
dist/
build/
Adjust the entries if your build needs a file listed here. A local .env file can contain credentials; excluding it prevents accidental inclusion in image layers, but you still need to rotate a credential that has already been committed or baked into an image.
Write a development Dockerfile
Choose and record a trusted base image
Start from a maintained Python image from a trusted registry. A slim variant usually contains fewer operating-system packages than a full image, but a package that compiles native extensions may need additional build tools. Record the exact Python tag you selected and update it deliberately; floating tags make later rebuilds harder to reproduce.
Install dependencies before application code
Docker reuses a layer only when the instructions and their inputs are unchanged. Copying the dependency file first means a source-code edit does not invalidate the expensive dependency-install layer. This is the central cache optimization for a Python image.
Recommended Free Tools
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN python -m pip install --no-cache-dir --upgrade pip
&& python -m pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
The app:app value means “import the app module and use its app object.” Change it to your module and application object, such as main:api. EXPOSE documents the container port; it does not publish that port on the host.
Rank #2
Build and run the image
- From the directory containing the Dockerfile, run
docker build -t my-python-app .. The final dot is the build context. - Start a disposable container with
docker run --rm -p 8000:8000 my-python-app. The first port is on the host; the second is inside the container. - Open
http://localhost:8000or the application’s health endpoint. For FastAPI, the interactive documentation is commonly available at/docswhen enabled. - Stop the process with
Ctrl-C. The--rmoption removes the stopped container while leaving the image.
The server must listen on 0.0.0.0, not only on 127.0.0.1. The latter accepts connections from inside the container but is unreachable through Docker’s published port.
Use a multi-stage image for production
A single-stage build can leave compilers, header files, downloaded archives, and package-manager caches in the final image. Docker’s multi-stage guidance recommends separating the build environment from the runtime environment. The runtime stage copies only the artifacts needed to run the application, reducing image size and the number of packages that could be exploited.
# syntax=docker/dockerfile:1
FROM python:3.12-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN python -m pip install --upgrade pip
&& pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
FROM python:3.12-slim AS runtime
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/*
&& rm -rf /wheels
COPY . .
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
The Python tag shown is an example. Select a supported version compatible with your application and pin it in the Dockerfile. The builder creates wheels; the runtime installs those wheels without retaining the wheel directory. If a dependency requires system libraries at runtime, install only those libraries in the runtime stage, while keeping compilers and development headers in the builder.
Run the process as a non-root user
Processes in a container start as root unless you change the user. Create an unprivileged account, give it ownership of the application files, and switch to it before the command runs:
FROM python:3.12-slim AS runtime
WORKDIR /app
RUN addgroup --system appgroup && adduser --system --ingroup appgroup appuser
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/* && rm -rf /wheels
COPY --chown=appuser:appgroup . .
USER appuser
EXPOSE 8000
CMD ["gunicorn", "app:app", "--bind", "0.0.0.0:8000"]
Choose a writable directory explicitly if the application creates temporary files. A non-root process may expose permission assumptions that were hidden during local development; fix those assumptions rather than switching back to root.
Add a health check when the platform uses it
Expose a lightweight endpoint such as /health that verifies the process is alive and, if appropriate, that critical dependencies are reachable. A Docker health check can probe it:
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"
Use a probe that matches the application contract. A health endpoint that performs an expensive database query on every interval can create load or mark a healthy process unhealthy when an optional dependency is unavailable.
Rank #3
Choose the server command for your framework
| Application type | Typical command | What to decide |
|---|---|---|
| FastAPI or another ASGI app | python -m uvicorn app:app --host 0.0.0.0 --port 8000 |
Whether one Uvicorn process is sufficient for the container’s CPU and memory limits. |
| WSGI app such as Flask | gunicorn app:app --bind 0.0.0.0:8000 |
Worker class, worker count, timeout, and graceful-shutdown behavior. |
| ASGI app managed by Gunicorn | gunicorn app:app --bind 0.0.0.0:8000 with the project’s ASGI worker configuration |
That the installed Gunicorn and worker implementation match the framework. |
Uvicorn is a direct ASGI server and is the command used in Docker’s FastAPI example. Gunicorn manages workers and is commonly used for WSGI deployments; its documented examples use JSON-form commands and bind to 0.0.0.0:8000. Size worker counts against the CPU and memory assigned to the container rather than copying a universal formula. More workers consume more memory, and an orchestrator may already provide process-level scaling.
Use exec-form JSON CMD, not a shell string. Exec form lets the server receive stop and termination signals directly, which improves graceful shutdown during a rolling deployment.
Configure the container at runtime
Do not bake passwords, API keys, certificates, or environment-specific URLs into the image. Pass non-secret configuration as environment variables and use the deployment platform’s secret mechanism for sensitive values. An image can be pulled, cached, and inspected by more people than the running service.
docker run --rm
-p 8000:8000
-e APP_ENV=production
-e DATABASE_URL="$DATABASE_URL"
my-python-app
Read and validate variables at startup. Fail with a clear message when a required value is missing, and provide safe defaults only for values that are genuinely non-sensitive. Never log a full connection string or token while diagnosing startup failures.
Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →Use Compose for local development and supporting services
Compose describes several containers and their relationships in one file. It is useful when the web service needs a database, a named volume, environment variables, or local resource limits. Keep live-reload tools and interactive shells in a development stage; use the minimal runtime stage for production.
services:
web:
build:
context: .
target: builder
ports:
- '8000:8000'
environment:
APP_ENV: development
DATABASE_URL: postgresql://app:password@db:5432/app
volumes:
- .:/app
depends_on:
- db
command: ["python", "-m", "uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: password
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
The bind mount makes source edits visible to the development container; it is not a production deployment strategy. The named volume keeps database data outside the disposable database container. Replace example credentials with a local-only mechanism and never reuse them in production. A database service becoming “started” does not necessarily mean it is ready to accept connections, so application retry logic or an explicit readiness check may still be required.
Make builds faster and reproducible
Preserve cache boundaries
Copy lock files and dependency declarations before source code. Avoid changing an early RUN instruction for unrelated reasons, because every later layer must then be rebuilt. Docker BuildKit can use cache mounts for package downloads; the exact mount syntax depends on the Dockerfile frontend and build environment, so test it in the CI builder you actually use.
Rank #4
- This dive logbook is made from genuine cowhide leather, and just like fingerprints, each piece is one-of-a-kind. Each logbook flaunts its own unique personality with varying colors, textures, and markings. Over time, the leather develops its own charming "battle scars," making it even more beautiful and uniquely yours. It's like your favorite pair of jeans – the more you use it, the cooler it gets
- Its compact A6 size (5.1in x 7.5in) makes it super easy to carry around, letting you jot down your dive logs anytime, anywhere. Whether you toss it in your dive bag or take it on the go, it’s a breeze to bring along. Perfectly suited for A6 dive logs and A6 binders. Think of it as your trusty sidekick – always ready for the next adventure
- This dive logbook isn't just a pretty face – it's got some serious chops too. The genuine leather cover laughs in the face of splashes, and the 120g high-quality paper ensures your notes won't dissolve into a soggy mess. Perfect for those damp and drizzly dives
- 3 Card Slots: Perfect for stashing your dive cards, transit passes, and other important cards. 1 Zipper Pocket: Keep your valuables secure and safe. 4 Receipt Pockets: Perfect for holding tickets, passports, and other essential documents We’ve included 2 removable, expandable PVC pages: Transparent PVC Page: Holds up to 3 cards, making them easy to see and use. PVC Storage Bag: Specially designed waterproof bag for those items that just hate getting wet.
- Our dive logbook includes all the essential fields for divers to record every dive, such as date, dive site, conditions, equipment, dive stats, and dive verification, among others. With 50 pages designed to capture the key details of each dive adventure, it's perfect for PADI divers and fits the A6 size dive log requirements
Pin both dependency and image inputs
A lock file or fully pinned requirements.txt controls Python packages. An explicit Python image tag controls the interpreter and operating-system base. Rebuild regularly to receive security updates, but review and test those updates rather than silently changing production artifacts.
Keep the runtime contents intentional
- Use a small trusted base image appropriate for your compatibility needs.
- Install build-only packages only in the builder stage.
- Remove package caches and temporary wheel directories.
- Copy only the source and assets required at runtime.
- Do not include VCS metadata, local virtual environments, tests, or secrets unless the application explicitly needs them.
Common failures and precise fixes
“Connection refused” from the host
Check all three links: the process is running, it listens on 0.0.0.0, and the host mapping matches the container port. For a server on port 8000, use -p 8000:8000. If you changed the internal port, change both the command and the right-hand side of the mapping.
Module or application object not found
Confirm the working directory contains the module, then correct the command’s import path. main:api means a file named main.py with an object named api; it is not interchangeable with app:app. Package layouts may require a dotted path such as src.main:app and a matching Python path.
Dependency installation fails during build
Read the first compiler or system-library error, not only the final pip summary. Add the required compiler and headers to the builder stage, then install the corresponding runtime shared libraries in the runtime stage. If a wheel exists for the selected Python version and architecture, using it may avoid compilation.
Changes are missing while developing
Rebuild when changing dependencies or the Dockerfile. For source edits, use a development bind mount and a reload-capable server. A stale image is not fixed by repeatedly starting another container from the same tag.
The container exits immediately
Inspect logs with docker logs <container>. A container remains alive only while its main process runs; a shell that finishes, a failed import, or a server bound to an invalid port will stop it. Keep the server as the foreground process and use exec-form CMD.
Files cannot be written after switching users
Find the path the application writes, create it during the image build, and assign ownership with --chown or chown. Prefer ephemeral directories such as /tmp for temporary data and external storage for data that must survive a replacement container.
Production readiness checklist
- Dependency versions and the Python base-image tag are explicit and reviewed.
- The image uses a trusted, maintained, reasonably small base.
- Build tools and caches are excluded from the runtime stage.
- The process runs as a non-root user.
- Secrets enter at runtime through environment or a secret manager.
- The server binds to the container interface and receives termination signals directly.
- A health endpoint and, where useful, a Docker health check are defined.
- Logs go to standard output and error so the platform can collect them.
- Database and user-uploaded data use external persistence rather than the writable container layer.
- CI builds the image, starts it, exercises a health endpoint, and scans the resulting artifact according to the organization’s security process.
For one web process, a Dockerfile may be enough. Add Compose when local development needs a database, volume, or coordinated environment. In production, an orchestrator can provide replicas, resource limits, rolling updates, and readiness probes; the image should remain focused on starting one well-behaved application process.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

