虚拟化和容器以及docker
docker
1.服务部署历史
1.1传统部署-物理机
- 部署架构
物理机部署架构.png
- 缺点
资源浪费:一台服务器,至少32核CPU、64G内存,如果只部署一个应用,那就太浪费了
资源抢占:多个应用进程,DB,缓存进程等等都部署在同一个机器上。进程间资源抢占
环境冲突:部署相同的服务但是依赖库的版本不同,配置无法隔离.
1.2虚拟化部署-VM
-
部署架构
虚拟机部署架构.png
- 优化项
资源分配和环境隔离:每台机器事先分布CPU核数、内存和磁盘等硬件资源后单独运行,解决了资源浪费、资源抢占和环境冲突问题.
- 缺点
环境管理:虚拟机依赖的环境软件更新时已经部署的虚拟机得一个个更新环境
1.3容器部署-CONTAINER
- 部署架构
容器部署架构.png
镜像文件,通俗的理解就是一个进程运行时依赖的软件文件的集装箱,安装镜像后产生了docker容器。
- 优化项
环境管理:当环境软件需要更新时直接修改镜像文件然后重新拉取容器部署即可
2.linux虚拟化技术
3.linux容器技术
3.1容器隔离机制
如果多个进程运行在同 一个操作系统上,那容器到底是怎样隔 离它们的。 有两个机制可用 :
第一个是 Linux命名空间,它使每个进程只看到它自 己的系统视图(文件、进程、网络接口、主机名等〉:
第二个是 Linux控制组 (cgroups), 它限制了进程能使用的资源量( CPU、内存、网络带 宽等)。
3.2用linux命名空间隔离进程
每个 Linux 系统最初仅有一个命名 空 间 。 所有系统资源(诸如文 件系统、用户 ID、网络接口等)属于这一个命名空间 。
但是你能创建额外的命名空间,以及在它们之间组织资源 。 对于一个进程,可以在其中一个命名空间中运行它 。进程将只能看到同一个命名空间下的资源。
当然,会存在多种类型的多个命名空间, 所以 一个进程不单单只属于某 一个命名空间,而属于每个类型的 一个命名空间 。
linux命名空间.png
| 命名空间 | 具体实现 | 带来影响 |
|---|---|---|
| pid | 不同用户的进程就是通过pid命名空间隔离开的,不同的命名空间中可以有相同的pid. 所有的 LXC (内核虚拟化)进程在Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间 | 各命名空间进程相对独立 |
| net | 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来 Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker网桥 docker0 连接在一起。 | 容器内的端口可以重复,例如c1和c2都可部署mysql到3306,然后再映射到基础命名空间的不同端口上 |
| ipc | 容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication – IPC), 包括信号量、消息队列和共享内存等。 然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 名字空间中的进程间交互 | |
| mnt | mnt 名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间 中的进程所看到的文件目录就被隔离开了。 同 chroot 不同,每个名字空间中的容器在 /proc/mounts 的信息只包含所在名字空间的 mount point。 | |
| uts | UTS(“UNIX Time-sharing System”) 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。 | |
| user | 每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。 |
3.3限制进程的可用资源
通过 cgroups 来实现 。 cgroups是一个 Linux 内核功能, 它被用来限制一个进程或者一组进程的资源使用。
一个进程的资源 CCPU、内 存、网络带宽等)使用 量不能超出被分配的量 。
这种方式下,进程不能过分使用为其他进程保留的资源,这和进程运行在不同的机器上是类似的。
4.容器与虚拟化技术区别点
-
docker容器不需要hypervisor实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源
-
docker利用的宿主机的内核,而不需要GuestOS,当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核
-
新建一个虚拟机时,虚拟软件需要加载GuestOS,这个新建过程是分钟级别的
| 比较项目 | Docker容器 | 虚拟机VM |
|---|---|---|
| 操作系统 | 与宿主机共享OS | 宿主机OS上运行虚拟机OS |
| 存储大小 | 镜像小,便于存储传输 | 镜像庞大(VMDK,VDi等) |
| 运行性能 | 几乎无额外损失的性能 | 操作系统额外的CPU、内存消耗 |
| 移植性 | 轻便灵活适用于Linux | 笨重与虚拟化技术耦合度高 |
| 硬件亲和性 | 面向软件开发者 | 面向硬件运维者 |
传统虚拟化与容器的区别.png
5.docker架构
概念
要理解 Docker 的内部构建,必须知道Docker 包括三个基本概念:
-
镜像(Image):Docker 镜像(Image),就相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
-
容器(Container):镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
-
仓库(Repository):仓库可看成一个代码控制中心,用来保存镜像。
镜像与容器的关系类似面向对象的类和对象
| Docker | 面向对象 |
|---|---|
| 镜像-image | 类-class |
| 容器-Container | 对象-object |
docker架构.png
| 概念 | 说明 |
|---|---|
| Docker 镜像(Images) | Docker 镜像是用于创建 Docker 容器的模板,比如 Ubuntu 系统。 |
| Docker 容器(Container) | 容器是独立运行的一个或一组应用,是镜像运行时的实体。 |
| Docker 客户端(Client) | Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。 |
| Docker 主机(Host) | 一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。 |
| Docker Registry | Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。 Docker Hub(https://hub.docker.com) 提供了庞大的镜像集合供使用。 一个 Docker Registry 中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。 通常,一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 <仓库名>:<标签> 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签。 |
| Docker Machine | Docker Machine是一个简化Docker安装的命令行工具,通过一个简单的命令行即可在相应的平台上安装Docker,比如VirtualBox、 Digital Ocean、Microsoft Azure。 |
镜像层
Docker 镜像由多层构成 。 不同镜像可能包含完全相同的层,因 为这些 Docker 镜像都是基于另 一个镜像之上构建的,不同的镜像都能使用相同的父 镜像作为它们的基础镜像 。 这提升了镜像在网络上的分发效率,当传输某个镜像时, 因为相同的层己被之前的镜像传输,那么这些层就不需要再被传输 。
层不仅使分发更高效 ,也 有助于减少镜像 的存储 空 间 。每一层仅被存 一 次,当 基于相同基础 层 的镜像被创建成两个容器时,它 们 就能够读相同的文件 。 但是如果 其中 一个容器写入某些文件,另外 一个是无法看见文件变更的。因此,即使它们共 享文件 ,仍然彼此隔离 。 这是因为容器镜像层是只读的 。 容器运行 时, 一个新的可 写层在镜像层之上被创建 。 容器中进程写入位于底层的 一个文件时,此文件的一个 拷贝在顶层被创建,进程写的是此拷贝。
容器镜像可移植性的限制
理论上, 一个容器镜像能运行在任何一个运行 Docker 的机器上。但有一个小警 告一一-一个关于运行在一台机器上的所有容器共享主机 Linux 内核的警告。 如果一 个容器化的应用需要一个特定的内核版本,那它可能不能在每台机器上都工作。如 果一 台机器上运行了 一个不匹配的 Linux 内核版本 ,或者没有相同 内核模块可用 , 那么此应用就不能在其上运行 。
虽然容器相比虚拟机轻量许多 ,但也给运行于其中的应用带来了一些局限性。 虚拟机没有这些局限性,因为每个虚拟机都运行自己的内核 。
还不仅是内核 的问 题 。一 个 在特定硬 件 架构之上编译 的容器化应用,只能在 有 相同硬件架构的机器上运行。 不能将一个 x86架构编译的应用容器化后,又期望它 能运行在 ARM 架构的机器上 。 你仍然需要 一 台虚拟机来做这件事情。