Ravindra BagaleCourses & study guides मराठी

Chapter 73: DevOps Projects Part 3: Docker Websites, APIs, Compose, Registry and ECR

73.3 Project 19: Dockerize a Python Flask app

Friends, Flask APIs love small Alpine images. Today we write a tiny Flask app, pin python:3.12-alpine, build, run on 5000, and prove /health with curl. Pin python:3.12-alpine. Copy requirements.txt before app code. Prove /health with curl before you open the browser.

What you will build in this project

  1. A tiny Python Flask app with /health.
  2. Dockerfile FROM python:3.12-alpine.
  3. Image flask-api:1.0.
  4. Container on host port 5000.

1. Start from a real company story

At Swiggy in Bengaluru, the Python Flask service was copied by hand onto several VMs. One box had the wrong runtime version. The ops lead asked every engineer to paste the exact docker images size line into the pull request before merge. That one habit cut surprise production rollbacks. The on-call chart now shows image size next to deploy time. New joiners pair on the health curl before they touch Compose.

Errors during peak cost about ₹14 lakh in delayed orders.

Meera packed the app into python:3.12-alpine. The same tag ran on every box. Rollback was one previous tag.

Today we dockerize that Python Flask app.

App filesPython FlaskDockerfilepython:3.12-alpinedocker buildflask-api:1.0run -p 5000curl proves
Picture 1: from zip copy to Python Flask container

Ravindra Bagale's Tip

Many students forget requirements.txt and then wonder why the image has no Flask. Copy requirements before the app code. Keep that habit. Write every command in your notebook. When something fails, copy the exact error line before you change anything else. Measure twice, change once. Never forget requirements.txt. When pip fails, read the exact package line first. Keep a notebook of image sizes after every successful build.

2. Start and prepare

Step 1: Make project folder

Why: We need a clean folder for the Python Flask app. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: mkdir and cd. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 1: mkdir

Type this:

mkdir -p /tmp/flask-api && cd /tmp/flask-api && echo ready

You will see:

ready

What it means: Folder.

Example 2: pwd

Type this:

pwd

You will see:

/tmp/flask-api

What it means: In place.

Example 3: empty

Type this:

ls | wc -l

You will see:

0

What it means: Fresh.

Step 2: Write app files

Why: The Python Flask files are the product we ship. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: printf the source files. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 4: req

Type this:

printf '%s\n' 'flask==3.0.3' > requirements.txt && cat requirements.txt

You will see:

flask==3.0.3

What it means: Pinned Flask.

Example 5: app

Type this:

printf '%s\n' 'from flask import Flask, jsonify' 'app = Flask(__name__)' '@app.get("/health")' 'def health():' '    return jsonify(ok=True)' '@app.get("/api/hello")' 'def hello():' '    return jsonify(msg="order-api")' 'if __name__ == "__main__":' '    app.run(host="0.0.0.0", port=5000)' > app.py && wc -l app.py

You will see:

11 app.py

What it means: Tiny Flask.

Example 6: grep

Type this:

grep health app.py

You will see:

def health

What it means: Route.

Step 3: Local syntax check

Why: Broken syntax must fail before Docker. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: Language check command. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 7: pycheck

Type this:

python3 -c 'import ast;ast.parse(open("app.py").read());print("syntax_ok")'

You will see:

syntax_ok

What it means: Parses.

Example 8: ver

Type this:

python3 --version

You will see:

Python 3.12.x

What it means: Near image.

Example 9: req ok

Type this:

test -f requirements.txt && echo req_ok

You will see:

req_ok

What it means: Present.

3. Build the main pieces

Step 4: Write Dockerfile

Why: Dockerfile pins python:3.12-alpine. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: FROM pin + COPY + CMD. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 10: df

Type this:

printf '%s\n' 'FROM python:3.12-alpine' 'WORKDIR /app' 'COPY requirements.txt .' 'RUN pip install --no-cache-dir -r requirements.txt' 'COPY app.py .' 'EXPOSE 5000' 'CMD ["python","app.py"]' > /tmp/flask-api/Dockerfile && head -3 /tmp/flask-api/Dockerfile

You will see:

FROM python:3.12-alpine
WORKDIR /app
COPY requirements.txt .

What it means: Dockerfile written.

Example 11: from

Type this:

head -1 /tmp/flask-api/Dockerfile

You will see:

FROM python:3.12-alpine

What it means: Pinned base.

Example 12: ls

Type this:

ls /tmp/flask-api/Dockerfile

You will see:

/tmp/flask-api/Dockerfile

What it means: Present.

Step 5: Write dockerignore

Why: Context must stay lean. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: .dockerignore lists junk. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 13: ignore

Type this:

printf '%s\n' '.git' '*.md' '__pycache__' 'node_modules' 'target' 'bin' 'obj' > /tmp/flask-api/.dockerignore && cat /tmp/flask-api/.dockerignore

You will see:

