一、docker简介
1.1 Docker是什么
首先Docker是一个在2013年开源的应用程序并且是一个基于go语言编写是一个开源的PAAS服务(Platform as a Service,平台即服务的缩写),go语言是由google开发,docker公司最早叫dotCloud后由于Docker开源后大受欢迎就将公司改名为 Docker Inc,总部位于美国加州的旧金山,Docker是基于linux 内核实现,Docker最早采用LXC技术(LinuX Container的简写,LXC是Linux 原生支持的容器技术,可以提供轻量级的虚拟化,可以说 docker 就是基于 LXC 发展起来的,提供 LXC 的高级封装,发展标准的配置方法),而虚拟化技术KVM(Kernelbased Virtual Machine) 基于模块实现,Docker后改为自己研发并开源的runc技术运行容器。
Docker 相比虚拟机的交付速度更快,资源消耗更低,Docker 采用客户端/服务端架构,使用远程API来管理和创建Docker容器,其可以轻松的创建一个轻量级的、可移植的、自给自足的容器,docker 的三大理念是build(构建)、ship(运输)、 run(运行),Docker遵从apache 2.0协议,并通过(namespace及cgroup等)来提供容器的资源隔离与安全保障等,所以Docke容器在运行时不需要类似虚拟机(空运行的虚拟机占用物理机6-8%性能)的额外资源开销,因此可以大幅提高资源利用率,总而言之Docker是一种用了新颖方式实现的轻量级虚拟机.类似于VM但是在原理和应用上和VM的差别还是很大的,并且docker的专业叫法是应用容器(Application Container)。
1.2 Docker的组成
官方说明 https://docs.docker.com/engine/docker-overview/
-
Docker 主机(Host):一个物理机或虚拟机,用于运行Docker服务进程和容器。
-
Docker 服务端(Server):Docker守护进程,运行docker容器。
-
Docker 客户端(Client):客户端使用docker 命令或其他工具调用docker API。
-
Docker 仓库(Registry): 保存镜像的仓库,类似于git或svn这样的版本控制系
-
Docker 镜像(Images):镜像可以理解为创建实例使用的模板。
-
Docker 容器(Container): 容器是从镜像生成对外提供服务的一个或一组服务。
1.3 Docker对比虚拟机
- 资源利用率更高:一台物理机可以运行数百个容器,但是一般只能运行数十个虚拟机。
- 开销更小:不需要启动单独的虚拟机占用硬件资源。
- 启动速度更快:可以在数秒内完成启动。
使用虚拟机是为了更好的实现服务运行环境隔离,每个虚拟机都有独立的内核,虚拟化可以实现不同操作系统的虚拟机,但是通常一个虚拟机只运行一个服务,很明显资源利用率比较低且造成不必要的性能损耗,我们创建虚拟机的目的是为了运行应用程序,比如Nginx、PHP、Tomcat等web程序,使用虚拟机无疑带来了一些不必要的资源开销,但是容器技术则基于减少中间运行环节带来较大的性能提升。
但是,如上图一个宿主机运行了N个容器,多个容器带来的以下问题怎么解决:
- 怎么样保证每个容器都有不同的文件系统并且能互不影响?
- 一个docker主进程内的各个容器都是其子进程,那么实现同一个主进程下不同类型的子进程?各个进程间通信能相互访问(内存数据)吗?
- 每个容器怎么解决IP及端口分配的问题?
- 多个容器的主机名能一样吗?
- 每个容器都要不要有root用户?怎么解决账户重名问题?
1.4 Linux 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.4.1 MNT Namespace
每个容器都要有独立的根文件系统有独立的用户空间,以实现在容器里面启动服务并且使用容器的运行环境,即一个宿主机是ubuntu的服务器,可以在里面启动一个centos运行环境的容器并且在容器里面启动一个Nginx服务,此Nginx运行时使用的运行环境就是centos系统目录的运行环境,但是在容器里面是不能访问宿主机的资源,宿主机是使用了chroot技术把容器锁定到一个指定的运行目录里面。
1.4.1 IPC Namespace
一个容器内的进程间通信,允许一个容器内的不同进程的(内存、缓存等)数据访问,但是不能夸容器访问其他容器的数据。
1.4.2 UTS Namespace
UTS namespace(UNIX Timesharing System包含了运行内核的名称、版本、底层体系结构类型等信息)用于系统标识,其中包含了hostname 和域名domainname ,它使得一个容器拥有属于自己hostname标识,这个主机名标识独立于宿主机系统和其上的其他容器。
1.4.3 PID Namespace
Linux系统中,有一个PID为1的进程(init/systemd)是其他所有进程的父进程,那么在每个容器内也要有一个父进程来管理其下属的子进程,那么多个容器的进程通PID namespace进程隔离(比如PID编号重复、器内的主进程生成与回收子进程等)。
1.4.4 Net Namespace
每一个容器都类似于虚拟机一样有自己的网卡、监听端口、TCP/IP协议栈等, Docker使用network namespace启动一个vethX接口,这样你的容器将拥有它自己的桥接ip地址,通常是docker0,而docker0实质就是Linux的虚拟网桥,网桥是在OSI七层模型的数据链路层的网络设备,通过mac地址对网络进行划分,并且在不同网络直接传递数据。
docker 实逻辑网络图
1.4.5 User Namespace
各个容器内可能会出现重名的用户和用户组名称,或重复的用户UID或者GID,那么怎么隔离各个容器内的用户空间呢?
User Namespace允许在各个宿主机的各个容器空间内创建相同的用户名以及相同的用户UID和GID,只是会把用户的作用范围限制在每个容器内,即A容器和B容器可以有相同的用户名称和ID的账户,但是此用户的有效范围仅是当前容器内,不能访问另外一个容器内的文件系统,即相互隔离、互补影响、永不相见。
1.5 Linux control groups
在一个容器,如果不对其做任何资源限制,则宿主机会允许其占用无限大的内存空间,有时候会因为代码bug程序会一直申请内存,直到把宿主机内存占完,为了避免此类的问题出现,宿主机有必要对容器进行资源分配限制,比如CPU、内存等,Linux Cgroups的全称是Linux Control Groups,它最主要的作用,就是限制一个进程组能够使用的资源上限,包括CPU、内存、磁盘、网络带宽等等。此外,还能够对进程进行优先级设置,以及将进程挂起和恢复等操作。
1.5.1 查看系统cgroups
ubuntu cgroups
1.5.2 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上的线程
1.6 容器管理工具
目前主要是使用docker,早期有使用lxc。
1.6.1 lxc
LXC:LXC为Linux Container的简写。可以提供轻量级的虚拟化,以便隔离进程和资源,官方网站:https://linuxcontainers.org/
lxc启动容器依赖于模板,清华模板源:
https://mirrors.tuna.tsinghua.edu.cn/help/lxc-images/,但是做模板相对较难,需要手动一步步创构建文件系统、准备基础目录及可执行程序等,而且在大规模使用容器的场景很难横向扩展,另外后期代码升级也需要重新从头构建模板,基于以上种种原因便有了docker。
1.6.2 pouch
阿里巴巴自研容器技术 Pouch
https://www.infoq.cn/article/alibaba-pouch https://github.com/alibaba/pouch
1.6.3 Docker
Docker 启动一个容器也需要一个外部模板但是较多镜像,docke的镜像可以保存在一个公共的地方共享使用,只要把镜像下载下来就可以使用,最主要的是可以在镜像基础之上做自定义配置并且可以再把其提交为一个镜像,一个镜像可以被启动为多个容器。
Docker的镜像是分层的,镜像底层为库文件且只读层即不能写入也不能删除数据,从镜像加载启动为一个容器后会生成一个可写层,其写入的数据会复制到容器目录,但是容器内的数据在删除容器后也会被随之删除。
1.7 Docker的优势
- 快速部署:短时间内可以部署成百上千个应用,更快速交付到线上。
- 高效虚拟化:不需要额外的hypervisor支持,直接基于linux 实现应用虚拟化,相比虚拟机大幅提高性能和效率。
- 节省开支:提高服务器利用率,降低IT支出
- 简化配置:将运行环境打包保存至容器,使用时直接启动即可。
- 快速迁移和扩展:可夸平台运行在物理机、虚拟机、公有云等环境,良好的兼容性可以方便将应用从A宿主机迁移到B宿主机,甚至是A平台迁移到B平台。
1.8 Docker的缺点
隔离性:各应用之间的隔离不如虚拟机彻底。
1.9 docker(容器)的核心技术
容器规范:
容器技术除了的docker之外,还有coreOS的rkt,还有阿里的Pouch,为了保证容器生态的标准性和健康可持续发展,包括Linux 基金会、Docker、微软、红帽谷歌和、IBM、等公司在2015年6月共同成立了一个叫open container(OCI)的组织,其目的就是制定开放的标准的容器规范,目前OCI一共发布了两个规范,分别是runtime spec和image format spec,有了这两个规范,不同的容器公司开发的容器只要兼容这两个规范,就可以保证容器的可移植性和相互可操作性。
容器runtime:
runtime是真正运行容器的地方,因此为了运行不同的容器runtime需要和操作系统内核紧密合作相互在支持,以便为容器提供相应的运行环境。
目前主流的三种runtime:
Lxc:linux上早期的runtime,Docker早期就是采用lxc作为runtime。
runc:目前Docker默认的runtime,runc遵守OCI规范,因此可以兼容lxc。
rkt:是CoreOS开发的容器runtime,也符合OCI规范,所以使用rktruntime也可以运行Docker容器。
容器管理工具:
管理工具连接runtime与用户,对用户提供图形或命令方式操作,然后管理工具将用户操作传递给runtime执行。
lxc是lxd的管理工具。
Runc的管理工具是docker engine,docker engine包含后台deamon和cli两部分,大家经常提到的Docker就是指的docker engine。
Rkt的管理工具是rkt cli。
容器定义工具:
容器定义工具允许用户定义容器的属性和内容,以方便容器能够被保存、共享和重建。
Docker image:是docker 容器的模板,runtime依据docker image创建容器。
Dockerfile:包含N个命令的文本文件,通过dockerfile创建出docker image。
ACI(App container image):与docker image类似,是CoreOS开发的rkt容器的镜像格式。
Registry:
统一保存镜像而且是多个不同镜像版本的地方,叫做镜像仓库。
Image registry:docker 官方提供的私有仓库部署工具。
Docker hub:docker官方的公共仓库,已经保存了大量的常用镜像,可以方便大家直接使用。
Harbor:vmware 提供的自带web界面自带认证功能的镜像仓库,目前有很多公司使用。
编排工具:
当多个容器在多个主机运行的时候,单独管理容器是相当复杂而且很容易出错,而且也无法实现某一台主机宕机后容器自动迁移到其他主机从而实现高可用的目的,也无法实现动态伸缩的功能,因此需要有一种工具可以实现统一管理、动态伸缩、故障自愈、批量执行等功能,这就是容器编排引擎。
容器编排通常包括容器管理、调度、集群定义和服务发现等功能。
Docker swarm:docker 开发的容器编排引擎。
Kubernetes:google领导开发的容器编排引擎,内部项目为Borg,且其同时支持docker和CoreOS。
Mesos+Marathon:通用的集群组员调度平台,mesos(资源分配)与marathon(容器编排平台)一起提供容器编排引擎功能。
1.10 docker(容器)的依赖技术
容器网络:
docker自带的网络docker network仅支持管理单机上的容器网络,当多主机运行的时候需要使用第三方开源网络,例如calico、flannel等。
服务发现:
容器的动态扩容特性决定了容器IP也会随之变化,因此需要有一种机制可以自动识别并将用户请求动态转发到新创建的容器上,kubernetes自带服务发现功能,需要结合kube-dns服务解析内部域名。
容器监控:
可以通过原生命令docker ps/top/stats 查看容器运行状态,另外也可以使heapster/ Prometheus等第三方监控工具监控容器的运行状态。
数据管理:
容器的动态迁移会导致其在不同的Host之间迁移,因此如何保证与容器相关的数据也能随之迁移或随时访问,可以使用逻辑卷/存储挂载等方式解决。
日志收集:
docker 原生的日志查看工具docker logs,但是容器内部的日志需要通过ELK等专门的日志收集分析和展示工具进行处理。