跳到正文
Docker:治「我机器上能跑」这桩老案子
Docker:治「我机器上能跑」这桩老案子

Docker:治「我机器上能跑」这桩老案子

装服务装到后面,系统里 Python、Java 各种库混在一起,依赖打架。这篇不讲 Docker 命令大全,讲它到底在解决什么——以及为什么我说它是 venv 那条线的延续。

速读#

Docker 治的是“我机器上能跑”背后的环境不一致,本质上是把 venv 的隔离思路放大到整个运行环境。会在多台机器、多个项目间流动的东西,第一件事都是隔离;端口绑哪里,也直接决定攻击面。

问题从哪来#

装服务装到后面,系统里 Python、Java、各种库混在一起。图省事把包都 pip install 到全局,两个项目依赖同一库的不同版本时直接打架——升级一个弄坏另一个;更坑的是坏的那个当时不报错,过几天重跑才发现。

根因一句话:全局环境谁都能往里扔,出事难追是谁破坏的。

Docker 把应用和它需要的整个环境打成镜像,换机器跑结果一样。它解决的是环境问题——而那摊烂账,往往是自己图省事堆出来的。

venv 的放大版#

venvDocker
隔离什么Python 依赖整个运行环境(系统库、运行时、配置)
治什么给 A 项目装依赖,弄坏了 B 项目我机器能跑、你机器不行

逻辑同一条:会在多台机器 / 多个项目间流动的东西,第一件事是隔离。 从 venv → Docker,只是粒度从「依赖」放大到「整个运行时」。venv 只管 Python 包,管不了系统库版本、管不了「你机器是 Debian 我机器是 CentOS」;Docker 把这些一起冻进镜像。环境和进程一样,不会自己保持干净——不主动隔离,混乱是默认结局,区别只是早晚。

镜像和容器:用类与对象理解#

概念类比说明
镜像 Image类 / 模板只读打包结果,含应用 + 依赖 + 系统库
容器 Container对象 / 实例镜像跑起来的实例,可启停销毁

一个镜像可以跑出多个容器,就像一个类 new 出多个对象。把熟悉的 OOP 概念迁过来,Docker 就不玄了——这也是「底层是通的」的一次落地。

顺着这个类比还能多推一步:类改了要重新实例化,镜像改了也要重建容器。在容器里改文件,就像给某个对象临时 patch 属性——容器一删就没了。要留下来的改动,进 Dockerfile 重新构建,或者挂载出去。

容器不是轻量虚拟机#

我最初把 Docker 理解成「启动快一点的虚拟机」,这个心智模型会误导判断:

虚拟机容器
隔离层级完整客机 OS + 虚拟硬件进程级,共享宿主内核
启动分钟级秒级
开销每台 VM 一份 OS 内存几乎只有进程本身

容器本质是被隔离的进程,不是缩小的机器。 想通这一点,很多行为就解释得通:为什么容器里主进程退出容器就停(进程没了,「机器」自然没了);为什么不该在一个容器里塞一堆服务(一个进程一个容器,才谈得上独立启停和替换)。

共享内核同时也是代价:容器的隔离边界天然比虚拟机弱,一个内核漏洞理论上波及宿主机上所有容器。我的场景里跑的都是自己的服务,这个弱边界可以接受;要隔离互不信任的负载,虚拟机仍是更硬的答案。快和轻不是白来的,知道换走了什么,用起来才踏实。

端口绑哪,直接决定攻击面#

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

-p 8080:80 把宿主机 8080 映射到容器 80。

容易忽略的一点:默认 -p 绑的是 0.0.0.0,对外暴露。 后面部署时我改成 127.0.0.1:8080:8080 只绑回环,外网进不来,一律由 Nginx 转发——这是防护面的事。

绑定方式效果
-p 8080:800.0.0.0,公网直接可达
-p 127.0.0.1:8080:80仅本机,适合反代后置

更隐蔽的一层:Docker 发布端口时直接写 iptables 规则,ufw 里的「默认拒绝」并不覆盖它。以为防火墙会兜底、实际端口已经在公网裸奔,是这里最经典的误判。所以我不把安全压在防火墙上,直接从绑定层面收住——回环之外根本不存在这个端口。

端口绑哪,直接决定攻击面。 命令会了只是起点;绑法选错,等于自己把门开大。

这篇留下的判断就两条:环境要主动隔离,别等依赖打架才动手;端口默认全网可达,有了反代之后绑回环就该是常规动作,不是可选项。

版权许可

CC BY-NC-SA 4.0 本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

相关文章

s1oopX

登录 s1oopX