本文档将对近期所学习到的k8s知识、概念进行简单的总结,并结合实践加以记录。
Kubernetes 是谷歌开源的容器集群管理系统,是 Google 多年大规模容器管理技术 Borg 的开源版本,主要功能包括:
- 基于容器的应用部署、维护和滚动升级
- 负载均衡和服务发现
- 跨机器和跨地区的集群调度
- 自动伸缩
- 无状态服务和有状态服务
- 广泛的 Volume 支持
- 插件机制保证扩展性
- ….
以上这些功能,几乎完美贴合一套运维架构体系。实现了运维的部署更新,动态扩容,这都交由k8s强大调度系统进行完成。
像以前单体的运维架构,无非就是:
提交代码仓库—>交由CI/CD工具进行源码的编译和打包—>将需要更新的应用包解压至服务器上—>逐一停止业务应用—>逐一启动—>完成更新
以上种种步骤,取决于运维团队的自动化、规范化完善度到达何种程度。有的通过脚本进行管控,有的可能会有运维发布平台。
目前,Kubernetes 是 DevOps 应用必须掌握的一个平台。如果要构建一套比较不错的devops 体系,那k8s是必不可少的。现在,提到容器第一个联想到的就是k8s,外加微服务时代的盛行,使用和学习k8s再适合不过了。
核心组件
Kubernetes 主要由以下几个核心组件组成:
etcd 保存了整个集群的状态;
apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;
controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;
scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;
kubelet 负责维护容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;
Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI);
kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡
Kubernetes 整体架构
核心组件
组件通信
Kubernetes 多组件之间的通信原理为
- apiserver 负责 etcd 存储的所有操作,且只有 apiserver 才直接操作 etcd 集群
- apiserver 对内(集群中的其他组件)和对外(用户)提供统一的 REST API,其他组件均通过 apiserver 进行通信
- controller manager、scheduler、kube-proxy 和 kubelet 等均通过 apiserver watch API 监测资源变化情况,并对资源作相应的操作
- 所有需要更新资源状态的操作均通过 apiserver 的 REST API 进行
- apiserver 也会直接调用 kubelet API(如 logs, exec, attach 等),默认不校验 kubelet 证书,但可以通过
--kubelet-certificate-authority开启(而 GKE 通过 SSH 隧道保护它们之间的通信)
比如典型的创建 Pod 的流程为
- 用户通过 REST API 创建一个 Pod
- apiserver 将其写入 etcd
- scheduluer 检测到未绑定 Node 的 Pod,开始调度并更新 Pod 的 Node 绑定
- kubelet 检测到有新的 Pod 调度过来,通过 container runtime 运行该 Pod
- kubelet 通过 container runtime 取到 Pod 状态,并更新到 apiserver 中
C/S 架构
从宏观上看,K8S 遵循 C/S 架构,可以用下面的图来表示:
1 | +-------------+ |
Master
Master是整个 K8S 集群的大脑,他有几个重要的功能:
- 接收:外部的请求和集群内部的通知反馈
- 发布:对集群整体的调度和管理
- 存储:存储集群所需持久化的状态信息
Master主要包含以下几个重要的组成部分:
1. Cluster state store
用来存储集群所有需要持久化的状态,并且提供watch的功能支持,可以快速的通知各组件的变更等操作。
目前 Kubernetes 的存储层选择是etcd,所以一般情况下,我们直接以etcd来代表集群状态存储服务,即将所有状态存储到etcd实例中。
2. API Server
这是整个集群的入口,类似于人体的感官,接收外部的信号和请求,并将相应的信息写入到etcd中。
为了保证安全,API Server 还提供了认证相关的功能,用于判断客户端是否有权限进行操作。API Server 支持多种认证方法,不过一般情况下,我们使用x509证书来进行认证。
API Server 的目标是成为一个极简的 Server,只提供
REST操作,更新etcd,并充当着集群的网关。至于其他的业务逻辑,则通过插件或者其他组件来实现
3. Controller Manager
Controller Manager 大概是 K8S 集群中最繁忙的部分,它在后台运行着许多不同的控制器进程,用来调节集群的状态。
当集群的配置发生改变时,控制器就会朝着预期的状态开始工作。
4. Scheduler
Scheduler 是集群的调度器,它会持续关注集群中未被调度的 Pod,并根据资源可用性、节点亲和性或是其他一些限制条件,通过绑定的 API 将 Pod 调度/绑定到 Node 上。
在这个过程中,调度程序一般只考虑调度开始时 Node 的状态,而不考虑在调度过程中 Node 的状态变化
节点(Node)
K8s集群中的计算能力由Node提供,最初Node称为服务节点Minion,后来改名为Node。K8s集群中的Node也就等同于Mesos集群中的Slave节点,是所有Pod运行所在的工作主机,可以是物理机也可以是虚拟机。不论是物理机还是虚拟机,工作主机的统一特征是上面要运行kubelet管理节点上运行的容器。
Pod
K8s有很多技术概念,同时对应很多API对象,最重要的也是最基础的是微服务Pod。Pod是在K8s集群中运行部署应用或服务的最小单元,它是可以支持多容器的。Pod的设计理念是支持多个容器在一个Pod中共享网络地址和文件系统,可以通过进程间通信和文件共享这种简单高效的方式组合完成服务。Pod对多容器的支持是K8s最基础的设计理念。比如你运行一个操作系统发行版的软件仓库,一个Nginx容器用来发布软件,另一个容器专门用来从源仓库做同步,这两个容器的镜像不太可能是一个团队开发的,但是他们一块儿工作才能提供一个微服务;这种情况下,不同的团队各自开发构建自己的容器镜像,在部署的时候组合成一个微服务对外提供服务。
Pod是K8s集群中所有业务类型的基础,可以看作运行在K8s集群中的小机器人,不同类型的业务就需要不同类型的小机器人去执行。目前K8s中的业务主要可以分为长期伺服型(long-running)、批处理型(batch)、节点后台支撑型(node-daemon)和有状态应用型(stateful application);分别对应的小机器人控制器为Deployment、Job、DaemonSet和StatefulSet。
Pod分类:
- 自主式Pod
- 由控制器管理的Pod,管理不同类型的Pod资源
- ReplicaSet(替代ReplicationController)
- Deployment(只能管理无状态的应用)
- StatefulSet(管理有状态的应用)
- DaemonSet(在每一个node上运行一个副本)
- Job(运行结束自动删除)
- Ctonjob(周期性job)
其中DaemonSet、Job、Ctonjob是给特殊应用使用,另外Deployment还支持二级控制器HPA(HorizontalPodAutoscaler),HPA控制器自动监控资源,当前服务能力不能满足时,自动扩展Pod,当Pod资源空闲时,自动回收资源,这些阈值由用户设置。
附上k8s各种对象详细表格:
Kubernetes主要模块概念:
| 名称 | 说明 |
|---|---|
| Cluster | Cluster是指由Kubernetes使用一系列的物理机、虚拟机和其他基础资源来运行你的应用程序。 |
| Node | 一个node就是一个运行着Kubernetes的物理机或虚拟机,并且pod可以在其上面被调度。 |
| Pod | 一个pod对应一个由相关容器和卷组成的容器组。 |
| Label | 一个label是一个被附加到资源上的键/值对,例如附加到一个Pod上,为它传递一个用户自定的并且可识别的属性,Label还可以被应用来组织和选择子网中的资源。 |
| selector | selector是一个通过匹配labels来定义资源之间关系得表达式,例如为一个负载均衡的service指定所目标Pod。 |
| Replication Controller | replication controller 是为了保证一定数量被指定的Pod的复制品在任何时间都能正常工作,它不仅允许复制的系统易于扩展,还会处理当pod在机器在重启或发生故障的时候再次创建一个。 |
| Service | 一个service定义了访问pod的方式,就像单个固定的IP地址和与其相对应的DNS名之间的关系。 |
| Volume | 一个volume是一个目录,可能会被容器作为未见系统的一部分来访问。 |
| Kubernetes volume | 构建在Docker Volumes之上,并且支持添加和配置volume目录或者其他存储设备。 |
| Secret | Secret 存储了敏感数据,例如能允许容器接收请求的权限令牌。 |
| Name | 用户为Kubernetes中资源定义的名字。 |
| Namespace | Namespace 好比一个资源名字的前缀。它帮助不同的项目、团队或是客户可以共享cluster,例如防止相互独立的团队间出现命名冲突。 |
| Annotation | 相对于label来说可以容纳更大的键值对,它对我们来说可能是不可读的数据,只是为了存储不可识别的辅助数据,尤其是一些被工具或系统扩展用来操作的数据。 |
一些实际应用的经验
- 在引用一个yaml文件时,请使用–record选项,带了这个选项之后,每次升级的时都会保存到部署的日志里面,这样就提供了回滚一个变更的能力。
- 部署大多数应用都需要配套一个service对象,如果需要外部访问需要映射NodePort类型
- 使用git管理k8s yml 可以方便回滚
- ….
实践
使用k8s创建应用
1 | cat > nginx-ds.yml <<EOF |
访问service资源映射的nodeport
1 | curl k8s-node01:22462 |
架构图