作者 青鸟
学习了Docker后,顺带把k8s 也学了,原理就顺带水篇博客,之后可能会尝试使用minikube来试着部署微服务

Kubernetes(k8s)是一个用于容器编排和管理的开源平台,负责自动化运维管理多个容器化程序(比如 Docker)的集群,可以帮助开发人员和运维团队更轻松地部署、扩展和管理容器化应用程序,从而提高了应用程序的可用性和可伸缩性。是一个生态极其丰富的容器编排框架工具。

k8s提供了一种高度抽象化的方式来处理底层基础设施,使开发人员和运维团队能够专注于应用程序的开发和管理,而不必担心底层的复杂性。

一句话来说,k8s的作用是自动化运维管理Docker(容器化)程序

Kubernetes 的强大之处在于其高度可扩展性和灵活性,使得它适用于各种不同的应用程序和用例,从简单的Web应用程序到复杂的微服务架构。它已成为云原生应用程序开发和运维的事实标准,被广泛用于容器化工作负载的管理和编排。

Kubernetes 官方文档:https://kubernetes.io/zh/

k8s的组成

以下是 Kubernetes 的一些关键概念和组件:

  1. 节点(Nodes): 节点是 Kubernetes 集群中的物理或虚拟机器。Node是Kubernetes中的一个工作机器,通常是一个虚拟机或者物理机。每个节点上运行一个容器运行时(如Docker),它们用于运行应用程序容器。节点分为主节点(Master Node)和工作节点(Worker Node)两种类型。

  2. Pods: Pod是 Kubernetes 中最小的可部署单元。它可以包含一个或多个容器,这些容器共享相同的网络命名空间和存储卷,可以协作运行应用程序。Pods 通常用于部署具有紧密耦合关系的容器。

  3. Container(Containers): 容器是一个轻量级、可移植、自包含的软件单元。它包含了应用程序及其依赖项,并可以在不同的计算机上运行。Docker 是 Kubernetes 最常用的容器技术之一。

  4. Cluster(Clusters) 集群是由一组节点组成的集合,它们一起工作来管理和运行你的容器化应用程序。集群中的节点可以分布在不同的物理机器或虚拟机上。Kubernetes 管理集群中的资源,负责调度容器,以确保应用程序在集群中的所有节点上都能高效运行。

k8s的架构

控制面负责管理整个集群。 控制面协调集群中的所有活动,例如调度应用、维护应用的所需状态、应用扩容以及推出新的更新。

节点是一个虚拟机或者物理机,它在 Kubernetes 集群中充当工作机器的角色。 每个节点都有 Kubelet,它管理节点而且是节点与控制面通信的代理。 节点还应该具有用于​​处理容器操作的工具,例如 Docker 或 rkt。 处理生产级流量的 Kubernetes 集群至少应具有三个节点,因为如果一个节点出现故障其对应的 etcd成员和控制面实例都会丢失, 并且冗余会受到影响。你可以通过添加更多控制面节点来降低这种风险。

在 Kubernetes 上部署应用时,你告诉控制面启动应用容器。 控制面就编排容器在集群的节点上运行。 节点使用控制面暴露的 Kubernetes API 与控制面通信。终端用户也可以使用 Kubernetes API 与集群交互。

K8S 是属于主从设备模型(Master-Slave 架构),即有 Master 节点负责集群的调度、管理和运维,Slave 节点是集群中的运算工作负载节点。

主节点一般被称为 Master 节点,master节点上有 apiserver、controller-manager、scheduler 以及使用 etcd 做k8s集群存储;而从节点则被称为 Worker Node 节点,node节点上有 kubelet、kube-proxy、容器引擎(比如docker),每个 Node 都会被 Master 分配一些工作负载。

Master 组件可以在群集中的任何计算机上运行,但建议 Master 节点占据一个独立的服务器。因为 Master 是整个集群的大脑,如果 Master 所在节点宕机或不可用,那么所有的控制命令都将失效。除了 Master,在 K8S 集群中的其他机器被称为 Worker Node 节点,当某个 Node 宕机时,其上的工作负载会被 Master 自动转移到其他节点上去。

