写这篇文章主要是为了今后毕业论文素材上的整理,同时对docker进行巩固温习。
大纲:
-
docker简介
docker出现的背景、docker是什么。 -
docker生态系统和应用场景
哪些工作与社区与docker有关,docker有哪些具体实用价值。 -
docker原理
docker与linux究竟有何渊源,从技术层面进行介绍。 -
docker与虚拟机性能对比
docker与vm技术有哪些区别,本文将进行对比,并总结出docker优缺点。 -
docker技术点
docker安装、dockerfile编写、常用docker命令。 -
容器管理工具kubernetes介绍
巨头谷歌开源的解决方案k8s介绍,k8s环境搭建和小案例 -
docker学习总结与展望
一、docker简介
Docker是一个由GO语言写的程序运行的“容器”(Linux containers, LXCs); 目前云服务的基石是操作系统级别的隔离,在同一台物理服务器上虚拟出多个主机。Docker则实现了一种应用程序级别的隔离; 它改变我们基本的开发、操作单元,由直接操作虚拟主机(VM),转换到操作程序运行的“容器”上来。
Docker是2013年Docker 是 PaaS提供商 dotCloud 开源的一个基于 LXC 的高级容器引擎,源代码托管在 Github上, 基于go语言并遵从Apache2.0协议开源,是dotCloud公司的绝处逢生之作,目前该公司以[docker]为名。
从2013年3月20日,第一个版本的Docker正式发布到 2014年6月Docker 1.0 正式发布,经历了15个月。 虽然发展历程很短,但Docker正在有越来越流行的趋势。
其实Container技术并非Docker的创新,HeroKu, NodeJitsu 等云服务商都采用了类似这种轻量级的虚拟化技术,但Docker是第一个将这这种Container技术大规模开源并被社区广泛接受的。
截止2016年9月1日,docker版本已经发展到了1.12,支持容器管理功能。
![](https://img.haomeiwen.com/i764980/9d00087087057bb6.png)
二、docker生态系统和应用场景
2.1 docker生态系统
docker生态系统如下图所示。
![](https://img.haomeiwen.com/i764980/0232f1211972bb3e.png)
Docker具备大量的合作用户如亚马逊、jekins等公司,社区活跃度也非常高。
Docker提供的平台主要有Docker Hub和Docker Engine(Docker Engine是一系列linux技术的集合体现,之后会有详细介绍)。
Docker生态系统需要了解的核心概念主要有三大组件。
- Docker 镜像 - Docker images
- Docker 仓库 - Docker registeries
- Docker 容器 - Docker containers
2.1.1 Docker镜像
Docker 镜像是 Docker 容器运行时的只读模板,每一个镜像由一系列的层 (layers) 组成。Docker 使用 UnionFS 来将这些层联合到单独的镜像中。UnionFS 允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统。正因为有了这些层的存在,Docker 是如此的轻量。当你改变了一个 Docker 镜像,比如升级到某个程序到新的版本,一个新的层会被创建。因此,不用替换整个原先的镜像或者重新建立(在使用虚拟机的时候你可能会这么做),只是一个新 的层被添加或升级了。现在你不用重新发布整个镜像,只需要升级,层使得分发 Docker 镜像变得简单和快速。
![](https://img.haomeiwen.com/i764980/52f8ebb75bec0a0b.png)
2.1.2 Docker仓库
Docker Hub是类似于Github的一种代码仓库,同样的,Docker 仓库也有公有和私有的概念。公有的 Docker 仓库名字是 Docker Hub。Docker Hub 提供了庞大的镜像集合供使用。这些镜像可以是自己创建,或者在别人的镜像基础上创建。Docker 仓库是 Docker 的分发部分。
![](https://img.haomeiwen.com/i764980/4d8f2036299ff006.png)
2.1.3 Docker 容器
Docker 容器和文件夹很类似,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台,Docker 容器是 Docker 的运行部分。
![](https://img.haomeiwen.com/i764980/ec5717a0083be2d6.png)
2.2 Docker应用场景
Docker的生态系统如此庞大和受欢迎,那么它的应用场景在哪些方面呢?
我查阅资料,整理了一些场景如下。
-
权衡资源隔离和低消耗的场景
在AVOS平台上,一台 16 核 32G 内存的虚拟机上,需要跑 500+ 个用户的应用(每个应用的功能可以认为是一个网站 + 一系列的 RESTful API),有两个事情很重要: -
资源隔离:比如限制应用最大内存使用量,或者资源加载隔离等。
-
低消耗:虚拟化本身带来的损耗需要尽量的低。
我们不可能在一台机器上开 500 个虚拟机,虽然可以在资源隔离方面做的很好,但这种虚拟化本身带来的资源消耗太严重。
另一个方面,我们可以考虑使用语言级别沙箱,虽然这种「虚拟化」本身的消耗可以低到忽略不计,但是资源隔离方面绝对是噩梦,比如你打算在一个 JVM 里隔离内存的使用。
而 Docker 很好的权衡了两者,即拥有不错的资源隔离能力,又有很低的虚拟化开销。 -
孙宏亮:从轻量级工具、持续集成到微服务架构
- 就我个人所知,早在14年国内有一些公司,开始尝试docker,当时毕竟docker是一个新事物,很多新特性方面的优点,并没有被大大的利用起来,这个也可以理解。那时docker对一些企业的价值在于计算的轻量级,也就是对于一些计算型的任务,通过docker的形式来分发,部署快,隔离性好,这样的任务包括:消息传递,图像处理等。
- 14下半年到15年初,docker的价值被更大化,应用的运行,服务的托管,外界的接受度也变高,国内也出现了一些startup公司,比如DaoCloud,灵雀云等。但这些仅仅是这些公司的第一步,后续紧跟的更多的是基于代码与镜像之间的CI/CD,缩减开发测试发布的流程,这方面的实践逐渐成熟。
- 微服务架构的兴起。微服务会对现阶段的软件架构有一些冲击,同样也是软件系统设计方法论的内容。这些方面国外讨论的要多一些,相信这一点也会近年来多家公司发力的地方。
-
需要配置多种不同环境的场景
这是Docker公司宣传的Docker的主要使用场景。虚拟机的最大好处是能在你的硬件设施上运行各种配置不一样的平台(软件、系统),Docker在降低额外开销的情况下提供了同样的功能。它能让你将运行环境和配置放在代码中然后部署,同一个Docker的配置可以在不同的环境中使用,这样就降低了硬件要求和应用环境之间耦合度。 -
快速部署和整合服务器的场景
正如通过虚拟机来整合多个应用,Docker隔离应用的能力使得Docker可以整合多个服务器以降低成本。由于没有多个操作系统的内存占用,以及能在多个实例之间共享没有使用的内存,Docker可以比虚拟机提供更好的服务器整合解决方案。在虚拟机之前,引入新的硬件资源需要消耗几天的时间。Docker的虚拟化技术将这个时间降到了几分钟,Docker只是创建一个容器进程而无需启动操作系统,这个过程只需要秒级的时间。这正是Google和Facebook都看重的特性。
你可以在数据中心创建销毁资源而无需担心重新启动带来的开销。通常数据中心的资源利用率只有30%,通过使用Docker并进行有效的资源分配可以提高资源的利用率。 -
李肇中:利用Docker体验不易安装的场景,提高工作效率
我认为docker的出现对于linux开发者是重大利好,我们都知道在linux上面做开发,配置环境变量异常繁琐,尤其是在设置交叉编译环境的时候。
举个例子比如我要设置mips的编译环境,而我宿主机是debian.有些优秀的工具只存在于gentoo平台,而gentoo又不好安装,我们使用docker只要从docker hub上面pull下镜像,就可以完美使用,这使得开发人员效率最大化。
以上场景应用摘自知乎问答https://www.zhihu.com/question/22969309
小结:个人认为在linux进行学习时,可以将学习内容进行docker化打包保存到docker hub或者私有仓库,这样就不怕在环境丢失时重新配置环境。当然,实际应用时,一个用户数不大的web应用放在docker上操作也简单,是可以作为一个备份保存下来的。
三、Docker原理
Docker核心解决的问题是利用LXC来实现类似VM的功能,从而利用更加节省的硬件资源提供给用户更多的计算资源。同VM的方式不同, LXC其并不是一套硬件虚拟化方法 - 无法归属到全虚拟化、部分虚拟化和半虚拟化中的任意一个,而是一个操作系统级虚拟化方法, 理解起来可能并不像VM那样直观。所以我们从虚拟化到docker要解决的问题出发,看看他是怎么满足用户虚拟化需求的。
用户需要考虑虚拟化方法,尤其是硬件虚拟化方法,需要借助其解决的主要是以下4个问题:
- 隔离性 - 每个用户实例之间相互隔离, 互不影响。 硬件虚拟化方法给出的方法是VM, LXC给出的方法是container,更细一点是kernel namespace
- 可配额/可度量 - 每个用户实例可以按需提供其计算资源,所使用的资源可以被计量。硬件虚拟化方法因为虚拟了CPU, memory可以方便实现, LXC则主要是利用cgroups来控制资源
- 移动性 - 用户的实例可以很方便地复制、移动和重建。硬件虚拟化方法提供snapshot和image来实现,docker(主要)利用AUFS实现
- 安全性 - 这个话题比较大,这里强调是host主机的角度尽量保护container。硬件虚拟化的方法因为虚拟化的水平比较高,用户进程都是在KVM等虚拟机容器中翻译运行的, 然而对于LXC, 用户的进程是lxc-start进程的子进程, 只是在Kernel的namespace中隔离的, 因此需要一些kernel的patch来保证用户的运行环境不会受到来自host主机的恶意入侵, dotcloud(主要是)利用kernel grsec patch解决的。
![](https://img.haomeiwen.com/i764980/37bfc1d698d4a95b.png)
3.1 Namespace
Namespace主要负责资源隔离,可以保障一个容器中运行一个进程而且不能看到和影响容器外的其它进程。
![](https://img.haomeiwen.com/i764980/e651c24cae849861.png)
有了以上5种namespace从进程、网络、IPC、文件系统、UTS和用户角度的隔离,一个container就可以对外展现出一个独立计算机的能力,并且不同container从OS层面实现了隔离。然而不同namespace之间资源还是相互竞争的,仍然需要类似ulimit来管理每个container所能使用的资源 - LXC 采用的是cgroup。
3.2 Control Groups(cgroup)
cgroups 实现了对资源的配额和度量。 cgroups 的使用非常简单,提供类似文件的接口,在 /cgroup目录下新建一个文件夹即可新建一个group,在此文件夹中新建task文件,并将pid写入该文件,即可实现对该进程的资源控制。具体的资源配置选项可以在该文件夹中新建子 subsystem ,{子系统前缀}.{资源项} 是典型的配置方法.
通过cgroup限制资源如cpu、内存、硬盘I/O的使用。
3.3 Linux 容器 (LXC)
借助于namespace的隔离机制和cgroup限额功能,LXC提供了一套统一的API和工具来建立和管理container。
LXC 旨在提供一个共享kernel的 OS 级虚拟化方法,在执行时不用重复加载Kernel, 且container的kernel与host共享,因此可以大大加快container的 启动过程,并显著减少内存消耗。在实际测试中,基于LXC的虚拟化方法的IO和CPU性能几乎接近 baremetal 的性能, 大多数数据有相比 Xen具有优势。当然对于KVM这种也是通过Kernel进行隔离的方式, 性能优势或许不是那么明显, 主要还是内存消耗和启动时间上的差异。
3.4 AUFS
Docker对container的使用基本是建立在LXC基础之上的,然而LXC存在的问题是难以移动 - 难以通过标准化的模板制作、重建、复制和移动 container。
在以VM为基础的虚拟化手段中,有image和snapshot可以用于VM的复制、重建以及移动的功能。想要通过container来实现快速的大规模部署和更新, 这些功能不可或缺。
Docker 正是利用AUFS来实现对container的快速更新 - 在docker0.7中引入了storage driver, 支持AUFS, VFS, device mapper, 也为BTRFS以及ZFS引入提供了可能。 但除了AUFS都未经过dotcloud的线上使用,因此我们还是从AUFS的角度介绍。
AUFS (AnotherUnionFS) 是一种 Union FS, 简单来说就是支持将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)的文件系统, 更进一步地, AUFS支持为每一个成员目录(AKA branch)设定'readonly', 'readwrite' 和 'whiteout-able' 权限, 同时AUFS里有一个类似
分层的概念, 对 readonly 权限的branch可以逻辑上进行修改(增量地, 不影响readonly部分的)。通常 Union FS有两个用途, 一方面可以实现不借助 LVM, RAID 将多个disk和挂在到一个目录下, 另一个更常用的就是将一个readonly的branch和一个writeable的branch联合在一起,Live CD正是基于此可以允许在 OS image 不变的基础上允许用户在其上进行一些写操作。Docker在AUFS上构建的container image也正是如此。
![](https://img.haomeiwen.com/i764980/11121d3ed5675ecf.png)
如上图所示,AUFS技术利用了写时拷贝技术,只读部分是Image,可写部分是container.允许read-only和read-write目录并存;可以实现把多个不同目录的内容合并在一起。
3.5 GRSEC
grsec是linux kernel安全相关的patch, 用于保护host防止非法入侵。由于其并不是docker的一部分,我们只进行简单的介绍。
grsec可以主要从4个方面保护进程不被非法入侵:
- 随机地址空间 - 进程的堆区地址是随机的
- 用只读的memory management unit来管理进程流程, 堆区和栈区
- 内存只包含数据结构/函数/返回地址和数据, 是non-executeable
- 审计和Log可疑活动
- 编译期的防护
安全永远是相对的,这些方法只是告诉我们可以从这些角度考虑container类型的安全问题可以关注的方面。
3.6 Docker运行原理
Docker本身是基于C/S架构的,有自己的服务器和客户端,Docker实际上由三大组件构成,如下图所示。
![](https://img.haomeiwen.com/i764980/e5af88e835814c06.png)
其中,docker client是用户界面,docker daemon处理服务请求,docker containers负责应用程序的运行。
四、Docker与vm性能对比
4.1 Docker性能测试测试环境:
- 操作系统:CentOS7、openstack nova-docker启动的centos7、openstack环境启动的centos7
- 虚拟机CPU:Intel(R) Xeon(R) CPU E5-2690 v3 @ 2.60GHz * 2
- 内存:Micron 2133MHz 16G * 8
- 网卡:Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection关键字:Linpack、netperf、iometer
测试从计算效率、内存访问效率、启动时间和资源消耗进行比较。
4.1.1 Docker与虚拟机计算效率比较
在测试中是通过运算Linpack程序来获得计算能力数据的。结果如下图所示:
![](https://img.haomeiwen.com/i764980/c0a1f5a5f6351287.png)
图中从左往右分别是物理机、docker和虚拟机的计算能力数据。可见docker相对于物理机其计算能力几乎没有损耗,而虚拟机对比物理机则有着非常明显的损耗。虚拟机的计算能力损耗在50%左右。 为什么会有这么大的性能损耗呢?一方面是因为虚拟机增加了一层虚拟硬件层,运行在虚拟机上的应用程序在进行数值计算时是运行在Hypervisor虚拟的CPU上的;另外一方面是由于计算程序本身的特性导致的差异。虚拟机虚拟的cpu架构不同于实际cpu架构,数值计算程序一般针对特定的cpu架构有一定的优化措施,虚拟化使这些措施作废,甚至起到反效果。比如对于本次实验的平台,实际的CPU架构是2块物理CPU,每块CPU拥有16个核,共32个核,采用的是NUMA架构;而虚拟机则将CPU虚拟化成一块拥有32个核的CPU。这就导致了计算程序在进行计算时无法根据实际的CPU架构进行优化,大大减低了计算效率。
4.1.2 docker与虚拟机内存访问效率比较
内存访问效率的比较相对比较复杂一点,主要是内存访问有多种场景:
- 大批量的,连续地址块的内存数据读写。这种测试环境下得到的性能数据是内存带宽,性能瓶颈主要在内存芯片的性能上;
- 随机内存访问性能。这种测试环境下的性能数据主要与内存带宽、cache的命中率和虚拟地址与物理地址转换的效率等因素有关。 以下将主要针对这两种内存访问场景进行分析。在分析之前我们先概要说明一下docker和虚拟机的内存访问模型差异。下图是docker与虚拟机内存访问模型:
![](https://img.haomeiwen.com/i764980/9b157f4763ae9bfa.png)
可见在应用程序内存访问上,虚拟机的应用程序要进行2次的虚拟内存到物理内存的映射,读写内存的代价比docker的应用程序高。
4.1.3 docker与虚拟机启动时间及资源耗费比较
上面两个小节主要从运行在docker里的程序和运行在虚拟机里的程序进行性能比较。事实上,docker之所以如此受到开发者关注的另外一个重要原因是启动docker的系统代价比启动一台虚拟机的代价要低得多:无论从启动时间还是从启动资源耗费角度来说。docker直接利用宿主机的系统内核,避免了虚拟机启动时所需的系统引导时间和操作系统运行的资源消耗。利用docker能在几秒钟之内启动大量的容器,这是虚拟机无法办到的。快速启动、低系统资源消耗的优点使docker在弹性云平台和自动运维系统方面有着很好的应用前景。
4.2 docker优缺点总结
4.2.1优点
- 容积小且速度快,易于分发且能隔离应用
- cpu/内存的低消耗
- 可以部署在本地,虚拟机或者云上
- 支持绝大多数linux系统,windows、mac除了虚拟版,也有beta版投入研发,平台较为完善
- Google、微软、亚马逊等公司都支持Docker
4.2.2缺点
-
真实投入生产,还需要多种开源组件和技术的支持,如kubernetes管理容器、etcd管理存储、应用打包技术dockerfile、容器间的网络管理flannel、私有仓库的构建、持续集成jenkins的结合、监控docker的工具等等。
-
docker自身版本迭代较快,国内还未有完善的解决方案
-
docker部署过程中对基础运维的要求更高,会遇到问题如Docker镜像热升级、Docker版本热升级、监控报警等等。
-
docker对于windows、mac的原生支持尚处在beta版本。
五、Docker技术点
5.1 Docker安装
windows、mac、linux版本安装均可在官网https://docs.docker.com/
5.2 常用docker命令
- 查看容器日志
docker logs -f <容器名orID> - 查看正在运行的容器
- docker ps
- docker ps -a为查看所有的容器,包括已经停止的。
- 删除所有容器
docker rm $(docker ps -a -q) - 删除单个容器
docker rm <容器名orID> - 停止、启动、杀死一个容器
- docker stop <容器名orID>
- docker start <容器名orID>
- docker kill <容器名orID>
- 查看所有镜像
docker images - 拉取镜像
docker pull <镜像名:tag>
如docker pull sameersbn/redmine:latest - 当需要把一台机器上的镜像迁移到另一台机器的时候,需要保存镜像与加载镜像。
机器a
docker save busybox-1 > /home/save.tar
使用scp将save.tar拷到机器b上,然后:
docker load < /home/save.tar - 构建自己的镜像
docker build -t <镜像名> <Dockerfile路径>
如Dockerfile在当前路径:
docker build -t xx/gitlab . - 后台运行(-d)、并暴露端口(-p)
docker run -d -p 127.0.0.1:33301:22 centos6-ssh
其它语法可通过docker命令查询学习,后面的案例会介绍一些实际命令的使用。
5.3 dockerfile文件的编写
- dockerfile referencehttps://docs.docker.com/engine/reference/builder/
- bestpractice https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
5.4 Docker应用案例
5.4.1 javeee应用
5.4.2 mysql服务
5.4.3 wordpress博客服务
5.4.4 tomcat的web应用,以现有应用为例
六、容器管理工具kubernetes
6.1 kubernetes简介
Kubernetes是Google开源的容器集群管理系统,其提供应用部署、维护、 扩展机制等功能,利用Kubernetes能方便地管理跨机器运行容器化的应用,其主要功能如下:
-
使用Docker对应用程序包装(package)、实例化(instantiate)、运行(run)。
-
以集群的方式运行、管理跨机器的容器。
-
解决Docker跨机器容器之间的通讯问题。
-
Kubernetes的自我修复机制使得容器集群总是运行在用户期望的状态。
它透明地为用户提供原生态系统,如“需要5个 WildFly服务器和1个 MySQL服务器运行". Kubernetes具有自我修复机制,如重新启动 重新启动定时计划 复制容器以确保恢复状态,用户只需要定义状态,那么 Kubernetes就会确保状态总是在集群中。
Docker定义了运行代码时的容器,有命令用来启动 停止 重启 链接容器,Kubernetes使用Docker打包以及实例化应用程序。
一个典型的应用程序必须跨多个主机。 例如,您的web层(Apache )可能运行在一个容器。 同样地,应用程序层将会运行在另外一组不同的容器中。 web层需要将请求委托给应用程序层。 当然,在某些情况下,你可能将web服务器和应用服务器打包在一起放在相同的容器。 但是数据库层通常运行在一个单独层中。 这些容器之间需要相互交互。 使用上面的任何解决方案都需要编制脚本启动容器,以及监控容器,因防止出现问题。 而Kubernetes在应用程序状态被定义后将为用户实现所有这些工作。
6.2 kubernetes原理与架构
6.2.1 kubernetes概念
![](https://img.haomeiwen.com/i764980/778ca2c87e406b39.png)
6.2.1.1 Pods
Pod是Kubernetes的基本操作单元,把相关的一个或多个容器构成一个Pod,通常Pod里的容器运行相同的应用。Pod包含的容器运行在同一个Minion(Host)上,看作一个统一管理单元,共享相同的volumes和network namespace/IP和Port空间。
6.2.1.2 Services
Services也是Kubernetes的基本操作单元,是真实应用服务的抽象,每一个服务后面都有很多对应的容器来支持,通过Proxy的port和服务selector决定服务请求传递给后端提供服务的容器,对外表现为一个单一访问接口,外部不需要了解后端如何运行,这给扩展或维护后端带来很大的好处。
6.2.1.3 Replication Controllers
Replication Controller确保任何时候Kubernetes集群中有指定数量的pod副本(replicas)在运行, 如果少于指定数量的pod副本(replicas),Replication Controller会启动新的Container,反之会杀死多余的以保证数量不变。Replication Controller使用预先定义的pod模板创建pods,一旦创建成功,pod 模板和创建的pods没有任何关联,可以修改pod 模板而不会对已创建pods有任何影响,也可以直接更新通过Replication Controller创建的pods。对于利用pod 模板创建的pods,Replication Controller根据label selector来关联,通过修改pods的label可以删除对应的pods。Replication Controller主要有如下用法:
- Rescheduling
如上所述,Replication Controller会确保Kubernetes集群中指定的pod副本(replicas)在运行, 即使在节点出错时。 - Scaling
通过修改Replication Controller的副本(replicas)数量来水平扩展或者缩小运行的pods。 - Rolling updates
Replication Controller的设计原则使得可以一个一个地替换pods来rolling updates服务。 - Multiple release tracks
如果需要在系统中运行multiple release的服务,Replication Controller使用labels来区分multiple release tracks。
6.2.1.4 Labels
Labels是用于区分Pod、Service、Replication Controller的key/value键值对,Pod、Service、 Replication Controller可以有多个label,但是每个label的key只能对应一个value。Labels是Service和Replication Controller运行的基础,为了将访问Service的请求转发给后端提供服务的多个容器,正是通过标识容器的labels来选择正确的容器。同样,Replication Controller也使用labels来管理通过pod 模板创建的一组容器,这样Replication Controller可以更加容易,方便地管理多个容器,无论有多少容器。
6.2.2 kubernetes架构
Kubenetes整体框架如下图,主要包括kubecfg、Master API Server、Kubelet、Minion(Host)以及Proxy。
![](https://img.haomeiwen.com/i764980/e7a4709fe3728fb3.png)
具体每部分功能可参考书籍《kubernetes权威指南》。
6.3 kubernetes中算法介绍
6.3.1算法概览
最新一版的kubernetes release中我们看到了一个令人欣喜的特性:Autoscaling。它实现了replicationcontroller中pod的横向自动扩容。以下是摘自官方文档的相关内容:
自动扩容将通过一个新的resource(就像之前的pod,service等等)实现。目前只支持针对cpu使用度进行动态扩容。未来的版本中,将会实现基于另一个resource:metrics(这是说未来监控数据将会有一个更统一的展示?)
主要结构
1.Scale subresourceScale subresource是一个虚拟的resource,用来记录扩容进度。其主要结构如下:
// represents a scaling request for a resource.
type Scale struct {
unversioned.TypeMeta
api.ObjectMeta
// defines the behavior of the scale.
Spec ScaleSpec
// current status of the scale.
Status ScaleStatus
}
// describes the attributes of a scale subresource
type ScaleSpec struct {
// desired number of instances for the scaled object.
Replicas int json:"replicas,omitempty"
}
// represents the current status of a scale subresource.
type ScaleStatus struct {
// actual number of observed instances of the scaled object.
Replicas int json:"replicas"
// label query over pods that should match the replicas count. Selector map[string]string json:"selector,omitempty"
}
其中ScaleSpec.Replicas表示我们预定的集群实例数目标。ScaleStatus.Replicas表示当前实例数,ScaleStatus.Selector是一个选择器,选择对应的pods。
2.HorizontalPodAutoscaler 这个就是真正控制扩容的resource,其结构如下:
// configuration of a horizontal pod autoscaler.
type HorizontalPodAutoscaler struct {
unversioned.TypeMeta
api.ObjectMeta
// behavior of autoscaler.
Spec HorizontalPodAutoscalerSpec
// current information about the autoscaler.
Status HorizontalPodAutoscalerStatus
}
// specification of a horizontal pod autoscaler.
type HorizontalPodAutoscalerSpec struct {
// reference to Scale subresource; horizontal pod autoscaler will learn the current resource
// consumption from its status,and will set the desired number of pods by modifying its spec.
ScaleRef SubresourceReference
// lower limit for the number of pods that can be set by the autoscaler, default 1.
MinReplicas *int
// upper limit for the number of pods that can be set by the autoscaler.
// It cannot be smaller than MinReplicas.
MaxReplicas int
// target average CPU utilization (represented as a percentage of requested CPU) over all the pods;
// if not specified it defaults to the target CPU utilization at 80% of the requested resources.
CPUUtilization *CPUTargetUtilization
}
type CPUTargetUtilization struct {
// fraction of the requested CPU that should be utilized/used, // e.g. 70 means that 70% of the requested CPU should be in use.
TargetPercentage int
}
// current status of a horizontal pod autoscaler
type HorizontalPodAutoscalerStatus struct {
// most recent generation observed by this autoscaler. ObservedGeneration *int64
// last time the HorizontalPodAutoscaler scaled the number of pods;
// used by the autoscaler to control how often the number of pods is changed.
LastScaleTime *unversioned.Time
// current number of replicas of pods managed by this autoscaler.
CurrentReplicas int
// desired number of replicas of pods managed by this autoscaler. DesiredReplicas int
// current average CPU utilization over all pods, represented as a percentage of requested CPU,
// e.g. 70 means that an average pod is using now 70% of its requested CPU.
CurrentCPUUtilizationPercentage *int
}
其中的ScaleRef是一个Scale subresource的引用,MinReplicas, MaxReplicas and CPUUtilization定义了自动扩容的配置(允许的最大实例数,最小实例数,以及cpu使用配额)。
3.HorizontalPodAutoscalerList用于记录一个namespace下的所有HorizontalPodAutoscaler。本质上是一个结构数组。
6.3.2自动扩容算法
官方文档给出的并不是算法, 而是实现步骤,整个自动扩容的流程是:1.通过podselector找到要扩容的集群2.收集集群最近的cpu使用情况(CPU utilization)3.对比在扩容条件里记录的cpu限额(CPUUtilization)4.调整实例数(必须要满足不超过最大/最小实例数)5.每隔30s做一次自动扩容的判断(这个日后应该会成为一个扩容条件的参数)
CPU utilization的计算方法是用cpu usage(最近一分钟的平均值,通过heapster可以直接获取到)除以cpu请求(疑问:这个是是什么意思?)。未来k8s会开放一个api直接获取heapster收集到的监控数据。
真正的算法是:
A.TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target)ceil()表示取大于或等于某数的最近一个整数举个栗子:我们有一个集群实例数是3 pods。cpu限额,即Target是每个pod分配1.1核,当cpu的使用度CurrentPodsCPUUtilization为1.1,1.4,1.3时,要扩容成多少个呢?ceil((1.1+1.4+1.3)/1.1)= 4 所以扩容成四个实例。
B.由于启动实例时cpu的使用度会陡增,所以自动扩容会等待一段时间以收集准确的运行时监控数据。每次扩容/缩容后冷却三分钟才能再度进行扩容,而缩容则要等5分钟后。这是因为自动扩容使用保守的方法,尽可能满足pods业务的正常使用,所以扩容的优先级要大于缩容。
C.当满足:avg(CurrentPodsConsumption) / Target >1.1 或 <0.9时才会触发进行扩容/缩容。这也是为了避免出现频繁的扩容缩容。
扩容条件的相对与绝对度量
为了方便使用,建议采用相对(relative)的度量标准(如 90%的cpu资源)而不是绝对的标准(如0.6个cpu核心)来描述扩容条件。否则,当用户修改pods的请求资源时还需要去修改这些绝对值。比如:我们创建一个集群时,podtemplate中的resource里填入了cpu为1,即最多分配一个cpu核心给该pod,如果在扩容条件中采用绝对标准,我们必须填一个小于1的数,否则这个条件根本不会被触发。而当我们要修改分配的资源为0.8个核心时,又必须要修改扩容条件以确保其小于0.8。这就很麻烦了。
kubectl中的支持以及待支持
为了方便使用,在kubectl的cmd命令中加入了 creating/updating/deleting/listing 命令用来操作HorizontalPodAutoscaler
未来可能会加入像kubectl autoscale这样的命令,对一个已经在跑的集群实时进行动态扩容。
6.4 kubernetes环境搭建与工具介绍
本人已通过此教程搭建单机版kubernetes成功http://dockone.io/article/950
多机版由于条件限制还未成功实施。
七、Docker学习总结与展望
7.1 总结
容器技术究竟其成熟与否,也是互联网发展的一种趋势,它所提出的理念是值得每一位互联网工作者去学习和探讨的。
7.2 展望
docker官网在容器编排上的持续发力,今年7月份时docker公司将swarm整合进入docker engine层,其实我希望看到docker生态系统不要过多的碎片化,解决方案过多,容易导致迷失方向。
网友评论