.git
*.md
__pycache__
node_modules
target
bin
obj

What it means: Lean context.

Example 14: count

Type this:

wc -l /tmp/flask-api/.dockerignore

You will see:

7 /tmp/flask-api/.dockerignore

What it means: Seven lines.

Example 15: mode

Type this:

stat -c '%a' /tmp/flask-api/.dockerignore

You will see:

644

What it means: Safe.

Step 6: Build the image

Why: build creates the image layers. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: docker build -t flask-api:1.0. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 16: build

Type this:

docker build -t flask-api:1.0 /tmp/flask-api

You will see:

Successfully tagged flask-api:1.0

What it means: Built.

Example 17: images

Type this:

docker images flask-api --format '{{.Repository}}:{{.Tag}}'

You will see:

flask-api:1.0

What it means: Listed.

Example 18: hist

Type this:

docker history flask-api:1.0 | head -3

You will see:

IMAGE CREATED CREATED BY SIZE

What it means: Layers.

4. Automate and verify

Step 7: Run the container

Why: run starts a live container. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: docker run -d --name flask-api. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 19: run

Type this:

docker rm -f flask-api >/dev/null 2>&1; docker run -d --name flask-api -p 5000:5000 flask-api:1.0 && echo started

You will see:

started

What it means: Detached.

Example 20: ps

Type this:

docker ps --filter name=flask-api --format '{{.Names}} {{.Ports}}'

You will see:

flask-api 0.0.0.0:5000->5000/tcp

What it means: Mapped.

Example 21: sleep

Type this:

sleep 2; echo up

You will see:

up

What it means: Warmup.

Step 8: Map the port

Why: Host port 5000 reaches the app. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: -p 5000:5000. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 22: port

Type this:

ss -ltn | grep ':5000 ' | head -1 || echo listening_via_docker

You will see:

LISTEN ... :5000

What it means: Port open.

Example 23: fmt

Type this:

docker port flask-api

You will see:

5000/tcp -> 0.0.0.0:5000

What it means: Publish map.

Example 24: names

Type this:

docker inspect -f '{{.Name}}' flask-api

You will see:

/flask-api

What it means: Name.

Step 9: curl health

Why: /health proves ready. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: curl returns 200. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 25: health

Type this:

curl -s http://127.0.0.1:5000/health

You will see:

{"ok":true}

What it means: Health.

Example 26: code

Type this:

curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/health

You will see:

200

What it means: OK.

Example 27: hello

Type this:

curl -s http://127.0.0.1:5000/api/hello

You will see:

{"msg":"order-api"}

What it means: Route.

5. Harden and accept

Step 10: Read logs

Why: Logs show listen lines. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: docker logs tail. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 28: logs

Type this:

docker logs flask-api 2>&1 | tail -5

You will see:

listen or Started

What it means: App logged.

Example 29: follow

Type this:

echo 'docker logs -f flask-api'

You will see:

docker logs -f flask-api

What it means: Follow tip.

Example 30: inspect

Type this:

docker inspect -f '{{.State.Status}}' flask-api

You will see:

running

What it means: Running.

Step 11: Exec inside

Why: exec is for quick checks. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: docker exec. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 31: exec

Type this:

docker exec flask-api sh -c 'echo inside'

You will see:

inside

What it means: Shell works.

Example 32: pwd

Type this:

docker exec flask-api pwd

You will see:

/app

What it means: WORKDIR.

Example 33: id

Type this:

docker exec flask-api id | head -c 40; echo

You will see:

uid=...

What it means: User inside.

Step 12: Acceptance checklist

Why: Meera signs off when these pass. We do this before the next step so mistakes stay small and easy to undo. Read the output; the names and numbers tell you if the machine is healthy.

What: All green checks. Follow the numbered examples below. Type each command, read the exact output, and match the meaning line before you move on. That is how real teams learn a tool.

Example 34: smoke

Type this:

curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:5000/health

You will see:

200

What it means: Smoke.

Example 35: mode

Type this:

stat -c '%a' /tmp/flask-api/Dockerfile

You will see:

644

What it means: Safe.

Example 36: Sign-off

Type this:

echo 'Meera: PASS'

You will see:

Meera: PASS

What it means: Done.

Check yourself

Q1. Base image?

python:3.12-alpine

Q2. Host port?

5000

Q3. Health path?

/health

Q4. Who fixed Swiggy?

Meera

Q5. Build command?

docker build

Q6. Why pin?

So builds stay repeatable

Friends, you dockerized a Python Flask app with a pinned image. Did you understand? Let us try it once more. Change the health text, rebuild as 1.1, and switch the container.

Lab: try at home

  1. Write the app files.
  2. Write Dockerfile with pinned tag.
  3. Build 1.0.
  4. Run and curl.
  5. Tag 1.1 after a text change.

Recap

  • Pin base image tags.
  • COPY only what you need.
  • -p maps host to container.
  • Same image on every host.
  • Logs prove listen.