编程语言研究书库

技巧与杂项 — 清理、限额、非 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。三重收益:

  1. 构建提速:构建上下文里的大文件(日志、缓存)不再被打包发送给守护进程;
  2. 安全:防止 .env 之类带私钥的文件混进镜像;
  3. 镜像瘦身:无关文件不进层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 512MMEM 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:

  1. 漏洞扫描:Clair、Anchore、Trivy(对照已知漏洞库);
  2. secrets 扫描:AquaSec、Sysdig(抓误打包进镜像的私钥、密码);
  3. 两者兼备:Docker Bench for Security(几十项部署基线检查);
  4. 合规评估: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. 可带走的

  1. 容器/镜像可 prune,卷只能点名删;prune 不加 -f,给警告留机会1。
  2. .dockerignore = 提速 + 防泄密 + 瘦身,写法照 .gitignore23。
  3. 一次性脚本用容器跑(--rm + 挂目录),连"老版本解释器"问题一起解决224。
  4. 四个限额参数 --memory/--cpus/--blkio-weight/--pids-limit;docker stats 亲眼看生效69。
  5. 容器别跑 root;生产在 Dockerfile 里 USER appuser1112。
  6. 容器内自动化 Docker = 挂 docker.sock + docker:cli 镜像;真 DinD 不推荐1413。
  7. 缓存铁律再强调:依赖清单先 COPY,慢指令前置15。
  8. CVE 是动态数据库,扫描要例行;扫出 critical,先换基础镜像重建再复扫1720。

13. 原文地图

主题原书章原文位置
prune 与卷纪律Using a .dockerignore filetext/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 filetext/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 containertext/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 containertext/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 containertext/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 containertext/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 containertext/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 containertext/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-limitAvoiding running a container as roottext/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 roottext/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 收益与 USERRunning Docker CLI commands from within Dockertext/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 Dockertext/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 Dockertext/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 secretstext/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 secretstext/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 secretstext/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 secretstext/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 secretstext/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 ContainerRunning your development environment in a containertext/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

  1. 出处:「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

  2. 出处:「Using a .dockerignore file」第 42–49 段(text/89-fm-using-a-dockerignore-file.txt:43,搜「ignore certain files」;:46,搜「.gitignore」)。 ↩ ↩2

  3. 出处:「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

  4. 出处:「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

  5. 出处:「Executing simple admin tasks in a container」第 139–142 段(text/90-fm-executing-simple-admin-tasks-in-a-container.txt:142,搜「any OS」)。 ↩

  6. 出处:「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

  7. 出处:「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%」)。 ↩

  8. 出处:「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

  9. 出处:「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

  10. 出处:「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」)。 ↩

  11. 出处:「Running Docker CLI commands from within Docker」第 27–35 段(该节开头因转码顺序位于本文件:text/93-fm-running-docker-cli-commands-from-within-docker.txt:29,搜「privilege escalation」)。 ↩ ↩2

  12. 出处:「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

  13. 出处:「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

  14. 出处:「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

  15. 出处:「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

  16. 出处:「Scanning for vulnerabilities and secrets」第 33–43 段(text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:36,搜「publicly known」;:38,搜「uniquely identifies」)。 ↩

  17. 出处:「Scanning for vulnerabilities and secrets」第 43–50 段(text/95-fm-scanning-for-vulnerabilities-and-secrets.txt:45,搜「suddenly be vulnerable」;:49,搜「routinely」)。 ↩ ↩2

  18. 出处:「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」)。 ↩

  19. 出处:「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」)。 ↩

  20. 出处:「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

  21. 出处:「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

  22. 出处:「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」)。 ↩

On this page