1.Master 组件
(1)Kube-apiserver
用于暴露 Kubernetes API,任何资源请求或调用操作都是通过 kube-apiserver 提供的接口进行。以 HTTP Restful API 提供接口服务,所有对象资源的增删改查和监听操作都交给 API Server 处理后再提交给 Etcd 存储。

可以理解成 API Server 是 K8S 的所有服务的请求入口。API Server 负责接收 K8S 所有请求(来自 UI 界面或者 CLI 命令行工具), 然后根据用户的具体请求,去通知其他组件干活。可以说 API Server 是 K8S 集群架构的大脑。

(2)Kube-controller-manager
运行管理控制器,是 K8S 集群中处理常规任务的后台线程,是 K8S 集群里所有资源对象的自动化控制中心。

在 K8S 集群中,一个资源对应一个控制器,而 Controller manager 就是负责管理这些控制器的。

由一系列控制器组成,通过 API Server 监控整个集群的状态,并确保集群处于预期的工作状态,比如当某个 Node 意外宕机时,Controller Manager 会及时发现并执行自动化修复流程,确保集群始终处于预期的工作状态。

这些控制器主要包括:

Node Controller(节点控制器):负责在节点出现故障时发现和响应。
Replication Controller(副本控制器):负责保证集群中一个 RC(资源对象 Replication Controller)所关联的 Pod 副本数始终保持预设值。可以理解成确保集群中有且仅有 N 个 Pod 实例,N 是 RC 中定义的 Pod 副本数量。
Endpoints Controller(端点控制器):填充端点对象(即连接 Services 和 Pods),负责监听 Service 和对应的 Pod 副本的变化。 可以理解端点是一个服务暴露出来的访问点,如果需要访问一个服务,则必须知道它的 endpoint。
Service Account & Token Controllers(服务帐户和令牌控制器):为新的命名空间创建默认帐户和 API 访问令牌。
ResourceQuota Controller(资源配额控制器):确保指定的资源对象在任何时候都不会超量占用系统物理资源。
Namespace Controller(命名空间控制器):管理 namespace 的生命周期。
Service Controller(服务控制器):属于 K8S 集群与外部的云平台之间的一个接口控制器
(3)Kube-scheduler
是负责资源调度的进程,根据调度算法为新创建的 Pod 选择一个合适的 Node 节点。

可以理解成 K8S 所有 Node 节点的调度器。当用户要部署服务时,Scheduler 会根据调度算法选择最合适的 Node 节点来部署 Pod。

调度算法:

预选策略(predicate)
优选策略(priorities)
API Server 接收到请求创建一批 Pod ,API Server 会让 Controller-manager 按照所预设的模板去创建 Pod,Controller-manager 会通过 API Server 去找 Scheduler 为新创建的 Pod 选择最适合的 Node 节点。比如运行这个 Pod 需要 2C4G 的资源,Scheduler 会通过预选策略过滤掉不满足策略的 Node 节点。Node 节点中还剩多少资源是通过汇报给 API Server 存储在 etcd 里,API Server 会调用一个方法找到 etcd 里所有 Node 节点的剩余资源,再对比 Pod 所需要的资源,如果某个 Node 节点的资源不足或者不满足 预选策略的条件则无法通过预选。预选阶段筛选出的节点,在优选阶段会根据优选策略为通过预选的 Node 节点进行打分排名, 选择得分最高的 Node。例如,资源越富裕、负载越小的 Node 可能具有越高的排名。

2.配置存储中心
etcd 是分布式键值存储系统,是K8S 的存储服务,存储了 K8S 的关键配置和用户配置,K8S 中仅 API Server 才具备读写权限,其他组件必须通过 API Server 的接口才能读写数据。

etcd是一个高可用的分布式键值 (kev-value)数据库。etcd内部采用raft协议作为一致性算法。

etcd 作为服务发现系统,有以下的特点:

