目录

kubernetes简介

kubernetes是Google开源的分布式容器管理平台,而我们已经知道了容器的本质就是由Linux Namespace、Cgroup和rootfs组成的进程隔离环境

一个正在运行的容器,可以分为两部分:

  • 一个由Namespace+Cgroup构成的隔离环境,是进程正在运行的环境,称为“容器运行时”(runtime)
  • 一个联合挂载在/var/lib/docker/aufs/mnt上的rootfs,称为"容器镜像"(image)

那么这两个部分哪个比较重要?

我认为是镜像比较重要,因为在"开发->测试->发布"流程中,承载容器信息的是镜像,而容器运行时是到了宿主机上才运行,我们可以通过镜像移植容器到不同机器上。

一、容器编排

假设有10台机器,需要部署多个服务,如果使用容器进行部署,需要运维人员自己分配不同机器上运行容器,这会带来很大的工作量。

而“容器编排”技术能够将用户提交的Docker镜像以容器的方式运行起来,自动实现CI/CD,监控,安全,网络,存储等,将开发运维关联起来。

这其中,最具代表性的容器编排工具,就是Docker的compose+swarm组合,和google和redhat主导的kubernetes。

1.1、compose+swarm

docker-compose是用来管理容器的,在compose中可以定义多个镜像,但是仅仅只能运行在本机。而swarm弥补了compose的缺陷,可以管理容器集群。优点是适用简单,容易集成到现有系统中,但是在复杂调度就会比较困难。

1.2、kubernetes

kubernetes基于Google内部项目Brog,在它的成长阶段,每一个核心特性的提出,几乎都基于Brog系统的设计和经验。

kubernetes项目架构,由master和node两类节点组成,这两类节点分别担任控制节点和计算节点的角色。

其中,控制节点即master节点,由三个紧密协作的独立组件而成:

  • 负责API服务的kube-apiserver
  • 负责调度的kube-scheduler
  • 负责容器编排的controller-manager

整个集群的持久化数据,由kube-apiserver处理后保存在etcd中。

而计算节点最核心的部分,是kubelet组件,主要负责和容器运行时交互。而这个容器运行时,是CRI(Container Runtime Interface)的远程调用接口,这个接口定义了容器运行时的所有操作,所以在kubernetes部署时并不关心使用的是什么容器运行时,使用什么技术实现,所以在kubernetes之后的版本中,把dockershim移除了。

1.3、对比

这两样一对比,就能发现,swarm停留在拉取用户镜像,运行容器,及常见的运维功能,而kubernetes已经在另一个维度上降维打击了。

其实,在运行大规模集群的各种任务之间,存在各种各样的联系,而这些关系才是作业编排和管理系统中最困难的地方。

比如web应用和数据库之间的访问关系,负载均衡器和后端服务之间的关系,门户应用和授权应用之间的关系。

二、基础对象

Pod是kubernetes项目中最基础的一个对象,就是一组共享了同一个Network Namespace、Volume的容器。

而Pod的实现需要一个中间容器infra,在pod中,infra容器永远是第一个被创建,而其他的容器加入infra容器的network namespace。

如果没有中间容器,那么一个pod中的两个容器,需要定义启动顺序,才能加入到另一个网络,这两个容器就不是对等关系。

infra容器其实就是一个用汇编写的、永远处于"暂停状态"的容器,占用资源非常小,作用就是hold住network namespace,让其他容器加入。而对于这个pod的其他容器来说:

  • 可以通过localhost互相通信
  • 看到的网络设备和infra一样
  • 只有一个ip地址,就是pod的ip地址
  • 共享网络资源
  • pod生命周期和infra一致,和其他容器无关

通过这个特点,就能实现很多与pod网络相关的配置和管理,可以通过sidecar来实现,无需干涉业务。最典型的例子就是Istio微服务治理项目,prometheus、jaeger等都不需要侵入用户代码即可完成状态收集。


接下来,我们从容器开始出发

1、首先是容器间紧密协作的关系,用Pod来定义这种关系,可以包含多个容器

2、有了Pod之后,希望能够一次运行多个应用的实例,这样就需要Deployment这个Pod的多实例管理器

3、有了一组Pod之后,需要通过固定的IP地址和端口以负载均衡的方式访问,所以有了Service

4、Pod运行需要配置,于是存在ConfigMap和Secret来存储配置和秘钥信息

5、如果存在一次性任务或定时任务,所以有了新的基于Pod改进后的Job和CronJob

6、比如每台宿主机都需要且只要一个副本运行的守护进程服务,于是有了DaemonSet

这仅仅只是一小部分内容,通过这个流程,我们能看到kubernetes推崇的是“一切皆对象”的思想。

首先,通过定义一个“编排对象”,比如Pod,来描述管理的应用。

然后,定义“服务对象”,比如Service,负责具体的动作。

当然,关联关系也是一个对象,比如在RBAC中,存在sa(账号),Role(角色),RoleBinding(绑定关系)。

三、总结

创建一个pod的流程

1、用户通过kubectl命令提交创建pod的请求

2、这个请求通过kube-apiserver响应,经过一系列认证授权,将pod数据存储到etcd中,创建Deployment资源并初始化

3、controller-manager通过list-watch机制监听到了新的Deployment,将该资源加入到内部的工作队列中,如果没有发现关联的pod,启用Deployment Controller创建ReplicaSet,再通过ReplicaSet Controller创建pod

4、所有的Controller创建完成后,再将Deployment、ReplicaSet、pod资源更新到etcd中

5、schedule通过list-watch机制,监听到了新的pod,经过主机过滤、打分机制后,将pod绑定到合适的宿主机上,然后将结果更新到etcd中

6、kubelet定时(20s)向kube-apiserver获取自身要运行的pod清单,然后与自身比较,如果发现新增pod,就创建pod

7、kube-proxy为新创建的pod注册动态dns到CoreDNS,给pod的service添加iptables/ipvs规则,用于服务发现和负载均衡

8、Controller-manager通过control loop将当前pod状态和用户期望状态做对比,如果不符合,就更新状态

到这里,就是kubernetes的一个整体的介绍。