Docker 容器技术
Docker 容器技术 #
轻量级容器化技术,应用打包、部署、运行的标准解决方案
📋 目录 #
核心概念 #
Docker vs 虚拟机 #
传统虚拟机:
特点: 每个虚拟机独立操作系统,资源占用大,启动慢
Docker容器:
特点: 共享宿主机内核,轻量级,启动快
核心组件 #
| 组件 | 说明 | 作用 |
|---|---|---|
| Docker Client | 客户端 | 用户与Docker交互的接口 |
| Docker Daemon | 守护进程 | 管理容器、镜像、网络 |
| Docker Image | 镜像 | 只读模板,包含运行环境 |
| Docker Container | 容器 | 镜像的运行实例 |
| Docker Registry | 仓库 | 存储和分发镜像 |
镜像与容器关系 #
镜像 (Image):
- 只读模板
- 分层存储 (Union FS)
- 通过Dockerfile构建
容器 (Container):
- 镜像的运行实例
- 可读写层
- 通过镜像启动
关系:
Image + 启动命令 = Container
Image ≈ 类
Container ≈ 对象
Docker命令 #
镜像操作 #
# 搜索镜像
docker search redis
# 拉取镜像
docker pull redis:7.0
docker pull nginx:latest
# 查看本地镜像
docker images
docker image ls
# 删除镜像
docker rmi redis:7.0
docker image prune # 删除未使用的镜像
# 构建镜像
docker build -t my-app:1.0 .
# 导出/导入镜像
docker save -o my-app.tar my-app:1.0
docker load -i my-app.tar
容器操作 #
# 运行容器
docker run -d \
--name my-redis \
-p 6379:6379 \
-v /data/redis:/data \
redis:7.0
# 查看运行中的容器
docker ps
# 查看所有容器(包括已停止)
docker ps -a
# 停止容器
docker stop my-redis
# 启动容器
docker start my-redis
# 重启容器
docker restart my-redis
# 删除容器
docker rm my-redis
docker container prune # 删除已停止的容器
# 查看容器日志
docker logs my-redis
docker logs -f my-redis # 实时跟踪
docker logs --tail 100 my-redis
# 进入容器
docker exec -it my-redis /bin/bash
# 查看容器详细信息
docker inspect my-redis
网络操作 #
# 查看网络
docker network ls
# 创建网络
docker network create my-network
# 连接容器到网络
docker network connect my-network my-redis
# 断开网络
docker network disconnect my-network my-redis
数据卷操作 #
# 创建数据卷
docker volume create my-volume
# 查看数据卷
docker volume ls
# 删除数据卷
docker volume rm my-volume
Dockerfile #
基本结构 #
# 多阶段构建示例 - Spring Boot应用
FROM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 依赖缓存优化:先下载依赖再构建
RUN mvn dependency:go-offline -B
RUN mvn clean package -DskipTests
# 运行阶段
FROM eclipse-temurin:21-jre
WORKDIR /app
# 从builder阶段复制jar包
COPY --from=builder /app/target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
ENTRYPOINT ["java", "-jar", "app.jar"]
常用指令 #
| 指令 | 说明 | 示例 |
|---|---|---|
FROM |
基础镜像 | FROM openjdk:21-jre |
WORKDIR |
工作目录 | WORKDIR /app |
COPY |
复制文件 | COPY target/app.jar /app/ |
ADD |
复制+解压 | ADD app.tar.gz /app/ |
RUN |
执行命令(构建时) | RUN mvn package |
CMD |
启动命令(可被覆盖) | CMD ["java", "-jar", "app.jar"] |
ENTRYPOINT |
入口点(不可覆盖) | ENTRYPOINT ["java"] |
ENV |
环境变量 | ENV JAVA_OPTS="-Xmx512m" |
EXPOSE |
暴露端口 | EXPOSE 8080 |
VOLUME |
数据卷 | VOLUME /data |
最佳实践 #
# ✅ 好的实践
FROM eclipse-temurin:21-jre-alpine
# 设置标签
LABEL maintainer="your-email@example.com"
LABEL version="1.0.0"
# 非root用户
RUN addgroup -S appuser && adduser -S appuser -G appuser
USER appuser
# 工作目录
WORKDIR /app
# 依赖缓存:分层COPY
COPY pom.xml .
RUN mvn dependency:go-offline -B
COPY . .
RUN mvn clean package -DskipTests
# 清理
RUN mv target/*.jar app.jar \
&& rm -rf target/
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/actuator/health || exit 1
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Docker Compose #
基本示例 #
version: '3.8'
services:
# 应用服务
app:
build: .
container_name: spring-boot-app
ports:
- "8080:8080"
environment:
- SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb
- REDIS_HOST=redis
depends_on:
- mysql
- redis
networks:
- app-network
restart: unless-stopped
# MySQL数据库
mysql:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: root123
MYSQL_DATABASE: mydb
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
networks:
- app-network
restart: unless-stopped
# Redis缓存
redis:
image: redis:7.0
container_name: redis
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
networks:
- app-network
restart: unless-stopped
# 数据卷
volumes:
mysql-data:
redis-data:
# 网络
networks:
app-network:
driver: bridge
常用命令 #
# 启动服务(后台运行)
docker-compose up -d
# 停止服务
docker-compose stop
# 停止并删除容器
docker-compose down
# 停止删除容器和数据卷
docker-compose down -v
# 查看日志
docker-compose logs -f app
# 重新构建并启动
docker-compose up -d --build
# 扩容服务
docker-compose up -d --scale app=3
# 查看服务状态
docker-compose ps
生产实践 #
国内镜像加速 #
{
"registry-mirrors": [
"https://docker.mirrors.sjtug.sjtu.edu.cn",
"https://docker.imroc.io"
]
}
配置位置:
- Mac/Linux:
~/.docker/daemon.json - Windows:
C:\ProgramData\docker\config\daemon.json
多阶段构建 #
优势:
- 减小镜像体积
- 分离构建环境和运行环境
- 不需要构建工具运行时
优化对比:
单阶段:
Docker Image Size: ~800MB
- 包含Maven、JDK、工具类
多阶段:
Docker Image Size: ~200MB
- 仅包含JRE和应用
安全最佳实践 #
# 1. 使用最小化基础镜像
FROM alpine:latest
# 2. 非root用户运行
RUN addgroup -S appuser && adduser -S appuser -G appuser
USER appuser
# 3. 只读文件系统
READONLY_ROOT_FILESYSTEM=true
# 4. 限制资源
--memory="512m"
--cpus="1.5"
# 5. 扫描镜像漏洞
docker scan my-app:1.0
# 6. 定期更新基础镜像
监控与日志 #
services:
app:
image: my-app:1.0
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
容器编排选择 #
| 规模 | 推荐方案 |
|---|---|
| 单机 | Docker Compose |
| 小集群 | Docker Swarm |
| 大规模 | Kubernetes |
面试题汇总 #
基础篇 #
- Docker vs 虚拟机区别?
- Docker核心组件有哪些?
- 镜像与容器关系?
- 容器之间如何通信?
实践篇 #
- 如何优化Dockerfile?
- 如何减小镜像体积?
- 如何实现持久化存储?
- 如何实现容器编排?
进阶篇 #
- Docker网络模式有哪些?
- 如何实现容器安全?
- 生产环境Docker部署方案?
- 如何排查容器问题?
面试题答案详解 #
基础篇 #
- Docker vs 虚拟机区别?
答案:
| 对比项 | Docker容器 | 虚拟机 |
|---|---|---|
| 隔离级别 | 进程级隔离 | 完全隔离 |
| 内核 | 共享宿主机内核 | 独立内核 |
| 镜像体积 | 小(MB级) | 大(GB级) |
| 启动速度 | 秒级 | 分钟级 |
| 性能开销 | 低(几乎无) | 高(Hypervisor层) |
| 资源利用率 | 高 | 低 |
架构对比:
- 虚拟机:Hypervisor虚拟化硬件,每个VM有完整OS
- Docker:容器共享宿主机内核,通过Cgroups和Namespace隔离
- Docker核心组件有哪些?
答案:
| 组件 | 说明 | 作用 |
|---|---|---|
| Docker Client | 客户端 | 命令行工具,用户与Docker交互 |
| Docker Daemon | 守护进程 | 运行在后台,管理容器、镜像、网络 |
| Docker Image | 镜像 | 只读模板,分层存储,构建容器的基础 |
| Docker Container | 容器 | 镜像的运行实例,有独立的可写层 |
| Docker Registry | 仓库 | 存储和分发镜像(Docker Hub、私有仓库) |
交互流程:
Client → Daemon → Registry
↓
Container
- 镜像与容器关系?
答案:
镜像(Image):
- 只读模板
- 分层存储(Union FS)
- 通过Dockerfile构建
- 类似面向对象中的"类"
容器(Container):
- 镜像的运行实例
- 有独立的可写层
- 类似面向对象中的"对象"
关系:
- 一个镜像可以启动多个容器
- 容器可以基于镜像创建新镜像(docker commit)
- 镜像 ≈ 类,容器 ≈ 对象
- 容器之间如何通信?
答案:
方法1:同一网络内通过容器名访问
docker network create my-network
docker run --network my-network --name container1 ...
docker run --network my-network --name container2 ...
# container2可以通过container1访问container1
方法2:端口映射
docker run -p 8080:80 ... # 宿主机8080映射到容器80
方法3:通过宿主机IP访问
# 容器内访问宿主机
host.docker.internal
方法4:使用Docker Compose网络
services:
app:
networks:
- app-network
db:
networks:
- app-network
# app和db可以通过服务名互相访问
实践篇 #
- 如何优化Dockerfile?
答案:
优化策略:
- 多阶段构建
FROM maven:3.9 AS builder
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
FROM eclipse-temurin:21-jre
COPY --from=builder /app/target/*.jar app.jar
- 分层缓存
COPY pom.xml . # 依赖层,不变则不重构建
RUN mvn dependency:go-offline
COPY src ./src # 代码层,变化才重构建
RUN mvn package
- 使用最小化基础镜像
FROM eclipse-temurin:21-jre-alpine # Alpine比Ubuntu小很多
- 清理缓存
RUN apt-get update && apt-get install -y \
package1 \
package2 \
&& rm -rf /var/lib/apt/lists/* # 清理apt缓存
- 如何减小镜像体积?
答案:
方法对比:
| 方法 | 效果 |
|---|---|
| 多阶段构建 | 减小50-80% |
| 使用Alpine镜像 | 减小60-70% |
| 合并RUN指令 | 减小层数 |
| 清理缓存 | 减小10-30% |
| 使用.dockerignore | 减小构建上下文 |
示例:
# ❌ 不好的实践
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y openjdk-21-jdk
COPY . .
RUN mvn package
# ✅ 好的实践
FROM maven:3.9-eclipse-temurin-21 AS builder
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src ./src
RUN mvn package
FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=builder /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
- 如何实现持久化存储?
答案:
三种方式:
- Volume(推荐)
docker volume create my-volume
docker run -v my-volume:/data ...
# 生命周期独立于容器,适合生产
- Bind Mount
docker run -v /host/data:/container/data ...
# 挂载宿主机目录,适合开发
- Tmpfs Mount
docker run --tmpfs /data ...
# 内存存储,容器删除即丢失,适合临时数据
Docker Compose示例:
volumes:
mysql-data: # 声明Volume
services:
mysql:
volumes:
- mysql-data:/var/lib/mysql # 使用Volume
- 如何实现容器编排?
答案:
方案选择:
| 规模 | 推荐方案 | 特点 |
|---|---|---|
| 单机 | Docker Compose | YAML定义,简单易用 |
| 小集群 | Docker Swarm | 内置,简单但功能有限 |
| 大规模 | Kubernetes | 功能强大,生产标准 |
Docker Compose示例:
version: '3.8'
services:
app:
image: my-app:1.0
ports:
- "8080:8080"
depends_on:
- mysql
- redis
mysql:
image: mysql:8.0
volumes:
- mysql-data:/var/lib/mysql
redis:
image: redis:7.0
volumes:
mysql-data:
进阶篇 #
- Docker网络模式有哪些?
答案:
| 模式 | 说明 | 特点 |
|---|---|---|
| bridge | 默认模式,桥接网络 | 容器间可通过IP/容器名访问 |
| host | 共享宿主机网络 | 性能好,无隔离 |
| container | 共享其他容器网络 | 与指定容器共用网络栈 |
| none | 无网络 | 完全隔离 |
| 自定义网络 | 用户定义的bridge网络 | 更好的隔离和DNS解析 |
使用示例:
# 自定义网络
docker network create --driver bridge my-network
docker run --network my-network ...
# host网络
docker run --network host ...
- 如何实现容器安全?
答案:
最佳实践:
- 使用非root用户
RUN addgroup -S appuser && adduser -S appuser -G appuser
USER appuser
- 最小化基础镜像
FROM alpine:latest # Alpine比Ubuntu安全
- 限制资源
docker run --memory="512m" --cpus="1.5" ...
- 只读文件系统
services:
app:
read_only: true
tmpfs:
- /tmp
- /run
- 扫描镜像漏洞
docker scan my-app:1.0
- 定期更新基础镜像
- 生产环境Docker部署方案?
答案:
生产架构:
| 组件 | 推荐方案 |
|---|---|
| 容器运行时 | containerd |
| 编排 | Kubernetes |
| 镜像仓库 | Harbor / Docker Registry |
| 监控 | Prometheus + Grafana |
| 日志 | ELK Stack / Loki |
| 安全扫描 | Clair / Trivy |
部署建议:
- 使用K8s编排,不要手动管理容器
- 资源限制,设置requests和limits
- 健康检查,配置liveness和readiness探针
- 滚动更新,保证服务不中断
- 持久化存储,使用PV/PVC
- 如何排查容器问题?
答案:
排查步骤:
- 查看容器状态
docker ps -a
docker inspect container-name
- 查看容器日志
docker logs container-name
docker logs -f container-name # 实时
docker logs --tail 100 container-name # 最后100行
- 进入容器调试
docker exec -it container-name /bin/bash
docker exec -it container-name /bin/sh # Alpine用sh
- 查看资源使用
docker stats
docker top container-name
- 查看网络
docker network ls
docker network inspect my-network
常见问题:
- 容器启动失败:看logs,检查CMD/ENTRYPOINT
- 无法访问:检查端口映射、网络模式
- 性能问题:看stats,检查资源限制
实战案例 #
本地 AI 环境:Ollama + Open-WebUI + Portainer #
完全离线的本地 AI 开发环境,保护数据隐私。
组件说明 #
| 组件 | 作用 | 端口 | 官网 |
|---|---|---|---|
| Ollama | 大模型运行时,提供 OpenAI 兼容 API | 11434 | https://ollama.com |
| Open-WebUI | 美观的 Web 聊天界面(类似 ChatGPT) | 3000 或 8080 | https://openwebui.com |
| Portainer | Docker 容器可视化管理 | 9443 (HTTPS) | https://www.portainer.io |
架构 #
浏览器 → Open-WebUI (Web UI) → Ollama (LLM 后端)
↓
Portainer (管理界面)
访问地址 #
| 服务 | 地址 |
|---|---|
| Open-WebUI | http://localhost:3000 |
| Ollama API | http://localhost:11434 |
| Portainer | https://localhost:9443 |
Ollama 常用命令 #
# 拉取模型
ollama pull llama3.1
ollama pull qwen2.5
ollama pull qwen2.5:7b
ollama pull deepseek-coder-v2
# 运行模型交互
ollama run llama3.1
# 列出已安装模型
ollama list
# 删除模型
ollama rm model-name
# 查看 Ollama 状态
ollama serve
推荐模型 #
| 模型 | 说明 |
|---|---|
| llama3.1 | Meta 官方,综合能力强 |
| qwen2.5 | 阿里通义千问,中文友好 |
| deepseek-coder-v2 | 代码生成专用 |
Docker 管理命令 #
# 查看运行中的容器
docker ps
# 查看所有容器
docker ps -a
# 查看日志
docker logs ollama
docker logs open-webui
docker logs portainer
# 重启容器
docker restart ollama
docker restart open-webui
docker restart portainer
🔗 相关笔记 #
- Kubernetes
- 云原生
- [[2026-05-08]] - 部署日记
最后更新: 2026-05-08