การ Dockerize Python App
Node Dockerfile ที่คุณรู้จักอยู่แล้ว
หัวข้อที่มีชื่อว่า “Node Dockerfile ที่คุณรู้จักอยู่แล้ว”ถ้าคุณเคย containerize Node/TypeScript app มาก่อน คุณรู้ pattern: copy package.json, รัน npm ci, copy source, build และรัน Python Dockerfile ตาม multi-stage logic เดียวกัน — แต่มี best practices เฉพาะ Python บางอย่างที่คุณต้องเข้าใจ
เทียบกันชัดๆ: Node vs Python Dockerfile
หัวข้อที่มีชื่อว่า “เทียบกันชัดๆ: Node vs Python Dockerfile”# ---- Node / TypeScript multi-stage Dockerfile ----FROM node:20-alpine AS depsWORKDIR /appCOPY package*.json ./RUN npm ci --only=production
FROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ciCOPY . .RUN npm run build
FROM node:20-alpine AS runnerWORKDIR /appENV NODE_ENV=productionCOPY --from=deps /app/node_modules ./node_modulesCOPY --from=builder /app/dist ./distRUN addgroup -S appgroup && adduser -S appuser -G appgroupUSER appuserEXPOSE 3000CMD ["node", "dist/main.js"]# ---- Python multi-stage Dockerfile ----FROM python:3.12-slim AS builderWORKDIR /app
# ติดตั้ง build tools แล้วสร้าง venv ภายใน imageRUN python -m venv /app/.venvENV PATH="/app/.venv/bin:$PATH"
COPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt
FROM python:3.12-slim AS runnerWORKDIR /app
# Copy pre-built venv จาก builderCOPY --from=builder /app/.venv /app/.venvENV PATH="/app/.venv/bin:$PATH"
# Copy application sourceCOPY src/ ./src/
# รันด้วย non-root userRUN addgroup --system appgroup && adduser --system --ingroup appgroup appuserUSER appuser
EXPOSE 8000CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]Python Dockerfile แบบ production เต็มรูปแบบ พร้อม comment
หัวข้อที่มีชื่อว่า “Python Dockerfile แบบ production เต็มรูปแบบ พร้อม comment”# syntax=docker/dockerfile:1
# ---- Stage 1: Build / dependency installation ----FROM python:3.12-slim AS builder
WORKDIR /app
# PYTHONDONTWRITEBYTECODE: ไม่เขียน .pyc files (ประหยัด space)# PYTHONUNBUFFERED: log output ทันที (12-Factor: log ไปยัง stdout)ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1
# สร้าง virtual environment ภายใน image# ทำให้เรา copy ทั้ง /app/.venv ไปยัง final stage ได้RUN python -m venv /app/.venvENV PATH="/app/.venv/bin:$PATH"
# Copy dependency manifest ก่อน (Docker layer caching)COPY pyproject.toml uv.lock* requirements.txt* ./
# ติดตั้ง dependencies — no cache เพื่อให้ image เล็กRUN pip install --no-cache-dir --upgrade pip && \ pip install --no-cache-dir -r requirements.txt
# ---- Stage 2: Runtime image ----FROM python:3.12-slim AS runner
WORKDIR /app
# Copy venv ที่มี dependencies ครบจาก builderCOPY --from=builder /app/.venv /app/.venvENV PATH="/app/.venv/bin:$PATH" \ PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1
# Copy application source (หลัง deps — cache hit ที่ดีกว่าเมื่อ rebuild)COPY src/ ./src/
# สร้างและเปลี่ยนไปใช้ non-root user (security best practice)RUN addgroup --system appgroup && \ adduser --system --ingroup appgroup --no-create-home appuserUSER appuser
# Expose port ที่ app รับฟังEXPOSE 8000
# CMD ใช้ exec form (ไม่มี shell wrapper — signals ส่งตรงถึง process)CMD ["uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8000"]ทำไมต้องสร้าง venv ภายใน Docker image?
หัวข้อที่มีชื่อว่า “ทำไมต้องสร้าง venv ภายใน Docker image?”รันในเทอร์มินัลของคุณเพื่อ build และรัน:
docker build -t my-python-app .docker run -p 8000:8000 my-python-app
# หรือด้วย docker compose:# docker compose up --build.dockerignore
หัวข้อที่มีชื่อว่า “.dockerignore”เหมือน .gitignore สำหรับ Docker สร้างเสมอเพื่อหลีกเลี่ยงการ copy venv, cache และ secrets ลงใน image:
.venv/__pycache__/*.pyc*.pyo.pytest_cache/.mypy_cache/.ruff_cache/.env.env.**.log