1 容器原理要回答什么
设想你维护着 1 个小型商店的订单 API。顾客提交订单,API 校验身份、计算金额,再把订单写入数据库。开发电脑上运行正常的程序,搬到云服务器后却提示缺少库;升级另 1 个服务时,又意外改变了它依赖的文件。你希望把程序需要的运行环境带走,让部署更可重复,同时让多个服务能够共用计算资源。容器正是围绕这些需要形成的运行方式。
理解容器,首先要回答 3 个问题:程序看见什么,程序能够使用多少资源,以及程序带来的文件如何组织。它们分别涉及隔离视图、资源约束和镜像文件系统。把这 3 件事分开,才能解释为什么容器内的进程编号可能从 1 开始,为什么内存超限可能结束进程,以及为什么重新创建容器后临时文件会消失。只记住“轻量虚拟机”,会把这些现象混成错误的直觉。
在常见的 Linux 容器中,订单 API 仍然是由 Linux 内核管理的进程。运行时为它准备文件系统和隔离环境,设置资源控制,再启动应用。应用读取文件、建立连接、申请内存时,最终仍向共享的内核提出请求。容器没有因为拥有独立目录和进程列表,就获得了另 1 套内核。理解这点,也就抓住了容器启动较轻便和隔离需要额外审视的共同原因。

容器镜像主要提供程序及其用户态依赖,例如解释器、动态库和配置默认值。它通常不携带启动独立操作系统所需的整套内核。镜像里出现某种发行版的目录或版本文件,说明的是用户态环境;容器能够调用哪些内核能力,仍取决于实际运行它的 Linux 内核。这也解释了为什么镜像可迁移仍有条件:处理器架构、内核功能和运行配置都可能影响结果。
把订单 API 放进容器,并没有自动完成整个云方案。对外入口和网络规则决定请求能否到达;服务身份决定它能否读取订单库;数据存储决定订单是否持久;日志和指标帮助发现故障。容器主要解决应用进程如何被打包、启动和约束。它与这些云资源协作,但不会替代数据库、身份系统或监控系统的职责。
本课把“隔离”理解为有明确对象和条件的限制。例如,“订单 API 看不到其他容器的进程”必须说明是否使用独立 PID 命名空间,也要排除额外挂载宿主机进程目录等通道。判断容器的能力时,始终追问:这是镜像提供的内容、运行配置施加的约束,还是内核实际执行的规则?这比根据容器名称推断安全性可靠得多。
2 命名空间、cgroup 与联合文件系统
Linux 的命名空间把某类系统资源组织成不同的可见范围。可以把它想成不同的通讯录:进程查询资源时,在自己的范围内看到名称和对象。不同命名空间解决不同问题,彼此并不互相代替。PID 命名空间影响进程编号和可见范围;网络命名空间提供独立的网络设备、路由等视图;挂载命名空间影响文件系统挂载的可见布局。
例如,订单 API 在自己的 PID 命名空间里可以是 PID 1,而在宿主机上又有另 1 个编号。这里有 2 种视角下的编号,对应的仍是同一个进程。宿主机通常能观察它管理的容器进程;容器里的进程列表则受到所在命名空间和进程文件系统挂载方式的影响。隔离视图并不意味着宿主机失去了管理能力,也不意味着进程被复制了 1 份。
网络命名空间让不同容器可以各自监听内部的 8080 端口,因为监听发生在不同网络范围内。外部请求如何进入,还需要端口映射、路由或服务入口。命名空间本身不会表达“订单服务只能访问订单库”这样的业务规则;允许哪些连接,需要额外的网络策略和访问控制。网络可达也不能代替数据库认证,连接成功以后仍须验证调用者的权限。
用户命名空间涉及用户和组编号的映射。有些配置可以让容器内的 UID 0 映射为宿主机上的非特权用户,但这种映射并非每个环境都会自动启用。看到容器里的 root,既不能直接推断它拥有宿主机全部权限,也不能直接认定它毫无风险。必须结合编号映射、授予的能力、可访问设备和挂载内容判断。初学阶段先记住:用户身份隔离需要检查配置。
cgroup,也就是控制组,负责把进程组织起来,进行资源统计和控制。订单 API 可以与后台报表任务使用不同的控制组,并分别设置内存、CPU 或进程数量限制。命名空间关注“看见哪些资源”,cgroup 关注“这些进程的资源使用如何受约束”。即使文件系统看上去完全独立,如果没有合适的资源限制,报表任务仍可能占满共享主机的资源。

