11.1 Docker容器技术
面试重要程度:⭐⭐⭐⭐
常见提问方式:Docker的底层原理是什么?如何优化Docker镜像?
预计阅读时间:30分钟
📋 知识点概览
Docker作为容器化技术的代表,已成为现代软件开发和部署的标准工具。本节将深入讲解Docker的核心概念、底层原理、镜像构建优化以及网络存储机制。
🔧 Docker核心概念与架构
Docker架构组件
/** * Docker架构组件说明 */ public class DockerArchitecture { /** * Docker核心组件 */ public enum DockerComponent { DOCKER_CLIENT("Docker客户端", "用户与Docker交互的接口"), DOCKER_DAEMON("Docker守护进程", "管理容器、镜像、网络等"), DOCKER_REGISTRY("Docker仓库", "存储和分发Docker镜像"), DOCKER_IMAGE("Docker镜像", "容器的只读模板"), DOCKER_CONTAINER("Docker容器", "镜像的运行实例"); private final String name; private final String description; DockerComponent(String name, String description) { this.name = name; this.description = description; } } /** * Docker底层技术 */ public static class DockerTechnology { // Linux命名空间(Namespace) public static final String[] NAMESPACES = { "PID Namespace", // 进程隔离 "NET Namespace", // 网络隔离 "IPC Namespace", // 进程间通信隔离 "MNT Namespace", // 文件系统挂载点隔离 "UTS Namespace", // 主机名和域名隔离 "USER Namespace" // 用户和用户组隔离 }; // Linux控制组(Cgroups) public static final String[] CGROUPS = { "CPU限制", // CPU使用限制 "内存限制", // 内存使用限制 "磁盘IO限制", // 磁盘读写限制 "网络带宽限制", // 网络带宽限制 "设备访问控制" // 设备访问权限 }; // 联合文件系统(Union File System) public static final String[] UNION_FS = { "AUFS", // Advanced Multi-Layered Unification Filesystem "OverlayFS", // Overlay Filesystem "DeviceMapper", // Device Mapper "Btrfs", // B-tree File System "ZFS" // Zettabyte File System }; } }
Docker命令实践
# Docker基础命令示例 # 1. 镜像管理 docker images # 查看本地镜像 docker pull ubuntu:20.04 # 拉取镜像 docker rmi image_id # 删除镜像 docker build -t myapp:v1.0 . # 构建镜像 # 2. 容器管理 docker run -d --name mycontainer ubuntu:20.04 # 运行容器 docker ps # 查看运行中的容器 docker ps -a # 查看所有容器 docker stop container_id # 停止容器 docker rm container_id # 删除容器 # 3. 容器操作 docker exec -it container_id bash # 进入容器 docker logs container_id # 查看容器日志 docker cp file.txt container_id:/path/ # 文件拷贝 # 4. 网络管理 docker network ls # 查看网络 docker network create mynet # 创建网络 docker run --network mynet ubuntu # 指定网络运行容器 # 5. 数据卷管理 docker volume ls # 查看数据卷 docker volume create myvolume # 创建数据卷 docker run -v myvolume:/data ubuntu # 挂载数据卷
🏗️ Dockerfile最佳实践
优化的Dockerfile示例
# Spring Boot应用的优化Dockerfile # 使用多阶段构建 FROM maven:3.8.4-openjdk-17 AS builder # 设置工作目录 WORKDIR /app # 先复制依赖文件,利用Docker缓存 COPY pom.xml . COPY src/main/resources/application.yml src/main/resources/ # 下载依赖(这一层会被缓存) RUN mvn dependency:go-offline -B # 复制源代码 COPY src ./src # 构建应用 RUN mvn clean package -DskipTests # 运行时镜像 FROM openjdk:17-jre-slim # 创建非root用户 RUN groupadd -r appuser && useradd -r -g appuser appuser # 设置工作目录 WORKDIR /app # 安装必要的系统包 RUN apt-get update && apt-get install -y \ curl \ && rm -rf /var/lib/apt/lists/* # 从构建阶段复制jar文件 COPY --from=builder /app/target/*.jar app.jar # 创建日志目录 RUN mkdir -p /app/logs && chown -R appuser:appuser /app # 切换到非root用户 USER appuser # 健康检查 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8080/actuator/health || exit 1 # 暴露端口 EXPOSE 8080 # JVM优化参数 ENV JAVA_OPTS="-Xms512m -Xmx1024m -XX:+UseG1GC -XX:G1HeapRegionSize=16m" # 启动命令 ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
镜像构建优化策略
/** * Docker镜像优化策略 */ public class DockerImageOptimization { /** * 镜像大小优化技巧 */ public static class ImageSizeOptimization { public static final String[] OPTIMIZATION_TECHNIQUES = { "使用Alpine Linux基础镜像", "多阶段构建分离构建和运行环境", "合并RUN指令减少镜像层数", "清理包管理器缓存", "删除不必要的文件和依赖", "使用.dockerignore忽略不需要的文件" }; /** * 基础镜像选择建议 */ public static void baseImageRecommendations() { System.out.println("基础镜像选择建议:"); System.out.println("1. Java应用:openjdk:17-jre-slim (约200MB)"); System.out.println("2. Node.js应用:node:18-alpine (约170MB)"); System.out.println("3. Python应用:python:3.9-slim (约150MB)"); System.out.println("4. Go应用:scratch或alpine (约5-10MB)"); System.out.println("5. Nginx:nginx:alpine (约25MB)"); } } /** * 构建缓存优化 */ public static class BuildCacheOptimization { /** * 依赖缓存优化示例 */ public static String getOptimizedDockerfile() { return """ # 错误做法:每次代码变更都要重新下载依赖 # COPY . . # RUN mvn clean package # 正确做法:先复制依赖文件,利用缓存 COPY pom.xml . RUN mvn dependency:go-offline # 然后复制源代码 COPY src ./src RUN mvn clean package -DskipTests """; } /** * 层缓存策略 */ public static String[] getLayerCacheStrategies() { return new String[]{ "将变化频率低的操作放在前面", "将变化频率高的操作放在后面", "合理使用COPY指令的缓存特性", "避免在同一层中混合不同类型的操作" }; } } }
🌐 Docker网络机制
网络模式详解
/** * Docker网络模式 */ public class DockerNetworking { /** * Docker网络驱动类型 */ public enum NetworkDriver { BRIDGE("bridge", "默认网络模式,容器间可通信"), HOST("host", "容器使用宿主机网络"), NONE("none", "容器没有网络接口"), OVERLAY("overlay", "跨主机容器通信"), MACVLAN("macvlan", "容器分配MAC地址"); private final String name; private final String description; NetworkDriver(String name, String description) { this.name = name; this.description = description; } } /** * 自定义网络配置示例 */ public static class CustomNetworkExample { /** * 创建自定义桥接网络 */ public static void createCustomBridgeNetwork() { String[] commands = { "# 创建自定义网络", "docker network create --driver bridge \\", " --subnet=172.20.0.0/16 \\", " --ip-range=172.20.240.0/20 \\", " --gateway=172.20.0.1 \\", " my-bridge-network", "", "# 运行容器并指定IP", "docker run -d --name web1 \\", " --network my-bridge-network \\", " --ip 172.20.0.10 \\", " nginx:alpine", "", "# 运行另一个容器", "docker run -d --name web2 \\", " --network my-bridge-network \\", " --ip 172.20.0.11 \\", " nginx:alpine" }; for (String command : commands) { System.out.println(command); } } /** * 容器间通信示例 */ public static void containerCommunication() { String[] examples = { "# 通过容器名通信", "docker exec web1 ping web2", "", "# 通过IP地址通信", "docker exec web1 ping 172.20.0.11", "", "# 端口映射", "docker run -d -p 8080:80 --name web nginx", "", "# 链接容器(已废弃,使用自定义网络替代)", "docker run --link web1:web nginx" }; for (String example : examples) { System.out.println(example); } } } }
网络配置实践
# docker-compose网络配置示例 version: '3.8' services: web: image: nginx:alpine ports: - "80:80" networks: - frontend - backend depends_on: - api api: build: ./api ports: - "8080:8080" networks: - backend - database environment: - DB_HOST=db - DB_PORT=5432 depends_on: - db db: image: postgres:13 environment: - POSTGRES_DB=myapp - POSTGRES_USER=user - POSTGRES_PASSWORD=password volumes: - db_data:/var/lib/postgresql/data networks: - database networks: frontend: driver: bridge ipam: config: - subnet: 172.20.0.0/16 backend: driver: bridge internal: true # 内部网络,不能访问外网 database: driver: bridge internal: true volumes: db_data:
💾 Docker存储机制
数据卷管理
/** * Docker存储管理 */ public class DockerStorage { /** * 存储类型 */ public enum StorageType { BIND_MOUNT("绑定挂载", "直接挂载宿主机目录"), VOLUME("数据卷", "Docker管理的存储"), TMPFS("临时文件系统", "内存中的临时存储"); private final String name; private final String description; StorageType(String name, String description) { this.name = name; this.description = description; } } /** * 存储最佳实践 */ public static class StorageBestPractices { /** * 数据卷使用示例 */ public static void volumeExamples() { String[] examples = { "# 创建命名数据卷", "docker volume create mydata", "", "# 查看数据卷信息", "docker volume inspect mydata", "", "# 使用数据卷", "docker run -d -v mydata:/data postgres:13", "", "# 匿名数据卷", "docker run -d -v /data postgres:13", "", "# 绑定挂载", "docker run -d -v /host/path:/container/path postgres:13", "", "# 只读挂载", "docker run -d -v /host/path:/container/path:ro nginx", "", "# 临时文件系统", "docker run -d --tmpfs /tmp nginx" }; for (String example : examples) { System.out.println(example); } } /** * 数据备份和恢复 */ public static void backupAndRestore() { String[] commands = { "# 备份数据卷", "docker run --rm -v mydata:/data -v $(pwd):/backup \\", " alpine tar czf /backup/backup.tar.gz -C /data .", "", "# 恢复数据卷", "docker run --rm -v mydata:/data -v $(pwd):/backup \\", " alpine tar xzf /backup/backup.tar.gz -C /data", "", "# 数据卷迁移", "docker run --rm -v old_volume:/from -v new_volume:/to \\", " alpine ash -c 'cd /from && cp -av . /to'" }; for (String command : commands) { System.out.println(command); } } } }
存储驱动优化
# 存储驱动配置示例 # 1. 查看当前存储驱动 docker info | grep "Storage Driver" # 2. 配置存储驱动(/etc/docker/daemon.json) { "storage-driver": "overlay2", "storage-opts": [ "overlay2.override_kernel_check=true" ] } # 3. 清理存储空间 docker system prune -a # 清理所有未使用的资源 docker volume prune # 清理未使用的数据卷 docker image prune -a # 清理未使用的镜像 # 4. 监控存储使用 docker system df # 查看存储使用情况 docker system df -v # 详细存储使用情况
🔧 容器运行时优化
资源限制配置
/** * 容器资源限制 */ public class ContainerResourceLimits { /** * CPU限制配置 */ public static class CPULimits { public static void configureCPULimits() { String[] examples = { "# 限制CPU使用率为50%", "docker run -d --cpus=\"0.5\" nginx", "", "# 限制CPU核心数", "docker run -d --cpuset-cpus=\"0,1\" nginx", "", "# CPU权重设置", "docker run -d --cpu-shares=512 nginx", "", "# CPU配额设置", "docker run -d --cpu-period=100000 --cpu-quota=50000 nginx" }; for (String example : examples) { System.out.println(example); } } } /** * 内存限制配置 */ public static class MemoryLimits { public static void configureMemoryLimits() { String[] examples = { "# 限制内存使用", "docker run -d -m 512m nginx", "", "# 限制内存和交换空间", "docker run -d -m 512m --memory-swap=1g nginx", "", "# 禁用交换空间", "docker run -d -m 512m --memory-swap=512m nginx", "", "# 内存预留", "docker run -d --memory-reservation=256m nginx" }; for (String example : examples) { System.out.println(example); } } } /** * IO限制配置 */ public static class IOLimits { public static void configureIOLimits() { String[] examples = { "# 限制磁盘读写速度", "docker run -d --device-read-bps /dev/sda:1mb nginx", "docker run -d --device-write-bps /dev/sda:1mb nginx", "", "# 限制磁盘读写IOPS", "docker run -d --device-read-iops /dev/sda:1000 nginx", "docker run -d --device-write-iops /dev/sda:1000 nginx", "", "# 磁盘权重设置", "docker run -d --blkio-weight=500 nginx" }; for (String example : examples) { System.out.println(example); } } } }
💡 面试常见问题
Q1: Docker与虚拟机的区别是什么?
标准回答:
Docker容器与虚拟机的主要区别: 1. 架构层面: - 虚拟机:在宿主机上运行完整的操作系统 - Docker:共享宿主机内核,只包含应用和依赖 2. 资源消耗: - 虚拟机:资源开销大,启动慢(分钟级) - Docker:资源开销小,启动快(秒级) 3. 隔离程度: - 虚拟机:完全隔离,安全性更高 - Docker:进程级隔离,性能更好 4. 可移植性: - 虚拟机:依赖虚拟化平台 - Docker:跨平台一致性更好
Q2: 如何优化Docker镜像大小?
标准回答:
Docker镜像优化策略: 1. 选择合适的基础镜像: - 使用Alpine Linux等轻量级镜像 - 避免使用完整的操作系统镜像 2. 多阶段构建: - 分离构建环境和运行环境 - 只保留运行时必需的文件 3. 减少镜像层数: - 合并RUN指令 - 清理包管理器缓存 4. 使用.dockerignore: - 排除不必要的文件 - 减少构建上下文大小 5. 删除临时文件: - 及时清理缓存和临时文件 - 使用&&连接命令避免中间层
Q3: Docker的网络模式有哪些?
标准回答:
Docker主要网络模式: 1. Bridge模式(默认): - 容器连接到docker0网桥 - 容器间可以通信 - 需要端口映射访问外部 2. Host模式: - 容器直接使用宿主机网络 - 性能最好,但隔离性差 - 端口冲突风险 3. None模式: - 容器没有网络接口 - 完全隔离的网络环境 - 适用于批处理任务 4. Container模式: - 与其他容器共享网络 - 适用于紧密协作的容器 5. 自定义网络: - 更好的隔离和控制 - 支持服务发现 - 推荐在生产环境使用
核心要点总结:
- ✅ 理解Docker的底层原理和核心概念
- ✅ 掌握Dockerfile编写和镜像优化技巧
- ✅ 熟悉Docker网络和存储机制
- ✅ 具备容器资源管理和性能优化能力
Java面试圣经 文章被收录于专栏
Java面试圣经