简单:安装配置简单,而且提供了HTTP API进行交互,使用也很简单
安全:支持SSI证书验证
快速:单实例支持每秒2k+读操作
可靠:采用rat算法,实现分布式系统数据的可用性和一致性
etcd 目前默认使用2379端口提供HTTP API服务, 2380端口和peer通信(这两个端口已经被IANA官方预留给etcd)。即etcd默认使用2379端口对外为客户端提供通讯,使用端口2380来进行服务器间内部通讯。

etcd 在生产环境中一般推荐集群方式部署。由于etcd 的leader选举机制,要求至少为3台或以上的奇数台。

3.Node 组件
(1)Kubelet
Node 节点的监视器,以及与 Master 节点的通讯器。Kubelet 是 Master 节点安插在 Node 节点上的“眼线”,它会定时向 API Server 汇报自己 Node 节点上运行的服务的状态,并接受来自 Master 节点的指示采取调整措施。

从 Master 节点获取自己节点上 Pod 的期望状态(比如运行什么容器、运行的副本数量、网络或者存储如何配置等), 直接跟容器引擎交互实现容器的生命周期管理,如果自己节点上 Pod 的状态与期望状态不一致,则调用对应的容器平台接口(即 docker 的接口)达到这个状态。

还负责管理镜像和容器的清理工作,保证节点上镜像不会占满磁盘空间,退出的容器不会占用太多资源。

即在 Kubernetes 集群中,在每个 Node 上都会启动一个 kubelet 服务进程。该进程用于处理 Master 下发到本节点的任务,管理 Pod 及 Pod 中的容器。每个 kubelet 进程都会在 API Server 上注册节点自身的信息,定期向 Master 汇报节点资源的使用情况,并通过 cAdvisor 监控容器和节点资源。

(2)Kube-Proxy
在每个 Node 节点上实现 Pod 网络代理,是 Kubernetes Service 资源的载体,负责维护网络规则和四层负载均衡工作。 负责写入规则至iptables、ipvs实现服务映射访问的。

Kube-Proxy 本身不是直接给 Pod 提供网络,Pod 的网络是由 Kubelet 提供的,Kube-Proxy 实际上维护的是虚拟的 Pod 集群网络。

Kube-apiserver 通过监控 Kube-Proxy 进行对 Kubernetes Service 的更新和端点的维护。

在 K8S 集群中微服务的负载均衡是由 Kube-proxy 实现的。Kube-proxy 是 K8S 集群内部的负载均衡器。它是一个分布式代理服务器,在 K8S 的每个节点上都会运行一个 Kube-proxy 组件。

(3)docker 或 rocket
容器引擎,运行容器,负责本机的容器创建和管理工作。当 kubernetes 把 pod 调度到节点上,节点上的 kubelet会指示 docker 启动特定的容器。接着,kubelet 会通过 docker 持续地收集容器的信息, 然后提交到主节点上。docker 会如往常一样拉取容器镜像、启动或停止容器。不同点仅仅在于这是由自动化系统控制而非管理员在每个节点上手动操作的。

部署一个服务

Kubernetes 通过将容器放入在节点(Node)上运行的 Pod 中来执行你的工作负载。 节点可以是一个虚拟机或者物理机器,取决于所在的集群配置。 每个节点包含运行 Pod 所需的服务; 这些节点由控制面负责管理。

这里我们简单提一下使用Deployment来部署

Deployment(部署)是 Kubernetes 中的一个重要资源对象,用于定义和管理容器化应用程序的部署策略。它允许你轻松地指定应用程序的副本数量,升级应用程序版本,以及自动处理故障恢复。Deployment 是 Kubernetes 控制器的一种类型,用于确保指定数量的Pod副本保持运行,并根据需要进行滚动升级。

下面是一个 Deployment 示例。其中创建了一个 ReplicaSet,我们创建了一个controllers/nginx-deployment.yaml,负责启动三个 nginx Pod:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

这里的ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的 Pod 的可用性。

