# docker面试题

#

# docker底层依托于linux怎么实现资源隔离的?

#

基于 Namespace 的视图隔离:Docker利用Linux命名空间(Namespace)来实现不同容器之间的隔离。每个容器都运行在自己的一组命名空间中,包括PID(进程)、网络、挂载点、IPC(进程间通信)等。这样,容器中的进程只能看到自己所在命名空间内的进程,而不会影响其他容器中的进程。

基于 cgroups 的资源隔离:cgroups 是Linux内核的一个功能,允许在进程组之间分配、限制和优先处理系统资源,如CPU、内存和磁盘I/O。它们提供了一种机制,用于管理和隔离进程集合的资源使用,有助于资源限制、工作负载隔离以及在不同进程组之间进行资源优先处理。

# 讲讲cgroup v2.0

#

cgroup v2 是 Linux cgroup API 的下一个版本。cgroup v2 提供了一个具有增强资源管理能力的统一控制系统。

cgroup v2 对 cgroup v1 进行了多项改进,例如:

API 中单个统一的层次结构设计

API 中单个统一的层次结构设计

更安全的子树委派给容器

更安全的子树委派给容器

更新的功能特性, 例如压力阻塞信息(Pressure Stall Information,PSI) (opens new window)

更新的功能特性, 例如压力阻塞信息(Pressure Stall Information,PSI) (opens new window)

压力阻塞信息(Pressure Stall Information,PSI) (opens new window)

跨多个资源的增强资源分配管理和隔离

跨多个资源的增强资源分配管理和隔离

统一核算不同类型的内存分配(网络内存、内核内存等)

统一核算不同类型的内存分配(网络内存、内核内存等)

考虑非即时资源变化,例如页面缓存回写

考虑非即时资源变化,例如页面缓存回写

v1 的 cgroup 为每个控制器都使用独立的树(目录)

[root@docker cgroup]# ls /sys/fs/cgroup/ blkio  cpu  cpuacct  cpuacct,cpu  cpu,cpuacct  cpuset  devices  freezer  hugetlb  memory  net_cls  net_cls,net_prio  net_prio  perf_event  pids  rdma  systemd
[root@docker cgroup]# ls /sys/fs/cgroup/ blkio  cpu  cpuacct  cpuacct,cpu  cpu,cpuacct  cpuset  devices  freezer  hugetlb  memory  net_cls  net_cls,net_prio  net_prio  perf_event  pids  rdma  systemd

每个目录就代表了一个 cgroup subsystem,比如要限制 cpu 则需要到 cpu 目录下创建子目录(树),限制 memory 则需要到 memory 目录下去创建子目录(树)。

比如 Docker 就会在 cpu、memory 等等目录下都创建一个名为 docker 的目录,在 docker 目录下在根据 containerID 创建子目录来实现资源限制。

各个 Subsystem 各自为政,看起来比混乱,难以管理

因此最终的结果就是:

用户空间最后管理着多个非常类似的 hierarchy,

在执行 hierarchy 管理操作时,每个 hierarchy 上都重复着相同的操作。

v2 中对 cgroups 的最大更改是将重点放在简化层次结构上

v1 为每个控制器使用独立的树(例如 /sys/fs/cgroup/cpu/GROUPNAME和 /sys/fs/cgroup/memory/GROUPNAME)。

v2 将统一/sys/fs/cgroup/GROUPNAME中的树,如果进程 X 加入/sys/fs/cgroup/test,则启用 test 的每个控制器都将控制进程 X。

# Docker 和虚拟机有什么区别?

#

核心区别:虚拟机虚拟化的是操作系统,Docker 虚拟化的是进程。

虚拟机(VM):通过 Hypervisor 在宿主机上模拟一整套硬件,每台 VM 都跑着一个完整的 Guest OS 内核,隔离性极强但开销大——启动要几十秒、镜像几个 GB、单实例内存占用 GB 级别。

Docker 容器:所有容器共享宿主机的 Linux 内核,通过 Namespace 做视图隔离、cgroups 做资源限制,本质上容器就是一组被隔离起来的特殊进程。启动秒级、镜像几十到几百 MB、内存开销 MB 级别。

形象一点说:VM 像"独立的房子",容器像"同一栋楼里的房间"。容器牺牲了一点隔离性(共用内核),换来了远高于 VM 的启动速度和资源利用率,这也是云原生时代首选 Docker 的根本原因。

