本文档将对近期所学习到的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 的流程为

  1. 用户通过 REST API 创建一个 Pod
  2. apiserver 将其写入 etcd
  3. scheduluer 检测到未绑定 Node 的 Pod,开始调度并更新 Pod 的 Node 绑定
  4. kubelet 检测到有新的 Pod 调度过来,通过 container runtime 运行该 Pod
  5. kubelet 通过 container runtime 取到 Pod 状态,并更新到 apiserver 中

C/S 架构

从宏观上看,K8S 遵循 C/S 架构,可以用下面的图来表示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
                               +-------------+                              
| |
| | +---------------+
| | +-----> | Node 1 |
| Kubernetes | | +---------------+
+-----------------+ | Server | |
| CLI | | | | +---------------+
| (Kubectl) |----------->| ( Master ) |<------+-----> | Node 2 |
| | | | | +---------------+
+-----------------+ | | |
| | | +---------------+
| | +-----> | Node 3 |
| | +---------------+
+-------------+

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
cat > nginx-ds.yml <<EOF
apiVersion: v1
kind: Service
metadata:
name: nginx-ds
labels:
app: nginx-ds
spec:
type: NodePort
selector:
app: nginx-ds
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
name: nginx-ds
labels:
addonmanager.kubernetes.io/mode: Reconcile
spec:
template:
metadata:
labels:
app: nginx-ds
spec:
containers:
- name: my-nginx
image: nginx:1.7.9
ports:
- containerPort: 80
EOF

kubectl create -f nginx-ds.yml
kubectl get pods -o wide|grep nginx-ds
kubectl get svc -o wide|grep nginx-ds

访问service资源映射的nodeport

1
curl k8s-node01:22462

架构图

参考资料