极客时间的课程。作者是张磊。课程很不错。

    大部分内容记录到了相应主题的目录中,此处保留一点网友笔记等。

    我现在有了一大批物理服务器,想要租界给别人使用。因此我搭建了一个物理集群,并向用户售卖,这是最初的IaaS。 用户通过购买我的虚拟机,就能在虚拟机上部署自己的应用来使用虚拟机。在使用过程中发现(1)由于本地的开发环境和购买的虚拟机之间有各种不一致导致调试、部署困难 (2)不用应用之间可能在同一个虚拟机上,没有隔离(3)大规模的应用部署也比较麻烦。 因此出现了PaaS,比如Cloud Foundry,它提供了(1)大规模部署应用的能力 (2)提供了“沙盒”容器来对应用隔离,让用户进程互不干扰。 但是在使用过程中,发现“沙盒”使用起来还是不方便,比如打包过程非常痛苦,就需要大量的人力投入来让本地应用和远端PaaS适配 ,因此出现了Docker。Docker用镜像来实现本地环境和云端环境的高度一致,解决了打包困难的问题,取代了Cloud Foundry这类PaaS项目中的“沙盒”。Docker因此崛起。

    随着Docker被大范围使用,PaaS的定义逐渐演变成了一套以Docker容器技术为核心,全新的”容器化“思路。2014年,Docker公司也顺势发布了自己的PaaS项目Swarm。Swarm项目的集群管理功能触发了其他公司的利益分配,因此CoreOS推出了自己的rkt容器、Mesos发布了Marathon与Swarm竞争、Google公司宣告Kubernetes诞生。Docker公司为完善平台能力,收购了第一个提出“容器编排”概念的项目Fig,并更名为Compose。“容器编排”第一次正式进入视野

    Docker公司有了Docker,Swarm,Compose后,在容器商业生态具有很大的优势和话语权。为了竞争, Google、Redhat等基础设施领域的玩家们组建了CNCF(Cloud Native Computing Foundation)基金会,开始打造Kuberentes。Kubernetes很快远远将Swarm项目甩在身后。为了与Kubernetes竞争“容器编排”领域,Docker公司甚至放弃了Swarm项目,但最终未能打败Kubernetes,在2017年,Docker在自己的主打产品Docker企业版中内置Kubernetes项目,这标志着“编排之争”落地帷幕。容器化社区以Kuberentes为核心愈加繁荣。

    容器的本质是一个进程,只不过这个进程加上了视图上的隔离和资源上的限制。 就容器本质而言,它并没有在宿主机上启动一个“容器进程”,它启动的还是用户原来要启动的应用程序,只不过这个应用程序上加了视图隔离和资源限制。虚拟机也能实现视图隔离和资源限制,但它底层的技术实现与容器不同,在宿主机上你能看到这样一个“虚拟机进程”。因此,与容器相比,虚拟机会带来更多的性能损耗,主要在(1)虚拟机本身的进程需要占用一部分资源 (2)与底层硬件交互的时候(网络、磁盘I/O)都需要经过虚拟化软件拦截,会有损耗。但是它比容器有更好的隔离性和安全性。
    容器使用的底层技术:
    (1)视图隔离:Namespace
    (2)资源限制:cgropus

    对于Docker项目来说,它最核心的原理实际就是为待创建的用户进程:
    1、启用Linux Namespace配置:视图隔离
    2、设置指定的Cgroups参数:资源限制
    3、切换进程的根目录(Change Root):容器镜像生效,以实现环境一致性。所谓容器镜像,本质就是容器的根文件系统(rootfs)。

    Docker容器的增量rootfs:即下层已经生成的永远不会改变,所有的修改都通过在上层叠加。比如,删除A文件,就是在上层添加一个“白障”,让系统无法读取到下层A文件。修改则是先copy一个备份到新的层(新老的文件可能都在可读写层),然后读取的时候直接读取新的层。
    Docker通过Volume来实现将宿主机的文件挂载到容器中

    Kubernetes 项目要着重解决的问题,则来自于 Borg 的研究人员在论文中提到的一个非常重要的观点:运行在大规模集群中的各种任务之间,实际上存在着各种各样的关系。这些关系的处理,才是作业编排和管理系统最困难的地方。

    【与Docker Compose相比】Kubernetes 项目最主要的设计思想是,从更宏观的角度,以统一的方式来定义任务之间的各种关系,并且为将来支持更多种类的关系留有余地。

    对于 Pod 状态是 running,实际上不能提供服务的情况能想到几个例子:

    1. 程序本身有 bug,本来应该返回 200,但因为代码问题,返回的是500;
    2. 程序因为内存问题,已经僵死,但进程还在,但无响应;
    3. Dockerfile 写的不规范,应用程序不是主进程,那么主进程出了什么问题都无法发现;
    4. 程序出现死循环。

    Kuberentes可以理解为操作系统,那么容器就是进程,而Pod就是进程组or虚拟机(几个进程关联在一起)。

    Pod的设计之初有两个目的:
    (1)为了处理容器之间的调度关系
    (2) 实现容器设计模式: Pod会先启动Infra容器设置网络、Volume等namespace(如果Volume要共享的话),其他容器通过加入的方式共享这些Namespace。

    如果对Pod中的容器启动有顺序要求,可以使用Init Contianer。所有Init Container定义的容器,都会比spec.containers定义的用户容器按顺序优先启动。Init Container容器会按顺序逐一启动,而直到它们都启动并且退出了,用户容器才会启动。

    Pod使用过程中的重要字段:
    (1)pod自定义/etc/hosts: spec.hostAliases
    (2)pod共享PID : spec.shareProcessNamespace
    (3)容器启动后/销毁前的钩子: spec.container.lifecycle.postStart/preStop
    (4)pod的状态:spec.status.phase
    (5)pod特殊的volume(投射数据卷):
    5.1) 密码信息获取:创建Secrete对象保存加密数据,存放到Etcd中。然后,你就可以通过在Pod的容器里挂载Volume的方式,访问到这些Secret里保存的信息
    5.2)配置信息获取:创建ConfigMap对象保存加密数据,存放到Etcd中。然后,通过挂载Volume的方式,访问到ConfigMap里保存的内容
    5.3)容器获取Pod中定义的静态信息:通过挂载DownwardAPI 这个特殊的Volume,访问到Pod中定义的静态信息
    5.4) Pod中要访问K8S的API:任何运行在Kubernetes集群上的应用,都必须使用这个ServiceAccountToken里保存的授权信息,也就是Token,才可以合法地访问API Server。因此,通过挂载Volume的方式,把对应权限的ServiceAccountToken这个特殊的Secrete挂载到Pod中即可
    (6)容器是否健康: spec.container.livenessProbe。若不健康,则Pod有可能被重启(可配置策略)
    (7)容器是否可用: spec.container.readinessProbe。若不健康,则service不会访问到该Pod