Docker基础面试题

5 阅读51分钟

一、Docker基础高频面试题(必背)

1. 什么是Docker?Docker的核心作用是什么?(基础必问)

核心答案:Docker是一个开源的容器化平台,基于Go语言开发,遵循Apache 2.0开源协议,它可以将应用程序及其依赖项(库、配置文件、运行环境等)打包成一个标准化的「容器」,实现应用程序的跨环境、可移植、一致性部署;核心作用是解决“环境不一致”“部署繁琐”“资源隔离”三大痛点,实现“一次构建,到处运行”,同时提升资源利用率,简化部署流程,降低运维成本。

原理解析

1. Docker的核心定位

Docker不是虚拟机,而是一种「轻量级容器化技术」,它基于Linux内核的Namespace(命名空间)和Cgroups(控制组)两大核心技术,实现应用程序的资源隔离和资源限制,无需模拟完整的操作系统,仅打包应用及其依赖,因此启动速度快、资源占用少。

2. 核心作用拆解

  1. 环境一致性:将应用及依赖(如Java、Python、数据库驱动等)打包成容器,容器在任何支持Docker的环境(开发、测试、生产)中运行效果一致,彻底解决“在我电脑上能运行,到服务器就报错”的问题;

  2. 资源隔离:通过Namespace实现进程、网络、文件系统等资源的隔离,每个容器相当于一个独立的“沙箱”,容器之间互不干扰,避免应用间的资源竞争和冲突;

  3. 轻量高效:容器无需启动完整的操作系统,仅共享宿主机的内核,启动时间通常在秒级(对比虚拟机的分钟级),且占用的内存、CPU资源远低于虚拟机;

  4. 简化部署:无需手动配置运行环境、安装依赖,只需通过Docker镜像启动容器,即可完成应用部署,大幅减少部署时间和运维工作量;

  5. 可扩展性:支持容器的快速启停、扩容缩容,结合Docker Compose、K8s等工具,可实现应用的自动化部署和集群管理。

扩展补充

  • Docker与虚拟机(VM)的核心区别(面试必背):
对比维度Docker 容器虚拟机(VM)
底层依赖共享宿主机 Linux 内核,无需独立内核需模拟完整操作系统(包含内核),依赖 Hypervisor
启动速度秒级(通常 1-10 秒)分钟级(通常 30 秒以上)
资源占用轻量,占用资源少(MB 级)笨重,占用资源多(GB 级)
隔离级别进程级隔离,隔离性较弱系统级隔离,隔离性强
部署效率快速部署,可秒级扩容部署繁琐,扩容较慢
镜像大小较小(通常几十 MB - 几百 MB)较大(通常几 GB)
跨平台性仅支持 Linux(Windows/Mac 需通过虚拟机模拟)支持跨操作系统(Windows、Linux、Mac)
  • 避坑点:Docker依赖Linux内核特性(Namespace、Cgroups),因此在Windows和Mac系统中,Docker会默认创建一个轻量级Linux虚拟机(如Docker Desktop中的WSL 2),再在虚拟机中运行容器,并非直接在宿主系统中运行。

2. Docker的核心组件有哪些?各自的作用是什么?(核心原理必问)

核心答案:Docker的核心组件包括「镜像(Image)、容器(Container)、仓库(Repository)」,三者构成Docker的完整生态,此外还包括Docker Daemon(守护进程)、Docker Client(客户端)等辅助组件;核心关系:通过Docker Client向Docker Daemon发送指令,从仓库拉取镜像,基于镜像创建并运行容器,完成应用部署。

原理解析

1. 核心组件(三大核心)

(1)镜像(Image):容器的“模板”
  1. 定义:镜像是一个只读的、静态的文件集合,包含运行应用所需的所有内容(代码、依赖库、配置文件、运行环境、操作系统内核片段等),相当于容器的“模板”或“快照”;

  2. 核心特性:

  • 只读性:镜像一旦构建完成,就无法修改,若需修改,只能基于原镜像创建新的镜像层(分层存储);

  • 分层存储:Docker镜像采用“分层文件系统(UnionFS)”,每一层都对应一个指令(如FROM、RUN、COPY等),分层存储的优势是共享层资源,减少镜像体积(如多个镜像共享基础层,无需重复存储);

  • 可复用性:一个镜像可以创建多个容器,多个容器共享镜像的只读层,仅在容器运行时创建可写层(存储容器的临时数据)。

  1. 常见镜像操作:拉取(docker pull)、构建(docker build)、查看(docker images)、删除(docker rmi)。
(2)容器(Container):镜像的“运行实例”
  1. 定义:容器是基于镜像创建的可运行实例,是一个动态的、可读写的环境,相当于“镜像的运行状态”;

  2. 核心特性:

  • 可读写性:容器在镜像的只读层之上,新增一个可写层,容器运行过程中产生的临时数据(如日志、配置修改)都存储在可写层,删除容器后,可写层数据会被清空,镜像不受影响;

  • 资源隔离:每个容器都有独立的Namespace(进程、网络、文件系统等),与其他容器和宿主机隔离,运行时互不干扰;

  • 生命周期:容器有启动(run)、停止(stop)、重启(restart)、暂停(pause)、删除(rm)等状态,容器停止后,可写层数据仍保留,再次启动可恢复;删除容器后,可写层数据彻底删除。

  1. 核心关系:镜像与容器的关系,类似于“类与对象”的关系——镜像是抽象的模板,容器是具体的实例,一个镜像可以创建多个容器。
(3)仓库(Repository):镜像的“存储仓库”
  1. 定义:仓库是用于存储和分发Docker镜像的平台,相当于“镜像的仓库”,分为公开仓库和私有仓库;

  2. 常见仓库:

  • 公开仓库:Docker Hub(官方仓库,包含大量官方镜像和社区镜像,如nginx、mysql、tomcat等)、阿里云容器镜像服务(ACR)、华为云容器镜像服务等;

  • 私有仓库:企业或个人搭建的内部仓库(如Harbor、Docker Registry),用于存储私有镜像(如公司内部应用镜像),保障镜像安全。

  1. 核心操作:推送镜像(docker push)、拉取镜像(docker pull)、搜索镜像(docker search)。

2. 辅助组件

  1. Docker Daemon(守护进程):运行在宿主机上的后台进程(docker.service),负责监听Docker Client的指令,管理镜像、容器、网络、存储等资源,是Docker的核心运行组件;

  2. Docker Client(客户端):用户与Docker Daemon交互的工具,通过命令行(如docker run、docker pull)或API向Daemon发送指令,Daemon执行指令后返回结果;

  3. Docker Compose:用于定义和运行多容器应用的工具,通过一个yaml文件(docker-compose.yml)配置多个容器的依赖关系、网络、存储等,实现多容器的一键启停、部署;

  4. Docker Swarm:Docker官方提供的容器集群管理工具,用于将多个Docker主机组成集群,实现容器的集群部署、扩容缩容、负载均衡等(目前已被K8s替代,面试了解即可)。

扩展补充

  • 镜像分层存储原理:Docker采用UnionFS(联合文件系统),将多个只读层叠加在一起,形成一个统一的文件系统,最上层为可写层(容器运行时使用);当容器修改文件时,只会修改可写层,不会影响底层的只读镜像层,实现镜像的复用和轻量化;

  • 私有仓库搭建:生产环境中,企业通常会搭建Harbor私有仓库(支持镜像管理、权限控制、漏洞扫描等功能),避免私有镜像泄露,步骤:安装Docker和Docker Compose → 下载Harbor压缩包 → 配置harbor.yml → 启动Harbor服务 → 配置Docker镜像推送权限;

  • 避坑点:删除镜像前,需先删除基于该镜像创建的所有容器(否则会报错);容器删除后,可写层数据会丢失,若需持久化数据,需使用Docker Volume(数据卷)。


