
Container,即容器,平时生活指的是可以装下其它物品的工具,以方便人类归纳放置物品、存储和异地运输,比如人类使用的杯子、背包、行李箱等都可以称为容器。
Container除了容器以外,另一个意思就是集装箱,很多码头工人将很多装有不同的物品但却整齐如一的箱子装载到停靠在货运大船,然后方便运输。

为什么这些集装箱可以很方便的运输呢?因为它们有大小一致标准化尺寸的箱子,并且可以安全的隔离开来,所以我们使用Container来形容容器的时候,就是我们想要让容器达到一个可以打包,符合标准的状态。

前面虽然说了这么多集装箱相关的东西,但我们所说的容器是一种IT技术。不过很多技术,都是由生活演变而来。容器,其实是一种沙盒技术。顾名思义,沙盒就是能够像一个集装箱一样,把应用装起来。这样,应用于应用之间就有了边界而不会互相干扰;同时装载沙盒里面的应用,也可以很方便的被搬运,这也是PaaS想要的最理想的状态(可移植性,标准化,隔离性)。
容器是软件工业上的集装箱的技术,集装箱的标准化,减少了包装成本,大大提高货物运输和装卸效率,是传统运输行业的重大变革。早期的软件项目中软件更新,发布低效,开发测试发布周期很长,很难敏捷。有了容器技术,就可以利用其标准化的特点,大幅提高生产效率。
容器技术是虚拟化、云计算、大数据之后的一门新兴的并且是炙手可热的新技术,容器技术提高了硬件资源利用率、 方便了企业的业务快速横向扩容(可以达到秒级快速扩容)、 实现了业务宕机自愈功能(配合K8S可以实现,但OpenStack无此功能),因此未来数年会是一个容器愈发流行的时代 ,这是 一个对于 IT 行业来说非常有影响和价值的技术,而对于IT行业的从业者来说, 熟练掌握容器技术无疑是一个很有前景的行业工作机会。
1.1 Docker介绍
1.1.1 容器历史
虽然 docker 把容器技术推向了巅峰,但容器技术却不是从 docker 诞生的。实际上,容器技术连新技术都算不上,因为它的诞生和使用确实有些年头了。下面的一串名称可能有的你都没有听说过,但它们的确都是容器技术的应用:
- Chroot Jail
就是我们常见的chroot命令用法。它在1979年的时候就出现了,被认为是最早的容器化技术之一。它可以把一个进程的文件系统隔离起来
2. The FreeBSD Jail
Freebsd Jail 实现了操作系统级别的虚拟化,它是操作系统级别的虚拟化技术的先驱之一。
3. Linux VServer
使用添加到Linux内核的系统级别的虚拟化功能实现的专用虚拟服务器。
4. Solaris Containers
它也是操作系统级别的虚拟化技术,专为x86和SPARC系统设计。Solaris容器是系统资源控制和通过“区域”提供边界隔离的组合。
5. OpenVZ
OpenVZ是一种Linux中操作系统级别的虚拟化技术。它允许创建多个安全隔离的Linux容器,即VPS。
6. Process Containers
Process 容器由 Google 的工程师开发,一般被称为 cgroups。
7. LXC
LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求
Linux Container提供了在单一可控主机节点上支持多个相互隔离的server container同时执行的机制。Linux Container有点像chroot,提供了一个拥有自己进程和网络空间的虚拟环境,但又有别于虚拟机,因为lxc是一种操作系统层次上的资源的虚拟化。
8. Warden
在最初阶段,Warden使用LXC作为容器运行时。如今已被CloudFoundy取代。
9. LMCTFY
LMCTY 是 Let me contain that for you 的缩写。它是 Google 的容器技术栈的开源版本。Google 的工程师一直在与 docker 的 libertainer 团队合作,并将 libertainer 的核心概念进行抽象并移植到此项目中。该项目的进展不明,估计会被 libcontainer 取代。
10. Docker
Docker是一个可以将应用程序及其依赖打包到几乎可以在任何服务器上运行的容器的工具。
11. RKT
RKT是Rocket的缩写,它是一个专注于安全和开放标准的应用程序容器引擎。
正如大家所看到的,docker并不是第一个容器化技术,但它确实是目前最知名的一个。
1.1.2 Docker是什么
Docker (码头工人)是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司(后由于 Docker 开源后大受欢迎就将公司改名为 Docker Inc ,总部位于美国加州的旧金山)内部的一个开源的 PAAS 服务 (Platform as a ServiceService )的业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。
Docker 是基于 linux 内核实现,Docker 最早采用 LXC 技术 ,LXC 是 Linux 原生支持的容器技术 ,可以提供轻量级的虚拟化 ,可以说 docker 就是基于 LXC 发展起来 的,提供 LXC 的高级封装,标准的配置方法,在LXC的基础之上,docker提供了一系列更强大的功能。而虚拟化技术 KVM(KernelKernelbasedVirtual Machine Machine) 基于 模块实现, 后来Docker 改为自己研发并开源的 runc 技术运行容器,彻底抛弃了LXC。
Docker 相比虚拟机的交付速度更快,资源消耗更低,Docker 采用客户端/服务端架构,使用远程API来管理和创建容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念是build(构建)、ship(运输)、 run(运行),Docker遵从apache 2.0协议,并通过(namespace及cgroup等)来提供容器的资源隔离与安全保障等,所以Docke容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机6-8%性能)的额外资源开销,因此可以大幅提高资源利用率,总而言之Docker是一种用了新颖方式实现的轻量级虚拟机.类似于VM但是在原理和应用上和VM的差别还是很大的,并且docker的专业叫法是应用容(Application Container)。
Docker的主要目标

