1、容器的概念
本质:一组受到资源限制,彼此间相互隔离的进程,是一种轻量级的虚拟化技术。
Dokcer的英文意思是码头工人,容器可以类比为集装箱。码头工人的工作就是搬运集装箱,Docker的工作就是负责容器的生命周期管理。为什么这么类比呢?
在集装箱出现之前,要进行远距离货物的运输,第一步是城市货运站要打包货物,把货物装到卡车里,到了火车站货物拆卸-再次打包-装载到火车上运输到码头,货物拆卸-打包-装载到货轮,通过货轮运输到目的国家城市,因此可以看到实际上运输货物的过程中最花费时间的是中间过程,即卸载载-打包-装载的过程,中间为什么要重复打包呢,因为不同的交通载具装载货物有不同要求,对大小,规格,尺寸有自己的要求,所有会重复打包,如果有一种方案能够统一上述标准是否能够极大的提高效率呢,集装箱就应运而生了,集装箱重要在它提供了一种通用的封装货物的标准规格(尺寸,外形符合统一标准),这样货物到达不同的站点就能够快速的装载卸载而不用重新打包,极大地额提高了效率。
容器就类似集装箱的功能,不过它不是打包货物,而是打包应用服务。我们知道传统的方式部署一个app需要操作系统,app运行的系统环境,app需要的基础插件等,上述工作需要花费大量的时间和精力,容器的好处就在于它把上面的所有工作都统一成1个image(类似集装箱),image符合统一的标准格式。通过容器的方式来部署app只需要根据image来实例化1个容器就可以了,不需要在安装1个操作系统,配置复杂的环境变量,安装各种依赖的服务和插件,因为这些都已经按照标准化的格式统一到镜像里了。
2、虚拟化的常见类型
前面提到容器是一组受到资源限制,彼此间相互隔离的进程,是一种轻量级的虚拟化技术。这里讲讲虚拟化。
2.1 传统的主机架构
可以看到所有app共享同1个OS和硬件资源。
2.2 主机级虚拟化
简而言之:就是在1个主机上运行多个虚拟机实例。
每一个虚拟机实例安装自己的独立的操作系统,拥有自己可视的,隔离于其它实例的基础硬件资源,包括CPU,内存等等,拥有自己的内核空间和用户空间(Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间。)。
按类型划分有。
Type1:直接在硬件上安装VMM,由VMM进行虚拟机的生命周期管理
Type2:宿主机之上安装主机OS和VMM,由VMM进行虚拟机的生命周期管理
从这我们可以看到,虚机的性能相比物理机要有损耗的但是提供了更高的灵活性,便捷性。接下来说说容器级虚拟化。
2.3 容器级虚拟化
容器运行在宿主机的OS之上,那么容器是如何实现硬件资源隔离的呢,答案就是Namespace和cgroups。
Namespace:名称空间
LinuxLinux 内核用来隔离内核资源的方式
举个简单例子理解namespace:1个公司有财务部,市场部,研发部,运维部。每个部门有自己的领导员工等人力资源,业务系统、支撑系统等软件资源,办公 室,电脑等硬件资源,这些系统,硬件资源之间是相互独立,互不影响的,换句话说是”隔离”的。部门就类似主机的namespace,而下面的各个资源就类似主机的cpu, 内存,硬盘等资源,所以namespace的作用就是隔离这些资源提供给上层使用。
Namespace的概念清楚了,那么liunx提供了哪些namespace来支持容器呢?
Linux的内核里通过namespace的方式原生支持下面的6类隔离来支持容器。
PID:进程隔离
进程:正在运行的程序的实例,比如QQ,微信,钉钉等运行都会产生进程
NET: 网络隔离 (网络端口,网络堆栈等)
IPC:跨进程通信(信号量,消息队列等)
MNT:挂载点隔离 (文件系统)
UTS:内核和版本标识隔离 (主机名和域名)
User: 用户隔离 (用户名和用户组)
这里也就解释了容器的隔离性。
Namespae解决了容器之间的隔离性问题,那么隔离后的容器之间的硬件资源占用怎么分配呢?答案就是Cgroups
Cgroups:控制组
控制每个控制组中的资源分配,包括IO设备,块设备,CPU,内存等的使用,将名称空间和控制组关联可以通过控制组来控制名称空间的资源分配。
2.4 容器和虚拟机对比
| 主机级虚拟化 | 容器级虚拟化 |
优势 | 隔离性好(独立的内核),安全性好 | 性能损耗小,启动速度快,轻量级(没有guestos) |
缺点 | 性能损耗大,启动速度慢 | 隔离性差(共享内核),安全性差 |
3、Docker简介
Docker 是一个开源的应用容器引擎,打包应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。
3.1 Docker架构
由上图可以看到,
docker主要有三部分组成:Docker Client,DOCKER_HOST和Registry。
docker是基于CS的架构,Clinet 是客户端,DOCKER_HOST是服务端。
Registry是镜像仓库(默认是docker hub)。
DOCKER_HOST由容器和镜像组成。Docker daemon是docker的守护进程,在指定端口负责监听docker客户端发来的API指令,并执行相关操作。
DOCKER的客户端和主机端默认都使用https协议,遵循restful api风格。
基本逻辑是docker client端操作docker主机(服务端)实现容器的生命周期管理,Registry负责存放容器需要使用的镜像。比如到镜像仓库拉镜像到本地,根据镜像 创建容器,销毁容器,制作镜像,推送镜像到仓库等。
3.2 Registry
用来存储docker容器启动镜像的仓库,官方的默认的Registry是https://hub.docker.com/
首页如下:
注册账号之后,会看到自己的项目名就是注册的名字
镜像仓库的存储方式是:项目-仓库名-镜像的格式
仓库名:因为dokcer容器一般都是1个APP1个容器,因此仓库名一般和应用app取相同的名字。比如这里我们创建1个nginx的仓库
点击crate repository
这里可以看到项目名:luoaye 仓库名:nginx 可见性选择public 表明所有dcoker hub的用户可以看到改仓库下的镜像,可以下载。点击create 即可创建成功。
镜像名:一般用来表示仓库内镜像的不同版本,比如nginx1.1,nginx1.2
比如上传1个nginx的1.1-1版本到上述仓库,则上传完毕后仓库存储结构如下:
luoaye/nginx/v1.1-1 这就表明luoaye项目下面nginx仓库的nginx:v1.1-1版本的镜像。
3.3 镜像和容器的关系
镜像和容器之间就类似于程序和进程之间的关系。
比如使用top命令,可以实时查看系统的CPU负荷状态,运行top时系统会启动1个进程,这个进程时动态的,实时的,而top命令本身就是1个程序,它是静态的, 关闭top产生的这个进程后,top程序本身还存在,不会因为top进程的关闭而删除top程序。同样的镜像也是静态的,容器是动态的,容器使用镜像启动,是实例化的镜 像。停止删除容器并不会影响镜像的存在,两者之间是解耦的。