内存限制限制的是相应控制组所计费的内存使用,并不只是应用堆大小。CPU 配额限制一定时间窗口内可获得的执行时间,通常不代表独占某个核心。进程数量限制有助于约束失控的进程或线程创建。具体行为受内核、控制组版本和运行时配置影响,因此应用显示的“总内存”不能直接替代控制组限制。资源计量的细节留到需要调优时再深入。
联合文件系统则提供文件组织方式:把多个目录层组合成应用看到的文件树。常见容器存储实现会把镜像层作为只读基础,再加上当前容器的可写层。程序看到的是合并结果,而不是必须逐个打开的多套目录。这里的“只读基础”有助于复用镜像内容,但不会天然阻止容器写入自己的可写层,也不会控制挂载卷上的所有写入。
因此,不能用“用了容器”概括全部保证。需要分别说清楚启用了哪些命名空间、设置了哪些资源限制,以及哪些路径可写。运行时把这些机制组合起来,内核执行相应规则。后续遇到问题时,也可以按这 3 个方向定位:视图错误查命名空间,资源争用查控制组,文件变化查镜像层、可写层和挂载点。
3 镜像层、可写层与运行时边界
镜像可以理解为带有配置元数据的文件系统内容集合。订单 API 的镜像可能由基础用户态文件、依赖库和应用文件等层组成。镜像层能够被多个容器复用;从同一镜像启动的 2 个容器,通常各自拥有可写层。这样既便于复用已有内容,也让各个运行实例的临时改动分开。镜像标签是便于引用的名字,标签指向可以改变;需要精确复现时,应记录镜像摘要。
如果应用修改了来自只读镜像层的文件,常见的 OverlayFS 实现会先把需要修改的文件复制到上层,再对上层副本操作,这称为写时复制。应用随后读到的是上层版本。即使只改动文件的一部分,也可能引起文件级复制,因此不能凭改动字节少就判断写入开销小。具体行为还与存储驱动有关,本课只用这个模型理解常见现象。
如果应用删除来自下层的文件,联合视图通常通过上层的隐藏标记让它不再出现,下层镜像内容仍然保留。这意味着在后续镜像层中删除曾经写入的密钥,不能保证历史层中的密钥已经消失。镜像构建和运行时秘密管理应分开设计。订单库口令应由受控机制在运行时提供,而不是先写进镜像,再依靠后续删除来补救。

