第一章:容器到底是什么
如果你想从 0 到 1 理解 Docker第一步不是安装 Docker不是背docker run命令也不是研究镜像仓库而是先回答一个问题容器到底是什么这个问题如果一开始答歪了后面所有东西都会变成一堆零散概念但如果这个问题答对了后面的 namespace、cgroups、rootfs、overlayfs、runc、containerd 都会顺起来。这一章的目标就是建立一个最核心的认识容器本质上不是虚拟机而是宿主机上的进程。注意这不是一句比喻而是接近 Linux 内核现实的说法。1.1 先从“程序”和“进程”说起在理解容器之前你必须先分清“程序”和“进程”。程序是磁盘上的静态文件比如/bin/bash/usr/sbin/nginxpythonredis-server它们只是文件还没有真正运行。进程则是程序被操作系统加载到内存之后的运行实例。进程有很多运行时属性比如PID进程号内存空间打开的文件描述符当前工作目录环境变量用户身份所以你可以简单记成程序 静态文件进程 运行中的程序实例这个区分非常重要因为容器最终一定会落到“某个程序被启动成一个进程”这件事上。1.2 Docker 的第一性原理先有进程再有容器感很多初学者会自然脑补这样一个过程Docker 先创造一台小型 Linux 机器然后再在里面启动 nginx、bash、python。这个脑补不完全错但从底层原理上讲它不够准确。更接近真实原理的顺序其实是先启动一个普通 Linux 进程再给这个进程施加隔离和限制再给它准备一个独立文件系统视角于是这个进程看起来像运行在独立机器里也就是说Docker 不是先创造一台机器再把进程塞进去而是先有进程再把这个进程“包装”成容器。这是整套容器技术最重要的思维转换。1.3 容器不是一种新物种从底层看容器不是 Linux 里突然冒出来的一种神秘对象。它更像是一个普通进程被放进了特殊的运行环境里。这个“特殊运行环境”主要包括三类东西第一类隔离视图让这个进程看到的系统世界不再是宿主机完整世界而是一个局部世界。这主要依赖namespace。第二类资源限制让这个进程不能无限吃 CPU、内存、IO。这主要依赖cgroups。第三类独立文件系统视角让这个进程眼里的/看起来像自己的一套系统目录而不是直接面对宿主机根目录。这主要依赖rootfs、mount namespace、overlayfs等机制。所以我们可以先写出一个非常重要的公式容器 进程 隔离视图 资源限制 独立文件系统视角你后面学的每一章其实都是在把这个公式拆开讲。1.4 容器和虚拟机最本质的区别这是第一章里一定要讲清楚的一件事。虚拟机做的事情虚拟机是在硬件抽象层做隔离。它会虚拟出CPU内存磁盘网卡然后在这套虚拟硬件上再运行一个完整的 Guest OS。所以虚拟机内部通常有自己的内核。容器做的事情容器不是虚拟硬件。容器是在操作系统层做隔离。它不自己带一套内核而是共享宿主机 Linux 内核。所以可以把两者差异概括成一句话VM 虚拟的是硬件Container 隔离的是进程运行环境这就是为什么容器一般比虚拟机更轻、更快、启动更迅速但隔离层级通常也没有虚拟机那么重。1.5 为什么说容器本质上还是宿主机上的进程现在回到本章最重要的命题。为什么说容器本质上还是宿主机上的进程因为无论你在命令行里敲的是dockerrun nginx还是dockerrun ubuntubash最后一定都会落到一件事上宿主机 Linux 内核启动了一个真实进程。比如docker run nginx本质上会有一个 nginx 主进程跑起来docker run ubuntu bash本质上会有一个 bash 进程跑起来docker run redis本质上会有一个 redis-server 进程跑起来这些进程不是假的不是模拟出来的它们就是宿主机内核调度的真实进程只不过它们被放进了特殊的 namespace、cgroup 和 rootfs 环境里。所以“容器是进程”这句话不是说容器和进程完全一模一样而是说容器的存在基础最终还是一个或一组真实的 Linux 进程。这是你以后理解一切 Docker 现象的根。1.6 容器为什么看起来像一台机器既然容器本质上只是进程那为什么它又会看起来像一台独立机器因为这个进程被精心“布景”了。它被布景的结果是看自己的进程列表时好像只有自己和少量相关进程看自己的 hostname 时好像自己是一台独立主机看自己的网络时好像有独立网卡和 IP看自己的根目录/时好像自己拥有一整套 Linux 文件系统使用资源时又像被分配了一台小机器的 CPU / 内存额度也就是说容器的“机器感”不是来自一套独立硬件而是来自多个 Linux 内核机制叠加出的错觉。后面你会学到namespace 负责“你看到了什么世界”cgroups 负责“你最多能用多少资源”rootfs 负责“你眼中的/是什么”这些机制叠起来进程就越来越像运行在一台独立机器里。1.7 为什么容器生命周期通常和主进程绑定这是第一章另一个必须打牢的理解点。当你执行dockerrun nginxDocker 会启动一个入口命令。这个入口命令就是容器的主进程通常在容器内部被视为 PID 1。只要这个主进程还活着容器通常就被认为还在运行。一旦这个主进程退出容器通常也就结束。为什么因为容器不像虚拟机那样有一个完整独立操作系统生命周期。它更像是为某个主进程临时搭起的一套运行时上下文。这个上下文包括进程隔离网络隔离文件系统视角资源限制日志、元数据、生命周期管理主进程活着这套上下文就有意义主进程退出这套上下文通常也就该收掉了。所以不要把容器想成“永远存在的一台小电脑”而要把它想成围绕主进程搭起来的一座舞台。演员退场舞台通常也就收了。1.8 镜像不是容器容器也不是镜像初学者还很容易把这两个概念混起来。镜像 Image镜像是静态模板。它更像是一套准备好的文件系统程序及依赖默认启动配置镜像本身不运行。容器 Container容器是镜像启动后的运行实例。它包括运行中的主进程容器可写层隔离和限制环境生命周期状态所以关系更像镜像模板容器模板启动后的实例你可以把它类比成类和对象程序安装包和运行中的程序实例这个区分后面讲 Dockerfile、镜像分层时会非常重要。1.9 第一章最重要的总结如果你只记住这一章的 5 句话那就记这 5 句程序是静态文件进程是运行中的程序实例。容器本质上还是宿主机上的真实 Linux 进程。Docker 更接近真实原理的顺序是先启动进程再给进程施加隔离和限制。虚拟机虚拟的是硬件容器隔离的是进程运行环境。容器生命周期通常和主进程绑定因为容器本来就是围绕主进程搭起来的运行时上下文。如果这 5 句你已经吃透第一章就算真正过关了。1.10 第一章的自测题你可以用这几题检查自己是不是真的理解了而不是“看着像懂了”。问题 1为什么说容器不是轻量虚拟机你应该能答出因为容器不虚拟硬件也没有独立 Guest OS 和独立内核它共享宿主机 Linux 内核只是在操作系统层隔离进程运行环境。问题 2为什么说容器本质上还是进程你应该能答出因为容器运行时最终落地成宿主机上的一个或一组真实 Linux 进程这些进程被放进特殊的 namespace、cgroup 和文件系统环境里。问题 3为什么容器退出通常和主进程退出有关你应该能答出因为容器并不是一台独立存在的小机器而是围绕入口主进程搭建的运行时上下文主进程退出后容器的主要运行目标也结束了。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2438760.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!