🐳 Docker Knowledge Base - Q&A Notes
📋 Table of Contents
- Multi-stage Build
- COPY & Filesystem
- WORKDIR
- Environment Variables
- ENTRYPOINT vs CMD
- Docker Shell & Debug
- Best Practices
Multi-stage Build
❓ Multi-stage build là gì và tại sao sử dụng?
💡 Trả lời:
- Multi-stage build = sử dụng nhiều
FROMtrong 1 Dockerfile - Mỗi stage là 1 container riêng biệt, chỉ copy những gì cần thiết sang stage cuối
- Ưu điểm:
- Image nhẹ hơn (150MB vs 500MB)
- Bảo mật tốt hơn (không chứa source code, build tools)
- Tách biệt concern (deps → build → runtime)
dockerfile
FROM node:alpine AS deps # Stage 1: Install dependencies
FROM node:alpine AS builder # Stage 2: Build application
FROM node:alpine AS runner # Stage 3: Runtime (final image)❓ COPY --from=deps nghĩa là gì?
💡 Trả lời:
- Copy file từ stage
depssang stage hiện tại - Cú pháp:
COPY --from=<stage_name> <source_path> <dest_path>
dockerfile
COPY --from=deps /usr/src/app/node_modules ./node_modules
# Từ stage "deps", copy folder node_modules sang stage hiện tạiCOPY & Filesystem
❓ Tại sao phải COPY trong Docker? Code của tôi đâu có copy ở đâu?
💡 Trả lời:
- Docker Container = 1 máy tính Linux riêng biệt, ban đầu RỖNG
- Code của bạn ở máy host, container không thấy được
COPY= chuyển file từ máy host → container
🏠 Máy bạn (host) 🏢 Container Docker
├── package.json → ├── (ban đầu trống)
├── src/ → ├── (sau COPY mới có)
└── ... └── ...❓ Folder /usr/src/app nằm ở đâu?
💡 Trả lời:
/usr/src/appnằm BÊN TRONG container, không phải máy bạn- Container có filesystem Linux riêng:
/,/usr/,/bin/,/etc/... - Bạn có thể xem bằng:
docker run -it <image> shrồils /
WORKDIR
❓ Có bắt buộc dùng /usr/src/app không? usr là gì?
💡 Trả lời:
- KHÔNG bắt buộc! Có thể dùng bất kỳ folder nào
usr= Unix System Resources (chứa user programs)/usr/src/appchỉ là convention phổ biến của Node.js
Các lựa chọn:
dockerfile
WORKDIR /app # ✅ Đơn giản nhất
WORKDIR /usr/src/app # ✅ Convention Node.js
WORKDIR /opt/myapp # ✅ Corporate style
WORKDIR /myproject/api # ✅ CustomTránh:
dockerfile
WORKDIR /bin # ❌ System folders
WORKDIR /etc # ❌ Config folders
WORKDIR /tmp # ❌ Temporary foldersEnvironment Variables
❓ Khi build app cần .env thì xử lý thế nào?
💡 Trả lời:
- TUYỆT ĐỐI TRÁNH copy .env vào image (nguy hiểm về security)
- Dùng runtime environment variables
❌ Sai:
dockerfile
COPY .env ./ # Secrets bị "nướng" vào image✅ Đúng:
bash
# Runtime injection
docker run --env-file .env.production my-app
docker run -e DATABASE_URL=xxx -e JWT_SECRET=yyy my-appCho build-time (config không nhạy cảm):
dockerfile
ARG NODE_ENV=production
ARG API_PORT=3000
RUN echo "NODE_ENV=${NODE_ENV}" > .env❓ Multi-environment với Docker?
💡 Trả lời:
yaml
# docker-compose.yml
services:
app-dev:
build: .
env_file: .env.development
app-prod:
build: .
environment:
- NODE_ENV=production
- DATABASE_URL=${PROD_DATABASE_URL}ENTRYPOINT vs CMD
❓ Tại sao có ENTRYPOINT thì không chạy được docker run -it my-app sh?
💡 Trả lời:
ENTRYPOINTluôn chạy, không thể override dễ dàngshđược truyền làm argument cho entrypoint script- Nếu script không xử lý arguments →
shbị bỏ qua
dockerfile
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
# docker run -it my-app sh
# → Thực tế chạy: /usr/local/bin/entrypoint.sh sh❓ Làm thế nào để debug khi có ENTRYPOINT?
💡 Trả lời:
Cách 1: Override entrypoint
bash
docker run -it --entrypoint sh my-appCách 2: Script entrypoint thông minh
bash
#!/bin/sh
# entrypoint.sh
if [ "$1" = "sh" ] || [ "$1" = "bash" ]; then
exec "$@" # Chạy shell
fi
# Chạy app bình thường
yarn startCách 3: Dùng CMD thay ENTRYPOINT
dockerfile
CMD ["/usr/local/bin/entrypoint.sh"] # Dễ override❓ ENTRYPOINT vs CMD khác nhau thế nào?
💡 Trả lời:
| ENTRYPOINT | CMD | |
|---|---|---|
| Override | Khó (cần --entrypoint) | Dễ |
| Use case | Logic bắt buộc (init, health check) | Default command |
| Debug | Cần xử lý đặc biệt | Đơn giản |
dockerfile
# Production app with init logic
ENTRYPOINT ["/init.sh"]
CMD ["yarn", "start"]
# Simple app
CMD ["yarn", "start"]Docker Shell & Debug
❓ Làm thế nào để thoát khỏi docker run -it my-app sh?
💡 Trả lời:
3 cách chính:
bash
exit # ✅ Thoát shell + container dừng
# Ctrl + D # ✅ Tương tự exit
# Ctrl + C # ⚠️ Chỉ dừng command hiện tại, KHÔNG thoát shellWorkflow debug:
bash
# 1. Vào container debug
docker run -it my-app sh
# 2. Debug
ls -la
cat package.json
env
# 3. Thoát
exit❓ Làm thế nào để debug container đang chạy?
💡 Trả lời:
bash
# Container đang chạy app
docker run -d -p 8080:8080 my-app
# Debug từ terminal khác
docker ps # Lấy container ID
docker exec -it <container_id> sh # Vào container
# ... debug ...
exit # App vẫn chạyBest Practices
❓ Dockerfile structure tốt nhất?
💡 Trả lời:
dockerfile
# Multi-stage cho Node.js
FROM node:alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN yarn --frozen-lockfile
FROM node:alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN yarn build
FROM node:alpine AS runner
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/*.json ./
CMD ["yarn", "start"]❓ Security best practices?
💡 Trả lời:
- ❌ Không copy .env vào image
- ❌ Không hardcode secrets trong Dockerfile
- ❌ Không dùng ARG cho sensitive data
- ✅ Dùng runtime environment variables
- ✅ Dùng secrets management (K8s secrets, Docker secrets)
- ✅ Multi-stage để giảm attack surface
❓ Development workflow với Docker?
💡 Trả lời:
bash
# Development
docker-compose up # với .env.development
# Debug
docker run -it --entrypoint sh my-app
# Production
docker run --env-file .env.production my-app
# CI/CD
docker build -t my-app .
docker run -e DATABASE_URL="$SECRET_DB_URL" my-app🔧 Quick Commands Reference
bash
# Build
docker build -t my-app .
docker build --target debug -t my-app:debug .
# Run
docker run my-app # Normal
docker run -it my-app sh # Debug shell
docker run --entrypoint sh my-app # Override entrypoint
docker run --env-file .env my-app # With env file
docker run -e VAR=value my-app # With env vars
# Debug running container
docker ps # List containers
docker exec -it <container_id> sh # Exec into running container
docker logs <container_id> # View logs
# Clean up
docker kill <container_id> # Force stop
docker rm <container_id> # Remove container
docker rmi <image> # Remove image📚 Additional Resources
📝 Note: Tài liệu này tóm tắt kiến thức từ conversation về Docker fundamentals, multi-stage builds, environment handling, và debugging techniques.