3. Docker镜像的分层存储原理是什么?为什么要采用分层存储?(原理高频)

核心答案:Docker镜像采用「UnionFS(联合文件系统)」实现分层存储,核心是将镜像拆分为多个只读的“层(Layer)”,每个层对应Dockerfile中的一条指令(如FROM、RUN、COPY等),所有层叠加在一起,形成一个统一的只读文件系统;采用分层存储的核心目的是实现镜像复用、减少镜像体积、提升构建和传输效率。

原理解析

1. 分层存储的核心原理

(1)UnionFS(联合文件系统)基础

UnionFS是一种轻量级的文件系统,核心能力是“将多个独立的文件系统(层)叠加在一起,形成一个统一的视图”,用户看到的是叠加后的文件系统,而底层的每个层都是独立的、只读的;Docker基于UnionFS(不同系统有不同实现,如Linux的overlay2、aufs,Windows的windowsfilter)实现镜像的分层存储。

(2)Docker镜像分层的具体逻辑
  1. 基础层(Base Layer):最底层的层,通常是官方基础镜像(如alpine、centos、ubuntu),包含操作系统的核心文件和基础工具,多个镜像可以共享同一个基础层,无需重复存储;

  2. 中间层(Intermediate Layers):位于基础层之上,对应Dockerfile中的每条指令(如RUN yum install -y nginx、COPY app.jar /app),每条指令都会创建一个新的中间层,且中间层都是只读的;

  3. 顶层(Top Layer):镜像的最上层,也是只读层,对应Dockerfile中的最后一条指令,包含应用的核心代码和配置;

  4. 可写层(Writable Layer):当基于镜像创建容器时,Docker会在镜像的只读层之上,新增一个可写层,容器运行过程中产生的所有临时数据(如日志、配置修改、文件创建)都存储在可写层,删除容器后,可写层数据会被清空,镜像的只读层不受任何影响。

(3)分层存储的示例(结合Dockerfile)

以一个简单的Nginx镜像Dockerfile为例,说明分层存储:

# 基础层:使用alpine基础镜像(约5MB) 
FROM alpine:3.18 

# 中间层1:安装nginx(新增层,约20MB) 
RUN apk add --no-cache nginx 
# 中间层2:复制配置文件(新增层,约1KB) 
COPY nginx.conf /etc/nginx/nginx.conf 

# 顶层:暴露80端口(新增层,几乎不占空间) 
EXPOSE 80 

# 启动指令(新增层,几乎不占空间) 
CMD ["nginx", "-g", "daemon off;"] 

该镜像的分层结构:基础层(alpine:3.18)→ 中间层1(安装nginx)→ 中间层2(复制配置)→ 顶层(暴露端口+启动指令),总体积约25MB;若另一个镜像也基于alpine:3.18基础层,仅新增不同的中间层,那么两个镜像会共享基础层,总占用空间不会重复计算(如两个镜像总占用空间=25MB + 新增中间层体积)。

2. 采用分层存储的核心优势(面试必背)

  1. 镜像复用,减少存储空间:多个镜像共享基础层和中间层,无需重复存储相同的内容,大幅减少宿主机的存储占用(如10个基于alpine的镜像,仅需存储1份alpine基础层);

  2. 提升镜像构建效率:当修改Dockerfile中的某一条指令时,仅需重新构建该指令对应的层及以上的层,底层未修改的层可以直接复用,无需重新构建(如修改COPY指令,仅需重新构建COPY层和顶层,基础层、安装nginx层可复用);

  3. 提升镜像传输效率:推送/拉取镜像时,仅需传输本地缺失的层,无需传输完整镜像(如本地已存在alpine基础层,拉取上述Nginx镜像时,仅需传输中间层1、中间层2和顶层,节省网络带宽);

  4. 容器隔离与数据安全:镜像的只读层无法修改,容器的所有修改都在可写层,删除容器后可写层数据清空,避免影响镜像本身,同时实现容器之间的数据隔离。

扩展补充

  • 分层存储的底层实现差异:不同Linux发行版采用的UnionFS实现不同,如Ubuntu默认使用aufs,CentOS 7+默认使用overlay2,overlay2相比aufs性能更优、占用空间更少,是目前Docker推荐的存储驱动;

  • 镜像层的查看方法:使用命令docker inspect 镜像ID/镜像名,在返回结果的“RootFS”字段中,可查看镜像的所有层ID和层数量;

  • 避坑点:镜像层数量不宜过多(建议不超过10层),过多的层会导致镜像体积增大、构建效率降低,可通过合并Dockerfile指令(如将多个RUN指令合并为一个)减少层数量。


4. Dockerfile是什么?Dockerfile的常用指令有哪些?各自的作用是什么?(实战必问)

核心答案:Dockerfile是一个文本文件,包含一系列指令(Instruction),用于定义镜像的构建过程,Docker通过读取Dockerfile中的指令,自动构建出符合需求的Docker镜像;常用指令包括FROM、RUN、COPY、ADD、EXPOSE、ENV、WORKDIR、CMD、ENTRYPOINT等,每个指令对应镜像的一个分层,指令执行顺序即镜像分层顺序。

原理解析

1. Dockerfile的核心作用

Dockerfile的核心是“将镜像构建过程代码化、标准化”,避免手动构建镜像的繁琐操作(如手动启动容器、安装依赖、配置环境),实现镜像的可重复构建、可版本控制,同时便于团队协作(所有人使用相同的Dockerfile构建镜像,确保镜像一致性)。

2. 常用指令详解(面试必背,按使用频率排序)

(1)FROM:指定基础镜像(必选指令)
  1. 作用:指定构建当前镜像的基础镜像,所有后续指令都基于该基础镜像执行,是Dockerfile的第一条指令(除注释外);

  2. 语法:FROM 镜像名:标签(标签可选,默认latest);

  3. 示例:FROM alpine:3.18FROM openjdk:11-jre-slim

  4. 注意:基础镜像建议选择官方镜像或私有仓库的可信镜像,避免使用不明来源的镜像,防止安全风险;同时选择轻量化的基础镜像(如alpine、slim版本),减少镜像体积。

(2)RUN:执行命令(常用指令)
  1. 作用:在构建镜像过程中,执行指定的命令(如安装依赖、创建目录、配置环境等),每条RUN指令都会创建一个新的镜像层;

  2. 语法:两种格式

  • shell格式:RUN 命令(如RUN apk add --no-cache nginx),相当于在容器中执行shell命令;

  • exec格式:RUN ["可执行文件", "参数1", "参数2"](如RUN ["mkdir", "-p", "/app/logs"]),避免shell解析带来的环境变量问题,推荐使用;

  1. 优化技巧:将多个RUN指令合并为一个,使用&&连接,减少镜像层数量,同时清理无用文件(如安装依赖后删除缓存),示例:

RUN apk add --no-cache nginx && mkdir -p /app/logs && rm -rf /var/cache/apk/*

(3)COPY:复制文件(常用指令)
  1. 作用:将宿主机上的文件或目录,复制到镜像的指定路径中;

  2. 语法:COPY [--chown=用户:组] 宿主机路径 镜像路径

  3. 示例:COPY app.jar /app/app.jar(将宿主机当前目录的app.jar复制到镜像的/app目录下);

  4. 注意:

  • 宿主机路径是相对路径,相对于Dockerfile所在的目录;

  • 若镜像路径不存在,Docker会自动创建该路径;

  • --chown参数用于指定复制文件的所有者和所属组(如COPY --chown=root:root app.jar /app/)。

(4)ADD:复制并解压文件(扩展指令)
  1. 作用:与COPY类似,可复制宿主机文件到镜像,额外支持“自动解压压缩文件”和“下载网络文件”;

  2. 语法:ADD [--chown=用户:组] 宿主机路径/网络地址 镜像路径

  3. 示例:

  • 解压本地压缩包:ADD nginx-1.24.0.tar.gz /usr/local/(将本地nginx压缩包复制到镜像,并自动解压);

  • 下载网络文件:ADD https://mirrors.aliyun.com/openjdk/jdk8u392-b08-linux-x64.tar.gz /usr/local/

  1. 注意:ADD功能比COPY更强大,但推荐优先使用COPY(功能更明确,避免自动解压带来的意外),仅在需要解压或下载网络文件时使用ADD。
(5)EXPOSE:暴露端口(声明指令)
  1. 作用:声明容器运行时需要暴露的端口(仅为声明,不实际映射端口到宿主机),用于文档说明和端口校验;

  2. 语法:EXPOSE 端口1 端口2 ...(如EXPOSE 80 443);

  3. 注意:EXPOSE仅为声明,若需将容器端口映射到宿主机,需在启动容器时使用-p参数(如docker run -p 8080:80 nginx),将宿主机8080端口映射到容器80端口。

(6)ENV:设置环境变量(常用指令)
  1. 作用:在镜像中设置环境变量,容器运行时可继承这些环境变量,也可在后续的Dockerfile指令中引用;

  2. 语法:两种格式

  • ENV 变量名=变量值(如ENV JAVA_HOME=/usr/local/jdk);

  • ENV 变量名 变量值(如ENV JAVA_HOME /usr/local/jdk);

  1. 示例:

ENV JAVA_HOME=/usr/local/jdk \ ``PATH=$JAVA_HOME/bin:$PATH

  1. 注意:环境变量可在容器运行时通过-e参数覆盖(如docker run -e JAVA_HOME=/usr/local/jdk11 镜像名)。
(7)WORKDIR:设置工作目录(常用指令)
  1. 作用:指定后续RUN、COPY、ADD、CMD、ENTRYPOINT等指令的工作目录(相当于“cd”到该目录);

  2. 语法:WORKDIR 目录路径(如WORKDIR /app);

  3. 注意:

  • 若目录不存在,Docker会自动创建该目录;

  • 建议使用绝对路径,避免相对路径带来的混乱;

  • 多次使用WORKDIR,会在之前的目录基础上叠加(如WORKDIR /appWORKDIR logs,最终工作目录为/app/logs)。

(8)CMD:容器启动命令(可选指令)
  1. 作用:指定容器启动时执行的命令,每个Dockerfile只能有一个CMD指令(若有多个,仅最后一个生效);

  2. 语法:三种格式

  • shell格式:CMD 命令(如CMD ["nginx", "-g", "daemon off;"]);

  • exec格式:CMD ["可执行文件", "参数1", "参数2"](推荐使用);

  • 参数格式:CMD ["参数1", "参数2"](与ENTRYPOINT配合使用,为ENTRYPOINT传递参数);

  1. 注意:容器启动时,若在命令行指定了启动命令(如docker run 镜像名 echo "hello"),会覆盖CMD指令的内容。
(9)ENTRYPOINT:容器入口点(可选指令)
  1. 作用:与CMD类似,指定容器启动时执行的命令,但ENTRYPOINT的命令不会被容器启动时的命令行参数覆盖(仅会传递参数);

  2. 语法:两种格式

  • exec格式:ENTRYPOINT ["可执行文件", "参数1", "参数2"](推荐使用);

  • shell格式:ENTRYPOINT 命令

  1. 与CMD的配合使用(面试高频):
  • 场景:当需要固定容器启动的核心命令,同时允许用户传递自定义参数时,可结合ENTRYPOINT和CMD;

  • 示例:

ENTRYPOINT ["java", "-jar", "app.jar"] ``CMD ["--spring.profiles.active=dev"]

  • 说明:容器默认启动命令为java -jar app.jar --spring.profiles.active=dev;若用户启动容器时传递参数(如docker run 镜像名 --spring.profiles.active=prod),则CMD的参数会被覆盖,启动命令变为java -jar app.jar --spring.profiles.active=prod
(10)其他常用指令
  1. VOLUME:声明数据卷(用于数据持久化),语法:VOLUME ["镜像路径"](如VOLUME ["/app/logs"]);

  2. USER:指定容器运行时的用户(默认root),语法:USER 用户名/用户ID(如USER appuser),用于提升容器安全性;

  3. ONBUILD:触发指令(用于基础镜像),语法:ONBUILD 指令,当基于该镜像构建子镜像时,会自动执行ONBUILD后的指令。

3. Dockerfile构建镜像的流程(实战操作)

  1. 创建Dockerfile文件(文件名必须为Dockerfile,无后缀),编写指令;

  2. 进入Dockerfile所在目录,执行构建命令:docker build -t 镜像名:标签 .(“.”表示当前目录,即Dockerfile所在目录);

  3. Docker读取Dockerfile中的指令,按顺序执行,每执行一条指令创建一个镜像层;

  4. 构建完成后,使用docker images查看构建好的镜像;

  5. 基于镜像启动容器:docker run -d --name 容器名 镜像名:标签

扩展补充

  • Dockerfile优化技巧(面试加分):
  1. 优先使用轻量化基础镜像(如alpine、slim),减少镜像体积;

  2. 合并RUN指令,减少镜像层数量,同时清理无用文件(如删除依赖缓存、临时文件);

  3. 使用.dockerignore文件,排除不需要复制到镜像的文件(如.git、node_modules、日志文件),减少镜像体积;

  4. 合理使用ENV指令,统一管理环境变量,便于维护;

  5. 避免使用root用户运行容器,创建普通用户,提升容器安全性;

  6. 结合多阶段构建(Multi-stage Build),仅保留运行所需的文件,删除构建过程中的临时文件(如编译Java项目时,第一阶段编译生成jar包,第二阶段仅复制jar包到基础镜像,大幅减少镜像体积)。

  • 多阶段构建示例(Java项目):
# 第一阶段:构建阶段(使用maven镜像编译项目) 
FROM maven:3.8.8-openjdk-11 AS build WORKDIR /app COPY pom.xml . 

# 下载依赖(缓存依赖,避免每次构建都重新下载) 
RUN mvn dependency:go-offline COPY src ./src 

# 编译生成jar包 
RUN mvn package -DskipTests 

# 第二阶段:运行阶段(使用轻量化基础镜像) 
FROM openjdk:11-jre-slim WORKDIR /app 
# 从构建阶段复制jar包 
COPY --from=build /app/target/app.jar ./app.jar 
# 暴露端口 EXPOSE 8080 

# 启动命令 
ENTRYPOINT ["java", "-jar", "app.jar"] 

5. Docker容器的数据持久化方式有哪些?各自的区别是什么?(实战高频)

核心答案:Docker容器的数据持久化,核心是解决“容器删除后,数据丢失”的问题,常用的持久化方式有3种:「数据卷(Volume)、绑定挂载(Bind Mount)、tmpfs挂载(临时挂载)」;其中数据卷是Docker官方推荐的持久化方式,绑定挂载依赖宿主机路径,tmpfs挂载仅存储在宿主机内存中,重启后数据丢失。

原理解析

1. 为什么需要数据持久化?

容器的可写层是临时的,删除容器后,可写层中的所有数据(如日志、数据库数据、用户上传文件)都会被清空;而实际业务中,很多数据需要长期保存(如MySQL数据库数据、Nginx日志),因此需要将容器内的数据挂载到宿主机或外部存储,实现数据持久化。

2. 三种持久化方式详解

(1)数据卷(Volume):Docker官方推荐
  1. 定义:数据卷是Docker管理的宿主机文件系统中的一个目录(默认存储路径:/var/lib/docker/volumes/卷名/_data),由Docker统一管理,与容器解耦,可独立创建、删除、挂载到多个容器。

  2. 核心特性:

  • 完全由Docker管理,无需手动管理宿主机路径,避免路径混乱;

  • 可挂载到多个容器,实现容器间的数据共享;

  • 容器删除后,数据卷不会被删除,数据仍保留在宿主机,可重新挂载到其他容器;

  • 支持命名卷(指定卷名)和匿名卷(不指定卷名,由Docker自动生成随机名称)。

  1. 常用操作(实战命令):
  • 创建数据卷:docker volume create 卷名(如docker volume create mysql-data);

  • 查看数据卷:docker volume ls(查看所有数据卷)、docker volume inspect 卷名(查看数据卷详情,包括宿主机路径);

  • 挂载数据卷启动容器:docker run -d --name 容器名 -v 卷名:容器内路径 镜像名(如docker run -d --name mysql -v mysql-data:/var/lib/mysql mysql:8.0);

  • 删除数据卷:docker volume rm 卷名(删除未挂载的卷)、docker volume prune(删除所有未挂载的卷)。

(2)绑定挂载(Bind Mount):依赖宿主机路径
  1. 定义:将宿主机上的任意目录或文件,直接挂载到容器内的指定路径,容器内对该路径的操作,会直接同步到宿主机,反之亦然。

  2. 核心特性:

  • 依赖宿主机路径,需手动指定宿主机路径(绝对路径),灵活性高;

  • 宿主机路径的权限和所有者,会直接影响容器内的访问权限(容易出现权限问题);

  • 容器删除后,宿主机路径中的数据仍保留,不会丢失;

  • 不支持Docker CLI命令管理(无法通过docker volume命令操作)。

  1. 常用操作(实战命令):
  • 挂载宿主机目录启动容器:docker run -d --name 容器名 -v 宿主机绝对路径:容器内路径 镜像名(如docker run -d --name nginx -v /root/nginx/conf:/etc/nginx/conf.d nginx);

  • 挂载宿主机文件:docker run -d --name nginx -v /root/nginx/nginx.conf:/etc/nginx/nginx.conf nginx(注意:挂载文件时,宿主机文件必须存在,否则会被当作目录挂载)。

(3)tmpfs挂载(临时挂载):内存级挂载
  1. 定义:将数据存储在宿主机的内存中,而非磁盘上,容器启动时创建,容器停止或宿主机重启后,数据会彻底丢失。

  2. 核心特性:

  • 数据存储在内存中,读写速度极快,适合存储临时数据(如缓存、临时日志);

  • 不占用磁盘空间,避免磁盘空间浪费;

  • 数据不持久化,容器停止或宿主机重启后丢失,不适合存储需要长期保存的数据。

  1. 常用操作(实战命令):
  • 挂载tmpfs启动容器:docker run -d --name 容器名 --tmpfs 容器内路径 镜像名(如docker run -d --name app --tmpfs /app/temp app:1.0);

  • 限制tmpfs大小:docker run -d --name app --tmpfs /app/temp:size=100m app:1.0(限制内存使用为100MB)。

3. 三种持久化方式的核心区别(面试必背)

对比维度数据卷(Volume)绑定挂载(Bind Mount)tmpfs 挂载
管理方式Docker 统一管理,有专门的 CLI 命令手动管理宿主机路径,无专门 CLI 命令Docker 管理,内存级存储
宿主机路径由 Docker 自动分配(/var/lib/docker/volumes/)手动指定宿主机绝对路径无实际宿主机路径(内存中)
数据持久性容器删除后,数据保留,可复用容器删除后,数据保留(宿主机路径中)容器停止 / 宿主机重启后,数据丢失
容器间共享支持,可挂载到多个容器支持,多个容器挂载同一个宿主机路径不支持,仅当前容器可用
权限控制Docker 自动处理权限,不易出问题依赖宿主机路径权限,易出现权限问题权限由容器用户控制,无磁盘权限问题
适用场景长期数据持久化(如数据库、日志)开发环境(挂载代码目录,实时同步)临时数据存储(如缓存、临时文件)

扩展补充

  • 数据卷的进阶使用:命名卷可通过docker-compose.yml配置,实现多容器的数据共享,示例:
version: '3'

# 定义全局数据卷(供多个服务共享)
volumes:
  shared-data:  # 自定义数据卷名称,Docker 会自动创建和管理

services:
  app1:
    image: app:1.0  # 替换为你实际的镜像名
    volumes:
      - shared-data:/app/data  # 将 shared-data 数据卷挂载到 app1 的 /app/data 目录
    restart: always  # 可选:容器异常退出时自动重启
    container_name: app1-container  # 可选:指定容器名称,便于管理

  app2:
    image: app:2.0  # 替换为你实际的第二个镜像名
    volumes:
      - shared-data:/app/data  # 同一个 shared-data 数据卷挂载到 app2 的 /app/data 目录
    restart: always
    container_name: app2-container
  • 权限问题解决:使用绑定挂载时,若出现“权限拒绝”错误,可在挂载时指定权限(如-v /root/nginx/conf:/etc/nginx/conf.d:ro,ro表示只读挂载),或修改宿主机路径的权限(如chmod 777 /root/nginx/conf,不推荐生产环境使用,建议使用数据卷);

  • 生产环境推荐:优先使用数据卷,其次使用绑定挂载(仅开发环境或特殊场景),避免使用tmpfs挂载(除非是临时数据);对于数据库等核心数据,还可结合外部存储(如NFS、云存储),提升数据安全性。


6. Docker的网络模式有哪些?各自的作用是什么?(核心原理必问)

核心答案:Docker默认提供5种网络模式,分别是「bridge(桥接模式,默认)、host(主机模式)、none(无网络模式)、container(容器模式)、overlay(覆盖网络模式)」;核心作用是实现容器之间、容器与宿主机之间、容器与外部网络之间的通信,不同网络模式对应不同的通信场景,其中bridge模式用于单机容器通信,overlay模式用于多机容器集群通信。

原理解析

1. 网络模式的核心基础

Docker的网络模式基于Linux的网络命名空间(Network Namespace)实现,每个容器默认拥有独立的网络命名空间(独立的网卡、IP地址、路由表),与其他容器和宿主机隔离;Docker通过不同的网络驱动,实现不同的网络通信模式。网络命名空间是Linux内核提供的资源隔离技术,能将网络资源(网卡、IP、端口、路由)进行隔离,让每个容器拥有独立的网络环境,避免相互干扰。

2. 5种网络模式详解(按使用频率排序)

(1)bridge模式(桥接模式,默认网络模式)
  1. 定义:Docker默认创建一个名为“docker0”的桥接网络(虚拟交换机),所有未指定网络模式的容器,都会自动连接到docker0桥接网络,容器通过桥接网络实现与其他容器、宿主机的通信。

  2. 核心原理:

  • 宿主机创建docker0虚拟网卡(IP默认172.17.0.1),作为桥接网络的网关;

  • 每个容器启动时,会创建一个虚拟网卡(veth pair,一对相互连接的虚拟网卡),一端连接容器内部(容器IP为172.17.0.0/16网段,由Docker自动分配),另一端连接到docker0桥接网络,形成“容器→veth pair→docker0→宿主机”的通信链路;

  • 容器之间通过docker0桥接网络通信(同一网段,可直接ping通),无需经过宿主机的NAT转换;

  • 容器与外部网络通信时,通过宿主机的NAT转换(将容器IP转换为宿主机IP)实现,外部网络无法直接访问容器IP。

  1. 常用操作:
  • 查看默认bridge网络:docker network inspect bridge

  • 启动容器时指定bridge模式(默认,可省略):docker run -d --name 容器名 --net bridge 镜像名

  • 自定义桥接网络(推荐,隔离性更好):docker network create my-bridge,启动容器时指定:docker run -d --name 容器名 --net my-bridge 镜像名(自定义桥接网络可实现不同容器组的隔离,如开发环境和测试环境容器分开部署)。

  1. 特点:
  • 隔离性:容器之间通过桥接网络通信,与宿主机网络隔离(容器IP不可直接被外部网络访问);

  • 灵活性:可自定义桥接网络,实现不同容器组的隔离;

  • 局限性:仅支持单机容器通信,多机容器无法通过bridge模式通信。

(2)host模式(主机模式)
  1. 定义:容器不创建独立的网络命名空间,而是共享宿主机的网络命名空间(共享宿主机的网卡、IP地址、端口、路由表),容器的网络配置与宿主机完全一致。

  2. 核心原理:

  • 容器启动时,使用--net host参数,容器会放弃创建自己的网络命名空间,直接复用宿主机的网络资源;

  • 容器内的端口直接映射到宿主机的对应端口,无需使用-p参数(如容器内启动nginx,监听80端口,宿主机的80端口直接被占用,外部可通过宿主机IP:80访问);

  • 容器内的网络操作(如修改路由、绑定端口),本质上是对宿主机网络的操作,会影响宿主机和其他容器。

  1. 常用操作:
  • 启动容器时指定host模式:docker run -d --name 容器名 --net host 镜像名
  1. 特点:
  • 性能高:无需NAT转换,容器网络通信效率与宿主机一致,适合对网络性能要求高的场景;

  • 配置简单:无需端口映射,直接使用宿主机端口;

  • 局限性:隔离性差(容器共享宿主机网络,容器的端口会占用宿主机端口,可能导致端口冲突);不支持多容器共享端口;容器内的网络操作可能影响宿主机。

  1. 适用场景:对网络性能要求高、无需端口隔离的场景(如单机部署的高性能服务、网络测试工具)。
(3)none模式(无网络模式)
  1. 定义:容器创建独立的网络命名空间,但不配置任何网络(无网卡、无IP地址、无路由表),容器无法与任何外部网络(包括宿主机、其他容器)通信。

  2. 核心原理:容器仅拥有自己的网络命名空间,但未配置任何网络接口(无eth0网卡),也未设置路由表,相当于“网络隔离的沙箱”,仅能在容器内部运行。

  3. 常用操作:

  • 启动容器时指定none模式:docker run -d --name 容器名 --net none 镜像名
  1. 特点:
  • 隔离性极强:完全与外部网络隔离,避免网络攻击,仅能在容器内部执行操作;

  • 局限性:无法通信,仅适用于不需要网络的场景。

  1. 适用场景:仅需在容器内部执行离线任务(如数据处理、文件转换、离线编译),无需与外部通信的场景。
(4)container模式(容器模式)
  1. 定义:容器不创建独立的网络命名空间,而是共享另一个容器的网络命名空间(即“共享网络的容器”),两个容器拥有相同的IP地址、端口、路由表,可直接通过localhost通信。

  2. 核心原理:

  • 启动容器时,使用--net container:目标容器名/容器ID参数,当前容器会复用目标容器的网络命名空间,与目标容器共享网卡、IP、端口、路由表;

  • 两个容器的网络环境完全一致,可通过localhost直接通信(如目标容器监听8080端口,当前容器可通过localhost:8080访问目标容器的服务);

  • 若目标容器停止运行,当前容器的网络也会失效(无法通信)。

  1. 常用操作:
  • 启动目标容器:docker run -d --name target-container nginx

  • 启动共享网络的容器:docker run -d --name share-container --net container:target-container busybox

  1. 特点:
  • 通信高效:容器之间无需通过桥接或NAT转换,直接通过localhost通信,延迟极低;

  • 隔离性:与宿主机和其他非共享容器隔离,仅共享目标容器的网络;

  • 局限性:依赖目标容器,目标容器停止后,当前容器无法通信;无法单独配置网络参数。

  1. 适用场景:需要两个容器紧密通信(如应用容器和日志收集容器),且无需独立网络环境的场景。
(5)overlay模式(覆盖网络模式)
  1. 定义:Docker提供的跨主机容器通信网络模式,基于VXLAN技术,将多个Docker主机组成集群,实现不同主机上的容器之间的通信,是Docker Swarm和K8s容器编排的核心网络模式。

  2. 核心原理:

  • overlay网络会在每个Docker主机上创建一个虚拟网卡(overlay0),用于跨主机的网络通信;

  • 容器启动时,会被分配一个全局唯一的IP地址(跨主机可见),容器之间的通信通过overlay网络的虚拟隧道(VXLAN隧道)实现,无需手动配置路由;

  • overlay网络会维护一个全局的网络拓扑信息,确保不同主机上的容器能够相互发现和通信。

  1. 常用操作(结合Docker Swarm):
  • 初始化Swarm集群:docker swarm init

  • 创建overlay网络:docker network create -d overlay my-overlay

  • 启动跨主机容器:docker service create --name app --network my-overlay nginx(容器会自动分布在Swarm集群的不同主机上,且可相互通信)。

  1. 特点:
  • 跨主机通信:支持不同Docker主机上的容器之间的通信,解决单机bridge模式的局限性;

  • 隔离性:overlay网络与宿主机网络隔离,容器IP全局唯一,互不干扰;

  • 可扩展性:支持动态添加Docker主机到集群,容器可自由扩容缩容。

  1. 适用场景:多机容器集群(如Docker Swarm、K8s),需要跨主机容器通信的场景(如分布式应用、微服务集群)。

扩展补充

  • 网络模式的选择技巧(面试加分):
  1. 单机部署、需隔离容器网络 → 优先使用自定义bridge网络;

  2. 对网络性能要求极高、无需端口隔离 → 使用host模式;

  3. 离线任务、需极高网络隔离 → 使用none模式;

  4. 两个容器紧密通信、无需独立网络 → 使用container模式;

  5. 多机集群、跨主机容器通信 → 使用overlay模式。

  • 避坑点:
  1. bridge模式下,容器IP是动态分配的,若需固定容器IP,需在自定义bridge网络中配置(如docker network create --subnet=172.18.0.0/16 my-bridge,启动容器时指定--ip 172.18.0.10);

  2. host模式下,容器不能使用-p参数(会报错),且需避免端口冲突;

  3. overlay模式依赖Docker Swarm或K8s集群,单机环境无法使用。


7. Docker Compose是什么?核心作用是什么?如何使用?(实战必问)

核心答案:Docker Compose是Docker官方提供的多容器应用编排工具,基于YAML文件(docker-compose.yml)定义和管理多个容器的依赖关系、网络、存储、环境变量等配置,实现多容器应用的一键启停、部署、扩容和管理;核心作用是解决“多容器部署繁琐”的问题,将多个容器的配置集中管理,简化多容器应用的部署流程,提升运维效率。

原理解析

1. Docker Compose的核心定位

在实际业务中,大多数应用都不是单容器部署(如Java应用需要搭配MySQL、Redis、Nginx等容器),若手动启动每个容器,需要依次执行docker run命令,手动配置网络、存储、依赖关系,操作繁琐且容易出错;Docker Compose通过一个YAML文件,将所有容器的配置(镜像、端口、网络、存储、环境变量、依赖关系)集中定义,执行一条命令即可完成所有容器的启动、停止、重启,实现多容器应用的标准化部署。

2. Docker Compose的核心特性

  1. 集中配置:所有容器的配置都集中在docker-compose.yml文件中,便于版本控制和团队协作(所有人使用相同的配置文件,确保部署一致性);

  2. 一键操作:通过docker-compose up一键启动所有容器,docker-compose down一键停止并删除所有容器,无需手动操作单个容器;

  3. 依赖管理:支持配置容器之间的依赖关系(如先启动MySQL容器,再启动Java应用容器),确保容器按正确顺序启动;

  4. 网络管理:自动创建自定义桥接网络,所有容器默认加入该网络,容器之间可通过容器名直接通信(无需指定IP);

  5. 动态更新:支持在不停止容器的情况下,更新容器配置(如修改环境变量、挂载路径),并重启受影响的容器;

  6. 可扩展性:支持通过docker-compose scale命令快速扩容缩容容器(如将web容器扩容到3个实例)。

3. Docker Compose的使用流程(实战操作)

(1)安装Docker Compose(前提:已安装Docker)

Linux系统安装命令(以CentOS为例):

# 1. 下载Docker Compose二进制文件(添加 -f 强制覆盖,-s 静默失败更友好)
sudo curl -fsSL "https://github.com/docker/compose/releases/download/v2.20.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

# 2. 赋予执行权限(确保所有用户可执行)
sudo chmod +x /usr/local/bin/docker-compose

# 3. 可选:创建软链接(兼容旧版命令路径,避免"command not found")
sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose

# 4. 验证安装(输出版本信息则说明成功)
docker-compose --version

Windows和Mac系统安装Docker Desktop后,会自动安装Docker Compose,无需手动安装。

(2)编写docker-compose.yml配置文件(核心)

docker-compose.yml是Docker Compose的核心配置文件,采用YAML语法,主要包含3个核心节点:version(版本)、services(容器服务)、volumes(数据卷)、networks(网络)(可选)。

示例(Java应用+MySQL+Redis+Nginx多容器部署):

# 版本号(需与Docker Compose版本匹配,v2版本最常用)
version: '3.8'

# 容器服务定义(核心节点)
services:
  # 1. MySQL容器(核心数据存储)
  mysql:
    # 镜像名:标签(指定版本避免latest不可控)
    image: mysql:8.0
    # 容器名(便于管理和日志查询)
    container_name: mysql
    # 环境变量(初始化MySQL配置)
    environment:
      - MYSQL_ROOT_PASSWORD=123456  # root用户密码
      - MYSQL_DATABASE=app_db       # 自动创建的初始数据库
    # 数据持久化(挂载数据卷/自定义配置)
    volumes:
      - mysql-data:/var/lib/mysql   # 持久化MySQL核心数据
      - ./mysql/conf:/etc/mysql/conf.d  # 挂载自定义配置文件
    # 端口映射(宿主机:容器)
    ports:
      - "3306:3306"
    # 重启策略(异常/宿主机重启后自动重启)
    restart: always
    # 健康检查(确保MySQL真正可用,而非仅容器启动)
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p123456"]
      interval: 10s  # 检查间隔
      timeout: 5s    # 单次检查超时时间
      retries: 3     # 连续失败次数阈值

  # 2. Redis容器(缓存服务)
  redis:
    image: redis:7.0
    container_name: redis
    volumes:
      - redis-data:/data  # 持久化Redis数据
    ports:
      - "6379:6379"
    restart: always
    # 启动命令(设置Redis密码,替代简单配置文件)
    command: redis-server --requirepass 123456

  # 3. Java应用容器(业务核心服务)
  app:
    image: app:1.0  # 替换为实际的Java应用镜像
    container_name: app
    # 依赖关系(控制启动顺序)
    depends_on:
      mysql:
        condition: service_healthy  # 等待MySQL健康检查通过
      redis:
        condition: service_started   # 仅等待Redis容器启动
    # 环境变量(配置应用连接信息)
    environment:
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/app_db?useSSL=false&serverTimezone=UTC
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=123456
      - SPRING_REDIS_HOST=redis
      - SPRING_REDIS_PASSWORD=123456
    ports:
      - "8080:8080"
    restart: always

  # 4. Nginx容器(反向代理)
  nginx:
    image: nginx:1.24
    container_name: nginx
    # 挂载自定义配置、静态资源、日志
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d    # 反向代理配置
      - ./nginx/html:/usr/share/nginx/html  # 静态页面
      - nginx-logs:/var/log/nginx        # 日志持久化
    ports:
      - "80:80"
    # 依赖Java应用启动后再启动
    depends_on:
      - app
    restart: always

# 数据卷定义(与services中的volumes对应)
volumes:
  mysql-data:    # MySQL数据持久化卷
  redis-data:    # Redis数据持久化卷
  nginx-logs:    # Nginx日志持久化卷

# 网络定义(可选,默认自动创建自定义桥接网络)
networks:
  default:
    driver: bridge

(3)常用Docker Compose命令(实战必背)
  1. 启动所有容器(后台运行):docker-compose up -d(“-d”表示后台运行,首次启动会拉取镜像);

  2. 停止并删除所有容器、网络、数据卷:docker-compose down(若需保留数据卷,添加-v参数:docker-compose down -v);

  3. 查看容器状态:docker-compose ps

  4. 查看容器日志(单个容器):docker-compose logs -f 容器名(“-f”表示实时跟踪日志);

  5. 重启所有容器:docker-compose restart(重启单个容器:docker-compose restart 容器名);

  6. 启动单个容器:docker-compose start 容器名

  7. 停止单个容器:docker-compose stop 容器名

  8. 扩容缩容容器:docker-compose scale 容器名=数量(如docker-compose scale app=3,将app容器扩容到3个实例);

  9. 构建镜像(若配置了build参数):docker-compose build(构建单个容器镜像:docker-compose build 容器名);

  10. 查看Docker Compose配置:docker-compose config(检查配置文件是否有语法错误)。

扩展补充

  • docker-compose.yml核心配置节点详解(面试加分):
  1. version:指定Docker Compose的版本,需与Docker版本匹配(如Docker 20.10+对应version 3.8);

  2. services:定义所有容器服务,每个服务对应一个容器,节点下可配置image(镜像)、container_name(容器名)、ports(端口映射)、volumes(数据挂载)、environment(环境变量)、depends_on(依赖关系)、restart(重启策略)、command(启动命令)等;

  3. volumes:定义数据卷,可用于多个容器共享数据,支持命名卷和绑定挂载;

  4. networks:定义网络,可自定义网络驱动(如bridge、overlay),实现容器网络隔离。

  • 避坑点:
  1. depends_on仅控制容器的启动顺序,不保证依赖容器的服务已完全启动(如MySQL容器启动但未完成初始化,app容器就已启动,可能导致连接失败),需结合healthcheck健康检查解决;

  2. 配置文件的缩进必须使用空格(不能使用Tab),YAML语法对缩进敏感,缩进错误会导致配置失效;

  3. 环境变量中若包含特殊字符(如&、$),需使用引号包裹,避免解析错误;

  4. Docker Compose仅适用于单机多容器部署,多机集群部署需使用Docker Swarm或K8s。

  • 进阶使用:Docker Compose支持.env文件,将环境变量集中存储在.env文件中,在docker-compose.yml中通过${变量名}引用,简化配置(如将MySQL密码、Redis密码存储在.env文件中,便于修改和维护)。

8. Docker镜像的优化方法有哪些?(实战优化必问)

核心答案:Docker镜像优化的核心目标是「减小镜像体积、提升构建效率、增强镜像安全性」,常用优化方法包括:使用轻量化基础镜像、合并Dockerfile指令、清理无用文件、使用多阶段构建、使用.dockerignore文件、优化镜像层缓存、避免使用root用户等,每种方法都能从不同维度优化镜像性能和体积。

原理解析

1. 优化的核心意义

镜像体积过大,会导致镜像拉取/推送速度慢、占用宿主机存储空间多、部署效率低;镜像构建效率低,会影响开发和部署流程;镜像安全性不足,会带来生产环境安全风险(如使用root用户运行容器、存在无用依赖);因此,镜像优化是Docker实战中的核心技能,也是面试高频考点。

2. 具体优化方法(按优化效果排序,实战必背)

(1)使用轻量化基础镜像(最核心优化)
  1. 核心原理:基础镜像占镜像体积的主要部分,选择轻量化的基础镜像,可大幅减小镜像体积;

  2. 推荐选择:

  • 通用基础镜像:alpine(体积约5MB,轻量级Linux发行版,适用于大多数应用)、slim版本(如openjdk:11-jre-slim,体积约100MB,比完整版openjdk小50%以上);

  • 语言专属基础镜像:node:alpine(Node.js应用)、python:alpine(Python应用)、golang:alpine(Go应用);

  1. 避坑点:避免使用centos、ubuntu等完整版基础镜像(体积约200-500MB),除非应用依赖完整版系统的特定工具。
(2)使用多阶段构建(Multi-stage Build,体积优化神器)
  1. 核心原理:将镜像构建过程分为多个阶段,第一阶段(构建阶段)使用包含编译工具、依赖库的镜像,完成应用编译、打包;第二阶段(运行阶段)使用轻量化基础镜像,仅复制构建阶段的产物(如jar包、二进制文件),删除构建过程中的临时文件(如编译依赖、源码),大幅减小镜像体积;

  2. 示例(Java项目多阶段构建):

# 第一阶段:构建阶段(使用maven镜像编译项目,体积约500MB)
FROM maven:3.8.8-openjdk-11 AS build
WORKDIR /app

# 先复制pom.xml,下载依赖(利用Docker缓存,仅pom.xml变更时重新下载)
COPY pom.xml .
RUN mvn dependency:go-offline

# 复制源码,编译生成jar包(跳过测试加快构建)
COPY src ./src
RUN mvn package -DskipTests

# 第二阶段:运行阶段(使用轻量化基础镜像,体积约100MB)
FROM openjdk:11-jre-slim
WORKDIR /app

# 从构建阶段仅复制编译后的jar包(舍弃构建环境,减小镜像体积)
COPY --from=build /app/target/app.jar ./app.jar

# 声明暴露的端口(仅文档作用,实际需docker run -p映射)
EXPOSE 8080

# 容器启动命令(固定参数形式,更稳定)
ENTRYPOINT ["java", "-jar", "app.jar"]
  1. 优化效果:构建后的镜像体积仅约100MB,比单阶段构建(约500MB)减小80%以上。
(3)合并Dockerfile指令,减少镜像层数量
  1. 核心原理:Docker镜像采用分层存储,每层都会占用存储空间,且层数量过多会影响镜像构建和传输效率;将多个RUN、COPY等指令合并,可减少镜像层数量,同时清理无用文件,减小镜像体积;

  2. 优化技巧:使用&&连接多个RUN指令,在每个RUN指令末尾清理无用文件(如依赖缓存、临时文件);

  3. 反例(不推荐):

RUN apk add --no-cache nginx RUN mkdir -p /app/logs RUN rm -rf /var/cache/apk/*
  1. 正例(推荐):
dockerfile RUN apk add --no-cache nginx && mkdir -p /app/logs && rm -rf /var/cache/apk/* 
  1. 注意:合并指令时,需确保指令之间有依赖关系,避免无关指令合并(如将COPY指令与RUN指令合并,可能导致缓存失效)。
(4)使用.dockerignore文件,排除无用文件
  1. 核心原理:Docker构建镜像时,会将Dockerfile所在目录下的所有文件复制到构建上下文(Build Context),若目录中存在无用文件(如.git、node_modules、日志文件、源码备份),会增加构建上下文大小,导致镜像体积增大、构建速度变慢;

  2. .dockerignore文件作用:指定需要排除的文件和目录,Docker构建时会忽略这些文件,不复制到构建上下文;

  3. 常用.dockerignore配置示例:

# 排除版本控制文件 
.git 
.gitignore 
# 排除依赖目录(如Node.js、Python依赖) 
node_modules venv dist 
# 排除日志文件 
*.log logs/ 
# 排除源码备份文件 
*.bak *.tmp 
# 排除Docker相关文件(避免循环复制) 
Dockerfile .dockerignore
(5)优化镜像层缓存,提升构建效率
  1. 核心原理:Docker构建镜像时,会缓存已构建的镜像层,若Dockerfile指令未修改,会直接复用缓存层,无需重新构建;因此,合理排列指令顺序,可最大化利用缓存,提升构建效率;

  2. 优化技巧:

  • 将不变的指令(如FROM、ENV)放在Dockerfile顶部,优先构建,便于缓存;

  • 将频繁修改的指令(如COPY src ./src、RUN mvn package)放在底部,避免修改后导致所有底层镜像层重新构建;

  1. 示例(优化缓存):
# 不变的指令(优先构建,缓存复用) 
FROM openjdk:11-jre-slim ENV JAVA_HOME=/usr/local/jdk WORKDIR /app 
# 频繁修改的指令(放在底部,修改后仅重新构建这一层)
COPY src ./src RUN mvn package -DskipTests 
(6)清理无用文件和依赖,减小镜像体积
  1. 核心原理:构建镜像过程中,会产生临时文件(如依赖缓存、编译临时文件、安装包),这些文件在容器运行时无需使用,清理后可减小镜像体积;

  2. 常见清理操作:

  • Alpine系统:rm -rf /var/cache/apk/*(清理apk依赖缓存);

  • CentOS系统:yum clean all && rm -rf /var/cache/yum/*(清理yum依赖缓存);

  • Ubuntu系统:apt-get clean && rm -rf /var/lib/apt/lists/*(清理apt依赖缓存);

  • 编译项目:删除源码、编译依赖(如maven的~/.m2目录)。

(7)避免使用root用户运行容器,提升安全性
  1. 核心原理:默认情况下,容器以root用户运行,若容器被入侵,攻击者可获得宿主机的root权限,存在安全风险;创建普通用户,以普通用户身份运行容器,可提升镜像安全性;

  2. 实现方法(Dockerfile中添加):

# 创建普通用户(appuser,用户ID 1000) 
RUN addgroup -S appgroup && adduser -S appuser -G appgroup -u 1000 
# 切换到普通用户 
USER appuser 
# 后续指令均以appuser身份执行
(8)其他优化方法
  1. 使用镜像瘦身工具:如docker-slim,可自动分析镜像,删除无用文件和依赖,进一步减小镜像体积;

  2. 避免在镜像中存储敏感信息(如密码、密钥),应通过环境变量(-e参数)或外部配置文件挂载的方式传递;

  3. 选择合适的镜像标签,避免使用latest标签(latest标签会自动指向最新版本,可能导致镜像版本不一致),建议使用固定版本标签(如nginx:1.24.0)。

扩展补充

  • 镜像体积查看方法:使用docker images查看镜像体积,使用docker history 镜像ID查看镜像各层的体积,便于定位体积过大的层;

  • 优化效果验证:优化前后对比镜像体积、构建时间、拉取时间,确保优化有效;

  • 面试加分点:结合实际项目案例,说明如何通过多阶段构建、合并指令等方法,将镜像体积从几百MB优化到几十MB,提升部署效率。


9. Docker容器的生命周期是什么?常用的容器操作命令有哪些?(实战必问)

核心答案:Docker容器的生命周期分为5个状态:「创建状态(Created)、运行状态(Running)、暂停状态(Paused)、停止状态(Exited)、删除状态(Removed)」;容器从创建到删除,会依次经历这些状态,通过Docker命令可实现状态之间的切换;常用容器操作命令涵盖容器的创建、启动、停止、重启、暂停、删除、查看等,是Docker实战的基础。

原理解析

1. 容器生命周期详解(5个状态)

(1)创建状态(Created)
  1. 定义:通过docker create命令创建容器,容器已完成初始化(分配了网络、存储、PID等资源),但未启动应用进程,处于未运行状态;

  2. 触发命令:docker create --name 容器名 镜像名

  3. 状态特点:容器已存在,占用少量资源(如网络、存储),但未运行任何进程。

(2)运行状态(Running)
  1. 定义:通过docker startdocker run命令启动容器,容器内的应用进程开始运行,容器处于正常工作状态;

  2. 触发命令:docker start 容器名/容器IDdocker run -d --name 容器名 镜像名docker run等价于“create+start”);

  3. 状态特点:容器占用CPU、内存等资源,应用进程正常运行,可提供服务。

(3)暂停状态(Paused)
  1. 定义:通过docker pause命令暂停容器,容器内的应用进程会被冻结(暂停执行),但容器的资源(网络、存储)仍被占用;

  2. 触发命令:docker pause 容器名/容器ID

  3. 恢复方法:docker unpause 容器名/容器ID(恢复后,应用进程继续执行,状态回到Running);

  4. 状态特点:容器占用资源,但应用进程不执行,适合临时暂停容器(如维护、调试)。

(4)停止状态(Exited)
  1. 定义:通过docker stopdocker kill命令停止容器,容器内的应用进程终止,容器不再占用CPU、内存资源,但仍保留容器的配置和可写层数据;

  2. 触发命令:

  • docker stop 容器名/容器ID:优雅停止容器(发送SIGTERM信号,让应用进程正常退出,等待30秒后强制终止);

  • docker kill 容器名/容器ID:强制停止容器(发送SIGKILL信号,立即终止应用进程,不等待);

  1. 恢复方法:docker start 容器名/容器ID(恢复后,应用进程重新启动,可写层数据保留);

  2. 状态特点:容器不占用CPU、内存资源,保留配置和数据,可随时重启。

(5)删除状态(Removed)
  1. 定义:通过docker rm命令删除容器,容器的配置、可写层数据、网络资源等全部被清理,容器不再存在;

  2. 触发命令:docker rm 容器名/容器ID(只能删除Exited状态的容器,若需删除Running状态的容器,添加-f参数:docker rm -f 容器名);

  3. 状态特点:容器完全被清理,无法恢复,需重新创建容器。

2. 容器生命周期状态切换流程(面试必背)

创建状态(Created) ←→ 运行状态(Running) ←→ 暂停状态(Paused)

运行状态(Running) → 停止状态(Exited) ←→ 运行状态(Running)

停止状态(Exited) → 删除状态(Removed)(不可逆)

3. 常用容器操作命令(实战必背,按使用频率排序)

(1)容器创建与启动
  1. 创建容器(不启动):docker create --name 容器名 镜像名(如docker create --name nginx-test nginx);

  2. 创建并启动容器(后台运行):docker run -d --name 容器名 镜像名(如docker run -d --name nginx nginx);

  3. 创建并启动容器(交互式运行,适合调试):docker run -it --name 容器名 镜像名 /bin/bash(“-i”表示交互式,“-t”表示分配终端);

  4. 启动已创建/停止的容器:docker start 容器名/容器ID

(2)容器停止与删除
  1. 优雅停止容器:docker stop 容器名/容器ID

  2. 强制停止容器:docker kill 容器名/容器ID

  3. 删除容器(停止状态):docker rm 容器名/容器ID

  4. 强制删除容器(运行状态):docker rm -f 容器名/容器ID

  5. 删除所有停止的容器:docker container prune

(3)容器暂停与恢复
  1. 暂停容器:docker pause 容器名/容器ID

  2. 恢复容器:docker unpause 容器名/容器ID

(4)容器查看与日志
  1. 查看所有容器(运行+停止):docker ps -a

  2. 查看运行中的容器:docker ps

  3. 查看容器详情(IP、网络、存储等):docker inspect 容器名/容器ID

  4. 查看容器日志(实时跟踪):docker logs -f 容器名/容器ID

  5. 查看容器内运行的进程:docker top 容器名/容器ID

(5)容器交互与文件操作
  1. 进入运行中的容器(交互式):docker exec -it 容器名/容器ID /bin/bash(退出容器不影响容器运行);

  2. 向容器内复制文件:docker cp 宿主机文件路径 容器名/容器ID:容器内路径(如docker cp app.jar nginx:/app/);

  3. 从容器内复制文件到宿主机:docker cp 容器名/容器ID:容器内路径 宿主机文件路径(如docker cp nginx:/etc/nginx/nginx.conf /root/)。

(6)容器其他操作
  1. 重启容器:docker restart 容器名/容器ID(等价于“stop+start”);

  2. 重命名容器:docker rename 旧容器名 新容器名

  3. 查看容器占用的资源(CPU、内存、网络):docker stats 容器名/容器ID

  4. 导出容器(保存为tar文件):docker export 容器名/容器ID > 容器名.tar

  5. 导入容器(从tar文件创建容器):cat 容器名.tar | docker import - 镜像名:标签

扩展补充

  • 避坑点:
  1. 删除容器前,需先停止容器(除非使用-f强制删除),否则会报错;

  2. docker run命令每次执行都会创建新的容器,若容器名已存在,会报错,需先删除原有容器或使用不同的容器名;

  3. 进入容器后,若执行exit命令,会退出容器,但容器仍在运行(交互式启动的容器除外);

  4. 容器导出(export)与镜像导出(save)的区别:export导出的是容器的可写层数据(不包含镜像的只读层),import后得到的是镜像;save导出的是完整镜像(包含所有层),load后得到的是镜像。

  • 面试加分点:结合容器生命周期,说明如何通过命令实现容器的状态切换(如从创建到运行、从运行到停止再到删除),并举例说明常用命令的使用场景(如调试容器用docker exec -it,查看日志用docker logs -f)。