2. Docker基础概念:镜像、容器、仓库、Docker架构
学MetaPhlAn部署,Docker是绕不开的坎。但别怕——核心概念其实就四个:镜像、容器、仓库,再加上它的整体架构。搞懂这些,后面搭建流程就顺了。
我刚开始接触Docker时,也觉得这些术语很绕。什么镜像容器的,跟虚拟机有啥区别?用过几次之后才发现,这玩意儿的设计思路其实非常简洁。说白了,就是把你的应用和它需要的环境打包成一个“箱子”,走到哪儿都能跑。
2.1 镜像——只读的“模板”
镜像是什么?你可以把它理解成一个只读的模板。就像装系统用的ISO文件,或者虚拟机用的镜像文件——但它比那些轻量得多。
镜像里包含了运行应用所需的一切:代码、运行时环境、系统库、环境变量、配置文件等等。你想想看,传统部署方式里,每次换台机器都要重新装一堆依赖,多折腾。用Docker镜像,这些依赖全部打包在一起了。
我记得刚开始学Docker时,对“分层存储”这个概念琢磨了好久。镜像不是一块整的,而是由一层一层堆叠起来的。每一层都是只读的,修改时只在最上层做增量。这样做的好处是——多个镜像可以共用底层,节省磁盘空间,拉取时也只传输差异部分。
拉取一个MetaPhlAn镜像试试看:
docker pull metaphlan/metaphlan:latest
docker images
docker images会列出你本地所有镜像。你会看到镜像的仓库名、标签(tag)、镜像ID、创建时间和大小。标签很重要,同一个镜像不同标签代表不同版本。
2.2 容器——运行的“实例”
镜像毕竟只是个静态模板,要让它干活,就得把它跑起来——跑起来的东西就叫容器。
镜像和容器的关系,说白了就像程序与进程。镜像是硬盘上的可执行文件,容器是内存里正在运行的进程。你可以从一个镜像启动多个容器,每个容器都是独立的运行环境,互不干扰。
容器在镜像的只读层之上,加了一层可写层。你在容器里做的所有修改——创建文件、安装软件包、修改配置——都写在这一层。但要注意,这一层是临时的。我就在项目里遇到过一件事:容器重启后,里面生成的分析结果全没了。嗯,从那以后,我再也不敢把重要数据放在容器内部了。
启动一个MetaPhlAn容器看看:
docker run --rm metaphlan/metaphlan:latest --help
docker ps -a
docker run从镜像启动容器。--rm表示容器退出后自动删除,适合一次性任务。docker ps -a列出所有容器(包括已停止的)。你会看到每个容器都有唯一的容器ID和名称。
2.3 仓库——镜像的“集散地”
镜像做好了,怎么分享给团队?怎么在不同机器之间传输?这就是仓库(Registry)要做的事。
仓库就是存镜像的地方,你可以把它想象成代码的GitHub——用来存储、分发和管理Docker镜像。最常用的是Docker Hub,它是Docker官方的公共仓库。企业里也常用自建的私有仓库,比如Harbor或Nexus。
我见过不少团队因为镜像标签管理混乱出过问题。曾经有个同事,没看清标签就把测试环境的镜像推到生产仓库了,结果线上服务挂了半小时。所以我的习惯是:给镜像打标签时一定要规范,比如project/env:version这种格式。
从仓库拉取和推送镜像的命令:
docker pull metaphlan/metaphlan:latest
docker tag metaphlan/metaphlan:latest my-registry:5000/metaphlan:v1
docker push my-registry:5000/metaphlan:v1
docker pull从仓库拉镜像到本地,docker tag给镜像打新标签,docker push把镜像推送到指定仓库。公共仓库不需要认证就能拉取,但推送需要登录。
域名:端口/命名空间/镜像名:标签。如果是Docker Hub,可以省略域名部分。
2.4 Docker架构——各组件怎么配合
搞清楚了镜像、容器、仓库各自是什么,再来看它们之间怎么配合。Docker采用的是客户端-守护进程-仓库的架构,非常清晰。
我习惯用“点外卖”来比喻:你(客户端)用手机下单,餐厅厨房(守护进程)接到指令后开始做菜,食材不够了就从供应商(仓库)那里进货。做好的菜放在餐台上(镜像),送餐员取走一份(容器)送到你桌上。
下面这张图把核心组件和它们之间的关系串起来了:
整个流程其实很简单:你通过docker命令行(Client)发送指令,守护进程(Daemon)负责执行——它管理着本地的镜像和容器,需要时从仓库(Registry)拉取镜像。所有的核心工作都由Daemon完成,Client只是发号施令。
2.5 概念对比
这四个概念容易搞混,我把它们放在一张表里对比一下,你一看就明白:
| 概念 | 类比 | 是否可变 | 生命周期 | 核心作用 |
|---|---|---|---|---|
| 镜像 (Image) | ISO安装盘 / 类模板 | 只读 | 长期存在,可反复使用 | 提供应用运行的环境模板 |
| 容器 (Container) | 运行中的进程 / 实例 | 可写(临时层) | 启动→运行→停止,短暂 | 执行应用的实际环境 |
| 仓库 (Registry) | GitHub / 应用商店 | 可读写(推送时) | 长期存在,用于分发 | 存储和分发镜像 |
| Daemon | 操作系统内核 | —— | 持续运行 | 管理镜像、容器、网络、存储 |
一句话总结:镜像是打包好的环境模板,容器是模板跑起来后的实例,仓库是存模板的地方,Daemon是背后干活的引擎。