容器技术
简单介绍
容器技术又称为容器虚拟化
首先是一种虚拟化技术
虚拟化技术包括硬件虚拟化 半虚拟化 操作系统虚拟化
容器虚拟化就是操作系统虚拟化,是属于轻量级的虚拟化
容器虚拟化技术是已经集成到 Linux 内核中的
容器的特性
容器首先是一个相对独立的运行环境,并且在一个容器环境中,应该最小化对外界的影响,比如不能在容器中把宿主机上的资源全部消耗完,这就是资源控制。
容器虚拟化的核心技术
一般来说容器技术主要包含 Namespace 和 Cgroup 这两个内核特性
- Namespace 又称为命名空间(或名字空间), 主要做访问隔离。其原理是针对一类资源进行抽象,并将其封装在一起提供给一个容器使用,对于这类资源,每个容器都有自己的抽象,而它们之间是不可见的,所以可以做到访问隔离。
- Cgroup 是 control group 的简称,又称为控制组,主要做资源控制。其原理是将一组进程放在一个控制组里,通过给这个控制组分配指定的可用资源,达到控制这一组进程可用资源的目的。
上述的两个核心技术两者并不存在依赖性,但是可以用组合的方式实现容器技术。
比如在一个 Namespace 中的进程恰好又在一个 Cgroup 中,那么这些进程就同时有了访问隔离和资源控制。这恰恰是容器的特性。
容器技术的发展史
1982年
在普通的目录结构中创建一个完整的子目录结构,可以称为抽象化目录结构。
通过 chroot 技术实现,就是把用户的文件系统根目录切换到某个指定的目录下。
缺点:
只是实现了视图上的虚拟化
用户实际上可以逃离设定的根目录
2000年
linux 内核版本 2.3.14 中引入了 pivot_root 技术,它有效的避免了 chroot 带来的安全性问题。
目前的容器技术都是使用了 pivot_root 技术来做根文件系统的切换。
缺点:
仅仅是对文件系统隔离的增强
市场上也出现了一些商用的容器技术,如 SWset(现在的 Odin) 开发的 Virtuozzo
2005年
Odin公司在 Virtuozzo 的基础上发布了 OpenVZ 技术,同时开始推动 OpenVZ 中的核心容器技术进入 Linux 内核主线,而此时 IBM 公司也在推动类似的技术,最后在社区的合作下,形成了目前大家看到的 Namespace 和 Cgorup
2013年
随着容器技术在内核主线中不断成熟和完善,Docker 诞生了,并且由于它的诞生,容器技术才真正引起了全世界技术公司和开发人员的关注。
容器的组成
对于 Linux 容器的最小组成:
容器 = cgroup + namespace + rootfs + 容器引擎(用户态工具)
- Cgroup 资源控制,消耗的限制
- Namespace 访问隔离,空间的限制
- rootfs 文件系统隔离
- 容器引擎 生命周期控制
容器核心技术介绍
Cgroup
Cgroup 是什么
是 control group 的简写,是属于 Linux 内核提供的一个特性,用于限制和隔离一组进程对系统资源的使用。
这些资源包括 CPU、内存、block I/O 和网络带宽。
Cgroup 从 2.6.24 开始进入内核主线。
从实现的角度来看,Cgroup 实现了一个通用的进程分组的框架,不同的资源由各个子系统管理。
- devices 设备权限控制
- cpuset 分配指定的 CPU 和内存节点。
- cpu 控制 CPU 占用率
- cpuacct 统计 CPU 使用情况
- memory 限制内存的使用上限
- freezer 冻结 (暂停) Cgroup 中的进程
- net_cls 配合 tranffic contronller 限制网络带宽
- net_prio 设置进程的网络流量优先级
- huge_tlb 限制 HugeTLB d 使用
- perf_event 允许 Perf 工具基于 Cgroup 分组做性能检测
Cgroup 的接口
原生接口通过 cgorupfs 提供,是一种虚拟文件系统。
要想使用必须先挂载 cgroupfs 文件系统,命令如下:
# mount -t cgroup -o cpuset cpuset /sys/fs/cgroup/cpuset
注意: 这个动作一般已经在启动时由系统自动完成了。
查看默认的 cgroupfs
[root@localhost ~]# ls -l /sys/fs/cgroup/cpuset
Namespace
Namespace 介绍
Namespace 是将内核的全局资源做封装, 使得每个 Namespace 都有一份独立的资源,因此不同的进程在各自的 Namespace 内对同一种资源的使用不会互相干扰。
目前实现了以下几种 Namespace
- IPC 隔离 SystemV IPC 和 POSIX 消息队列,IPC 就是进程间通信
- Network 隔离网络资源,有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。
- Mount 隔离文件系统挂载点,不同 Namspace 的进程看到的文件结构不同
- PID 隔离进程 ID
- UTS 隔离主机名和域名,UTS(“UNIX Time-sharing System”) 名字空间允许每个容器拥有独立的
hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非主机上的一个进程。 - User 隔离用户 ID 和组 ID,每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用
户执行程序而非主机上的用户。
Docker 容器和虚拟机的区别
1. 实现原理技术不同
虚拟机是用来进行硬件资源划分的完美解决方案,利用的是硬件虚拟化技术,如此VT-x 、AMD-V会通过一个 hypervisor 层来实现对资源的彻底隔离。
而容器则是操作系统级别的虚拟化,利用的是内核的 Cgroup 和 Namespace 特性,此功能通过软件来实现,仅仅是进程本身就可以实现互相隔离,不需要任何辅助。
2. 使用资源方面不同
Docker 容器与主机共享操作系统内核,不同的容器之间可以共享部分系统资源,因此更加轻量级,消耗的资源更少。
虚拟机会独占分配给自己的资源,不存在资源共享,各个虚拟机之间近乎完全隔离,更加重量级,也会消耗更多的资源。
3. 应用场景不同
若需要资源的完全隔离并且不考虑资源的消耗,可以使用虚拟机。
若是想隔离进程并且需要运行大量进程实例,应该选择 Docker 容器。
Docker 容器和虚拟机合作
可以在一台虚拟机上创建 Docker 容器
什么是Docker
2013 年初,一个叫 dotCloud 的 PaaS 服务提供商,将一个内部项目 Docker 开源。
之后 Docker 一词迅速爆红。
这家公司干脆出售了其所持有的 PaaS 平台业务,并且改名为 Docker.Inc ,之后专注于 Docker 的开发和推广。
Docker 实际上是一个开源的容器引擎,可以方便的对容器进行管理。
目前 Docker 已经加入 Linux 基金会,并遵循 Apache 2.0 协议,其代码托管于 Github
https://github.com/docker/docker
Docker 的架构
docker是一个C/S模式的架构,后端是一个松耦合架构,模块各司其职。
- 用户是使用Docker Client与Docker Daemon建立通信,并发送请求给后者。
- Docker Daemon作为Docker架构中的主体部分,首先提供Server的功能使其可以接受Docker Client的请求;
- Engine执行Docker内部的一系列工作,每一项工作都是以一个Job的形式的存在。
- Job的运行过程中,当需要容器镜像时,则从Docker Registry中下载镜像,并通过镜像管理驱动graphdriver将下载镜像以Graph的形式存储;
- 当需要为Docker创建网络环境时,通过网络管理驱动networkdriver创建并配置Docker容器网络环境;
- 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过execdriver来完成。
- libcontainer是一项独立的容器管理包,networkdriver以及execdriver都是通过libcontainer来实现具体对容器进行的操作
实际上 Docker 并不会直接于内核交互,是通过一个更底层的工具 Libcontainer 与内核交互的。
Libcontainer 才是真正意义上的容器引擎,它通过 clone 系统调用直接创建容器,通过 pivot_root 系统调用进入容器,且通过直接操作 Cgroupfs 文件实现对资源的管控,而 Docker 更侧重于处理更上层的业务。
Docker 的另一个优势是对层级镜像的创新应用,即不同的容器可以共享底层的只读镜像。
通过写入自己特有的内容后添加新的镜像层,新增的镜像层和下层的镜像一起又可以作为基础镜像被更上层的镜像使用。
Graph
先说 Union Mount,它支持把一个目录A叠加到另一个目录B之上;用户对目录B的读取就是A加上B的内容,而对B目录里文件写入和改写则会保存在目录A上,因为A在上一层。
比如一个最主要的应用是,把一张CD/DVD和一个硬盘目录给联合 mount在一起,然后,你就可以对这个只读的CD/DVD上的文件进行修改(当然,修改的文件存于硬盘上的目录里)。
Docker 对 Union mount 的应用,使得在多个容器使用通过一个基础镜像时,可以极大的减少内存占用,因为不同的容器访问同一个文件时,只会占用一份内存。这就需要使用支持 Union mount 的文件系统作为存储的 Graph设备,比如 AUFS 和 Overlay。
Docker 功能和组件
- Docker 客户端
- Docker daemon
- Docker 容器
- Registry
Docker 客户端
在 Linux 系统上,Docker 将客户端和服务端统一在同一个二进制文件中发布。
客户端用 docker command 来发起请求,也可以使用一整套 RESTful API 来发起请求。
Docker daemon
可以被理解为 Docker server ,另外也常常用 Docker Engine 来描述它,因为它实际上是驱动整个 Docker 功能的核心引擎。
接收客户端的请求,并实现请求所要求的功能,同时针对请求返回相应的结果。
Docker 容器
在Dockers 的功能和概念中, 容器是一个核心内容,在性能上给 Docker 在虚拟化方面带来了极大的优势。
功能上 Docker 同过 Libcontainer 实现对容器生命周期的管理,信息的设置和查询,以及监控和通信等功能。
并且容器是对镜像的完美诠释,容器以镜像为基础,使镜像有了鲜活的生命,同时为镜像提供了一个标准的和隔离的运行环境。
Docker 镜像
与容器对应,是一个还没有运行起来的环境。
包括了应用和这些应用运行时的环境。
它只是一个可定制的 rootfs。
Docker 镜像的另一创新就是 它是层级的并且可复用。
通常通过 Dockerfile 来创建,Dockerfile 提供了镜像内容的定制。
镜像就像是面向对象编程中的类,而容器就是这个类的实例
Registry
是一个存放镜像的仓库,通常被部署在互联网服务器或者云端。
Registry 相当于传输软件的中转站。
Docker 公司提供了官方的 Registry ,叫 Docker Hub。
Docker Hub 提供了大多数常用的软件和发行版的官方镜像,当然还有无数个人用户的个人镜像,都是免费的。
Registry 本身也是一个单独的开源项目,任何人都可以下载后部署自己的 Registry