Docker 入门:了解什么是虚拟机和容器
Docke 是一个在“容器”中打包、传输和运行应用程序的工具。很难忽视开发和运营人员目前对这个工具的关注程度。甚至像谷歌、VMware 和亚马逊这样的大公司也在构建服务来支持它。
无论 Docker 对你是否立即有用,我认为了解“容器”的一些基本概念以及它们与虚拟机(VM)之间的区别非常重要。虽然网上已经有很多优秀的 Docker 使用指南,但我还没有看到很多适合初学者的概念指南,尤其是与容器的组成相关的。希望这篇文章能帮助您解决这个问题:)
让我们了解一下什么是虚拟机和容器。
什么是“容器”和“虚拟机”
容器和虚拟机具有相同的目的:将应用程序及其依赖项放入可以在任何环境中运行的独立单元中。
此外,容器和虚拟机消除了对物理硬件的需求,让我们在能耗和成本效益方面能够更高效地使用计算资源,
容器和虚拟机的主要区别在于它们的运行方式架构。让我们继续仔细看看。
虚拟机
虚拟机实际上是真实计算机的模拟,并且像真实计算机一样运行程序。使用“hypervisor”在物理机上运行虚拟机。虚拟机管理程序可以在主机或“裸机”上运行。
让我们揭开这个术语的神秘面纱:
Hypervisor(现在称为虚拟机管理程序)是允许虚拟机在其上运行的软件、固件或硬件。虚拟机管理程序本身运行在称为“主机”的物理计算机上。主机为虚拟机提供资源,包括RAM和CPU。这些资源被划分为虚拟机,可以根据需要进行分配。因此,如果虚拟机运行资源密集型应用程序,您可以从同一主机上运行的其他虚拟机分配更多资源。
在主机上运行的虚拟机(同样,通过使用虚拟机管理程序)通常称为“来宾机”。来宾计算机包含应用程序以及运行应用程序所需的所有依赖项(例如系统二进制文件和库)。它还配备了完整的虚拟化硬件堆栈,包括虚拟网络适配器、存储和 CPU,这意味着它还拥有完整的客户操作系统。在虚拟机内部,来宾计算机就像使用自己的资源一样运行。从外部来看,我们知道它是一个虚拟机——它与其他虚拟机共享主机提供的资源。
如前所述,来宾可以在 托管虚拟机管理程序 或 裸机虚拟机管理程序 上运行。它们之间有一些重要的区别。
首先,托管虚拟机管理程序在主机操作系统上运行。例如,您可以在运行 OSX 操作系统的计算机上安装虚拟机(例如 VirtualBox 或 VMware Workstation 8)。虚拟机无法直接访问硬件,因此必须通过主机上运行的操作系统(在我们的示例中为 Mac OSX 操作系统)来访问硬件。
虚拟机管理程序托管的优点是底层硬件并不重要。主机操作系统将负责硬件驱动程序,而不需要管理程序参与。因此,这种方式被认为“硬件兼容性”较好。另一方面,硬件和管理程序之间的额外层会产生另一种资源开销,这会降低虚拟机的性能。
裸机管理程序通过直接在主机硬件上安装和运行来解决此性能问题。由于它直接面向底层硬件,因此不需要运行在主机操作系统上。在这种情况下,主机上安装的第一个作为操作系统运行的是裸机管理程序。与托管管理程序不同,它有自己的设备驱动程序,直接与每个组件交互以执行特定的 I/O、处理或操作系统任务。这会带来更好的性能、可扩展性和稳定性。这里的权衡是与硬件的兼容性有限,因为裸机管理程序只有少数内置设备驱动程序。
讨论完虚拟机管理程序后,您可能想知道为什么我们需要在虚拟机和主机之间添加一个额外的“虚拟机管理程序”层。
嗯,虚拟机管理程序在其中发挥着重要作用。由于虚拟机有自己的虚拟操作系统,虚拟机管理程序为虚拟机提供了一个管理和运行来宾操作系统的平台。这允许主机与作为客户端运行的虚拟机共享资源。
虚拟机图
如图所示,VMS为每个新虚拟机打包了虚拟硬件、内核(即操作系统)和用户空间。
容器
与提供硬件虚拟化的虚拟机不同,容器通过“用户空间”抽象提供操作系统级虚拟化。当我们分解这个术语时,你就会明白我的意思。
从所有意图和目的来看,容器看起来都像虚拟机。例如,它们有一个私有空间来运行进程,可以使用 root 权限执行命令,有专用的网络接口和 IP 地址,允许自定义路由和 iptable 规则,并且可以挂载文件系统等。虚拟机是与其他容器共享主机系统内核的容器。
容器图
这个图显示容器只会打包用户空间,而不是内核或虚拟机之类的虚拟硬件。每个容器都有自己的用户空间,允许多个容器在单个主机上运行。我们可以看到整个操作系统层面的架构是所有容器共享的。从头开始创建的唯一部分是 bins 和 libs 目录。这就是容器如此轻的原因。
Docker 从哪里来?
Docker是一个基于Linux容器技术的开源项目。它使用 Luinux 内核功能(例如命名空间和控制组)在操作系统中创建容器。
容器远非一项新技术:谷歌多年来一直在使用自己的容器技术。其他容器技术,包括 Solaris Zones、BSD Jails 和 LXC,已经存在多年了。
Docker为何突然成功?
- 易于使用:Docker 使任何人(开发人员、运营人员、架构师等)都可以轻松利用容器来快速创建和测试可移植应用程序。这使得任何人都可以在笔记本电脑上打包应用程序,并在公共云、私有云甚至金属上运行它,而无需修改。 Docker 的口号是:“构建一次,随处运行”。
- 速度:Docker 容器轻量且速度非常快。由于容器只是运行在内核上的沙箱环境,因此占用的资源较少。与虚拟机相比,您可以在几秒钟内创建 Docker 容器,而创建虚拟机则需要更多时间,因为虚拟机每次都必须启动完整的操作系统。
- Docker Hub:Docker 用户也可以从日益丰富的 Docker Hub 生态中受益。您可以将 Docker Hub 视为“Docker 镜像的应用商店”。 Docker Hub 拥有数以万计的社区构建的公共镜像可供使用。搜索符合您需求的图像非常容易。您所要做的就是准备拉图,几乎不需要任何修改。
- 模块化和可扩展性:Docker 可以轻松地将应用程序拆分为功能独立的容器。例如,您的 Postgre 数据库可以在一个容器中运行,您的 Redis 服务可以在另一个容器中运行,您的 Node.js 应用程序可以在另一个容器中运行。使用 Docker,可以更轻松地将这些容器链接在一起来构建应用程序,同时使将来添加和更新各个组件变得更容易。
最后,谁不喜欢 Docker 鲸鱼呢? :)
来自:www.docker.com/docker-birt...
Docker基本概念
现在我们对Docker有了一个大概的了解,我们来谈谈Docker的基本部分:
Docker Engine
Docker Engine 是 Docker 使用的底层。它是一个轻量级的运行时和工具,可用于管理容器、图像、构建等。它在 Linux 上本机运行,包括:
- 在主机上运行的 Docker 守护进程。
- Docker 客户端,用于与 Docker 守护进程通信以执行命令。
- REST API,用于与 Docker 守护程序进行远程交互。
Docker 客户端
Docker 客户端用于与 Docker 最终用户进行交互。将其想象为 Docker UI。例如:
您正在与 Docker 客户端交互,Docker 客户端会将您的指令发送给 Docker 守护进程。
docker build iampeekay/someImage .
Docker Daemon
发送到 Docker 客户端的命令实际上由 Docker 守护进程执行(例如构建、运行和部署容器)。 Docker 守护进程运行在主机上,但作为用户,您无法直接与守护进程交互。 Docker 客户端也可以在主机上运行,但这不是必需的。它可以运行在不同的机器上,并与运行在主机上的 Docker 守护进程进行通信。
Dockerfile
您可以在 Dockerfile 中编写用于构建 Docker 映像的指令。这些指令可以是:
- RUN apt-get y install some-package:安装软件包
- EXPOSE 8000:打开端口
- /usrENV ANT-/_LOMEV :传递变量环境
变得更加先进。配置 Dockfile 后,您可以使用命令 docker build 从中构建映像。以下是 Dockerfile 示例:
简单 Dockerfile:
# 构建基于 ubuntu 14.04 镜像
FROM ubuntu:14.04
MAINTAINER preethi kasireddy iam.preethi.k@gmail.com
# 用于 SSH 登陆和端口重定向
ENV ROOTPASSWORD sample
# 在安装包的过程中关闭提示
ENV DEBIAN_FRONTEND noninteractive
RUN echo "debconf shared/accepted-oracle-license-v1-1 select true" | debconf-set-selections
RUN echo "debconf shared/accepted-oracle-license-v1-1 seen true" | debconf-set-selections
# 更新包
RUN apt-get -y update
# 安装系统工具/库
RUN apt-get -y install python3-software-properties \
software-properties-common \
bzip2 \
ssh \
net-tools \
vim \
curl \
expect \
git \
nano \
wget \
build-essential \
dialog \
make \
build-essential \
checkinstall \
bridge-utils \
virt-viewer \
python-pip \
python-setuptools \
python-dev
# 安装 Node,npm
RUN curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
RUN apt-get install -y nodejs
# 把 oracle-jdk7 添加到 Ubuntu 包仓库
RUN add-apt-repository ppa:webupd8team/java
# 确保包仓库是最新的
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
# 更新 apt
RUN apt-get -y update
# 安装 oracle-jdk7
RUN apt-get -y install oracle-java7-installer
# 导出 JAVA_HOME 环境变量
ENV JAVA_HOME /usr/lib/jvm/java-7-oracle
# 执行 sshd
RUN apt-get install -y openssh-server
RUN mkdir /var/run/sshd
RUN echo "root:$ROOTPASSWORD" | chpasswd
RUN sed -i 's/PermitRootLogin without-password/PermitRootLogin yes/' /etc/ssh/sshd_config
# SSH 登陆修复。否则用户将在登陆后被踢出
RUN sed 's@session\s*required\s*pam_loginuid.so@session optional pam_loginuid.so@g' -i /etc/pam.d/sshd
# 暴露 Node.js 应用端口
EXPOSE 8000
# 创建 tap-to-android 应用目录
RUN mkdir -p /usr/src/my-app
WORKDIR /usr/src/my-app
# 安装应用依赖
COPY . /usr/src/my-app
RUN npm install
# 添加 entrypoint 执行入口点
ADD entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["npm", "start"]
Docker 映像
根据 Dockerfile 中的说明构建的映像是只读模板。镜像不仅定义了要打包的应用程序及其依赖项,还定义了启动时将执行的进程。
Docker 镜像是使用 Dockerfile 构建的。 Dockerfile 中的每条指令都会为镜像添加一个新的“镜像层”。镜像层是镜像文件系统的一部分,可以添加或更改以下镜像层的内容。镜像层是 Docker 轻量级且健壮的结构的关键。 Docker 使用 Union 文件系统来实现:
Union 文件系统
Docker 使用 Union 文件系统来创建镜像。您可以将联合文件系统视为可堆叠文件系统,这意味着不同文件系统(也称为分支)中的文件和目录可以透明地形成单个文件系统。
重叠分支中具有相同路径的目录中的内容将被视为单个合并目录,无需为每一层创建单独的副本。然而,它们都指向同一个来源;当某些图层需要改变时,复制一份并修改本地副本,而原始图层保持不变。这种方法使文件系统看起来可外部写入,但内部不可写入。 (换句话说,“写入时复制”系统。)
分层系统具有两个主要优点:
- 无需复制:图像层有助于避免每次创建或打开图像时都使用图像。容器中的所有文件都会同时复制,这使得 docker 容器实例化非常快速且廉价。
- 镜像层隔离:更改镜像时速度更快,Docker 更新只会传播到更改的镜像层。
Volume
Volume 是容器的“数据部分”,在创建容器时初始化。卷允许您在容器中保存和共享数据。数据卷与镜像中的标准联合文件系统分离,并作为常规目录和文件存在于主机文件系统中。因此,即使您销毁、更新或重建容器,数据量也将保持不变。如果要更新数据量,也可以直接编辑。 (此功能的另一个优点是数据卷可以在不同的容器中共享和重用,使其变得简单而优雅。) 打开一切都被打包到一个看不见的沙箱中。这包括操作系统、应用程序代码、运行时、系统库等等。 Docker容器是基于Docker镜像构建的。由于镜像是只读的,因此Docker在镜像的只读文件系统上添加了一个可读写的文件系统来创建容器。
来自:Docker
此外,Docker 有很多创建容器的步骤。它会创建一个网络接口,以便容器和本地主机可以通信,然后附加容器可用的IP地址,并打开当你打开应用程序时定义的特定进程。
成功创建容器后,您可以在任何环境中运行它,无需任何更改。
双击“容器”
唷!许多部分都被覆盖。总是让我好奇的一件事是容器的实际实现方式,特别是因为没有抽象的基础设施边界可供查看。读了很多,一切都是值得的,所以在这里我试着给大家解释一下! :)
“容器”其实只是一个抽象的概念,用来描述不同的功能如何协同工作,实现一个可视化的“容器”。让我们快速浏览一下这些功能:
1) 命名空间
命名空间为容器提供了自己的基本 Linux 视图,限制了容器可以看到和访问的内容。当您运行容器时,Docker 会创建容器将使用的命名空间。
Docker 使用内核中可用的多种类型的命名空间,例如:
a。 NET:提供仅可见的系统网络堆栈(例如网络设备本身、IP地址、IP路由表、/proc/net目录和端口号等)的容器。 b. PID:PID代表进程ID。如果您曾经从命令行运行 ps aux 来检测系统上运行的进程,您将看到一个名为“PID”的字段。 PID 命名空间为容器提供了仅在其自身范围内可见和交互的进程视图。包括一个单独的init进程(PID 1),这个进程是容器中所有进程的“祖先”。 C。 MNT:提供您自己的系统“安装”视图。因此,不同挂载命名空间上的进程具有不同的文件层次结构视图。 d. UTS:UTS 代表 UNIX 分时系统。允许进程识别系统标识符(即主机名、域名等)。 UTS允许容器拥有自己的主机名和NIS域名,独立于其他容器和主机系统。 e. IPC:IPC代表进程间通信。 IPC命名空间负责隔离每个容器中运行的进程之间的IPC资源。 F。 USER:此命名空间用于隔离每个容器内的用户。这样做的作用是为显示容器提供与主机系统不同的 uid(用户 ID)和 gid(组 ID)。因此,用户命名空间内部的进程uid和gid可以与外部主机不同,这使得容器外部的进程uid可以成为非特权用户,而无需牺牲容器内部进程uid的root权限。
Docker 使用这些命名空间来隔离和启动容器创建。以下功能称为控制组。
2) 控制组
控制组(也称为 cgroup)是 Linux 内核功能,用于隔离、优先级和计算资源使用情况(CPU、内存、磁盘 I/O 和网络等)。从这个意义上说,控制组确保 Docker 容器仅使用它们需要的资源,并且在必要时对它们可以使用的资源设置限制。控制组还确保单个容器不会耗尽其资源并导致系统崩溃。
最后,联合文件系统是 Docker 使用的另一个功能:
3) 隔离的联合文件系统:
这已在上面的 Docker 镜像部分中进行了解释:) Docker 容器都是关于(当然,问题在于实现细节 - 例如如何管理不同组件之间的交互)。
Docker的未来:Docker将与虚拟机共存
虽然Docker正在获得大量支持,但我认为它不会对虚拟机构成真正的威胁。容器将继续发挥作用,但在很多情况下虚拟机更适合。
例如,如果您需要在多台服务器上运行多个应用程序,则可能可以使用虚拟机。另一方面,如果您需要运行单个应用程序的多个副本,Docker 提供了一些有趣的优势。
此外,虽然容器允许您将应用程序划分为功能上更独立的部分,但它会造成关注点分离,这意味着有许多部分需要管理,而这些部分可能会变得难以管理。
安全性也是 Docker 容器所关心的问题——由于内核在容器之间共享,容器之间的墙会更薄。完整虚拟机只能向主机管理程序发出超级调用,但 Docker 容器可以向主机内核发出系统调用,这会暴露更多的攻击。当安全性特别重要时,开发人员可以选择通过抽象硬件隔离的虚拟机——这可以使不同虚拟机之间的进程更难以相互干扰。
当然,随着容器在生产环境中的使用越来越多以及用户的审核,安全和管理等问题也会不断演变。目前,容器与虚拟机之间的争论最好留给那些每天处理这个问题的人。
结论
我希望您现在已经掌握了理解 Docker 所需的知识,甚至有一天在您的项目中使用它。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网