[th][in-progress] Basic Docker
2025-02-10
Docker Components
What is docker ?
Docker คือแพลตฟอร์มที่ช่วยให้เราสามารถพัฒนา จัดส่ง และรัน applications ได้ในรูปแบบของ containers ซึ่งเป็นสภาพแวดล้อมที่แยกออกมาต่างหาก ทำให้แอพพลิเคชันของเราทำงานได้เหมือนกันในทุกๆ environment
ปัญหาที่ Docker มาช่วยแก้:
- “ที่เครื่องผมทำงานนะ” - Docker ทำให้สภาพแวดล้อมการทำงานเหมือนกันทุกเครื่อง
- ติดตั้งและเซ็ตอัพโปรเจคใหม่ได้รวดเร็ว
- ลดปัญหาความขัดแย้งของ dependencies ระหว่างโปรเจค
Comparing Containers and Virtual Machines

Containerized Applications (Left)
- ทุกแอพ (App A ถึง F) แชร์ Docker Engine เดียวกัน
- ใช้ Host OS เดียวกัน
- ไม่ต้องมี Guest OS แยกสำหรับแต่ละแอพ
- เบาและใช้ทรัพยากรน้อยกว่า
- เริ่มต้นได้เร็วกว่า (เป็นวินาที)
Virtual Machines (Right)
- แต่ละ VM ต้องมี Guest OS แยกกัน
- ใช้ Hypervisor ในการจัดการ VMs
- แยก OS สมบูรณ์แบบ
- ใช้ทรัพยากรมากกว่า
- เริ่มต้นช้ากว่า (เป็นนาที)
Architecture of Docker