数据卷和绑定挂载会在指定路径提供另外的存储内容。挂载覆盖了路径后,应用看到的是挂载内容,原镜像该路径的文件不会自动与它合并。卷的数据生命周期也不等于容器可写层的生命周期。写入数据库的数据应交给有明确持久化、权限、备份和恢复策略的存储;订单 API 的临时缓存则可以放在能够丢弃的位置。选择路径前,先决定数据允许在什么情况下消失。
重启同一个尚未删除的容器,通常仍能保留其可写层;删除容器再创建新容器,则不能指望恢复旧可写层。这是 2 种不同操作。生产部署常常会替换实例,所以“刚才重启没有丢文件”并不能证明持久化方案正确。还要注意日志增长:可写层中的日志可能占用主机磁盘,而内存限制并不会顺带给它设置合适的磁盘容量限制。
启动时,运行时根据镜像和运行配置准备根文件系统,建立或加入指定命名空间,把进程放进控制组,并设置身份和权限约束,然后启动应用。这些步骤形成理解顺序,具体实现不必机械地与动画逐帧对应。运行时、镜像和内核分别承担不同职责:镜像提供内容,运行时组织启动环境,内核处理进程及其系统调用。容器引擎与底层运行时的分层将在 C27 接触。
正在运行的容器包含了启动时选择的网络、资源限制、挂载和环境配置。所以“镜像相同”不等于“运行行为相同”。同样的订单 API 镜像,挂载不同配置后可能连接不同数据库;获得不同服务身份后能访问的数据也不同。部署记录至少应把镜像版本与运行配置关联起来,否则仅保存镜像,仍无法解释某次上线为何出现权限或连接问题。
4 动手:对照一次容器与宿主机视角
下面用短暂存在的演示进程观察视角差异,不启动订单业务,也不接入真实数据库。命令面向已安装 Docker 的 Linux 测试机,镜像使用已确认来源的 Alpine 示例镜像。首次运行可能需要获取镜像;记录实际使用的摘要可以让后续结果更容易比较。这些命令用于观察已学概念,完整的镜像构建、端口发布和部署流程放到 C27。
如果使用桌面容器环境,容器往往运行在工具管理的 Linux 虚拟机中。此时你电脑的 macOS 或 Windows 终端不是下文所说的 Linux 宿主机终端,无法直接按照相同方式检查那台 Linux 的进程。只观察容器内部结果仍然有价值,但宿主机对照需要在实际承载容器的 Linux 环境中完成,不应把看不到对应进程误判成隔离机制改变了。
docker run -d --rm --name c26-view \
--network none --memory 128m --cpus 0.5 --pids-limit 64 \
--user 10001:10001 --cap-drop ALL \
--security-opt no-new-privileges=true \
alpine:3.22 sleep 600
docker exec c26-view ps -o pid,ppid,user,args
docker top c26-view -eo pid,ppid,user,args
docker inspect --format '{{.State.Pid}}' c26-view
容器内的进程列表通常会显示 PID 1 的 sleep 600,以及刚刚执行的观察进程;后者会在命令结束后退出。docker top 展示由宿主机视角得到的进程信息,编号通常不同。docker inspect 返回容器主进程在承载它的 Linux 宿主机上的 PID。把命令、时间和两侧编号记在同一张记录中,就能说明“不同编号对应同一个运行进程”,无需根据编号大小猜测。
接着观察 PID 命名空间的标识。以下第 2 条命令应在实际的 Linux 宿主机执行,数字替换为上一步得到的 PID。命名空间标识仅用于当前环境中的对照,不应跨机器比较。
docker exec c26-view readlink /proc/self/ns/pid
readlink /proc/24680/ns/pid
readlink /proc/self/ns/pid
前 2 条结果应指向同一个 PID 命名空间对象,因为它们分别从内外观察该容器的命名空间;宿主机终端自身的标识通常与它不同。若权限策略禁止访问宿主机上的相应路径,应记录访问受限,使用获准的管理入口继续观察。不要为取得演示结果而开启特权模式。这个对照证明的是命名空间关系,不能同时证明文件、网络和用户身份也完全隔离。