Build, Ship and Run Any App, Anywhere,即通过对应用组件的封装(Packaging)、分发(Distribution)、部署(Deployment)、运行(Runtime)等生命周期的管理,达到应用组件级别的“一次封装,到处运行”。这里的应用组件,既可以是一个Web应用,也可以是一套数据库服务,甚至是一个操作系统。将应用运行在Docker 容器上,可以实现跨平台,跨服务器,只需一次配置准备好相关的应用环境,即可实现到处运行,保证研发和生产环境的一致性,解决了应用和运行环境的兼容性问题,从而极大提升了部署效率,减少故障的可能性
使用Docker 容器化封装应用程序的意义:

- 统一基础设施环境-docker环镜
- 硬件的组成配置
- 操作系统的版本
- 运行时环境的异构
- 统一程序打包(装箱)方式-docker images
- java程序
- python程序
- nodejs程序
- 统一程序部署(运行)方式-docker容器
- java-jar…–>docker run…
- python manage.py runserver…–>docker run…
- npm run dev…–>docker run…
1.1.3 Docker和虚拟机,物理主机

容器和虚拟机技术比较

- 传统虚拟机是虚拟出一个主机硬件,并且运行一个完整的操作系统,然后在这个系统上安装和运行软件
- 容器内的应用直接运行在宿主机的内核之上,容器并没有自己的内核,也不需要虚拟硬件,相当于轻量化
- 每个容器间是互相隔离,每个容器内都有一个属于自己的独立文件系统,独立的进程空间,网络空间,用户空间等,所以在同一个宿主机上的多个容器之间彼此不会相互影响
容器和虚拟机表现比较

- 资源利用率更高: 开销更小,不需要启动单独的虚拟机OS内核占用硬件资源,可以将服务器性能压榨至极致.虚拟机一般会有5-20%的损耗,容器运行基本无损耗,所以生产中一台物理机只能运行数十个虚拟机,但是一般可以运行数百个容器
- 启动速度更快:可以在数秒内完成启动
- 占用空间更小:容器一般占用的磁盘空间以MB为单位,而虚拟机以GB
- 集成性更好:和CI/CD相关技术结合性更好,实现打包镜像发布测试可以一键运行,做到自动化并快速的部署管理,实现高效的开发生命周期
比如: 一台96G内存的物理服务器,为了运行java程序的虚拟机一般需要分配8G内存/4核的资源,只能运行13台左右虚拟机,但是改为在docker容器上运行Java程序,每个容器只需要分配4G内存即可,同样的物理服务器就可以运行25个左右容器,运行数量相当于提高一倍,可以大幅节省IT支出,通常情况下至少可节约一半以上的物理设备
1.1.4 Docker的组成
docker官网:https//www.docker.com
帮助文档链接:https://docs.docker.com
docker镜像:https://hub.docker.com


