สวัสดีค่าา กลับมา EP.5 กันแล้ว

ใน EP.1 เราพูดถึงปัญหา "It works on my machine" ที่ทำให้นักพัฒนาและ ops ขัดแย้งกันมาตลอด EP นี้เราจะมาเรียนเครื่องมือที่แก้ปัญหานั้นได้จริงๆ ชื่อว่า Docker ค่ะ

Docker เป็นหนึ่งในเครื่องมือที่เปลี่ยนวงการ DevOps ไปมากที่สุด ถ้ายังไม่รู้จัก Docker ก็เหมือนไปยิมแต่ไม่รู้ว่า barbell คืออะไร 5555 ต้องรู้ค่ะ


ปัญหาก่อนมี Container

สมมติแอปของเราต้องการ

  • Python 3.11
  • PostgreSQL 15
  • Redis 7
  • Node.js 20

บนเครื่อง Dev มีทุกอย่างพร้อม แต่พอส่งให้ Ops deploy บน server จริง server นั้นมี Python 3.9, PostgreSQL 12 และไม่มี Redis เลย ผลลัพธ์? พังทั้งหมด

จะให้ Ops ไป install ทุกอย่างให้ตรงกันก็ใช้เวลามาก และถ้ามี 10 service ก็ต้องทำ 10 รอบ ไม่มีทางที่จะ consistent ได้


Container คืออะไร

Container คือการ "แพ็ค" app พร้อมทุกอย่างที่ต้องการไว้ด้วยกันในกล่องใบเดียว ทั้ง code, runtime, library, config ทุกอย่างอยู่ใน container แล้วกล่องนี้จะทำงานเหมือนกันทุก environment ไม่ว่าจะรันบนเครื่อง Dev, server test หรือ production

เปรียบเหมือน meal prep ค่ะ แทนที่จะทำอาหารใหม่ทุกวัน เตรียม box อาหารไว้เลย ทุก box มีส่วนผสมครบถ้วนเหมือนกันทุกใบ จะกินที่ไหนก็ได้ taste เหมือนกันหมด

Container = App + ทุก dependency ที่ต้องการ [App Code] [Python 3.11] [PostgreSQL client] [Redis client] [ทุก library ที่ต้องการ] ----- รันที่ไหนก็เหมือนกันหมด -----

Container vs Virtual Machine

Virtual Machine (VM)Container
Sizeหลาย GB ต่อ VMหลัก MB ต่อ container
Boot timeหลายนาทีไม่กี่วินาที
Isolationแยก OS ทั้งหมดแชร์ OS kernel, แยก process
ใช้ทรัพยากรเยอะกว่าน้อยกว่ามาก

VM เหมือนการเช่าบ้านทั้งหลัง Container เหมือนการเช่าห้องในอพาร์ตเมนต์เดียวกัน แชร์ผนังและโครงสร้างหลัก แต่แยก private space กัน


Docker: เครื่องมือทำ Container ที่ดังที่สุด

Docker ไม่ได้ invented container นะ แต่มันทำให้การใช้ container ง่ายมากขึ้นจนกลายเป็น standard ของวงการ

Image vs Container

  • Image คือ template หรือ "สูตรอาหาร" บอกว่า container ต้องมีอะไรบ้าง
  • Container คือ running instance ของ image เหมือน "อาหารที่ทำจากสูตรนั้นแล้ว"

Image หนึ่งใบสร้าง container ได้กี่ตัวก็ได้ ทุกตัวเหมือนกันทุกอย่าง

คำสั่ง Docker พื้นฐาน

# ดึง image จาก Docker Hub
docker pull nginx
docker pull python:3.11

# รัน container
docker run nginx
docker run -d -p 8080:80 nginx    # -d background, -p port mapping

# ดู container ที่กำลังรัน
docker ps
docker ps -a    # รวม stopped containers ด้วย

# หยุดและลบ
docker stop container_id
docker rm container_id