再查看资源配置并留下临时文件。这里查看的是运行配置,不是用压力负载验证配额;不要在共享主机上随意消耗内存来制造故障。
docker inspect --format '{{.HostConfig.Memory}} {{.HostConfig.NanoCpus}} {{.HostConfig.PidsLimit}}' c26-view
docker exec c26-view sh -c 'printf "temporary\n" > /tmp/c26-note'
docker exec c26-view stat /tmp/c26-note
docker stop c26-view
内存字段按字节显示,CPU 字段使用该接口规定的计量单位,不能把原始数值直接读成核心数量。临时文件写入当前容器的可写层。由于这里设置了 --rm,容器停止后会被移除;重新创建同名容器也不会继承这份文件。若 600 秒已经过去,演示进程可能已退出并触发清理,此时停止命令提示找不到容器是预期情况。实际配额效果与持久化验证,需要在受控测试中另外收集证据。
5 隔离强度与共享内核取舍
共享内核让容器能够复用已有的系统能力,省去为每个应用启动独立来宾内核的开销。同一主机可以承载多个服务实例,部署和替换通常比较快捷。启动时间仍受镜像获取、文件解压和应用初始化影响,不能因为采用容器就承诺固定的启动秒数。对订单 API 而言,程序建立连接池或加载配置的时间,可能比容器运行环境的准备更显著。
共享也带来共同依赖。多个容器最终依赖同一个内核,内核故障或某些主机级资源问题可能影响多个服务。cgroup 能限制多类资源消耗,但并不让所有内核对象、磁盘空间、网络链路和外部数据库都变成独占资源。因此,内存限额合理仍可能出现磁盘写满;CPU 配额足够也可能因数据库连接耗尽而超时。容量判断应沿着真实请求路径展开。
虚拟机通常让各个实例运行自己的来宾内核,通过虚拟化边界与其他实例分开。容器和虚拟机可以组合使用:云服务器提供虚拟机边界,服务器内部再运行多个容器。比较方案时,要说明比较的是哪层边界、哪些主体之间的信任关系,以及可接受的影响范围。容器之间共享内核,与不同虚拟机之间分别运行内核,是不同的风险结构,但都需要正确配置和维护。

同一团队维护的订单 API 与后台订单任务,可能允许在经过加固的主机上共同运行。面向互不信任用户提供任意代码执行服务时,则要重新评估边界,考虑独立虚拟机、沙箱等额外措施。这里的依据是执行内容和信任关系,不是服务名称。即使都叫“订单插件”,受审核的固定程序与用户上传的任意程序也有不同要求。
交互中的滑块表示要容忍的执行内容不确定性逐渐提高。它帮助比较隔离措施及管理负担,不给出安全分数,也不代表调高某个参数就完成隔离升级。资源密度、启动速度、维护成本和故障影响范围必须结合负载测量。安全边界尤其不能由简单百分比相加得到:只要仍开放了不受控的主机通道,增加其他限制也未必补得回来。
权限收缩是常见的基础措施。应用使用非 root 用户,减少不必要的 Linux capabilities,限制可调用的系统调用,结合主机访问控制,并及时更新内核与运行时,都能缩小可用攻击面。capabilities 是对传统特权能力的拆分;seccomp 可以对系统调用设置过滤规则。本课只需要识别它们的作用,具体规则编写和兼容性调试留到后续学习。
这些措施各有边界。非 root 应用如果获得了高权限云身份,仍可能读取本不该访问的订单;只读根文件系统如果另外挂载了可写目录,应用仍能修改那里的文件。设计取舍时应把本地进程权限、云端身份、网络通路和数据权限分开写清楚,再检查它们组合后的实际能力。对外声明隔离保证前,应能指出依赖哪项设置及其验证证据。
6 常见坑:把容器当虚拟机安全边界
最常见的错误,是看到独立进程列表和独立目录就推断“入侵只会留在容器里”。这些视图确实有用,但容器仍与其他容器共享内核,而且运行配置可能主动开放通道。应用发生代码执行漏洞后,攻击者能够做什么,取决于该进程实际拥有的身份、能力、挂载和网络访问范围。镜像是否精简只能影响其中部分因素。
特权模式会显著扩大容器可用能力和设备访问范围;共享宿主机 PID 或网络命名空间,会让相应视图靠近宿主机。它们有时服务于受控的管理任务,但不适合作为“遇到权限错误就打开”的默认修复。权限错误本身是一条线索:先明确应用需要完成什么操作,再判断是否可以调整目录所有者、使用专门接口或缩小挂载范围。
挂载宿主机目录时,容器中的路径只是入口,背后可能连接重要的主机文件。把目录挂载为只读,可以限制经由该挂载进行的常规写入,但不会隐藏文件里的秘密。暴露容器引擎管理接口尤其需要谨慎:持有管理能力的进程可能创建其他高权限容器或挂载主机路径,实际影响会远超它自己的可写层。不能把管理接口当作普通业务依赖随意传入。
“容器内 root 永远等于宿主机 root”与“容器内 root 永远安全”都过于简单。用户命名空间映射、capabilities 和主机安全策略会改变具体能力。稳妥的实践是让业务进程使用明确的非特权身份,并检查真实映射和文件权限。为了方便而把所有目录设成任意用户可写,通常会引入另外的篡改风险,也使不同业务进程之间的权限关系更难解释。
排查退出问题时,也容易把每次退出都归为“容器坏了”。进程可能正常结束、配置错误、接收终止信号,或因内存压力被终止。常见的退出码 137 与被 SIGKILL 终止相符,但不能单凭它判定发生了内存超限;管理操作也可能产生类似结果。应结合运行时状态、内存事件、应用日志和操作时间线,说明哪条证据支持哪种原因。