# Docker 有哪几个核心组件?

#

主要是三个:

镜像(Image):只读的模板,包含了运行一个应用所需要的代码、依赖、环境变量、配置等,相当于"安装包"。

容器(Container):镜像的运行时实例,可以启动、停止、删除,是一个独立隔离的进程组,相当于"安装后运行起来的程序"。

仓库(Registry):存储和分发镜像的地方,分公有仓库(如 Docker Hub)和私有仓库(如 Harbor、阿里云 ACR、腾讯云 TCR),类似于"应用商店"。

三者的协作流程是:从 Registry 拉镜像 → 由镜像启动容器 → 容器运行应用。

# 镜像和容器有什么区别?

#

最常被问的基础题,一句话记住:镜像是静态的模板,容器是镜像的动态运行实例。

类比关系就像编程里的 类(Class)和对象(Object):

镜像 = 类,定义了应用的结构和行为,是只读的

容器 = 对象,是镜像被启动后的具体实例,有自己的文件系统读写层、网络、进程

一个镜像可以启动多个容器实例,每个容器之间互不影响;停止/删除容器也不会影响镜像本身。

# Docker 镜像的分层原理是什么?

#

Docker 镜像采用分层只读的结构,底层基于 UnionFS(联合文件系统),现代 Docker 主要使用 overlay2 作为默认的存储驱动。

Dockerfile 里每一条指令都会产生一个新的镜像层,这些层都是只读的。例如:

FROM ubuntu:22.04       # 层 1
RUN apt-get update      # 层 2
COPY app /app           # 层 3
CMD ["./app"]           # 层 4
FROM ubuntu:22.04       # 层 1
RUN apt-get update      # 层 2
COPY app /app           # 层 3
CMD ["./app"]           # 层 4

当容器启动时,Docker 会在所有只读层之上再叠加一层可写层(容器层),容器对文件的任何修改都发生在这一层,通过 Copy-on-Write(写时复制) 机制实现。

分层带来的好处:

共享与复用:多个镜像可以共享相同的底层(比如都基于 ubuntu:22.04),节省存储和网络传输

ubuntu:22.04

构建缓存:重新构建时,只要某一层没变就直接复用缓存,速度极快

增量分发:docker pull 只会下载变化的那一层

docker pull

这也解释了 Dockerfile 最佳实践里的一条重要原则:把"不常变的层"(如依赖安装)放在"常变的层"(如 COPY 源码)之前,这样缓存命中率更高、构建更快。

# Dockerfile 常用指令有哪些?

#

面试一般不会考冷门指令,记住这几个就足够:

FROM:指定基础镜像,必须是 Dockerfile 的第一条指令

FROM

WORKDIR:设置容器内的工作目录,相当于 cd

WORKDIR
cd

COPY / ADD:把宿主机的文件拷贝到镜像里

COPY
ADD

RUN:在构建阶段执行命令(如安装依赖),每条 RUN 产生一个新层

RUN
RUN

ENV:设置环境变量(运行时也能看到)

ENV

ARG:构建时的参数,只在 docker build 阶段有效

ARG
docker build

EXPOSE:声明容器要监听的端口(只是声明,不会真的开放端口)

EXPOSE

VOLUME:声明数据卷挂载点

VOLUME

CMD / ENTRYPOINT:指定容器启动时默认要运行的命令

CMD
ENTRYPOINT

USER:切换到非 root 用户运行

USER

一个典型的 Java Spring Boot 应用 Dockerfile:

FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY target/app.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

# Dockerfile 中 CMD 和 ENTRYPOINT 有什么区别?

#

两者都用于指定容器启动时执行的命令,但有微妙而关键的区别:

CMD:提供"默认命令",可以被 docker run 后面跟的参数完全覆盖。

CMD
docker run

ENTRYPOINT:设置容器的"主命令",不会被 docker run 覆盖,后面跟的参数会作为参数追加到 ENTRYPOINT 后面。

ENTRYPOINT
docker run

推荐组合用法:ENTRYPOINT 设主命令,CMD 设默认参数,这样用户既能使用默认行为,也能灵活传参:

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

docker run myapp:运行 java -jar app.jar --spring.profiles.active=prod

docker run myapp
java -jar app.jar --spring.profiles.active=prod