# ดู logs
docker logs container_id
docker logs -f container_id    # follow แบบ real-time

# เข้าไปใน container
docker exec -it container_id bash

Dockerfile เขียน Image เอง

Dockerfile คือไฟล์ที่บอก Docker ว่า Image ของเราประกอบด้วยอะไรบ้าง

# Dockerfile สำหรับ Python app

# เริ่มจาก base image
FROM python:3.11-slim

# กำหนด working directory
WORKDIR /app

# copy requirements ก่อน (layer caching)
COPY requirements.txt .

# ติดตั้ง dependencies
RUN pip install --no-cache-dir -r requirements.txt

# copy โค้ดทั้งหมด
COPY . .

# expose port ที่ app รันอยู่
EXPOSE 8000

# คำสั่งที่จะรันเมื่อ container เริ่ม
CMD ["python", "app.py"]
# build image จาก Dockerfile
docker build -t my-python-app:1.0 .

# รัน image ที่ build มา
docker run -d -p 8000:8000 my-python-app:1.0

💡 ลำดับ instruction ใน Dockerfile สำคัญมากค่ะ Docker cache ทีละ layer ถ้าเปลี่ยน line ไหน layer นั้นและทุก layer หลังจากนั้นจะ rebuild ใหม่ เลยควรวาง instruction ที่เปลี่ยนบ่อย (เช่น COPY code) ไว้ล่างๆ และวางสิ่งที่ stable (เช่น install dependencies) ไว้บนๆ จะ build ได้เร็วกว่ามาก


Docker Compose รัน หลาย Container พร้อมกัน

App จริงๆมักต้องการหลาย service พร้อมกัน เช่น web server + database + cache Docker Compose ช่วยให้กำหนดและรันพวกนั้นในไฟล์เดียว

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
    depends_on:
      - db
      - redis

  db:
    image: postgres:15
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine

volumes:
  postgres_data:
# รันทุก service ด้วยคำสั่งเดียว
docker compose up -d

# หยุดทุก service
docker compose down

# ดู logs ทุก service
docker compose logs -f

ไฟล์นี้ไฟล์เดียว dev คนไหนก็ clone repo มาแล้วรัน docker compose up ได้เลย ไม่ต้อง install อะไรเพิ่มเลย นี่แหละคือ magic ของ Docker ค่ะ


Docker Hub และ Registry

Docker Hub คือ registry กลางที่เก็บ image สาธารณะ เหมือน GitHub แต่สำหรับ Docker image มี official image ของ nginx, postgres, redis, python ฯลฯ ให้ใช้ฟรีหมดเลย

# push image ขึ้น Docker Hub
docker login
docker tag my-app:1.0 chawadesu/my-app:1.0
docker push chawadesu/my-app:1.0

# pull image ของเราจาก Hub
docker pull chawadesu/my-app:1.0

ในงานจริงบริษัทส่วนใหญ่จะใช้ private registry เช่น AWS ECR หรือ GitLab Registry แทน Docker Hub สาธารณะ เพื่อเก็บ image ที่มี business logic ไว้ข้างใน


สรุป EP.5

  • Container แพ็ค app พร้อม dependency ทั้งหมดไว้ด้วยกัน รันที่ไหนก็เหมือนกัน
  • Image คือ template, Container คือ running instance
  • Dockerfile คือสูตรสร้าง image เอง
  • Docker Compose รัน หลาย service พร้อมกันด้วยไฟล์เดียว
  • Docker Hub คือ registry สาธารณะเก็บ image

🏋️ การบ้าน: ลง Docker Desktop แล้วลอง docker run -d -p 80:80 nginx เปิด browser ไปที่ localhost แล้วดูว่าเห็น nginx welcome page ไหม ถ้าเห็น แสดงว่า run container แรกได้แล้ว ปรบมือให้ตัวเองด้วยนะ 🎉