Docker ใช้สถาปัตยกรรมแบบ client-server ในการทำงาน โดยมีการแบ่งส่วนประกอบหลักและการทำงานดังนี้:
Core Components
1. Docker Client
- เป็นวิธีหลักที่ผู้ใช้โต้ตอบกับ Docker
- ส่งคำสั่งต่างๆ เช่น
docker build,docker run,docker pullไปยัง Docker Daemon - สามารถเชื่อมต่อกับ Docker Daemon ได้หลายตัว
- ใช้ Docker REST APIs ในการสื่อสาร
2. Docker Daemon (dockerd)
- ทำหน้าที่รับและประมวลผลคำสั่ง Docker API
- จัดการ Docker objects ทั้งหมด (images, containers, networks, volumes)
- สามารถสื่อสารกับ Daemon ตัวอื่นเพื่อจัดการ Docker services
- ทำงานอยู่เบื้องหลังและจัดการงานหนักทั้งหมด
3. Docker Host
- เป็นสภาพแวดล้อมสำหรับรัน containerized applications
- ประกอบด้วย:
- Docker Daemon
- Images
- Containers
- Networks
- Volumes และ Storage
4. Docker Registry
- เป็นที่เก็บ Docker Images
- Docker Hub เป็น public registry ที่ใหญ่ที่สุด
- สามารถสร้าง private registry ได้
- ใช้คำสั่ง
docker pullเพื่อดึง images - ใช้คำสั่ง
docker pushเพื่อส่ง images
การทำงานของ Docker Architecture
-
การสื่อสาร:
- Docker Client และ Daemon สื่อสารผ่าน REST API
- สามารถสื่อสารผ่าน UNIX sockets หรือ network interface
- Client และ Daemon สามารถอยู่บนเครื่องเดียวกันหรือคนละเครื่องก็ได้
Docker Images
Docker Image คือแม่แบบ read-only ที่ใช้ในการสร้าง container โดยภายในจะมีทุกอย่างที่จำเป็นสำหรับการรันแอพพลิเคชัน
1. Docker Image คืออะไร?
- เป็น template สำหรับสร้าง container
- เป็น read-only package ที่มีทุกอย่างที่จำเป็นสำหรับรันแอพพลิเคชัน
- เปรียบเสมือน “พิมพ์เขียว” หรือ snapshot ของระบบ
- สามารถแชร์และนำกลับมาใช้ใหม่ได้
- เก็บไว้ใน Docker Registry (เช่น Docker Hub)
2. โครงสร้างของ Image
- Base Layer: เป็นชั้นล่างสุด มักเป็น OS เช่น Ubuntu, Alpine
- Middle Layers: ชั้นกลางที่เพิ่มซอฟต์แวร์และ dependencies
- Application Layer: ชั้นบนสุดที่มีโค้ดของแอพพลิเคชัน
Docker Containers
Container คือ instance ที่รันได้ของ Docker Image โดยจะแยกสภาพแวดล้อมการทำงานออกจากกัน
1. Container คืออะไร?
- เป็นสภาพแวดล้อมที่แยกออกมาต่างหาก
- มี filesystem และ network interface แยกเป็นของตัวเอง
- สามารถเริ่ม หยุด ลบ หรือย้ายได้อย่างอิสระ
- แต่ละ container แยกกันทำงานอย่างอิสระ
2. Container Lifecycle
- Created: สร้าง container จาก image
- Running: container กำลังทำงาน
- Stopped: หยุดการทำงานชั่วคราว
- Deleted: ลบ container
Part 2: Hands-on
การจัดการ Container
คำสั่งพื้นฐานสำหรับการสร้างและรัน container:
docker run [OPTIONS] IMAGE
Key Options
-
-d หรือ --detech: Run the container in the background (detached mode)
รันแบบ background แบบไม่ต้องการการโต้ตอบ#ตัวอย่าง docker run -d nginx -
-i หรือ --interactive: Keep STDIN open even if not attached
คงการเชื่อมต่อ input ไว้แม้จะไม่ได้ attach#ตัวอย่าง docker run -i ubuntu -
-t หรือ --tty: Allocate a pseudo-TTY (terminal)
จัดสรรและจำลอง terminal#ตัวอย่าง docker run -it ubuntuมักใช้คู่กับ -i เป็น -it
-
-p หรือ --publish: Map a port from the container to the host
map port จาก container ไปยัง host#ตัวอย่าง docker run -p 8080:80 nginx -
-v หรือ --volume: Bind mount a volumemount directory หรือ file system จาก host เข้าไปใน container
#ตัวอย่าง docker run -v /host/path:/container/path nginx -
--name: Assign a name to the container กำหนดชื่อให้ container#ตัวอย่าง docker run --name my-nginx nginx -
--rm: Automatically remove the container when it exits
ลบ container อัตโนมัติเมื่อ container หยุดทำงาน#ตัวอย่าง docker run --rm nginx -
-e หรือ --env: Set environment variables
กำหนดค่าตัวแปรสภาพแวดล้อม#ตัวอย่าง docker run -e MYSQL_ROOT_PASSWORD=secret mysql
Docker Start & Stop
docker start
- เริ่มการทำงานของ container ที่หยุดอยู่
#รูปแบบพื้นฐาน
docker start <container_id/name>
#เริ่มหลาย containers พร้อมกัน
docker start container1 container2
docker stop
- หยุดการทำงานของ container ที่กำลังทำงานอยู่
#รูปแบบพื้นฐาน
docker stop <container_id/name>
#หยุดหลาย containers พร้อมกัน
docker stop container1 container2
คำสั่งอื่นๆ ที่เกี่ยวข้อง
# สำหรับ restart container
docker restart <container_id/name>
# สำหรับหยุด container ชั่วคราว แต่ resources ยังใช้งานอยู่
docker pause <container_id/name>
# สำหรับเริ่ม container ที่ pause ไว้
docker unpause <container_id/name>
# สำหรับหยุด container แบบทันที **เมื่อ stop ไม่ได้**
docker kill <container_id/name>
Docker Inspect Command
คำสั่งสำหรับดูรายละเอียด container:
# รูปแบบพื้นฐาน
docker inspect [OPTIONS] CONTAINER/IMAGE/VOLUME/NETWORK
คำสั่งพื้นฐานอื่นๆ ที่เกี่ยวข้อง
แสดง containers ที่กำลังทำงาน
docker ps
แสดง containers ทั้งหมด (ทั้งที่กำลังทำงานและหยุดทำงาน)
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cccc68e19206 postgres:13 "docker-entrypoint.s…" 10 days ago Up 10 days (healthy) 0.0.0.0:5432->5432/tcp kong-database
6d67edde7c16 postgres:14.3 "docker-entrypoint.s…" 3 weeks ago Up 11 days 0.0.0.0:5442->5432/tcp setup-db-1
76e0e7122cce postgres:14.3 "docker-entrypoint.s…" 2 months ago Up 11 days 0.0.0.0:5440->5432/tcp db-migrations-db-1
28b4afb59b35 postgres:12 "docker-entrypoint.s…" 2 months ago Up 11 days 0.0.0.0:5435->5432/tcp exam_api-db-1
63d94687328b postgres:latest "docker-entrypoint.s…" 3 months ago Up 11 days 0.0.0.0:5434->5432/tcp hua-db
6dd5d3308774 postgres "docker-entrypoint.s…" 8 months ago Up 11 days 0.0.0.0:5430->5432/tcp pg-learn-db-1
คำสั่งสำหรับตรวจสอบ Logs
docker logs [OPTIONS] CONTAINER
คำสั่งสำหรับ Monitor Resources Usage
docker stats
Docker Data Persistence
Docker containers มีลักษณะเป็น ephemeral (ชั่วคราว) คือข้อมูลจะหายไปเมื่อ container ถูกลบ ดังนั้นเราจึงต้องมีวิธีจัดการข้อมูลให้คงอยู่ถาวร
1. Docker Volumes
วิธีที่แนะนำในการจัดเก็บข้อมูลถาวรใน Docker
# สร้าง volume
docker volume create my_volume
# ใช้งาน volume กับ container
docker run -v my_volume:/path/in/container image_name
# ดูรายละเอียด volume
docker volume inspect my_volume
# ลบ volume
docker volume rm my_volume
2. Bind Mounts
เชื่อมต่อ directory จาก host เข้ากับ container โดยตรง
# รูปแบบพื้นฐาน
docker run -v /host/path:/container/path image_name
# ตัวอย่างการใช้งานกับ nginx
docker run -v $(pwd)/html:/usr/share/nginx/html nginx
3. เปรียบเทียบ Volumes vs Bind Mounts
-
Volumes:
- จัดการโดย Docker
- ปลอดภัยกว่า
- ง่ายต่อการ backup และ migrate
- สามารถจัดการผ่าน Docker CLI
- เหมาะสำหรับเก็บข้อมูลของ application
-
Bind Mounts:
- ต้องระบุ path บน host
- ใช้งานง่าย เหมาะกับการพัฒนา
- ขึ้นอยู่กับโครงสร้าง directory ของ host
- เหมาะสำหรับการแชร์ configuration files
4. ตัวอย่างการใช้งาน
# PostgreSQL with volume
docker run -d \
--name postgres-db \
-e POSTGRES_PASSWORD=mysecret \
-v postgres_data:/var/lib/postgresql/data \
postgres
# MySQL with volume
docker run -d \
--name mysql-db \
-e MYSQL_ROOT_PASSWORD=mysecret \
-v mysql_data:/var/lib/mysql \
mysql
# Web development with bind mount
docker run -d \
--name web-server \
-v $(pwd):/usr/share/nginx/html \
-p 8080:80 \
nginx
Docker Port Mapping
Port mapping ใน Docker ช่วยให้เราสามารถเข้าถึง services ที่รันอยู่ใน container จากภายนอกได้
1. รูปแบบพื้นฐานของ Port Mapping
docker run -p [HOST_PORT]:[CONTAINER_PORT] [IMAGE]
Specific port mapping
# Map port 8080 ของ host ไปยัง port 80 ของ container
docker run -p 8080:80 nginx
Random port mapping:
# ให้ Docker สุ่มเลือก port จาก host
docker run -P nginx
Multiple port mapping:
# Map หลาย ports พร้อมกัน
docker run -p 8080:80 -p 443:443 nginx
ตัวอย่างการใช้งานกับ Applications ต่างๆ
# Web Server (Nginx)
docker run -d -p 8080:80 nginx
# Database (PostgreSQL)
docker run -d -p 5432:5432 postgres
# Web Application (Node.js)
docker run -d -p 3000:3000 node-app
# Multiple Services (Web + SSL)
docker run -d \
-p 80:80 \
-p 443:443 \
nginx
# Redis Cache
docker run -d -p 6379:6379 redis
# MongoDB
docker run -d -p 27017:27017 mongo
Docker Network
Docker Network ช่วยให้ containers สามารถสื่อสารกันได้ และยังสามารถกำหนดรูปแบบการเชื่อมต่อที่เหมาะสมกับการใช้งาน
1. Network Drivers
Docker มี network drivers หลายประเภท:
-
bridge: (default)
- ใช้สำหรับ containers ที่ต้องการสื่อสารกันในเครื่องเดียวกัน
- เหมาะสำหรับการรันแอพแบบ standalone
-
host:
- ใช้ network stack ของ host โดยตรง
- ประสิทธิภาพดีที่สุด แต่ไม่มีการแยก network
-
none:
- ไม่มีการเชื่อมต่อ network
- ใช้เมื่อต้องการความปลอดภัยสูงสุด
-
overlay:
- สำหรับการสื่อสารระหว่าง containers ต่าง host
Docker Image Commands
Docker Image เป็น template ที่ใช้ในการสร้าง container โดยมีคำสั่งพื้นฐานดังนี้
1. การดึง Images (Pull)
# รูปแบบพื้นฐาน
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
# ตัวอย่าง
docker pull nginx # ดึง nginx version ล่าสุด
docker pull nginx:1.19 # ดึง nginx version 1.19
docker pull mysql:8.0 # ดึง mysql version 8.0
docker pull ubuntu:20.04 # ดึง ubuntu version 20.04
2. การแสดงรายการ Images
# ดูรายการ images ทั้งหมด
docker images
# ดูเฉพาะ image IDs
docker images -q
# ดูรายละเอียดแบบ formatted
docker images --format "table {{.ID}}\t{{.Repository}}\t{{.Tag}}"
3. การลบ Images
# ลบ image เดียว
docker rmi image_name
# ลบหลาย images
docker rmi image1 image2
# ลบ images ที่ไม่ได้ใช้ทั้งหมด
docker image prune
# ลบ images ที่ไม่มี tag
docker image prune -a
4. การ Tag Images
# รูปแบบพื้นฐาน
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
# ตัวอย่าง
docker tag nginx:latest myapp:v1.0
docker tag mysql:8.0 registry.example.com/mysql:8.0
5. การ Push Images
# รูปแบบพื้นฐาน
docker push [OPTIONS] NAME[:TAG]
# ตัวอย่าง
docker push myusername/myapp:1.0
docker push registry.example.com/myapp:latest
6. การค้นหา Images
# ค้นหา images จาก Docker Hub
docker search nginx
docker search --filter stars=100 nginx # ค้นหาที่มี stars มากกว่า 100
7. การดูรายละเอียด Image
# ดูรายละเอียดของ image
docker inspect image_name
# ดูประวัติการสร้าง image
docker history image_name
Part 3: Dockerfile
Dockerfile คือไฟล์ที่ใช้สำหรับสร้าง Docker Image โดยระบุขั้นตอนการสร้างแบบอัตโนมัติ
Basic Dockerfile Instructions
1. FROM
- เป็นคำสั่งแรกที่ต้องมีใน Dockerfile (ยกเว้น ARG)
- ระบุ base image ที่จะใช้
FROM ubuntu:20.04
FROM node:14-alpine
2. WORKDIR
- กำหนด working directory สำหรับคำสั่งที่จะทำงานต่อไป
- สร้าง directory ใหม่ถ้ายังไม่มี
WORKDIR /app
3. COPY และ ADD
- COPY: คัดลอกไฟล์จาก host เข้า image
- ADD: คล้าย COPY แต่มีความสามารถเพิ่มเติม (เช่น ดึงไฟล์จาก URL, แตก tar)
COPY package.json .
COPY src/ ./src/
ADD https://example.com/file.txt /app/
4. RUN
- รันคำสั่งระหว่างการสร้าง image
- สร้าง layer ใหม่ทุกครั้งที่รัน
RUN apt-get update && apt-get install -y nodejs
RUN npm install
5. ENV
- กำหนด environment variables
ENV NODE_ENV=production
ENV PORT=3000
6. EXPOSE
- ระบุ port ที่ container จะรับการเชื่อมต่อ
- เป็นเพียงการระบุเอกสาร ไม่ได้ทำการ publish port
EXPOSE 80
EXPOSE 3000
7. CMD และ ENTRYPOINT
- CMD: กำหนดคำสั่งเริ่มต้นเมื่อ run container
- ENTRYPOINT: คล้าย CMD แต่ไม่สามารถ override ได้ง่าย
CMD ["node", "app.js"]
ENTRYPOINT ["nginx", "-g", "daemon off;"]
ตัวอย่าง Dockerfile
Node.js Application
# ใช้ Node.js official image
FROM node:14-alpine
# กำหนด working directory
WORKDIR /app
# คัดลอก package files
COPY package*.json ./
# ติดตั้ง dependencies
RUN npm install
# คัดลอกโค้ดแอพพลิเคชัน
COPY . .
# กำหนด environment variables
ENV PORT=3000
# เปิด port
EXPOSE 3000
# รันแอพพลิเคชัน
CMD ["npm", "start"]
Python Web Application
# ใช้ Python official image
FROM python:3.9-slim
# กำหนด working directory
WORKDIR /app
# คัดลอก requirements file
COPY requirements.txt .
# ติดตั้ง dependencies
RUN pip install --no-cache-dir -r requirements.txt
# คัดลอกโค้ดแอพพลิเคชัน
COPY . .
# เปิด port
EXPOSE 5000
# รันแอพพลิเคชัน
CMD ["python", "app.py"]
Best Practices สำหรับการเขียน Dockerfile
- ใช้ .dockerignore
- ไม่คัดลอกไฟล์ที่ไม่จำเป็น
- ลดขนาด build context
# ตัวอย่าง .dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
- ลดจำนวน layers
- รวมคำสั่ง RUN ที่เกี่ยวข้องกัน
- ใช้ multi-stage builds สำหรับ production
# ไม่ดี
RUN apt-get update
RUN apt-get install -y package1
RUN apt-get install -y package2
# ดี
RUN apt-get update && \
apt-get install -y \
package1 \
package2
- ใช้ Multi-stage Builds
- แยก build environment และ runtime environment
- ลดขนาด final image
# Build stage
FROM node:14 AS builder
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
# Production stage
FROM node:14-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main.js"]
- ใช้ Specific Tags
- หลีกเลี่ยงการใช้ latest tag
- ระบุ version ที่แน่นอน
# ไม่ดี
FROM node:latest
# ดี
FROM node:14.17.0-alpine3.13
- จัดลำดับ Instructions อย่างเหมาะสม
- วาง instructions ที่เปลี่ยนแปลงน้อยไว้ด้านบน
- ใช้ประโยชน์จาก Docker build cache
# ดี - dependencies ไม่ค่อยเปลี่ยน
COPY package*.json ./
RUN npm install
# โค้ดแอพที่เปลี่ยนบ่อย
COPY . .
Part 4: Docker Compose
Docker Compose เป็นเครื่องมือสำหรับกำหนดและรันแอพพลิเคชันที่ประกอบด้วย Docker containers หลายตัว
Docker Compose คืออะไร?
- เป็นเครื่องมือสำหรับจัดการ multi-container applications
- ใช้ไฟล์ YAML ในการกำหนดค่า (docker-compose.yml)
- ช่วยให้จัดการ services, networks, และ volumes ได้ง่าย
- เหมาะสำหรับการพัฒนาและการทดสอบ
Basic Docker Compose Commands
# Start containers
docker-compose up
# Start in detached mode
docker-compose up -d
# Stop containers
docker-compose down
# Show running containers
docker-compose ps
# View logs
docker-compose logs
# Build or rebuild services
docker-compose build
# Start specific service
docker-compose up <service_name>
ตัวอย่าง docker-compose.yml
1. Basic Web Application with Database
version: "3.8"
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DB_HOST=db
- DB_USER=postgres
- DB_PASSWORD=secret
depends_on:
- db
db:
image: postgres:13
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
2. Full Stack Application
version: "3.8"
services:
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
backend:
build: ./backend
ports:
- "3000:3000"
environment:
- DB_HOST=db
- REDIS_HOST=redis
depends_on:
- db
- redis
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
- MYSQL_DATABASE=myapp
volumes:
- db_data:/var/lib/mysql
redis:
image: redis:alpine
ports:
- "6379:6379"
volumes:
db_data:
Key Concepts ใน Docker Compose
1. Services
- กำหนด container ที่จะรัน
- สามารถ build จาก Dockerfile หรือใช้ image ที่มีอยู่
- กำหนดค่าต่างๆ เช่น ports, environment variables, volumes
services:
web:
build: .
ports:
- "8080:80"
api:
image: node:14
command: npm start
2. Networks
- จัดการการเชื่อมต่อระหว่าง containers
- สามารถกำหนด custom networks ได้
services:
web:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
3. Volumes
- จัดการการเก็บข้อมูลถาวร
- แชร์ข้อมูลระหว่าง containers
services:
db:
volumes:
- db_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
volumes:
db_data:
Advanced Features
1. Environment Variables
services:
web:
env_file:
- .env
environment:
- API_KEY=${API_KEY}
- DEBUG=1
2. Health Checks
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
3. Deploy Configuration
services:
web:
deploy:
replicas: 3
resources:
limits:
cpus: "0.50"
memory: 512M
restart_policy:
condition: on-failure
Best Practices
-
ใช้ Version Control
- เก็บ docker-compose.yml ไว้ใน version control
- แยก development และ production configurations
-
Environment Variables
- ใช้ .env file สำหรับค่า sensitive
- ไม่ควรเก็บ .env ใน version control
# docker-compose.yml
services:
web:
env_file:
- .env.development
- แยก Configurations
- ใช้ docker-compose.override.yml สำหรับ development
- ใช้ docker-compose.prod.yml สำหรับ production
# Development
docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
# Production
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up
- การจัดการ Dependencies
- ใช้ depends_on อย่างเหมาะสม
- พิจารณาการใช้ health checks
services:
web:
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
- Resource Management
- กำหนด resource limits
- ใช้ restart policies ที่เหมาะสม
services:
web:
deploy:
resources:
limits:
cpus: "0.50"
memory: 256M
restart: unless-stopped
Part 5: Example Project
Business Requirements
Project: Health Check Microservice
Requirement
ต้องการสร้าง Health Check API Microservice สำหรับตรวจสอบสถานะการทำงานของระบบ โดยมีความต้องการดังนี้:
- API Endpoint:
- Route:
/health-check - Method: GET
- Response Format: JSON
- Response Requirements:
{
"code": 200,
"message": "OK"
}
- Technical Requirements:
- Build เป็น Docker Image
- Image size ต้องเล็กที่สุดเท่าที่เป็นไปได้