按照以下步骤创建上述 Deployment :

  1. 通过运行以下命令创建 Deployment :

    1
    kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
  2. 运行 kubectl get deployments 检查 Deployment 是否已创建。 如果仍在创建 Deployment,则输出类似于:

    1
    2
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment 0/3 0 0 1s

    在检查集群中的 Deployment 时,所显示的字段有:

    • NAME 列出了名字空间中 Deployment 的名称。
    • READY 显示应用程序的可用的“副本”数。显示的模式是“就绪个数/期望个数”。
    • UP-TO-DATE 显示为了达到期望状态已经更新的副本数。
    • AVAILABLE 显示应用可供用户使用的副本数。
    • AGE 显示应用程序运行的时间。

    请注意期望副本数是根据 .spec.replicas 字段设置 3。

  3. 要查看 Deployment 上线状态,运行 kubectl rollout status deployment/nginx-deployment
    输出类似于:

    1
    2
    Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
    deployment "nginx-deployment" successfully rolled out
  4. 几秒钟后再次运行 kubectl get deployments。输出类似于:

    1
    2
    NAME               READY   UP-TO-DATE   AVAILABLE   AGE
    nginx-deployment 3/3 3 3 18s

注意 Deployment 已创建全部三个副本,并且所有副本都是最新的(它们包含最新的 Pod 模板) 并且可用。

创建应用实例后,Kubernetes Deployment 控制器会持续监视这些实例。 如果托管实例的节点关闭或被删除,则 Deployment 控制器会将该实例替换为集群中另一个节点上的实例。 这提供了一种自我修复机制来解决机器故障维护问题。

k8s的网络

Service

在K8S的集群里,虽然每个Pod会被分配一个单独的IP地址,但由于Pod是有生命周期的(它们可以被创建,而且销毁之后不会再启动),随时可能会因为业务的变更,导致这个 IP 地址也会随着 Pod 的销毁而消失。而Service 就是用来解决这个问题的核心概念。

K8S 中的 Service 并不是我们常说的“服务”的含义,而更像是网关层,可以看作一组提供相同服务的Pod的对外访问接口、流量均衡器。

Service 作用于哪些 Pod 是通过标签选择器来定义的。在 K8S 集群中,Service 可以看作一组提供相同服务的 Pod 的对外访问接口。客户端需要访问的服务就是 Service 对象。每个 Service 都有一个固定的虚拟 ip(这个 ip 也被称为 Cluster IP),自动并且动态地绑定后端的 Pod,所有的网络请求直接访问 Service 的虚拟 ip,Service 会自动向后端做转发。

Service 除了提供稳定的对外访问方式之外,还能起到负载均衡(Load Balance)的功能,自动把请求流量分布到后端所有的服务上,Service 可以做到对客户透明地进行水平扩展(scale)。
而实现 service 这一功能的关键,就是 kube-proxy。kube-proxy 运行在每个节点上,监听 API Server 中服务对象的变化, 可通过以下三种流量调度模式: userspace(废弃)、iptables(濒临废弃)、ipvs(推荐,性能最好)来实现网络的转发。

Service 是 K8S 服务的核心,屏蔽了服务细节,统一对外暴露服务接口,真正做到了“微服务”。比如我们的一个服务 A,部署了 3 个副本,也就是 3 个 Pod; 对于用户来说,只需要关注一个 Service 的入口就可以,而不需要操心究竟应该请求哪一个 Pod。
优势非常明显:一方面外部用户不需要感知因为 Pod 上服务的意外崩溃、K8S 重新拉起 Pod 而造成的 IP 变更, 外部用户也不需要感知因升级、变更服务带来的 Pod 替换而造成的 IP 变化。

Ingress

Service 主要负责 K8S 集群内部的网络拓扑,那么集群外部怎么访问集群内部呢?这个时候就需要 Ingress 了。Ingress 是整个 K8S 集群的接入层,负责集群内外通讯。

Ingress 是 K8S 集群里工作在 OSI 网络参考模型下,第7层的应用,对外暴露的接囗,典型的访问方式是 http/https。

Service 只能进行第四层的流量调度,表现形式是 ip+port。Ingress 则可以调度不同业务域、不同URL访问路径的业务流量。

参考文章:

Kubernetes 官方文档

Kubernetes(k8s) 架构原理一文详解