我知道容器使用主机的内核,据我所知,这就是我们不需要操作系统的原因。我的问题是(我在网上找不到任何好的解释):
1)如果是这种情况,我们如何获得 shell 提示符,以及如何在容器上拥有诸如 systemctl、服务等内容
2)我们如何在 Ubuntu 主机上安装 CentOS 容器?在这种情况下,容器是否在容器映像中安装了操作系统?
答案1
这很大程度上取决于您对操作系统的看法。
容器从根本上来说是一种将正在运行的进程与计算机上的所有其他进程隔离开来的方法,并将二进制文件及其所有依赖项与主机文件系统隔离开来。这样一来,它们就可以轻松地在任意数量的机器之间移动和运行。它们绝不是虚拟化,因此正如您在问题中提到的那样,容器中运行的任何进程都在主机内核上运行。从某些角度来看,操作系统从根本上来说就是内核。
与此相对的是,大多数软件并非是整体式构建的,而是在编译时与任意数量的共享库链接。因此,当您安装操作系统发行版以及内核时,您会获得一系列库和实用程序,并且您从操作系统存储库安装的任何程序都将根据该操作系统发行版附带的库进行构建。
现在,构建容器时,所需的一切是您要运行的二进制文件,以及该二进制文件所依赖的任何内容。无需打包完整的 OS 发行版文件系统。如果您的二进制文件未链接到任何其他库,您几乎可以只使用单个二进制文件而不用其他任何文件。查看此项目https://github.com/davidcarboni-archive/ddd这篇文章的作者是与我目前合作的同一个客户,它演示了构建一个功能性容器所需的东西是多么的少。
因此,在理想情况下,鉴于最佳实践主要是构建一个运行单个进程的容器,每个容器将只包含相关的二进制文件以及它所需的任何库、配置文件和工作目录。然而,在很多情况下,要做到这一点是一个非常复杂且耗时的过程。因此,现在已经成为一种非常常见的模式,即简单地将整个文件系统从容器内的捐赠操作系统打包,因为这样您就知道要运行的进程所具有的任何依赖关系都将存在。它还增加了便利性,这意味着将存在包管理工具,这使得构建容器变得更容易。这也意味着还存在诸如 shell 之类的实用程序,这使得调试容器变得更容易(虽然在某些人看来,除了当您开发新的容器映像时,如果您需要访问容器内的 shell,那么您做错了)。
虽然我理解这种模式为何如此流行,但我确实认为它有缺点。首先从你的问题就可以看出——它让容器看起来很像虚拟化,因此造成了很多混乱。此外,作为一个刚刚将 CIS 服务器强化应用到机器资产的人,把所有东西(包括厨房水槽)都打包到每个容器中,感觉这不是很好的安全做法,我怀疑在某个时候,这可能会给我们带来麻烦。
扩展您的两个具体问题:
1) 我已经讨论了 shell 的问题。至于 systemd 之类的东西,它们在容器中基本上没有位置。Dockefile 定义了启动容器时要运行的进程。如果您尝试在容器内运行服务管理器和多个服务,那么您很可能做错了。
2) 这又回到了什么是操作系统的问题。在容器中安装给定发行版的唯一意义在于,您获得了文件系统,因此获得了发行版的二进制文件和共享库副本。这与虚拟化不同,在虚拟化中,您可以在运行 Debian 等操作系统的主机上的虚拟机中运行 Centos 等操作系统的副本。
答案2
是的,每个容器都基于一个操作系统映像,例如 Alpine、CentOS 或 Ubuntu。
它们只是共享主机内核,但在特定于该容器的单独名称空间中运行每个用户空间进程。
看看dockerfile 示例(由我改编)来理解这一点:
FROM ubuntu
MAINTAINER Kimbro Staken version: 0.1
RUN apt-get update && apt-get install -y apache2 && apt-get clean && rm -rf /var/lib/apt/lists/*
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
EXPOSE 80
CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]
这告诉 Docker 从 Ubuntu 基础映像(如果未指定版本,则为最新版本)创建一个容器,在其中安装并运行 Apache,并向主机操作系统公开端口 80。
答案3
操作系统到底是什么?
Linux 内核本身满足了操作系统的大部分关键要求。它对 CPU 进行时间切片,管理控制台 IO、磁盘 IO 和网络,可以为图形输出提供与硬件无关的帧缓冲区等等。能编写一个在 Linux 内核上运行且无需加载任何库的程序并利用这些功能。
然而,当谈到现代通用操作系统时,大多数人对操作系统的看法要广泛得多。除了内核之外,它们还包括许多其他东西。shell、init 系统、X 服务器、通用库、用于加载驱动程序模块的系统(这样您就不必将所有驱动程序都构建到内核中)、用于启动网络接口的工具、用于安装其他文件系统的工具、包管理器等等。我们把这些用于构建现代操作系统的内核之外的部分统称为“用户空间”。
Linux 发行版的大部分特性都来自用户空间。如果你有一个在 Ubuntu 内核上运行的 Centos 用户空间,那么它会感觉更像 Centos 而不是 Ubuntu。
容器是一种允许单个内核伪装成多个独立内核的功能。每个内核都有自己的 PID、自己的文件系统继承权、自己的网络接口和自己的用户帐户。
与运行 Linux 内核的真实系统一样,您可以编写一个在容器中运行的程序,而无需任何支持。事实上,在容器中比在真实系统上更容易,因为您不必担心驱动程序,并且您的容器管理器可能能够预先初始化容器,以便已经安装正确的文件系统并且网络接口已经启动。
但大多数时候,人们希望从容器中获得的是“虚拟化但更便宜”。他们希望拆分服务器的逻辑功能,以便每个功能都可以单独备份、迁移、更新等,但他们希望继续使用他们正在使用的软件堆栈,该软件堆栈利用了现代操作系统中上述部分或全部非内核部分,并且他们不想支付虚拟机的费用。
因此,容器通常最终会包含常规 Linux 发行版的整个用户空间。包括 init 系统、shell 和 ssh 服务器。这算不算操作系统?好吧,这最终取决于你如何定义操作系统!
答案4
1)如果是这种情况,我们如何获得 shell 提示符,以及如何在容器上拥有诸如 systemctl、服务等内容
您可以使用完整操作系统映像容器,以下是一些示例:
所有以前的映像都是官方映像,这意味着它们由维护操作系统的同一组维护。通过运行这些映像,您将运行整个操作系统,并且它们可以在任何 Linux 主机上运行。
您可以通过两种方式访问提示:
- docker exec -it 容器名称 /bin/bash
- 远程控制
对于第二种方法,您必须向外部公开端口 22。
2)我们如何在 Ubuntu 主机上安装 CEntOS 容器?在这种情况下,容器是否在容器映像中安装了操作系统?
要在 docker 环境中运行 CEntOS 容器非常简单,只需安装 docker 并运行:
docker run --rm -p 2020:22 -v vol_data:/data centos:7
上一个命令将:
- 说停止时必须移除容器
--rm
- 将主机端口 2020 绑定到容器端口 22
-p 2020:22
(这是为了避免与已在使用的主机端口发生冲突。 - 创建一个名为的持久卷
vol_data
,并将其安装在容器内的 /data 位置 - 来自docker镜像
centos:7
要在容器内运行 systemd,镜像的 docker hub 页面将向您描述如何执行此操作。
您可以考虑使用另一种方法来达到您的目标machinectl
(应该是 systemd 的一部分,不确定),这里有一些参考:https://www.freedesktop.org/software/systemd/man/machinectl.html
当然您也可以使用 chroot 环境,但是您必须通过并且完成所有操作,并且实现起来并不是很友好。
关于操作系统,我要澄清一点,操作系统是一个随时可用的环境(无论是否带有 GUI),因此内核是操作系统的众多部分之一,简而言之,在容器镜像中,您将拥有一个不直接访问物理硬件的操作系统,甚至可以说根本没有硬件。容器镜像仅用于运行一项服务,它是运行该特定服务所需组件的最小安装(无论如何都可以扩展)。
为了更好地理解什么是操作系统及其所有组成部分(当然是 Linux 操作系统),我建议你看一下LFS 项目。