资源限制也容易被误读成服务保证。给订单 API 设置 CPU 上限,可以约束它的消耗,却不等于保证它始终获得对应吞吐;给容器设置内存上限,也不等于数据库请求延迟自动稳定。请求链上还有队列、连接池和外部服务。应同时观察业务延迟、错误率、容器资源事件与主机状态,避免只盯着 1 条“CPU 使用率不高”的曲线。
最后,日志与诊断数据也可能泄露信息。环境变量、命令行参数或排障输出中可能含有口令和访问令牌。收集证据时优先记录版本、身份引用、命名空间关系及脱敏错误,不把秘密原文当作排查材料。容器隔离没有替你决定谁能查看监控平台,也没有替你设置日志保留时间;可观测数据同样需要访问控制。
7 案例:共享 PID 命名空间泄露信号
订单 API 偶尔变慢,团队给它增加了诊断容器,以便观察进程。为了看见应用,诊断容器被配置成加入 API 的 PID 命名空间。团队认为诊断容器使用不同镜像,而且没有挂载应用目录,就不会影响业务。上线后,订单 API 在没有新版本发布的情况下开始优雅退出,入口处短暂出现请求失败,平台随后又重新启动实例。
这里的“泄露信号”指发送信号的能力越过了团队原先假设的容器边界,并非凭空把所有信号广播出去。排查发现,诊断容器里运行着旧的清理脚本,它会按进程名查找目标并发送 SIGTERM。此前脚本只在自己的进程范围内工作;共享 PID 命名空间后,它能够发现订单 API,匹配条件又过于宽泛,于是选中了业务进程。
仅仅看得见进程,还不能推出一定能向它发送信号。Linux 会检查发送者与目标的用户身份关系,或相关权限。这个案例中,2 个容器使用相同的有效 UID,且用户命名空间关系没有阻止相应权限判断,因此清理脚本具备向目标发送该信号的权限。如果身份或权限不同,发送可能失败。这个条件必须写出,否则容易把案例误学成“共享 PID 就能控制任意进程”。
API 恰好是该 PID 命名空间中的 PID 1,并安装了 SIGTERM 处理器,用于停止接收请求、等待在途请求结束,然后退出。这使误发的信号触发了正常的退出流程。命名空间内 PID 1 对部分信号有特殊处理规则,不能假设任何无处理器的演示程序都会同样退出。这里无需研究全部规则,只需认识到信号能否送达和应用如何响应,是 2 个不同问题。
证据链从应用退出日志开始:它记录了收到终止请求,却没有记录内存错误。随后检查运行时事件和控制组内存事件,没有找到相应的内存超限证据。再比对配置,发现诊断容器共享 PID 命名空间;检查经脱敏的脚本执行记录,确认它在相同时间选择了 API 进程并请求发送 SIGTERM。这些证据组合起来,才支持误发信号的判断。
不同镜像和不同可写层没有阻止这条路径,因为问题发生在进程可见性和信号权限上。内存限制也没有提供帮助,因为它约束资源消耗,不负责拒绝这种信号。这个案例说明,任何隔离保证都要落到具体机制。文件隔离、资源隔离和进程控制权限的边界不能互相代用,更不能因为界面上显示为 2 个容器,就认定它们完全独立。
修复首先撤销业务与通用诊断任务之间不必要的 PID 共享,把常规观察交给受控的日志、指标和管理入口。同时修正清理脚本的目标选择,限制诊断身份,并对确需共享的短期排障流程规定授权和回收时间。分别使用不同身份有帮助,但仍需检查能力和命名空间配置,不能把更换 UID 当作全部修复。复盘应补上“谁能够观察及控制业务进程”的明确假设。
8 把容器隔离假设写进运行时方案
运行时方案应把抽象要求翻译成可以检查的条件。对于订单 API,可以写成:应用使用独立 PID、挂载和网络命名空间;不共享宿主机 PID 视图;业务进程以指定非特权身份运行;默认不授予多余能力;根文件系统按应用兼容性设为只读;只有声明的临时目录和数据挂载允许写入。这里每条要求都对应运行配置,审查者能够确认实际值。
涉及用户命名空间时,应说明是否启用映射以及平台支持情况。涉及资源时,应列出内存上限、CPU 配额和进程数量上限的初始值、依据和调整条件。初始数值可以来自受控负载测试,但不能把测试结果当作所有流量下的保证。例如,订单促销造成更高并发时,应同时检查内存峰值和数据库连接数,再决定是调整限制还是增加实例。
数据部分需要逐个说明路径和生命周期。应用代码来自镜像;临时上传放到有容量约束的临时空间;正式订单进入外部持久化数据库;日志发送到受控的收集系统。对挂载路径记录读写权限、所有者及删除容器后的去向。挂载为只读的配置仍可能包含秘密,因此还要说明哪些进程能读取、秘密如何更新,以及更新是否要求替换实例。

