Container là gì?
Container là một đơn vị phần mềm đóng gói code và tất cả dependencies để ứng dụng chạy nhất quán trên mọi môi trường.
Container vs Virtual Machine
┌──────────────────────────────────────────────────────────┐
│ Container Virtual Machine │
├──────────────────────────────────────────────────────────┤
│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │App A│ │App B│ │App C│ │App A│ │App B│ │App C│ │
│ ├─────┤ ├─────┤ ├─────┤ ├─────┤ ├─────┤ ├─────┤ │
│ │Bins │ │Bins │ │Bins │ │Bins │ │Bins │ │Bins │ │
│ └─────┴─┴─────┴─┴─────┘ ├─────┤ ├─────┤ ├─────┤ │
│ ┌─────────────────────┐ │Guest│ │Guest│ │Guest│ │
│ │ Container Engine │ │ OS │ │ OS │ │ OS │ │
│ │ (Docker) │ └─────┴─┴─────┴─┴─────┘ │
│ ├─────────────────────┤ ┌─────────────────────┐ │
│ │ Host OS │ │ Hypervisor │ │
│ ├─────────────────────┤ ├─────────────────────┤ │
│ │ Infrastructure │ │ Host OS │ │
│ └─────────────────────┘ ├─────────────────────┤ │
│ │ Infrastructure │ │
│ └─────────────────────┘ │
│ │
│ Lightweight, Fast Heavy, Slower │
│ Share Host OS kernel Full OS per VM │
│ MB in size GB in size │
│ Seconds to start Minutes to start │
└──────────────────────────────────────────────────────────┘
Tại sao DevOps cần Docker?
| Vấn đề | Docker giải quyết |
|---|---|
| ”Works on my machine” | Môi trường nhất quán |
| Dependency conflicts | Isolated environments |
| Slow deployments | Fast, lightweight containers |
| Manual setup | Automated, reproducible |
Cài đặt Docker
macOS
- Tải Docker Desktop
- Kéo vào Applications
- Mở Docker Desktop và chờ khởi động
Linux (Ubuntu)
# Update packages
sudo apt update
# Install prerequisites
sudo apt install -y ca-certificates curl gnupg
# Add Docker GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
# Add repository
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Install Docker
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Add user to docker group
sudo usermod -aG docker $USER
# Logout và login lại
# Verify
docker --version
docker compose version
Windows
- Enable WSL 2
- Tải Docker Desktop
- Cài đặt và restart
Verify Installation
# Check version
docker --version
# Docker version 24.0.7, build afdd53b
# Run test container
docker run hello-world
Docker Architecture
┌─────────────────────────────────────────────────────────┐
│ Docker Client │
│ (docker CLI) │
└────────────────────────┬────────────────────────────────┘
│ REST API
▼
┌─────────────────────────────────────────────────────────┐
│ Docker Daemon │
│ (dockerd) │
├─────────────────────────────────────────────────────────┤
│ ┌───────────┐ ┌───────────┐ ┌───────────────────┐ │
│ │ Images │ │ Containers│ │ Networks │ │
│ └───────────┘ └───────────┘ └───────────────────┘ │
│ ┌───────────┐ ┌───────────────────────────────────┐ │
│ │ Volumes │ │ Docker Registry │ │
│ └───────────┘ │ (Docker Hub, ECR) │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Key Concepts
| Concept | Mô tả |
|---|---|
| Image | Template read-only để tạo containers |
| Container | Instance đang chạy của image |
| Dockerfile | Script để build image |
| Registry | Nơi lưu trữ images (Docker Hub, ECR) |
| Volume | Persistent storage |
| Network | Container networking |
Docker Commands Cơ bản
Images
# List images
docker images
# Pull image từ registry
docker pull nginx
docker pull nginx:1.25 # Specific version
# Remove image
docker rmi nginx
# Search images
docker search nginx
Containers
# Run container
docker run nginx # Foreground
docker run -d nginx # Detached (background)
docker run -d -p 8080:80 nginx # Port mapping
docker run -d --name web nginx # Named container
# List containers
docker ps # Running
docker ps -a # All (including stopped)
# Stop/Start container
docker stop web
docker start web
docker restart web
# Remove container
docker rm web
docker rm -f web # Force remove running container
# View logs
docker logs web
docker logs -f web # Follow logs
# Execute command in container
docker exec -it web bash
docker exec web ls -la
Practical Examples
# Run Nginx web server
docker run -d -p 8080:80 --name nginx-server nginx
# Access: http://localhost:8080
# Run MySQL database
docker run -d \
--name mysql-db \
-e MYSQL_ROOT_PASSWORD=secret \
-p 3306:3306 \
mysql:8
# Run Node.js app
docker run -d \
--name node-app \
-p 3000:3000 \
-v $(pwd):/app \
node:20-alpine \
node /app/index.js
Dockerfile
Dockerfile là “recipe” để build Docker image.
Cấu trúc cơ bản
# Dockerfile
# Base image
FROM node:20-alpine
# Set working directory
WORKDIR /app
# Copy package files first (for caching)
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source code
COPY . .
# Expose port
EXPOSE 3000
# Default command
CMD ["node", "server.js"]
Dockerfile Instructions
| Instruction | Mô tả |
|---|---|
FROM | Base image |
WORKDIR | Set working directory |
COPY | Copy files vào image |
ADD | Copy + extract (tar, URL) |
RUN | Execute command khi build |
CMD | Default command khi run |
ENTRYPOINT | Main executable |
EXPOSE | Document exposed port |
ENV | Set environment variable |
ARG | Build-time variable |
VOLUME | Create mount point |
USER | Set user to run commands |
HEALTHCHECK | Container health check |
Build Image
# Build image
docker build -t my-app .
docker build -t my-app:v1.0 .
# Build với Dockerfile khác tên
docker build -f Dockerfile.prod -t my-app:prod .
# Build với build args
docker build --build-arg VERSION=1.0 -t my-app .
Multi-stage Builds
Giảm image size bằng cách tách build và runtime:
# Stage 1: Build
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]
Before vs After Multi-stage
Single-stage: 1.2GB (includes dev dependencies, source)
Multi-stage: 150MB (only runtime)
Docker Volumes
Volumes lưu data persistent, không bị mất khi container bị xóa.
# Create volume
docker volume create my-data
# List volumes
docker volume ls
# Use volume
docker run -d \
--name db \
-v my-data:/var/lib/mysql \
mysql:8
# Bind mount (map host directory)
docker run -d \
--name web \
-v $(pwd)/html:/usr/share/nginx/html \
nginx
# Remove volume
docker volume rm my-data
# Remove unused volumes
docker volume prune
Volume Types
┌─────────────────────────────────────────────────────────┐
│ Volume Types │
├─────────────────────────────────────────────────────────┤
│ │
│ Named Volumes Bind Mounts tmpfs │
│ ┌────────────┐ ┌────────────┐ ┌──────────┐ │
│ │ Docker │ │ Host │ │ Memory │ │
│ │ manages │ │ filesystem │ │ only │ │
│ └────────────┘ └────────────┘ └──────────┘ │
│ │
│ -v data:/app -v /host:/app --tmpfs /app │
│ Best for DBs Dev workflows Sensitive data │
└─────────────────────────────────────────────────────────┘
Docker Networking
# List networks
docker network ls
# Create network
docker network create my-network
# Run containers on same network
docker run -d --name app --network my-network my-app
docker run -d --name db --network my-network mysql
# Containers có thể communicate bằng name
# app container: mysql://db:3306
Network Types
| Type | Mô tả |
|---|---|
| bridge | Default, isolated network |
| host | Share host’s network |
| none | No networking |
| overlay | Multi-host (Swarm) |
Thực hành: Dockerize Node.js App
Project Structure
my-node-app/
├── Dockerfile
├── .dockerignore
├── package.json
├── server.js
└── src/
└── index.js
1. Create Application
// server.js
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;
app.get('/', (req, res) => {
res.json({ message: 'Hello from Docker!', timestamp: new Date() });
});
app.get('/health', (req, res) => {
res.status(200).json({ status: 'healthy' });
});
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
// package.json
{
"name": "my-node-app",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.2"
}
}
2. Create Dockerfile
# Dockerfile
FROM node:20-alpine
# Create non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /app
# Copy package files
COPY package*.json ./
# Install dependencies
RUN npm ci --only=production
# Copy source
COPY . .
# Change ownership
RUN chown -R appuser:appgroup /app
# Switch to non-root user
USER appuser
# Expose port
EXPOSE 3000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# Start command
CMD ["npm", "start"]
3. Create .dockerignore
# .dockerignore
node_modules
npm-debug.log
Dockerfile
.dockerignore
.git
.gitignore
README.md
.env
4. Build and Run
# Build image
docker build -t my-node-app:v1 .
# Run container
docker run -d \
--name my-app \
-p 3000:3000 \
my-node-app:v1
# Test
curl http://localhost:3000
# View logs
docker logs my-app
# Check health
docker inspect --format='{{.State.Health.Status}}' my-app
Docker Best Practices
1. Use Specific Tags
# Bad
FROM node
# Good
FROM node:20-alpine
2. Non-root User
RUN addgroup -S app && adduser -S app -G app
USER app
3. Layer Caching
# Dependencies change less often
COPY package*.json ./
RUN npm ci
# Source changes often
COPY . .
4. Small Base Images
node:20 ~1GB
node:20-slim ~200MB
node:20-alpine ~150MB
5. .dockerignore
node_modules
.git
*.log
.env
Cleanup Commands
# Remove all stopped containers
docker container prune
# Remove unused images
docker image prune
docker image prune -a # Including unused
# Remove unused volumes
docker volume prune
# Remove all unused resources
docker system prune -a
# View disk usage
docker system df
Bước tiếp theo
- ✅ Hiểu containers và Docker architecture
- ✅ Viết Dockerfile
- ✅ Build và run containers
- 📖 Học Docker Compose cho multi-container apps
- 🚀 Push images lên registry
💡 Pro tip: Luôn sử dụng
.dockerignorevà multi-stage builds để giảm image size!
Bài tiếp theo: Docker Compose - Orchestrate multi-container applications.