21、什么是半虚拟化(Paravirtualization)?
Paravirtualization,也称为第 1 类虚拟机管理(层)程序,其直接在硬件或裸机(bare-metal)上运行,提供虚拟机直接使用物理硬件的服务。
它帮助主机操作系统,虚拟化硬件和实际硬件进行协作以实现最佳性能。这种虚拟层管理技术的程序一般占用系统资源较小,其本身并不需要占用大量系统资源。
这种虚拟层管理程序有 Xen,KVM 等。
22、Docker 技术与虚拟机技术有何不同?
Docker 不是严格意义上的虚拟化硬件的技术。它依赖 container-based virtualization(基于窗口的虚拟化)的技术实现工具,或可以认为它是操作系统用户运行级别的虚拟化。
因此,Docker 最初使用 LXC 驱动它,后来移至由 libcontainer 基础库驱动它,现已更名为 runc。docker 主要致力于应用容器内的应用程序的自动化部署。
应用容器设计用于包装和运行单一服务,而操作系统设计用于运行多进程任务,提供多种运算服务的能力,如虚拟机中等同完全操作系统的能力。
因此,docker 被认为是容器化系统上管理容器及应用容器化的部署工具。
- 与虚拟机不同,容器无需启动操作系统内核,因此,容器可在不到 1 秒钏时间内运行起来。这个特性,使得容器化技术比其它虚拟化技术更具有独特性及可取性。
- 由于容器化技术很少或几乎不给主机系统增加负载,因此,基于容器的虚拟化技术具有近乎原生的性能表现。
- 基于容器的虚拟化,与其他硬件虚拟化不同,运行时不需要其他额外的虚拟管理层软件 。
- 主机上的所有容器共享主机操作系统上的进程调度,从而节省了额外的资源的需求。
- 与虚拟机 image 相比,容器(Docker 或 LXC images)镜像较小,因此,容器镜像易于分发。
- 容器中的资源分配由 Cgroups 实现。Cgroup 不会让容器占用比给它们分配的更多的资源。但是,现在其它的虚拟化技术,对于虚拟机,主机的所有资源都可见,但无法使用。这可以通过在容器和主机上同时运行 top 或 htop 来观察到。在两个环境中的输出看起来相同。
23、请解释一下 dockerfile 配置文件中的 ONBUILD 指令的用途含义?
配置文件中的 ONBUILD 指令为创建的 docker image(镜像)加入在将来执行的指令(译注:在当前配置文件生成的镜像中并不执行)。
用于在以这个创建的镜像为基础的创建的子镜像(image)中执行或定制。举例,以基镜像创建自己的镜像时,可定制创建特有的用户化的配置环境。
(译注:由于原文较短,关于这个总是容易迷惑。译者认为,总体来说,关键理解 —- 以基础镜像创建自有的镜像过程中,基础镜像中所有的创建层或指令是以整体或固化的方式导入自有镜像的。
自有镜像是不能对这个过程进行自有定制。而 ONBUILD 指令提供了将某些层从基础中剥离出来提供给之后以自有镜像为基础镜像派生新的镜像的可定制途径。
这对发布镜像而普适在不同的运行环境定制非常有用。不当之处,请指正!)
24、有否在创建有状态性的 docker 应用的较好实践?最适合的场景有什么?
有状态性 docker 应用的总是关键在于状态数据保存在哪儿的总是。若所有数据保存在容器内,当更新软件版本或想将 docker 容器移到其它机器上时,找回这些在运行中产生的状态数据将非常困难。
您需要做的是将这些表达运行状态的数据保存在永久卷中。参考如下 3 种模式:
译注:
1 图中文字:数据保存在容器中,当容器停止运行时,运行状态数据丢失!
2 图中文字:数据保存在主机卷(Host Volume)中,当主机停机时,运行状态数据将无法访问。
3 图中文字:数据保存在网络文件系统卷中,数据访问不依赖容器的运行与主机的运行。。若您使用如下命令运行您的容器:
docker run -v hsotFolder:/containerfolder
容器运行中任何对 /containerfolder 目录下数据的改变,将永久保存在主机的 hostfolder 目录下。使用网络文件系统(nfs)与此类似。
那样您就可以运行您的容器在任何主机上且其运行状态数据被保存在网络文件系统上。
25、在 windows 系统上可以运行原生的 docker 容器吗?
在 “windows server 2016” 系统上,你可以运行 windows 的有生容器,微软推出其镜像是 “windows Nano server”,一个轻量级的运行在容器中的 windows 原生容器。您可以在其中部署基于 .NET 的应用。
译注:结合 docker 的基本技术原理,参考后面的 问题 26 和问题 27,可推测,微软在系统内核上开发了对 docker 的支持,支持其闭源系统的容器化虚拟技术。
但译者认为,windows 系统本就是闭源紧耦合的系统,好像你在本机上不装 .NET 组件,各应用能很好运行似的。何必再弄个容器,浪费资源。
这只是译者自己之孔见,想喷就喷!另:windows server 2016 版本之后的都可支持这种原生 docker 技术,如windows server 2018 版。
26、在非 Linux 操作系统平台上如何运行 docker?
容器化虚拟技术概念可能来源于,在 Linux 内核版本 2.6.24 上加入的对 命名空间 (namespace)的技术支持特性。
容器化进程加入其进程 ID 到其创建的每个进程上并且对每个进程中的系统级调用进行访问控制及审查。
其本身是由系统级调用 clone() 克隆出来的进程,允许其创建属于自己命名空间的进程实例,而区别于之前的,归属与整个本机系统的进程实例。
如果上述在 Linux 系统内核上的技术实现成为可能,那么明显的问题是如何在非 Linux 系统上运行容器化的 docker。
过去,Mac 和 windows 系统上运行 docker 容器都使用 Linux 虚拟机(VMs)技术,docker 工具箱使用的容器运行在 VirtualBox 虚拟机上。
现在,最新的情况是,windows 平台上使用的是 Hyper-V 产品技术,Mac 平台上使用的是 Hypervisor.framework(框架)产品技术。
27、容器化技术在底层的运行原理?
2006 年前后,人们,包括一些谷歌的雇员,在 Linux 内核级别上实现了一种新的名为 命名空间(namespace)的技术(实际上这种概念在 FreeBSD 系统上由来已久)。
我们知道,操作系统的一个功能就是进程共享公共资源,诸如,网络和硬盘空间等。但是,如果一些公共资源被包装在一个命名空间中,只允许属于这个命名空间中的进程访问又如何呢?
也就是说,可以分配一大块硬盘空间给命名空间 X 供其使用,但是,命名空间 Y 中的进程无法看到或访问这部分资源。同样地,命名空间Y 中分配的资源,命名空间 X 中的进程也无法访问。
当然,X 中的进程无法与 Y 中的进程进行交互。这提供了某种对公共资源的虚拟化和隔离的技术。
这就是 docker 技术的底层工作原理:每个容器运动在它自己的命名空间中,但是,确实与其它运行中的容器共用相同的系统内核。
隔离的产生是由于系统内核清楚地知道命名空间及其中的进程,且这些进程调用系统 API 时,内核保证进程只能访问属于其命名空间中的资源。
图上文字说明:运行中的容器是隔离的。准确地说,各容器共享操作系统内核及操作系统 API。
28、说说容器化技术与虚拟化技术的优缺点
仅有下面的一些对比:
不能像虚拟机那样在容器上运行与主机完全不同的操作系统。 然而, 可以在容器上运行不同的 Linux 发布版,由于容器共享系统内核的缘故。容器的隔离性没有虚拟机那么健壮。
事实上, 在早期容器化技术实现上,存在某种方法使客户容器可接管整个主机系统。也可看到,载入新容器并运行,并不会像虚拟机那样装载一个新的操作系统进来。
所有的容器共享同一系统内核, 这也就是容器被认为非常轻量化的原因。同样的原因,不像虚拟机, 你不须为容器预分配大量的内存空间, 因为它不是运行新的整个的操作系统。
这使得在一个操作系统主机上,可以同时运行成百上千个容器应用, 在运行完整操作系统的虚拟机上,进行这么多的并行沙箱实验是不可能的。
29、如何使 docker 适应多种运行环境?
您必然想改变您的 Docker 应用配置以更适应现实运行环境的变化。下面包含一些修改建议:
- 移除应用代码中对任何固定存储卷的绑定,由于代码驻留在容器内部,而不能从外部进行修正。
- 绑定应用端口到主机上的不同端口。
- 差异化设置环境变量 (例如: 减少日志冗余或者使能发电子邮件)
- 设定重启策略(例如: restart: always ), 避免长时间宕机
- 加入额外的服务(例如: log aggregator)
由于以上原因, 您更需要一个 Compose 配置文件,大概叫 production.yml ,它配置了恰当的产品整合服务。 这个配置文件只需包含您选择的合适的原始 Compose 配置文件中,你改动的部分。
docker-compose -f docker-com
30、为什么 Docker compose 采取的是并不等待前面依赖服务项的容器启动就绪后再启动的组合容器启动策略?
Docker 的 Compose 配置总是以依赖启动序列来启动或停止 Compose 中的服务容器, 依赖启动序列是由 Compose 配置文件中的 depends_on , links , volumes_from 和 network_mode: “service : …” 等这些配置指令所确定的。
然而, Compose 启动中, 各容器的启动并不等待其依赖容器(这必定是你整个应用中的某个依赖的服务或应用)启动就绪后才启动。使用这种策略较好的理由如下:
等待一个数据库服务(举例)就绪这样的问题, 在大型分布式系统中仅是相比其它大问题的某些小问题。
在实际发布产品运维中, 您的数据库服务会由于各种原因,或者迁移宿主机导致其不可访问。 您发布的产品需要有应对这样状况的弹性。
掌控这些, 开发设计您的应用, 使其在访问数据库失效的情况下, 能够试图重连数据库, 直至其连接到数据库为止。
最佳的解决方案是在您的应用代码中检查是否有应对意外的发生,无论是任何原因导致的启动或连接失效都应考虑在内。