服务身份应独立于 Linux UID 描述。UID 决定许多本地文件和进程操作的权限;云端服务身份决定能调用哪些云 API 或读取哪些托管资源。订单 API 只需要访问自己的订单数据,不应因运行在同一主机上就继承管理者权限。网络规则则把业务入口、数据库出口和必要的观测通道写清楚,并明确数据库端仍须验证身份。
方案还应包含异常时的证据入口。应用日志记录启动、停止原因和请求错误,敏感字段脱敏;运行时事件用于对照容器启动和退出;控制组指标用于判断资源压力;主机指标用于发现磁盘、内核或共享资源问题。记录实例标识、镜像摘要和时间,才能把这些观察关联到同一次运行。单独保存容器名称不够,因为名称可能在重建后复用。
每个例外都应有理由和期限。若临时诊断必须共享 PID 命名空间,要声明可以观察哪些进程、诊断程序使用什么身份、能否发送信号以及何时撤销。若应用暂时不能使用只读根文件系统,也要指出必须写入的路径及改造计划。把例外写具体,有助于区分业务必需条件与历史遗留配置,避免临时权限成为永久默认值。
验证时按声明逐项取证,并在配置变更后重新检查相关假设。独立 PID 视图用受控观察确认,持久化用替换实例后读取测试数据确认,云端权限用最小范围的授权检查确认。不要在生产环境通过攻击共享内核来证明隔离强度。底层边界的可信度还依赖内核、运行时维护和平台约束,需要在责任分工中明确维护者。
9 从容器原理走向Docker 实战(C27)
到这里,可以把每次部署拆成可追问的对象:镜像中有什么,启动时选择什么隔离视图,进程以什么身份运行,资源限制落在哪里,以及数据写到哪里。这些问题不会因为更换工具而消失。Docker 实战会把它们变成具体命令与配置,使你能够构建镜像、启动服务、查看状态,并通过替换实例理解可重复部署。
学习 C27 时,先区分镜像与容器。镜像是可被引用和分发的内容及配置,容器是根据这些内容和运行选项形成的运行实例。从同一镜像启动的多个实例,可以有不同的环境变量、身份、网络与挂载。修改运行中容器的文件,不会自动生成新的镜像版本;把修改手工留在实例里,也会让下一次重建难以复现。
其次区分内部监听与外部发布。应用在容器里监听 8080,说明它在所在网络范围内等待连接;外部顾客能否访问,还取决于端口发布、路由、入口配置和网络规则。访问失败时,可以沿请求方向分段检查:入口收到请求了吗,转发目标正确吗,应用确实监听了吗,数据库是否允许该身份连接。不同层的故障可能表现为相似的“打不开”。
再把停止和删除分开。停止让当前进程结束,删除则移除容器实例及相应可写层。替换部署往往同时涉及旧实例退出和新实例建立,所以应用需要正确响应终止请求,并把应长期保留的数据写入持久存储。主进程的信号处理会影响退出过程;命令包装方式也可能影响信号传递。C27 会结合真实启动方式观察这些行为,本课先保留问题意识。
遇到故障时,优先判断应用进程、运行配置还是共享主机出现问题。容器启动失败可能是命令或依赖错误;运行后超时可能是网络与身份问题;多项服务同时异常则需要关注共同资源。按层提出可验证的假设,能够减少反复重建镜像的盲目操作。运行记录越清楚,越容易说明某项调整为何有效,而不只是记住“重启后好了”。
你现在应能用自己的话回答:为什么容器内外 PID 不同却对应同一个进程;为什么内存限制不等于完整资源隔离;为什么删除下层文件不会改写历史镜像层;为什么 2 个容器共享 PID 后还需检查信号权限。如果回答仍停留在“容器很轻”或“容器很安全”,就回到具体机制,指出对象、规则与证据,再进入命令练习。
下一课使用 Docker 时,把每条命令当作本课概念的入口:构建对应文件内容,运行对应隔离和权限选择,挂载对应数据生命周期,状态查询对应证据收集。更深入的内核实现、系统调用过滤规则设计和复杂编排策略可以继续延后。先让订单 API 的部署可解释、权限可检查、数据去向明确,实战就有了稳定的判断依据。
放进方案里
订单 API 的运行方案应明确:容器镜像交付应用及用户态依赖,所有业务实例共享承载节点的 Linux 内核。发布记录保存镜像摘要与运行配置版本。应用使用独立 PID、挂载和网络命名空间,以指定非特权 UID 运行;用户编号映射按平台实际能力声明。禁止默认启用特权模式、共享宿主机 PID 或挂载容器管理接口,确需例外时记录理由、负责人和撤销时间。
资源初始预算由负载测试给出,例如每个实例设置 512 MiB 内存上限、1 个 CPU 的时间配额和 128 的进程数量上限。这些值作为试运行起点,根据内存峰值、CPU 限流事件与业务延迟调整,不能视为吞吐承诺。节点同时监测磁盘和共享资源压力;达到扩容条件时增加实例,并复查数据库连接总量,防止把压力转移到数据层。
应用代码随镜像交付,根文件系统在兼容性验证后设为只读,临时目录单独配置容量约束。正式订单保存在外部数据库,声明备份和恢复责任;日志进入受控的观测系统,不依赖容器可写层长期保留。服务通过专用云端身份访问所需资源,数据库使用独立凭据。网络仅开放业务入口、必要的数据访问和观测通路。
验收证据包括内外进程视角、实际资源配置、授权范围及替换实例后的测试数据。故障记录关联实例标识、镜像摘要、退出事件、内存事件和脱敏日志。常规诊断通过指标与日志完成;临时共享 PID 的诊断必须单独审查进程身份和信号权限。内核及运行时由平台维护者更新,业务维护者负责应用权限和数据路径;这些责任共同支撑容器隔离假设。
10 小结:下一步Docker 实战(C27)
容器把应用文件组织、隔离视图和资源控制组合成可部署的运行环境。命名空间影响看见什么,cgroup 约束和统计资源使用,镜像层与可写层决定文件如何复用和变化。共享内核提高了资源复用效率,也要求你认真检查权限、挂载、身份与共同故障范围。
进入 C27 前,选 1 个准备容器化的小服务,说清楚它的启动命令、内部监听端口、持久数据位置和所需身份。再解释删除实例后哪些内容应保留,以及谁能够终止它的进程。带着这些答案学习 Docker,命令会成为有依据的部署选择。