技巧与杂项 — 清理、限额、非 root、套接字与扫描
技巧与杂项 — 清理、限额、非 root、套接字与扫描
这一章是一盒工具,但有三个主题比工具重要: 清理的纪律(什么能批量删、什么只能 逐个删)、限额的原理(cgroup 的驾驶舱)、最小权限(非 root、套接字、漏洞扫描)。 主线例子:一个被 stress 工具压测的容器,亲眼看内存撞到 512 MiB 的墙停住—— 配额不是配置项,是看得见的物理约束。
1. 清理:prune 系列与那条"卷要逐个删"的纪律
停掉的容器、没用的卷都会吃磁盘。批量清理的命令是 docker container prune --force
和 docker image prune;但卷不一样:书里的警告用了很强的措辞——
docker volume prune 会删除所有没有容器在用的本地卷,不可逆,建议不要加 -f,
让 CLI 弹出的 WARNING 给你"第二次思考的机会";生产或类生产环境干脆别用 prune,
一个卷一个卷地 docker volume rm <name>1。
道理在第 05 章已经埋过:容器层的数据丢了可以重建,卷里的数据常常活不过、 也复制不出第二次。清理纪律的本质是:分清"缓存类资源"(可批量删)和"状态类资源" (只能点名删)。
2. .dockerignore:一份文件,三重收益
.dockerignore 告诉 Docker 构建时忽略哪些文件,机制照抄 .gitignore2。三重收益:
- 构建提速:构建上下文里的大文件(日志、缓存)不再被打包发送给守护进程;
- 安全:防止
.env之类带私钥的文件混进镜像; - 镜像瘦身:无关文件不进层3。
写法示例(书里给的"先全拒再放行"模式,粒度可控):
# 全部忽略
**
# 只放行这两个目录
!my-app/
!scripts/
# 放行目录内再精确排除
my-app/*.log
scripts/temp/3. 一次性管理任务:不写安装,只租容器
机子上没装 Perl,但要跑一个 Perl 脚本怎么办?书里的答案:别装,租一个容器:
$ docker container run --rm -it \
-v $(pwd):/usr/src/app -w /usr/src/app \
perl:slim sh -c "cat sample.txt | perl -lpe 's/^\s*//'"
↑ 官方镜像 perl:slim;挂载当前目录;--rm 跑完即焚
输出:行首空白全部剥掉;宿主机上 Perl 一个字节都没装[^4]更狠的用法在 Tip 里:老脚本与新版 Perl 不兼容?直接拉老版本标签的镜像跑,
不用在宿主机上养多个 Perl 版本4。Python 脚本同理(python:3-alpine 一行起)。
书里的点评是这一节的题眼:这些脚本"现在能在任何装 Docker 的机器上跑,不管什么 OS"5——
第 01 章的 anywhere,在工具脚本尺度上又应验了一次。
4. 主线例子:资源限额,cgroup 的驾驶舱
$ docker container run --rm -it --name stress-test \
--memory 512M ubuntu:22.04 /bin/bash
容器里:apt-get install -y stress && stress -m 3
↑ stress -m 3:开 3 个进程,各按 256 MiB 块 malloc 内存
另一个终端:docker stats
→ MEM USAGE 一路逼近 LIMIT(512 MiB)——但永远不会超过
→ Docker 靠 Linux cgroups 强制执行这个上限[^7]| 限额 | 参数 | 书里演示的现象 |
|---|---|---|
| 内存 | --memory 512M | MEM USAGE 顶到 LIMIT 停住6 |
| CPU | --cpus=0.5 | 同样的 stress,CPU 负载 50% 而非 100%7 |
| 磁盘 I/O | --blkio-weight=900/100(权重 10–1000) | 两个容器争 I/O 时按权重分配(仅 Linux;macOS/Windows 的 Desktop VM 不暴露 blkio 控制器,会失败)8 |
| 进程数 | --pids-limit=10 | 循环 fork 到约 10 个进程后:fork: retry: Resource temporarily unavailable——防 fork 炸弹式 DoS9 |
为什么这组实验重要: 第 01/03 章说 cgroup"防止吵邻居",这里是亲眼看它工作—— 限额不是建议,是内核强制。开发机上不加限额的容器,就是等着被某个内存泄漏拖垮全家。
5. 别用 root 跑容器
多数应用不需要 root,默认却是 root。书里的对照实验10:
默认(root): whoami → root;touch /root-owned-file → 成功;id → uid=0
--user nobody: whoami → nobody;touch → Permission denied;id → uid=65534收益一句话:防提权——攻击者破了应用,也拿不到容器内 root,更难向宿主机逃逸11。
生产做法是在 Dockerfile 里建专用用户并以 USER appuser 收尾;--user 适合
快速演示和临时覆盖12。
6. 容器里跑 Docker:挂套接字,别 DinD
想在容器里做 Docker 自动化(Jenkins 之类)?书里的正统做法:把宿主机的 Docker socket 挂进容器,再装个 Docker CLI——CLI 通过 socket 指挥宿主机上的 Engine,容器里跑的是客户端,不是引擎:
$ docker image pull docker:cli
$ docker run --rm -it \
-v /var/run/docker.sock:/var/run/docker.sock \
docker:cli sh
→ 容器里 docker container ls / image ls / run hello-world 全部可用[^14]书里特意划清了界限:这套不是 Docker-in-Docker。真正的 DinD(容器里跑 Engine)
一般不推荐,四个理由:要特权模式或挂 socket,被攻破等于交出宿主机的守护进程;
存储/网络/命名空间的嵌套依赖易冲突;多一层虚拟化有性能损耗;
嵌套容器不继承父容器的资源限额,可能超额争抢13。
(Windows 对应物是命名管道 \\.\pipe\docker_engine,作用相同14。)
7. 别打碎构建缓存(再看一遍)
本章把第 04 章的缓存铁律又敲了一遍,这回的反面教材是"COPY . 在 npm install 之前"—— 任何源码变动都让缓存从 COPY 那层开始全线失效,慢几分钟的 npm install 每次重跑; 修法照旧:先 COPY package.json、再 npm install、最后 COPY 其余。 书里的承诺很直白:改代码后的重建时间"降到几分之一秒"15。
8. 扫漏洞:CVE 是什么、用什么扫、扫出来怎么办
CVE(Common Vulnerabilities and Exposures,公共漏洞与暴露) 是一个公开的 信息安全问题数据库,每条漏洞有唯一编号,由专家持续更新16。关键事实是动态的: 今天没问题的库,明天可能因新披露的 CVE 变得有问题——所以扫描要例行,不是一次性17。
四条扫描路线(书里并列给出)18:
- 漏洞扫描:Clair、Anchore、Trivy(对照已知漏洞库);
- secrets 扫描:AquaSec、Sysdig(抓误打包进镜像的私钥、密码);
- 两者兼备:Docker Bench for Security(几十项部署基线检查);
- 合规评估:OpenSCAP。
两个实操例子。Snyk:npm install -g snyk → snyk auth →
snyk test --docker <镜像>(也能 --file=Dockerfile 扫构建文件);
snyk protect 能自动修,但免费版不含19。
Docker Scout(Docker Desktop 自带):docker scout cves gnschenker/whoami-python:1.0
扫出一个基于 python:3.8.14-slim-buster 的镜像带 3 个 critical 漏洞;
修法朴素得可爱——把基础镜像换成 python:3.14-slim,重建,再扫,干净了20。
应用代码一行没改,这就是"基础镜像是供应链"的实战含义。
9. 整个开发环境住进容器
收尾的一招:VS Code 的 Remote Development 扩展 + Dev Container——
"Open Folder in Container",选 From Dockerfile,VS Code 会起一个容器、
把 VS Code Server 装进容器,只有 UI 留在宿主机;状态栏左下角变成
Dev Container: Existing Dockerfile @ <路径>。于是,一台只装了 Docker Desktop、
没装 Java 的工作站,秒变 Java 开发机,代码文件还在宿主机上21。
这和第 02 章装 Cursor 那段对照着看:编辑器已经演化成"宿主 UI + 容器内核"的分体结构。
10. 作者的判断与证据
- "卷用 prune 是高危操作":纪律性判断,依据是不可逆 + 数据常是关键业务数据1。
- "DinD 不推荐":四条理由(安全/稳定/性能/资源)都成立,且与业界共识一致13。
- "非 root + USER appuser":安全配置基线,与第 13 章加固清单同源12。
- 扫描演示是完整闭环(扫出 critical → 换基础镜像 → 重建 → 复扫),是本章证据最硬的一段20。
11. 边界与局限
- blkio 限额在 macOS/Windows 上不可用(Desktop VM 不暴露控制器)——书里明说, 演示需 Linux 真机8。
- Snyk/Docker Scout 的界面与免费额度随时变,照书操作前先核对当前版本。
- DinD 在 CI 场景(嵌套 Docker 构建)其实有合法席位,书里一刀切"不推荐"略保守; 现代 CI 更常用 rootless BuildKit 或挂 socket 的 dind 变体(补充,不在书里,来自通用知识)。
- Dev Container 一节依赖 VS Code 插件生态,版本差异大(书中自己提醒)21。
12. 可带走的
- 容器/镜像可 prune,卷只能点名删;prune 不加 -f,给警告留机会1。
- .dockerignore = 提速 + 防泄密 + 瘦身,写法照 .gitignore23。
- 一次性脚本用容器跑(
--rm+ 挂目录),连"老版本解释器"问题一起解决224。 - 四个限额参数 --memory/--cpus/--blkio-weight/--pids-limit;docker stats 亲眼看生效69。
- 容器别跑 root;生产在 Dockerfile 里
USER appuser1112。 - 容器内自动化 Docker = 挂 docker.sock + docker:cli 镜像;真 DinD 不推荐1413。
- 缓存铁律再强调:依赖清单先 COPY,慢指令前置15。
- CVE 是动态数据库,扫描要例行;扫出 critical,先换基础镜像重建再复扫1720。
13. 原文地图
| 主题 | 原书章 | 原文位置 |
|---|---|---|
| prune 与卷纪律 | Using a .dockerignore file | text/89-fm-using-a-dockerignore-file.txt:8(搜「prune --force」) · text/89-fm-using-a-dockerignore-file.txt:22(搜「docker volume prune」) · text/89-fm-using-a-dockerignore-file.txt:27(搜「second chance」) |
| .dockerignore 三重收益 | Using a .dockerignore file | text/89-fm-using-a-dockerignore-file.txt:43(搜「ignore certain files」) · text/90-fm-executing-simple-admin-tasks-in-a-container.txt:2(搜「speed up the build」) · text/90-fm-executing-simple-admin-tasks-in-a-container.txt:5(搜「sensitive information」) |
| Perl 一次性容器 | Executing simple admin tasks in a container | text/90-fm-executing-simple-admin-tasks-in-a-container.txt:74(搜「perl:slim」) · text/90-fm-executing-simple-admin-tasks-in-a-container.txt:92(搜「without leaving any traces」) |
| 老版本脚本容器 | Executing simple admin tasks in a container | text/90-fm-executing-simple-admin-tasks-in-a-container.txt:96(搜「hasn't convinced you」) · text/90-fm-executing-simple-admin-tasks-in-a-container.txt:105(搜「old-version」) |
| Python 一次性容器 | Executing simple admin tasks in a container | text/90-fm-executing-simple-admin-tasks-in-a-container.txt:130(搜「python:3-alpine」) · text/90-fm-executing-simple-admin-tasks-in-a-container.txt:142(搜「any OS」) |
| 内存限额实验 | Limiting the resource usage of a container | text/91-fm-limiting-the-resource-usage-of-a-container.txt:11(搜「--memory 512M」) · text/91-fm-limiting-the-resource-usage-of-a-container.txt:28(搜「stress -m 3」) · text/91-fm-limiting-the-resource-usage-of-a-container.txt:34(搜「never exceeds」) · text/91-fm-limiting-the-resource-usage-of-a-container.txt:35(搜「cgroups」) |
| CPU 限额 | Limiting the resource usage of a container | text/91-fm-limiting-the-resource-usage-of-a-container.txt:46(搜「--cpus」) · text/91-fm-limiting-the-resource-usage-of-a-container.txt:63(搜「50%」) |
| blkio 与平台限制 | Limiting the resource usage of a container | text/91-fm-limiting-the-resource-usage-of-a-container.txt:70(搜「macOS」) · text/92-fm-avoiding-running-a-container-as-root.txt:3(搜「blkio-weight=100」) |
| pids-limit | Avoiding running a container as root | text/92-fm-avoiding-running-a-container-as-root.txt:10(搜「fork bombs」) · text/92-fm-avoiding-running-a-container-as-root.txt:21(搜「Resource temporarily unavailable」) |
| 非 root 对照 | Avoiding running a container as root | text/92-fm-avoiding-running-a-container-as-root.txt:34(搜「minimal necessary privileges」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:2(搜「whoami」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:20(搜「Permission denied」) |
| 非 root 收益与 USER | Running Docker CLI commands from within Docker | text/93-fm-running-docker-cli-commands-from-within-docker.txt:29(搜「privilege escalation」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:31(搜「USER」) |
| docker.sock 挂载 | Running Docker CLI commands from within Docker | text/93-fm-running-docker-cli-commands-from-within-docker.txt:43(搜「bind-mount Linux sockets」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:53(搜「docker:cli」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:59(搜「docker.sock」) |
| DinD 四理由 | Running Docker CLI commands from within Docker | text/93-fm-running-docker-cli-commands-from-within-docker.txt:89(搜「not talking about」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:94(搜「generally not recommended」) · text/93-fm-running-docker-cli-commands-from-within-docker.txt:98(搜「Security」) |
| 缓存失效复盘 | Scanning for vulnerabilities and secrets | text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:5(搜「weak point」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:11(搜「busts」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:29(搜「fraction of a second」) |
| CVE 定义与动态性 | Scanning for vulnerabilities and secrets | text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:34(搜「CVEs」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:45(搜「suddenly be vulnerable」) |
| 扫描工具四路线 | Scanning for vulnerabilities and secrets | text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:53(搜「Clair」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:55(搜「AquaSec」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:58(搜「Docker Bench」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:60(搜「OpenSCAP」) |
| Snyk 与 Scout 实操 | Scanning for vulnerabilities and secrets | text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:82(搜「snyk test --docker」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:116(搜「scout version」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:129(搜「scout cves」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:136(搜「three critical」) · text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:143(搜「3.8.14-slim-buster」) |
| 换基础镜像修复 | Scanning for vulnerabilities and secrets | text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:146(搜「3.14-slim」) · text/96-fm-running-your-development-environment-in-a-contai.txt:1(搜「free from critical」) |
| Dev Container | Running your development environment in a container | text/96-fm-running-your-development-environment-in-a-contai.txt:13(搜「development environment inside a container」) · text/96-fm-running-your-development-environment-in-a-contai.txt:31(搜「Open Folder in Container」) · text/96-fm-running-your-development-environment-in-a-contai.txt:53(搜「Dev Container」) · text/96-fm-running-your-development-environment-in-a-contai.txt:58(搜「only the UI」) |
Footnotes
-
出处:「Using a .dockerignore file」第 1–38 段(
text/89-fm-using-a-dockerignore-file.txt:22,搜「docker volume prune」;:26,搜「second chance」;:30,搜「abstain」)。 ↩ ↩2 ↩3 -
出处:「Using a .dockerignore file」第 42–49 段(
text/89-fm-using-a-dockerignore-file.txt:43,搜「ignore certain files」;:46,搜「.gitignore」)。 ↩ ↩2 -
出处:「Executing simple admin tasks in a container」第 1–25 段(该节开头因转码顺序位于本文件:
text/90-fm-executing-simple-admin-tasks-in-a-container.txt:2,搜「speed up the build」;:4,搜「sensitive information」;:6,搜「minimal」)。 ↩ ↩2 -
出处:「Executing simple admin tasks in a container」第 95–107 段(
text/90-fm-executing-simple-admin-tasks-in-a-container.txt:97,搜「your-old-perl-script.pl」;:105,搜「old-version」)。 ↩ ↩2 -
出处:「Executing simple admin tasks in a container」第 139–142 段(
text/90-fm-executing-simple-admin-tasks-in-a-container.txt:142,搜「any OS」)。 ↩ -
出处:「Limiting the resource usage of a container」第 5–43 段(
text/91-fm-limiting-the-resource-usage-of-a-container.txt:11,搜「--memory 512M」;:23,搜「MEM USAGE」;:28,搜「stress -m 3」;:34,搜「never exceeds」;:35,搜「cgroups」)。 ↩ ↩2 -
出处:「Limiting the resource usage of a container」第 45–66 段(
text/91-fm-limiting-the-resource-usage-of-a-container.txt:46,搜「--cpus flag」;:53,搜「--cpus=0.5」;:63,搜「50%」)。 ↩ -
出处:「Limiting the resource usage of a container」第 68–73 段(
text/91-fm-limiting-the-resource-usage-of-a-container.txt:70,搜「macOS」;:72,搜「fail」)。 ↩ ↩2 -
出处:「Avoiding running a container as root」第 9–28 段(该节开头因转码顺序位于本文件:
text/92-fm-avoiding-running-a-container-as-root.txt:10,搜「fork bombs」;:15,搜「--pids-limit=10」;:21,搜「Resource temporarily unavailable」)。 ↩ ↩2 -
出处:「Avoiding running a container as root」第 30–47 段与「Running Docker CLI commands from within Docker」开头(
text/92-fm-avoiding-running-a-container-as-root.txt:34,搜「minimal necessary privileges」;text/93-fm-running-docker-cli-commands-from-within-docker.txt:2,搜「whoami」;:4,搜「uid=0」;:18,搜「Permission denied」)。 ↩ -
出处:「Running Docker CLI commands from within Docker」第 27–35 段(该节开头因转码顺序位于本文件:
text/93-fm-running-docker-cli-commands-from-within-docker.txt:29,搜「privilege escalation」)。 ↩ ↩2 -
出处:「Running Docker CLI commands from within Docker」第 31–35 段(
text/93-fm-running-docker-cli-commands-from-within-docker.txt:31,搜「dedicated non-root user」;:32,搜「USER」)。 ↩ ↩2 ↩3 -
出处:「Running Docker CLI commands from within Docker」第 87–114 段(
text/93-fm-running-docker-cli-commands-from-within-docker.txt:89,搜「not talking about running the Docker Engine」;:94,搜「generally not recommended」;:98,搜「Security」;:102,搜「Stability」;:106,搜「Performance」;:110,搜「Resource management」)。 ↩ ↩2 ↩3 -
出处:「Running Docker CLI commands from within Docker」第 38–85 段(
text/93-fm-running-docker-cli-commands-from-within-docker.txt:43,搜「bind-mount Linux sockets」;:53,搜「docker:cli」;:59,搜「docker.sock」;:74,搜「named pipe」)。 ↩ ↩2 -
出处:「Scanning for vulnerabilities and secrets」第 1–31 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:5,搜「weak point」;:12,搜「busts」;:24,搜「package.json」;:29,搜「fraction of a second」)。 ↩ ↩2 -
出处:「Scanning for vulnerabilities and secrets」第 33–43 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:36,搜「publicly known」;:38,搜「uniquely identifies」)。 ↩ -
出处:「Scanning for vulnerabilities and secrets」第 43–50 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:45,搜「suddenly be vulnerable」;:49,搜「routinely」)。 ↩ ↩2 -
出处:「Scanning for vulnerabilities and secrets」第 51–63 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:53,搜「Clair」;:55,搜「AquaSec」;:58,搜「Docker Bench for Security」;:60,搜「OpenSCAP」)。 ↩ -
出处:「Scanning for vulnerabilities and secrets」第 66–108 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:74,搜「npm install -g snyk」;:82,搜「snyk test --docker」;:89,搜「--file」;:99,搜「snyk protect」;:107,搜「paid plan」)。 ↩ -
出处:「Scanning for vulnerabilities and secrets」第 110–160 段(
text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:116,搜「scout version」;:129,搜「scout cves」;:136,搜「three critical」;:143,搜「3.8.14-slim-buster」;:146,搜「3.14-slim」)。 ↩ ↩2 ↩3 -
出处:「Running your development environment in a container」第 7–59 段(
text/96-fm-running-your-development-environment-in-a-contai.txt:13,搜「code editor and debugger」;:31,搜「Open Folder in Container」;:53,搜「Dev Container」;:58,搜「only the UI」)。 ↩ ↩2 -
出处:「Executing simple admin tasks in a container」第 27–93 段(
text/90-fm-executing-simple-admin-tasks-in-a-container.txt:74,搜「perl:slim」;:80,搜「perl -lpe」;:91,搜「without leaving any traces」)。 ↩