容器与镜像
核心概念
容器(Container)
容器是镜像的运行实例,是一个轻量级、可移植的运行环境。
与虚拟机的区别:
┌─────────────────────────────────────────────────────────┐
│ 虚拟机 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Guest OS + Hypervisor │ │
│ │ ┌─────────────────────────────────────────┐ │ │
│ │ │ App + Libs + Dependencies │ │ │
│ │ └─────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ Host OS + Hypervisor │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│ 容器 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ App + Libs + Dependencies (隔离) │ │
│ └─────────────────────────────────────────────────┘ │
│ ▲ │
│ ┌─────────┴─────────┐ │
│ │ Docker Engine │
│ │ Host OS │
│ └───────────────────┘ │
└─────────────────────────────────────────────────────────┘容器特点:
- 启动快(秒级)
- 资源占用少
- 环境一致性
- 隔离性好
镜像(Image)
镜像是一个只读的模板,包含运行应用所需的所有内容。
镜像分层结构:
┌─────────────┐
│ Layer 4 │ 应用层(最上层,可写)
├─────────────┤
│ Layer 3 │ 运行时依赖
├─────────────┤
│ Layer 2 │ 系统工具
├─────────────┤
│ Layer 1 │ 基础系统(Ubuntu、Alpine)
├─────────────┤
│ Layer 0 │ Bootfs(引导文件系统)
└─────────────┘Dockerfile 详解
基础指令
dockerfile
# 基础镜像
FROM node:18-alpine
# 维护者信息
LABEL maintainer="developer@example.com"
# 工作目录
WORKDIR /app
# 复制文件
COPY package*.json ./
COPY . .
# 安装依赖
RUN npm ci --only=production
# 暴露端口
EXPOSE 3000
# 启动命令
CMD ["node", "server.js"]常用指令对比
| 指令 | 作用 | 注意点 |
|---|---|---|
COPY | 复制本地文件 | 不能访问 URL |
ADD | 复制 + 解压 + URL | 优先使用 COPY |
RUN | 执行命令 | 尽量合并减少层数 |
CMD | 默认命令 | 只有一个生效 |
ENTRYPOINT | 入口点 | 与 CMD 配合 |
ENV | 设置环境变量 | 后续指令可用 |
ARG | 构建参数 | 构建时使用 |
最佳实践
dockerfile
# 1. 使用特定版本而非 latest
FROM node:18-alpine
# 2. 优先使用多阶段构建减小体积
FROM node:18-alpine AS builder
WORKDIR /app
COPY . .
RUN npm ci
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/server.js"]
# 3. 合理利用缓存层级(把变化少的放前面)
COPY package*.json ./
RUN npm ci --only=production
COPY . .
# 4. 使用 .dockerignore 排除不必要文件
# .dockerignore
node_modules
.git
*.log
.env
coverage
# 5. 非 root 用户运行
RUN addgroup -g 1001 -S nodejs && \
adduser -S nextjs -u 1001
USER nextjs常用命令
bash
# 构建镜像
docker build -t myapp:v1.0 .
docker build -t myapp:v1.0 --no-cache .
# 运行容器
docker run -d -p 8080:3000 --name myapp myapp:v1.0
docker run -it --rm node:18 node # 交互式运行
# 容器管理
docker ps # 运行中的容器
docker ps -a # 所有容器
docker logs myapp # 查看日志
docker logs -f myapp # 实时日志
docker exec -it myapp sh # 进入容器
docker stop myapp # 停止容器
docker start myapp # 启动容器
docker restart myapp # 重启容器
docker rm myapp # 删除容器
docker rm -f myapp # 强制删除
# 镜像管理
docker images
docker rmi myapp:v1.0
docker rmi $(docker images -q) # 删除所有镜像
# 查看资源使用
docker stats
docker top myapp
docker inspect myapp面试高频题
Q1: Docker 容器与虚拟机有什么区别?
答案:
- 虚拟机:每个虚拟机有独立的 Guest OS,通过 Hypervisor 虚拟化硬件,启动慢(分钟级),资源占用大
- 容器:共享 Host OS,通过 Docker Engine 实现进程级别隔离,启动快(秒级),资源占用小
核心区别:
| 特性 | 虚拟机 | 容器 |
|---|---|---|
| 启动时间 | 分钟级 | 秒级 |
| 资源占用 | 大 | 小 |
| 隔离级别 | 硬件级 | 进程级 |
| 操作系统 | 每个 VM 独立 | 共享 Host OS |
Q2: COPY 和 ADD 指令的区别?
答案:
COPY:纯复制本地文件到容器,简单直接ADD:具备复制 + 解压 tar 文件 + 访问 URL 功能
推荐: 优先使用 COPY,除非需要自动解压功能
Q3: CMD 和 ENTRYPOINT 的区别?
答案:
CMD:提供默认命令,可被 docker run 参数覆盖ENTRYPOINT:固定入口,通常与 CMD 配合提供默认参数
dockerfile
# CMD 示例(可被覆盖)
CMD ["node", "server.js"]
# docker run myapp debug.js → 执行 debug.js
# ENTRYPOINT 示例(固定入口)
ENTRYPOINT ["node"]
CMD ["server.js"]
# docker run myapp debug.js → node debug.jsQ4: 如何优化 Dockerfile 减小镜像体积?
答案:
- 使用合适的基础镜像(alpine)
- 多阶段构建
- 合理利用缓存层级
- 合并 RUN 指令减少层数
- 清理不必要的文件
- 使用非 root 用户