Ravindra BagaleCourses & study guides मराठी Track your progress

Guides

How to Containerize a Python Flask (or Django) App

Write a Flask (or Django) app with /health, pin requirements, build a gunicorn Dockerfile, run it, and curl health — no secrets in the image.

Friends, pin requirements, run gunicorn, expose a health route. Chala mitrano — flask run is not production.

Quick answer

Hold this vertical picture:

  1. Create app with /health.
  2. Pin requirements.
  3. Write Dockerfile with gunicorn.
  4. Add .dockerignore; build.
  5. Run; curl /health; use non-root.

Language: English · मराठी · हिंदी

app.py + requirementsPinned deps Dockerfilegunicorn CMD docker buildTagged image docker runPort 8000 curl /healthProve
Flask container path

Why containerize Python

Same runtime from laptop to cluster.

Why: Works-on-my-venv fails CI. What: Image with pinned deps + gunicorn. How: Health route for probes.

Example 1: Minimal Flask app

Type this:

mkdir -p /tmp/flaskapp && printf '%s\n' 'from flask import Flask' 'app = Flask(__name__)' '@app.get("/health")' 'def health():' '    return "ok", 200' '@app.get("/")' 'def hi():' '    return "hello"' > /tmp/flaskapp/app.py && cat /tmp/flaskapp/app.py

You will see:

from flask import Flask

What it means: Health route first — same habit as Node guides.

Example 2: requirements pin

Type this:

printf '%s\n' 'flask==3.0.3' 'gunicorn==22.0.0' > /tmp/flaskapp/requirements.txt && cat /tmp/flaskapp/requirements.txt

You will see:

flask==3.0.3
gunicorn==22.0.0

What it means: Pin versions — floating latest breaks Friday deploys.

Example 3: Dockerfile

Type this:

printf '%s\n' 'FROM public.ecr.aws/docker/library/python:3.12-slim' 'WORKDIR /app' 'COPY requirements.txt .' 'RUN pip install --no-cache-dir -r requirements.txt' 'COPY app.py .' 'EXPOSE 8000' 'CMD ["gunicorn", "-b", "0.0.0.0:8000", "app:app"]' > /tmp/flaskapp/Dockerfile && cat /tmp/flaskapp/Dockerfile

You will see:

FROM public.ecr.aws/docker/library/python:3.12-slim

What it means: gunicorn serves production; flask run is for laptop only.

Concept 1: Build and prove

Tag, run, curl.

Why: Skipping curl ships broken images. What: docker build; run -p; curl /health. How: .dockerignore speeds CI.

Example 4: Build image

Type this:

docker build -t flask-demo:1 /tmp/flaskapp && docker images flask-demo:1 --format '{{.Repository}}:{{.Tag}}'

You will see:

flask-demo:1

What it means: Numbered tag for rollback.

Example 5: Run and curl

Type this:

docker rm -f flask-demo >/dev/null 2>&1; docker run -d --name flask-demo -p 8000:8000 flask-demo:1 && sleep 1 && curl -s http://127.0.0.1:8000/health && echo && docker rm -f flask-demo >/dev/null

You will see:

ok

What it means: Prove /health before Compose or Kubernetes.

Example 7: .dockerignore

Type this:

printf '%s\n' '__pycache__/' '.venv/' '*.pyc' '.git/' > /tmp/flaskapp/.dockerignore && cat /tmp/flaskapp/.dockerignore

You will see:

__pycache__/

What it means: Keep build context small — faster CI.

Concept 2: Django and slim images

WSGI module; optional multi-stage.

Why: flask run in prod melts under load. What: gunicorn wsgi; collectstatic; multi-stage when needed. How: Non-root USER.

Example 6: Django note

Type this:

printf '%s\n' 'Django: CMD gunicorn myproject.wsgi:application -b 0.0.0.0:8000  and collectstatic in build or entrypoint'

You will see:

Django: CMD gunicorn myproject.wsgi:application -b 0.0.0.0:8000  and collectstatic in build or entrypoint

What it means: Same Dockerfile shape; different WSGI module.

Example 8: Multi-stage optional

Type this:

printf '%s\n' 'Builder installs deps; runtime copies site-packages — use when images must shrink under policy'

You will see:

Builder installs deps; runtime copies site-packages — use when images must shrink under policy

What it means: Link multi-stage guide mentally.

Example 9: Non-root user

Type this:

printf '%s\n' 'RUN useradd -u 10001 appuser && USER appuser'

You will see:

RUN useradd -u 10001 appuser && USER appuser

What it means: Accenture scans flag root containers.

Concept 3: Config and Compose

Env at runtime; local Compose.

Why: Secrets in layers get extracted. What: ENV non-secret; -e for secrets; Compose for deps. How: CI fails on bad health.

Example 10: Env for settings

Type this:

printf '%s\n' 'ENV APP_ENV=prod' '# secrets via runtime -e or orchestrator — not baked in image'

You will see:

ENV APP_ENV=prod
# secrets via runtime -e or orchestrator — not baked in image

What it means: Never COPY .env with passwords.

Example 11: Compose sketch

Type this:

printf '%s\n' 'services:' '  web:' '    image: flask-demo:1' '    ports: ["8000:8000"]' > /tmp/flaskapp/compose.yaml && cat /tmp/flaskapp/compose.yaml

You will see:

services:

What it means: Local multi-service later — DB as another service.

Example 12: Fail if health missing

Type this:

printf '%s\n' 'CI should curl /health and fail the job on non-200'

You will see:

CI should curl /health and fail the job on non-200

What it means: Same gate as the EC2 Node guide.

Flask/Django card

1 Health route 2 Pin requirements 3 Dockerfile + gunicorn 4 .dockerignore 5 build/run/curl 6 non-root; no secrets in image

Suppose: Module not found

WORKDIR and COPY paths; PYTHONPATH.

Suppose: Connection reset

Bind 0.0.0.0 not 127.0.0.1 inside the container.

Ravindra Bagale's Tip

At Capgemini Python deliveries, reviewers reject images that bake .env secrets or run as root without a story.

Check yourself (quiz)

Q1. Prod server?

gunicorn (or similar WSGI)

Q2. Why pin versions?

Reproducible builds

Q3. Health path?

/health returns 200

Q4. Bind address?

0.0.0.0 in container

Q5. Secrets in image?

No

Q6. Django entry?

wsgi/asgi module for gunicorn

Reading tracking

Mark this guide when you finish. Your browser remembers it on this device.

app → Dockerfile → build → run → curl /health. Did you understand? Let us try it once more.

Frequently asked questions

flask run in prod?

No — use gunicorn/uvicorn.

Django static files?

collectstatic in build or entrypoint.

Alpine vs slim?

slim is a fine default for Python.

Multi-stage?

When image size policy requires.

Compose with DB?

Add a db service and env DATABASE_URL.

K8s next?

Same image; Deployment + Service + probes.