- Docker 主机/宿主机OS(host):一个物理机或虚拟机,用于运行Docker服务进程和容器,也成为宿主机,node节点
- Docker 服务端(server):Docker守护进程,运行docker容器
- Docker 客户端(client):客户端使用docker命令或其他工具调用docker API
- Docker 仓库(registry):保存镜像的仓库,官方仓库:https://hub.docker.com,可以搭建私有仓库harbor
- Docker 镜像(images):镜像可以理解为创建实例使用的模板,相当于RPM或DEB包
- Docker 容器(container):容器是从镜像生成对外提供服务的一个或一组服务,相当于将RPM包中的程序运行起来

1.1.5 Namespace
一个宿主机运行多个容器,多个容器共用一个OS,必然会带来以下的问题:
- 如何保证每个容器都有不同的文件系统并且能互不影响
- 一个docker主进程内的各个容器都是其子进程,那么如何实现一个主进程下运行不同类型的子进程?各个容器子进程间能否相互通讯?
- 每个容器如何解决IP及端口分配的问题?
- 多个容器的主机名能否一样?
- 每个容器都要不要root用户?如何解决账户重名的问题?
那么则引入了Namespace的概念,接下来看下Namespace的表现:
namespace是Linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在内核,各个docker容器运行在同一个docker主进程并且共用一个宿主机系统内核,各个docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个进程内实现运行指定服务的运行环境,并且可以保护宿主机内核不受其它进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过以下技术实现容器运行空间的相互隔离:
隔离类型 | 功能 | 系统调用参数 | 内核版本 |
MNT Namespace(mount) | 提供磁盘挂载点和文件系统的隔离能力 | CLONE_NEWNS | Linux 2.4.19 |
IPC Namespace(Inter-Process Communication) | 提供进程间通信的隔离能力 | CLONE_NEWIPC | Linux 2.6.19 |
UTS Namespace(UNIX Timesharing System) | 提供内核和主机名隔离能力 | CLONE_NEWUTS | Linux 2.6.19 |
PID Namespace(Process Identification) | 提供进程隔离能力 | CLONE_NEWPID | Linux 2.6.24 |
Net Namespace(network) | 提供网络隔离能力 | CLONE_NEWNET | Linux 2.6.29 |
User Namespace(user) | 提供用户隔离能力 | CLONE_NEWUSER | Linux 3.8 |
1.1.6 Control groups
在一个容器,如果不对其做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码bug程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如CPU、内存等
Cgroups 最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,资源的计量以及资源的控制(比如:将进程挂起和恢复等操作)。
Cgroups在内核层默认已经开启,从CentOS 和 Ubuntu 不同版本对比,显然内核较新的支持的功能更多。
1.1.6.1 cgroups具体体现
- blkio: 块设备IO限制
- cpu: 使用调度程序为 cgroup 任务提供 cpu 的访问
- cpuacct: 产生 cgroup 任务的 cpu 资源报告
- cpuset: 如果是多核心的 cpu,这个子系统会为 cgroup 任务分配单独的 cpu 和内存
- devices: 允许或拒绝 cgroup 任务对设备的访问
- freezer: 暂停和恢复 cgroup 任务
- memory: 设置每个 cgroup 的内存限制以及产生内存资源报告
- net_cls: 标记每个网络包以供 cgroup 方便使用
- ns: 命名空间子系统
- perf_event: 增加了对每 group 的监测跟踪的能力,可以监测属于某个特定的 group 的所有线程以及运行在特定CPU上的线程
[root@zhouqihao ~]# ll /sys/fs/cgroup/
total 0
dr-xr-xr-x 6 root root 0 Sep 4 02:38 blkio
lrwxrwxrwx 1 root root 11 Sep 4 02:38 cpu -> cpu,cpuacct
lrwxrwxrwx 1 root root 11 Sep 4 02:38 cpuacct -> cpu,cpuacct
dr-xr-xr-x 8 root root 0 Sep 4 02:38 cpu,cpuacct
dr-xr-xr-x 3 root root 0 Sep 4 02:38 cpuset
dr-xr-xr-x 6 root root 0 Sep 4 02:38 devices
dr-xr-xr-x 3 root root 0 Sep 4 02:38 freezer
dr-xr-xr-x 3 root root 0 Sep 4 02:38 hugetlb
dr-xr-xr-x 7 root root 0 Sep 4 02:38 memory
lrwxrwxrwx 1 root root 16 Sep 4 02:38 net_cls -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Sep 4 02:38 net_cls,net_prio
lrwxrwxrwx 1 root root 16 Sep 4 02:38 net_prio -> net_cls,net_prio
dr-xr-xr-x 3 root root 0 Sep 4 02:38 perf_event
dr-xr-xr-x 6 root root 0 Sep 4 02:38 pids
dr-xr-xr-x 2 root root 0 Sep 4 02:38 rdma
dr-xr-xr-x 6 root root 0 Sep 4 02:38 systemd
1.1.7 容器管理工具
上面介绍了chroot、namespace、cgroups,就具备了基础的容器运行环境,但是还需要有相应的容器创建与删除的管理工具、以及如何把容器运行起来、容器数据怎么处理、怎么进行启动与关闭等问题需要解决,于是,容器管理技术就出现了。目前主流是使用docker,早期使用LXC,以及后来出现的红帽的podman
- LXC
LXC:Liunx Container。可以提供轻量级的虚拟化,以便隔离进程和资源
官方网站:https://linuxcontainers.org
lxc启动容器依赖于模板,但做模板相对比较难,需要手动创建文件系统、准备基础目录以及可执行程序等,而且在大规模使用容器的场景中很难横向扩展,另外后期代码升级也需要重新构建模板,基于以上种种原因便有了docker
- docker
Docker启动一个容器也需要一个外部模板,通常称为镜像,docker的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。