docker run myapp --server.port=9090:运行 java -jar app.jar --server.port=9090(--server.port=9090 覆盖了 CMD)

docker run myapp --server.port=9090
java -jar app.jar --server.port=9090
--server.port=9090

另外,两者都有两种语法写法:

exec 形式(推荐):CMD ["java", "-jar", "app.jar"],直接 exec,PID=1 就是你的进程,能正确接收 SIGTERM 等信号,优雅停止

CMD ["java", "-jar", "app.jar"]

shell 形式:CMD java -jar app.jar,会通过 /bin/sh -c 启动,PID=1 其实是 sh,容器停止时信号传不到应用进程,可能导致无法优雅退出

CMD java -jar app.jar
/bin/sh -c

# Dockerfile 中 COPY 和 ADD 有什么区别?

#

两者都是把文件从宿主机拷贝到镜像里,但 ADD 多了两个"魔法"功能:

自动解压:如果源文件是 tar.gz 之类的压缩包,ADD 会自动解压到目标目录

tar.gz
ADD

支持 URL:ADD 可以直接从 URL 下载远程文件到镜像里

ADD

听起来方便,但官方和 Docker 最佳实践都推荐优先使用 COPY,原因是:

COPY

ADD 的行为"太聪明"反而不透明,容易出 bug

ADD

如果需要下载远程文件,推荐用 RUN curl -fLO https://... && ... 明确写出来,行为可控

RUN curl -fLO https://... && ...

如果需要解压,在 RUN 里显式处理更清晰

RUN

简单原则:除非你明确需要 ADD 的自动解压或 URL 下载功能,否则一律用 COPY。

ADD
COPY

# 什么是多阶段构建(multi-stage build)?有什么好处?

#

多阶段构建是 Docker 17.05 引入的一个重要特性,允许在一个 Dockerfile 里写多个 FROM,每个 FROM 开启一个"构建阶段",后面的阶段可以从前面的阶段拷贝文件,但最终只有最后一个阶段的镜像会被保留。

FROM
FROM

核心价值:把"构建环境"和"运行环境"分开,大幅减小最终镜像体积。

以一个 Go 应用为例,传统做法:

FROM golang:1.21
COPY . /src
RUN cd /src && go build -o /app
CMD ["/app"]
FROM golang:1.21
COPY . /src
RUN cd /src && go build -o /app
CMD ["/app"]

问题是最终镜像里包含了整个 Go 编译器、依赖、源码,可能有 800MB+。

多阶段构建写法:

# 第一阶段:构建
FROM golang:1.21 AS builder
WORKDIR /src
COPY . .
RUN go build -o app

# 第二阶段:运行
FROM alpine:3.18
COPY --from=builder /src/app /app
CMD ["/app"]
# 第一阶段:构建
FROM golang:1.21 AS builder
WORKDIR /src
COPY . .
RUN go build -o app

# 第二阶段:运行
FROM alpine:3.18
COPY --from=builder /src/app /app
CMD ["/app"]

最终镜像只基于 alpine(5MB)加上编译好的二进制,可能只有 15MB,瘦身 50 倍。Java、Node.js、前端项目都适合用这种模式。

# 如何减小 Docker 镜像体积?

#

常见手段,面试可以组合说出:

选小的基础镜像:用 alpine(5MB)代替 ubuntu(70MB+),用 openjdk:17-jre-slim 代替 openjdk:17

alpine
ubuntu
openjdk:17-jre-slim
openjdk:17

多阶段构建:构建和运行分离,最终镜像只保留运行所需的产物

合并 RUN 指令:每条 RUN 都会产生一个新层,用 && 把多个命令合并成一条 RUN,减少层数

RUN
&&
RUN

清理构建中间产物:在同一条 RUN 里装完包就立刻清理缓存,例如:RUN apt-get update && apt-get install -y curl \

