TL;DR: Docker 通过容器技术将应用及其依赖打包成标准化单元,解决"在我机器上能跑"的经典难题。本文覆盖核心概念、常用命令、Dockerfile 编写和 Docker Compose 编排,帮助你在 30 分钟内上手。

本文假设读者熟悉 Linux 基础命令和软件开发流程,无需容器经验。

为什么需要 Docker Link to heading

在没有容器之前,部署应用最头疼的问题是环境一致性——不同机器的操作系统、库版本、依赖配置差异,导致同一份代码行为不一致。虚拟机能解决这个问题,但每个 VM 需要独立的操作系统,启动慢、资源开销大。

Docker 的方案是容器:与宿主机共享内核,通过 namespace 和 cgroup 实现进程隔离和资源限制。结果是:

对比项虚拟机Docker 容器
启动时间分钟级秒级
镜像大小GB 级MB 级
资源开销完整 OS共享内核,几乎无额外开销
隔离级别硬件级进程级

核心概念 Link to heading

Docker 有四个必须理解的概念:

镜像(Image):只读模板,包含应用运行所需的一切——代码、运行时、库、环境变量。类似 OOP 中的"类"。

容器(Container):镜像的运行实例,可启动、停止、删除。类似"对象"。

Dockerfile:构建镜像的指令文件,每行指令生成一层只读层(layer),多层叠加形成最终镜像。

仓库(Registry):存储和分发镜像的服务,Docker Hub 是默认的公共仓库。

它们的关系:编写 Dockerfile → docker build 生成镜像 → docker run 启动容器 → 从仓库拉取或推送镜像。

安装与验证 Link to heading

以 Ubuntu 为例:

# 安装 Docker
curl -fsSL https://get.docker.com | sh

# 将当前用户加入 docker 组,避免每次 sudo
sudo usermod -aG docker $USER

验证安装:

docker --version
# Docker version 27.5.1, build 9f9e405

docker run hello-world
# Unable to find image 'hello-world:latest' locally
# latest: Pulling from library/hello-world
# Hello from Docker!

hello-world 的完整流程:本地查找镜像 → 不存在则从 Docker Hub 拉取 → 创建容器 → 执行入口命令 → 输出信息 → 容器退出。

常用命令速查 Link to heading

# 拉取镜像
docker pull nginx:1.27-alpine

# 运行容器(-d 后台运行,-p 端口映射,--name 命名)
docker run -d -p 8080:80 --name my-nginx nginx:1.27-alpine

# 查看运行中的容器
docker ps

# 查看所有容器(含已停止的)
docker ps -a

# 查看容器日志
docker logs my-nginx

# 进入容器 shell
docker exec -it my-nginx /bin/sh

# 停止/启动/删除容器
docker stop my-nginx
docker start my-nginx
docker rm my-nginx

# 查看本地镜像
docker images

# 删除镜像
docker rmi nginx:1.27-alpine

# 清理所有已停止的容器和悬空镜像
docker system prune

关键端口映射 -p 8080:80 的含义是:宿主机端口:容器端口。访问 localhost:8080 等价于访问容器内的 80 端口。

编写 Dockerfile Link to heading

以一个 Node.js 应用为例:

# Dockerfile
# 使用 Alpine 基础镜像,体积小(约 5MB)
FROM node:20-alpine

# 设置工作目录
WORKDIR /app

# 先复制依赖文件,利用 Docker 层缓存
# 只有 package.json 变动时才重新安装依赖
COPY package*.json ./
RUN npm ci --only=production

# 复制应用代码
COPY . .

# 暴露端口(仅文档作用,不实际映射)
EXPOSE 3000

# 启动命令
CMD ["node", "server.js"]

构建镜像:

docker build -t my-app:1.0 .

# 构建输出示例
# [+] Building 12.3s (10/10) FINISHED
#  => [internal] load build definition from Dockerfile
#  => [1/5] FROM docker.io/library/node:20-alpine
#  => [2/5] WORKDIR /app
#  => [3/5] COPY package*.json ./
#  => [4/5] RUN npm ci --only=production
#  => [5/5] COPY . .

运行:

docker run -d -p 3000:3000 --name my-app my-app:1.0

Dockerfile 最佳实践 Link to heading

# 1. 使用多阶段构建减小镜像体积
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 生产阶段只包含运行产物
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --only=production
CMD ["node", "dist/server.js"]

# 2. 使用 .dockerignore 排除不必要的文件
# .dockerignore
node_modules
.git
.env
*.md

多阶段构建前镜像可能 1GB+,构建后通常可控制在 200MB 以内。

Docker Compose:多容器编排 Link to heading

实际项目很少只有一个容器。数据库、缓存、应用服务需要协同工作。Docker Compose 用 YAML 文件定义多容器应用。

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb

  cache:
    image: redis:7-alpine

volumes:
  pgdata:
# 一键启动全部服务
docker compose up -d

# 查看服务状态
docker compose ps

# 查看日志
docker compose logs -f app

# 停止并清理
docker compose down

depends_on 控制启动顺序,volumes 实现数据持久化——容器删除后数据库文件不会丢失。

局限性与替代方案 Link to heading

Docker 不是万能方案,以下场景需要权衡:

  • GUI 应用:容器主要面向后台服务,桌面应用容器化需要额外配置 X11 转发
  • 强安全隔离:容器共享内核,逃逸漏洞理论上存在(虽然罕见)。高安全场景用 VM 或 gVisor/Firecracker
  • macOS/Windows 性能:需要 Linux VM 层,磁盘 I/O 有 10-20% 损耗,可通过 VirtioFS 或 volume 挂载优化
  • 复杂编排:Docker Compose 适合开发和简单部署,生产环境多容器调度推荐 Kubernetes

总结 Link to heading

Docker 的核心价值在于一次构建,随处运行——开发、测试、生产环境保持一致,消除环境差异带来的部署问题。

下一步可以深入的方向:

  • Docker 网络模型(bridge、host、overlay)
  • 容器健康检查和自动重启策略
  • CI/CD 流水线中集成 Docker 构建
  • 从 Docker Compose 迁移到 Kubernetes

进一步阅读 Link to heading

本文由 AI 生成