Docker的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到宿主机上对应容器的目录,但是容器内的数据在删除容器后也会被随之删除。
- pouch
项目网点:https://github.com/alibaba/pouch
Pouch (小袋子)起源于 2011 年,并于2017年11月19日上午,在中国开源年会现场,阿里巴巴正式开源了基于 Apache 2.0 协议的容器技术 Pouch。Pouch 是一款轻量级的容器技术,拥有快速高效、可移植性高、资源占用少等特性,主要帮助阿里更快的做到内部业务的交付,同时提高超大规模下数据中心的物理资源利用率
目前的容器方案大多基于 Linux 内核提供的 cgroup 和 namespace 来实现隔离,然后这样轻量级方案存在弊端:
- 容器间,容器与宿主机间,共享一个内核
- 内核实现的隔离资源,维度不足
面对如此的内核现状,阿里巴巴采取了三方面的工作,来解决容器的安全问题:
- 用户态增强容器的隔离维度,比如网络宽带、磁盘使用量等
- 给内核提交patch,修复容器的资源可见性问题,cgroup方面的bug
- 实现基于Hypervisor的容器,通过创新内核来实现容器隔离
- Podman

什么是podman?
Podman即Pod Manager tool,从名称上可以看出和kubernets的pod的密切联系,不过就其功能来说,简而言之: alias docker = podman
,是CentOS 8 新集成的功能,或许不久的未来会代替docker
Podman是一个 为 Kubernetes 而生的开源的容器管理工具,原来是 CRI-O(即容器运行时接口CRI 和开放容器计划OCI) 项目一部分,后来被分离成一个单独的项目叫 libpod。其可在大多数Linux平台上使用,它是一种无守护程序的容器引擎,用于在Linux系统上开发,管理和运行任何符合Open Container Initiative(OCI)标准的容器和容器镜像。
Podman 提供了一个与Docker兼容的命令行前端,Podman 里面87%的指令都和Docker CLI 相同,因此可以简单地为Docker CLI别名,即“ alias docker = podman”,事实上,podman使用的一些库也是docker的一部分。
官网地址:https://podman.io/
Podman和docker不同之处
- docker 需要在我们的系统上运行一个守护进程(docker daemon),这会产生一定的开销,而podman 不需要
- 启动容器的方式不同:
docker cli
命令通过API跟 Docker Engine(引擎)
交互告诉它我想创建一个container,然后docker Engine
才会调用OCI container runtime(runc)
来启动一个container。这代表container的process(进程)不会是Docker CLI 的child process(子进程)
,而是Docker Engine
的child process
。
Podman 是直接给OCI containner runtime(runc)
进行交互来创建container的,所以container process
直接是podman 的child process
。
- 因为docke有docker daemon,所以docker启动的容器支持
--restart
策略,但是podman不支持 - docker需要使用root用户来创建容器。 这可能会产生安全风险,尤其是当用户知道docker run命令的–privileged选项时。podman既可以由root用户运行,也可以由非特权用户运行
- docker在Linux上作为守护进程运行扼杀了容器社区的创新。 如果要更改容器的工作方式,则需要更改docker守护程序并将这些更改推送到上游。 没有守护进程,容器基础结构更加模块化,更容易进行更改。 podman的无守护进程架构更加灵活和安全。
1.1.8 docker(容器)的核心技术
1.1.8.1 容器规范
容器技术除了的docker之外,还有coreOS的rkt,还有阿里的Pouch,为了保证容器生态的标准性和健康可持续发展,包括Linux 基金会、Docker、微软、红帽、谷歌和IBM等公司在2015年6月共同成立了一个叫open container(OCI)的组织,其目的就是制定开放的标准的容器规范,目前OCI一共发布了两个规范,分别是runtime spec和 image format spec,有了这两个规范,不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。
1.1.8.2 容器运行时 runtime
runtime是真正运行容器的地方,因此为了运行不同的容器runtime需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境
目前主流的三种 runtime:
- Lxc: linux上早期的runtime,Docker早期就是采用lxc作为runtime
- runc: 目前Docker默认的runtime,runc遵守OCI规范,因此可以兼容lxc
- rkt: 是CoreOS开发的容器runtime,也符合OCI规范,所以使用rktruntime也可以运行Docker容器
1.1.8.3 容器管理工具
管理工具连接runtime与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给runtime执行。
- lxc 是lxd 的管理工具
- Runc的管理工具是docker engine,docker engine包含后台deamon和cli两部分,大家经常提到的Docker就是指的docker engine
- Rkt的管理工具是rkt cli
1.1.8.4 容器定义工具
容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建。
Docker image: 是docker 容器的模板,runtime依据docker image创建容器
Dockerfile: 包含N个命令的文本文件,通过dockerfile创建出docker image
ACI(App container image): 与docker image类似,是CoreOS开发的rkt容器的镜像格式
1.1.8.5 镜像仓库 Registry
统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库
- Docker hub: docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用
- 阿里云,网易等第三方镜像仓库
- Image registry: docker 官方提供的私有仓库部署工具,无web管理界面,目前使用较少
- Harbor: vmware 提供的自带web界面自带认证功能的镜像仓库,目前有很多公司使用
1.1.8.6 编排工具
当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎
容器编排通常包括容器管理、调度、集群定义和服务发现等功能
- Docker swarm: docker 开发的容器编排引擎
- Kubernetes: google领导开发的容器编排引擎,内部项目为Borg,且其同时支持docker和CoreOS
1.1.9 docker(容器)的依赖技术
容器网络:
docker自带的网络docker network仅支持管理单机上的容器网络,当多主机运行的时候需要使用第三方开源网络,例如calico、flannel等
服务发现:
容器的动态扩容特性决定了容器IP也会随之变化,因此需要有一种机制自动识别并将用户请求动态转发到新创建的容器上kubernetes自带服务发现功能,需要结合kube-dns服务解析内部域名
容器监控:
可以通过原生命令docker ps/top/stats 查看容器运行状态,另外也可以使Prometheus 、heapster等第三方监控工具监控容器的运行状态
数据管理:
容器的动态迁移会导致其在不同的Host之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决
日志收集:
docker 原生的日志查看工具docker logs,但是容器内部的日志需要通过ELK等专门的日志收集分析和展示工具进行处理