&& rm -rf /var/lib/apt/lists/*

RUN
RUN apt-get update && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*

使用 .dockerignore:像 .gitignore 一样,排除不需要 COPY 进镜像的文件(比如 node_modules、.git、日志文件)

.dockerignore
.gitignore
node_modules
.git

避免在镜像里装无关调试工具:调试工具应该在需要时 docker exec 临时装,不该塞进生产镜像

docker exec

# Docker 容器数据持久化有哪些方式?

#

容器本身是"用完即扔"的,想持久化数据必须用外部存储。Docker 提供三种方式:

Volume(数据卷):Docker 官方推荐。由 Docker 管理,默认存储在宿主机的 /var/lib/docker/volumes/ 下,可以用 docker volume 系列命令管理,最通用也最推荐。docker run -v mydata:/app/data myimage

/var/lib/docker/volumes/
docker volume
docker run -v mydata:/app/data myimage
docker run -v mydata:/app/data myimage

Bind Mount(目录挂载):把宿主机的任意路径直接挂进容器,灵活但耦合宿主机路径、不利于迁移,适合开发阶段的热更新调试。docker run -v /home/user/code:/app myimage

docker run -v /home/user/code:/app myimage
docker run -v /home/user/code:/app myimage

tmpfs:挂载到宿主机内存里,容器停止数据就没了,适合存放敏感临时数据(如解密后的密钥、临时缓存)。

常见的最佳实践是:开发阶段用 bind mount 方便热更新,生产环境用 volume 保证可移植性和可管理性。

# Docker 的网络模式有哪些?

#

Docker 默认提供五种网络模式:

bridge(默认):Docker 创建一个 docker0 虚拟网桥,每个容器分配独立 IP,容器之间通过网桥通信,访问外网通过 NAT。单机多容器的默认场景。

host:容器直接使用宿主机的网络栈,不做隔离。性能最好但会和宿主机抢端口,无法在一台机器上起多个监听同一端口的容器。

none:容器没有任何网络,只有 loopback。适合完全不需要网络的纯计算任务。

container:和指定的另一个容器共享同一个网络栈(Kubernetes 里 Pod 内多个容器就是类似机制)。

overlay:跨宿主机的网络,通常在 Docker Swarm 或 Kubernetes 里使用。

日常接触最多的是 bridge,跨主机通信是 overlay。

# 同一个宿主机上的多个容器之间怎么通信?

#

有几种常见方式:

默认 bridge 网络(不推荐):通过容器的 IP 直接访问,但 IP 不固定、也不支持容器名 DNS 解析。

自定义 bridge 网络(推荐):自己创建一个网络,加入同一网络的容器之间可以直接用容器名作为 DNS 名互访:docker network create mynet

docker run -d --name redis --network mynet redis

docker run -d --name app --network mynet myapp

app 容器里可以直接通过 "redis:6379" 访问 redis

docker network create mynet
docker run -d --name redis --network mynet redis
docker run -d --name app --network mynet myapp
# app 容器里可以直接通过 "redis:6379" 访问 redis
docker network create mynet
docker run -d --name redis --network mynet redis
docker run -d --name app --network mynet myapp
# app 容器里可以直接通过 "redis:6379" 访问 redis

host 模式:所有容器共享宿主机网络,直接通过 localhost:port 访问,但失去了端口隔离。

localhost:port

通过 Docker Compose:Compose 会自动为一个 project 创建一个 bridge 网络,service 名就是容器名,互访非常方便。

生产中最常用的组合是自定义网络 + 容器名 DNS,既保留了隔离又方便访问。

# Docker Compose 是什么?什么场景用?

#

Docker Compose 是 Docker 官方提供的单机容器编排工具,用一个 YAML 文件定义一组相关服务,然后一条命令启动或停止整组服务。

典型场景:本地开发或小型单机部署一套"Web 应用 + 数据库 + 缓存"的组合。

# docker-compose.yml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - db
      - redis
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db_data:/var/lib/mysql
  redis:
    image: redis:7

volumes:
  db_data:
# docker-compose.yml
version: "3.9"
services:
  web:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - db
      - redis
  db:
    image: mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: root
    volumes:
      - db_data:/var/lib/mysql
  redis:
    image: redis:7

volumes:
  db_data:

常用命令:

docker compose up -d:后台启动所有服务

docker compose up -d

docker compose down:停止并删除所有服务

docker compose down

docker compose logs -f:实时查看日志

docker compose logs -f

docker compose ps:查看服务状态

docker compose ps

需要注意:Docker Compose 只解决单机编排;跨主机编排应该用 Docker Swarm 或者 Kubernetes。

# Docker 常用命令有哪些?

#

面试里经常让你当场说几个常用命令,下面这些是必须记住的:

镜像相关:

docker pull <image>:拉镜像

docker pull <image>

docker images:列出本地镜像

docker images

docker rmi <image>:删除镜像

docker rmi <image>

docker build -t name:tag .:基于当前目录的 Dockerfile 构建镜像

docker build -t name:tag .

容器相关:

docker run -d -p 8080:80 --name web nginx:启动一个后台容器

docker run -d -p 8080:80 --name web nginx

docker ps:查看运行中的容器(加 -a 看所有)

docker ps
-a

docker stop / start / restart <container>:停止 / 启动 / 重启

docker stop / start / restart <container>

docker rm <container>:删除容器

docker rm <container>

docker logs -f <container>:查看日志(-f 实时跟踪)

docker logs -f <container>
-f

docker exec -it <container> bash:进入容器

docker exec -it <container> bash

docker inspect <container>:查看详细信息(JSON 格式)

docker inspect <container>

docker stats:查看容器资源占用

docker stats

系统相关:

docker system df:查看 Docker 占用了多少磁盘

docker system df

docker system prune:清理无用资源

docker system prune

# 如何进入一个运行中的容器?

#

最常用的方式是 docker exec:

docker exec
docker exec -it <container> bash
# 如果镜像里没有 bash(比如 alpine 只有 sh)
docker exec -it <container> sh
docker exec -it <container> bash
# 如果镜像里没有 bash(比如 alpine 只有 sh)
docker exec -it <container> sh

参数含义:

-i:交互式(保留 stdin)

-i

-t:分配一个伪终端(TTY)

-t

bash / sh:要在容器里运行的 shell

bash
sh

另一个老办法是 docker attach,但不推荐——attach 进去后按 Ctrl+C 会直接杀掉容器的主进程,非常容易误操作。

docker attach

docker exec 是在容器里启动一个新的进程,退出时不会影响容器主进程,安全得多,面试里的推荐答案就是 exec。

docker exec

# 容器启动后立刻退出,怎么排查?

#

这是生产里超级高频的场景,常见原因和排查步骤:

先看日志:docker logs <container> 或 docker logs --tail 100 <container>,大部分问题从日志就能看出来(依赖缺失、端口冲突、配置错误)

docker logs <container>
docker logs --tail 100 <container>

看退出码:docker ps -a 的 STATUS 列会显示 Exited (X) 的退出码。0 是正常退出,137 通常是 OOM 被杀(128+9),139 是段错误,其他非 0 就是应用报错

docker ps -a
Exited (X)
0
137
139

思考 PID=1 问题:Docker 容器里主进程必须是前台运行的——如果启动命令是一个后台化的程序(比如写成 nginx 而不是 nginx -g 'daemon off;'),主进程启动完立刻退出,容器也就跟着结束了

nginx
nginx -g 'daemon off;'

临时用 shell 进去调试:如果容器一启动就挂,可以临时把 ENTRYPOINT 覆盖成 shell 进去查看:docker run -it --entrypoint sh <image>

进去之后手动执行原来的启动命令,看看到底报什么错

ENTRYPOINT
docker run -it --entrypoint sh <image>
docker run -it --entrypoint sh <image>

检查资源限制:是否因为 cgroups 内存限制太小被 OOM Killer 杀掉(docker inspect 能看到 OOMKilled: true)

docker inspect
OOMKilled: true

# docker commit 和 docker build 有什么区别?

#

docker commit
docker build

两者都能得到一个新镜像,但使用场景和推荐度完全不同:

docker commit <container> <image>:把一个正在运行的容器的当前状态打包成镜像,相当于"快照"。过程是手动的、隐式的,镜像里到底发生了什么只有操作者自己知道。

docker commit <container> <image>

docker build -f Dockerfile -t <image> .:根据 Dockerfile 脚本自动构建镜像。过程是可复现、可追溯、可版本控制的。

docker build -f Dockerfile -t <image> .

生产环境一定要用 docker build,因为:

docker build

Dockerfile 可以提交到 Git,方便团队协作和代码审查

构建过程完全自动化,随时可以从代码重新构建出一模一样的镜像

镜像层结构清晰,每一层对应一条指令,便于排查

docker commit 只在临时调试时用:比如你在容器里手动改了点东西想快速保存验证一下——事后还是要把这些改动沉淀回 Dockerfile。

docker commit

# docker run 的常用参数有哪些?

#

docker run

面试里经常让你现场写一条 docker run,这几个参数必须会:

docker run

-d:后台运行(detached)

-d

-it:交互式 + 分配终端,通常一起用

-it

-p 8080:80:端口映射(宿主机:容器)

-p 8080:80

-v /host:/container 或 -v volname:/container:目录/数据卷挂载

-v /host:/container
-v volname:/container

--name web:给容器起个名字

--name web

--network mynet:指定容器网络

--network mynet

-e KEY=VALUE:设置环境变量

-e KEY=VALUE

--rm:容器停止后自动删除(适合一次性任务)

--rm

--restart always / unless-stopped:自动重启策略

--restart always / unless-stopped

-m 512m --cpus=1:内存/CPU 资源限制

-m 512m --cpus=1

-u 1000:1000:以非 root 用户运行

-u 1000:1000

一个典型的生产启动命令:

docker run -d \
  --name myapp \
  -p 8080:8080 \
  -v mydata:/app/data \
  -e SPRING_PROFILES_ACTIVE=prod \
  --restart unless-stopped \
  --network mynet \
  -m 1g --cpus=2 \
  myapp:1.0.0
docker run -d \
  --name myapp \
  -p 8080:8080 \
  -v mydata:/app/data \
  -e SPRING_PROFILES_ACTIVE=prod \
  --restart unless-stopped \
  --network mynet \
  -m 1g --cpus=2 \
  myapp:1.0.0

# Docker 和 Kubernetes 是什么关系?

#

这是云原生面试的高频题。一句话总结:Docker 负责"怎么把一个容器跑起来",Kubernetes 负责"怎么把一大堆容器跨多台机器跑起来、管起来"。

再具体一点:

Docker 是一个容器运行时和镜像构建工具,解决的是"单机上如何打包、分发、运行一个容器"的问题。

Kubernetes(K8s) 是一个容器编排系统,解决的是"跨多台机器如何调度、扩缩容、自愈、负载均衡、服务发现、配置管理、发布回滚"的问题。

两者不是竞争关系,而是上下游关系:K8s 需要一个底层容器运行时来实际运行容器。历史上 K8s 默认用 Docker 作为运行时,但从 Kubernetes 1.24 起,K8s 已经移除了对 Docker Engine 的直接支持(dockershim),改用符合 CRI 规范的运行时,比如 containerd、CRI-O。不过:

用 docker build 打出来的镜像依然可以在 K8s 上跑(因为镜像格式遵循 OCI 标准)

docker build

开发者日常还是用 Docker 来构建镜像和本地调试

所以简单记:Docker 管"容器本身",K8s 管"容器集群"。

# 如何清理 Docker 的无用镜像、容器和卷?

#

Docker 用久了磁盘占用会越来越大,主要是"悬空镜像(dangling images)"、停止的容器、没人用的卷堆积。常见清理命令:

清理停止的容器:docker container prune

docker container prune

清理悬空镜像:docker image prune

docker image prune

清理所有无用镜像(包括没被任何容器使用的):docker image prune -a

docker image prune -a

清理无用的卷:docker volume prune

docker volume prune

清理无用的网络:docker network prune

docker network prune

一键清理所有无用资源(最常用):

docker system prune                 # 清理停止容器、悬空镜像、无用网络
docker system prune -a              # 加 -a 顺带清理没被使用的所有镜像
docker system prune -a --volumes    # 再加 --volumes 顺带清理无用卷
docker system prune                 # 清理停止容器、悬空镜像、无用网络
docker system prune -a              # 加 -a 顺带清理没被使用的所有镜像
docker system prune -a --volumes    # 再加 --volumes 顺带清理无用卷

清理前可以先用 docker system df 查看占用分布:

docker system df
docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          45        12        12.3GB    8.7GB (70%)
# Containers      18        5         123MB     45MB (36%)
# Local Volumes   23        8         2.1GB     1.4GB (66%)
docker system df
# TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
# Images          45        12        12.3GB    8.7GB (70%)
# Containers      18        5         123MB     45MB (36%)
# Local Volumes   23        8         2.1GB     1.4GB (66%)

生产环境建议在 CI/CD 流水线或定时任务里定期执行清理,避免磁盘爆满导致容器无法启动。

最新的图解文章都在公众号首发,别忘记关注哦!!如果你想加入百人技术交流群,扫码下方二维码回复「加群」。

img