245 lines
21 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

![输入图片说明](/imgs/2024-02-20/eFoHGp9laE9pMeTP.png)![](https://img-blog.csdnimg.cn/71dcbdf1f5374bb58db880feae7e690c.png)
## 写在前面
本文组织方式:
1. **K8S的架构、作用和目的。需要首先对K8S整体有所了解。**
K8S是什么
为什么是K8S
K8S怎么做
1. **K8S的重要概念即K8S的API对象。要学习和使用K8S必须知道和掌握的几个对象。**
Pod 实例
Volume 数据卷
Container 容器
Deployment 和 ReplicaSet
Service和Ingress
namespace 命名空间
其他
## I. K8S概览
### 1.1 K8S是什么
K8S是[Kubernetes](https://kubernetes.io/zh/docs/concepts/overview/what-is-kubernetes/)的全称,官方称其是:
> Kubernetes is an open source system for managing [containerized applications](https://kubernetes.io/docs/concepts/overview/what-is-kubernetes/) across multiple hosts. It provides basic mechanisms for deployment, maintenance, and scaling of applications.
> 用于自动部署、扩展和管理“容器化containerized应用程序”的开源系统。
翻译成大白话就是:**“K8S是负责自动化运维管理多个Docker程序的集群”。** 那么问题来了Docker运行可方便了为什么要用K8S它有什么优势
插一句题外话:
- 为什么Kubernetes要叫Kubernetes呢维基百科已经交代了老美对星际是真的痴迷
Kubernetes在希腊语意为“舵手”或“驾驶员”由Joe Beda、Brendan Burns和Craig
McLuckie创立并由其他谷歌工程师包括Brian Grant和Tim Hockin等进行加盟创作并由谷歌在2014年首次对外宣布
。该系统的开发和设计都深受谷歌的Borg系统的影响其许多顶级贡献者之前也是Borg系统的开发者。在谷歌内部Kubernetes的原始代号曾经是Seven即星际迷航中的Borg博格人。Kubernetes标识中舵轮有七个轮辐就是对该项目代号的致意。
- 为什么Kubernetes的缩写是K8S呢我个人赞同Why Kubernetes is Abbreviated
k8s中说的观点“嘛写全称也太累了吧不如整个缩写”。其实只保留首位字符用具体数字来替代省略的字符个数的做法还是比较常见的。
### 1.2 为什么是K8S?
试想下传统的后端部署办法:把程序包(包括可执行二进制文件、配置文件等)放到服务器上,接着运行启动脚本把程序跑起来,同时启动守护脚本定期检查程序运行状态、必要的话重新拉起程序。
有问题吗?显然有!最大的一个问题在于:**如果服务的请求量上来,已部署的服务响应不过来怎么办?** 传统的做法往往是如果请求量、内存、CPU超过阈值做了告警运维马上再加几台服务器部署好服务之后接入负载均衡来分担已有服务的压力。
问题出现了:从监控告警到部署服务,中间需要人力介入!那么,**有没有办法自动完成服务的部署、更新、卸载和扩容、缩容呢?**
**这就是K8S要做的事情自动化运维管理Docker容器化程序。**
### 1.3 K8S怎么做
我们已经知道了K8S的核心功能自动化运维管理多个容器化程序。那么K8S怎么做到的呢这里我们从宏观架构上来学习K8S的设计思想。首先看下图图片来自文章Components of Kubernetes Architecture
![在这里插入图片描述](https://img-blog.csdnimg.cn/3565874b8adc4e73ab250ae777d03728.png#pic_center =x300)
K8S是属于**主从设备模型Master-Slave架构**即有Master节点负责核心的调度、管理和运维Slave节点则在执行用户的程序。但是在K8S中主节点一般被称为**Master Node或者Head Node**本文采用Master Node称呼方式而从节点则被称为**Worker Node或者Node**本文采用Worker Node称呼方式
要注意一点Master Node和Worker Node是分别安装了K8S的Master和Woker组件的实体服务器每个Node都对应了一台实体服务器虽然Master Node可以和其中一个Worker Node安装在同一台服务器但是建议Master Node单独部署**所有Master Node和Worker Node组成了K8S集群**同一个集群可能存在多个Master Node和Worker Node。
首先来看**Master Node**都有哪些组件:
- **API Server。K8S的请求入口服务**。API Server负责接收K8S所有请求来自UI界面或者CLI命令行工具然后API
Server根据用户的具体请求去通知其他组件干活。
- **Scheduler。K8S所有Worker Node的调度器**。当用户要部署服务时Scheduler会选择最合适的Worker Node服务器来部署。
- **Controller Manager。K8S所有Worker Node的监控器**。Controller Manager有很多具体的Controller在文章Components of Kubernetes Architecture中提到的有Node Controller、Service Controller、Volume Controller等。Controller负责监控和调整在Worker Node上部署的服务的状态比如用户要求A服务部署2个副本那么当其中一个服务挂了的时候Controller会马上调整让Scheduler再选择一个Worker Node重新部署服务。
- **etcd。K8S的存储服务**。etcd存储了K8S的关键配置和用户配置K8S中仅API Server才具备读写权限其他组件必须通过API
Server的接口才能读写数据见Kubernetes Works Like an Operating System
接着来看**Worker Node**的组件,笔者更赞同[HOW DO APPLICATIONS RUN ON KUBERNETES](https://thenewstack.io/how-do-applications-run-on-kubernetes/)文章中提到的组件介绍:
- **Kubelet。Worker Node的监视器以及与Master Node的通讯器**。Kubelet是Master
Node安插在Worker Node上的“眼线”它会定期向Worker
Node汇报自己Node上运行的服务的状态并接受来自Master Node的指示采取调整措施。
- **Kube-Proxy。K8S的网络代理**。私以为称呼为Network-Proxy可能更适合Kube-Proxy负责Node在K8S的网络通讯、以及对外部网络流量的负载均衡。
- **Container Runtime。Worker Node的运行环境**。即安装了容器化所需的软件环境确保容器化程序能够跑起来比如Docker Engine。大白话就是帮忙装好了Docker运行环境。
- **Logging Layer。K8S的监控状态收集器**。私以为称呼为Monitor可能更合适Logging
Layer负责采集Node上所有服务的CPU、内存、磁盘、网络等监控项信息。
- **Add-Ons。K8S管理运维Worker Node的插件组件**。有些文章认为Worker
Node只有三大组件不包含Add-On但笔者认为K8S系统提供了Add-On机制让用户可以扩展更多定制化功能是很不错的亮点。
总结来看,**K8S的Master Node具备请求入口管理API ServerWorker Node调度Scheduler监控和自动调节Controller Manager以及存储功能etcd而K8S的Worker Node具备状态和监控收集Kubelet网络和负载均衡Kube-Proxy、保障容器化运行环境Container Runtime、以及定制化功能Add-Ons**。
## II. K8S重要概念
### 2.1 Pod实例
官方对于Pod的解释是
> Pod是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元。
这样的解释还是很难让人明白究竟Pod是什么但是对于K8S而言Pod可以说是所有对象中最重要的概念了因此我们**必须首先清楚地知道“Pod是什么”**,再去了解其他的对象。
从官方给出的定义联想下“最小的xxx单元”是不是可以想到本科在学校里学习“进程”的时候教科书上有一段类似的描述资源分配的最小单位还有”线程“的描述是CPU调度的最小单位。什么意思呢”**最小xx单位“要么就是事物的衡量标准单位要么就是资源的闭包、集合**。前者比如长度米、时间秒后者比如一个”进程“是存储和计算的闭包一个”线程“是CPU资源包括寄存器、ALU等的闭包。
同样的,**Pod就是K8S中一个服务的闭包**。这么说的好像还是有点玄乎,更加云里雾里了。简单来说,**Pod可以被理解成一群可以共享网络、存储和计算资源的容器化服务的集合**。再打个形象的比喻在同一个Pod里的几个Docker服务/程序好像被部署在同一台机器上可以通过localhost互相访问并且可以共用Pod里的存储资源这里是指Docker可以挂载Pod内的数据卷数据卷的概念后文会详细讲述暂时理解为“需要手动mount的磁盘”。笔者总结Pod如下图可以看到**同一个Pod之间的Container可以通过localhost互相访问并且可以挂载Pod内所有的数据卷但是不同的Pod之间的Container不能用localhost访问也不能挂载其他Pod的数据卷**。
![在这里插入图片描述](https://img-blog.csdnimg.cn/76dce54e8a554caeb95023db4f4547c0.png#pic_center =x300)
对Pod有直观的认识之后接着来看K8S中Pod究竟长什么样子具体包括哪些资源
K8S中所有的对象都通过yaml来表示笔者从[官方网站](https://kubernetes.io/zh/docs/tasks/configure-pod-container/assign-memory-resource/)摘录了一个最简单的Pod的yaml
```bash
apiVersion: v1
kind: Pod
metadata:
name: memory-demo
namespace: mem-example
spec:
containers:
- name: memory-demo-ctr
image: polinux/stress
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
volumeMounts:
- name: redis-storage
mountPath: /data/redis
volumes:
- name: redis-storage
emptyDir: {}
```
看不懂不必慌张,且耐心听下面的解释:
- apiVersion记录K8S的API Server版本现在看到的都是v1用户不用管。
- kind记录该yaml的对象比如这是一份Pod的yaml配置文件那么值内容就是Pod。
- metadata记录了Pod自身的元数据比如这个Pod的名字、这个Pod属于哪个namespace命名空间的概念后文会详述暂时理解为“同一个命名空间内的对象互相可见”
- spec记录了Pod内部所有的资源的详细信息看懂这个很重要
- containers记录了Pod内的容器信息containers包括了name容器名image容器的镜像地址resources容器需要的CPU、内存、GPU等资源command容器的入口命令args容器的入口参数volumeMounts容器要挂载的Pod数据卷等。可以看到**上述这些信息都是启动容器的必要和必需的信息。**
- volumes记录了Pod内的数据卷信息后文会详细介绍Pod的数据卷。
### 2.2 Volume 数据卷
K8S支持很多类型的volume数据卷挂载具体请参见[K8S卷](https://kubernetes.io/zh/docs/concepts/storage/volumes/)。前文就“如何理解volume”提到“需要手动mount的磁盘”此外有一点可以帮助理解数据卷volume是Pod内部的磁盘资源。
其实单单就Volume来说不难理解。但是上面还看到了volumeMounts这俩是什么关系呢
volume是K8S的对象对应一个实体的数据卷而volumeMounts只是container的挂载点对应container的其中一个参数。但是volumeMounts依赖于volume只有当Pod内有volume资源的时候该Pod内部的container才可能有volumeMounts。
### 2.3 Container 容器
本文中提到的镜像Image、容器Container都指代了Pod下的一个container。关于K8S中的容器在2.1Pod章节都已经交代了,这里无非再啰嗦一句:**一个Pod内可以有多个容器container**。
在Pod中容器也有分类对这个感兴趣的同学欢迎自行阅读更多资料
- **标准容器 Application Container**。
- **初始化容器 Init Container**。
- **边车容器 Sidecar Container**。
- **临时容器 Ephemeral Container**。
一般来说,我们部署的大多是**标准容器( Application Container**。
### 2.4 Deployment 和 ReplicaSet简称RS
除了Pod之外K8S中最常听到的另一个对象就是Deployment了。那么什么是Deployment呢官方给出了一个要命的解释
> 一个 Deployment 控制器为 Pods 和 ReplicaSets 提供声明式的更新能力。 你负责描述 Deployment 中的
> 目标状态,而 Deployment 控制器以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的
> ReplicaSet或删除现有 Deployment并通过新的 Deployment 收养其资源。
翻译一下:**Deployment的作用是管理和控制Pod和ReplicaSet管控它们运行在用户期望的状态中**。哎,打个形象的比喻,**Deployment就是包工头**主要负责监督底下的工人Pod干活确保每时每刻有用户要求数量的Pod在工作。如果一旦发现某个工人Pod不行了就赶紧新拉一个Pod过来替换它。
新的问题又来了那什么是ReplicaSets呢
> ReplicaSet 的目的是维护一组在任何时候都处于运行状态的 Pod 副本的稳定集合。 因此,它通常用来保证给定数量的、完全相同的
> Pod 的可用性。
再来翻译下ReplicaSet的作用就是管理和控制Pod管控他们好好干活。但是ReplicaSet受控于Deployment。形象来说**ReplicaSet就是总包工头手下的小包工头**。
笔者总结得到下面这幅图,希望能帮助理解:
![在这里插入图片描述](https://img-blog.csdnimg.cn/967c77c45b4a43bea5f6e87c061bea02.png#pic_center =x300)
新的问题又来了:**如果都是为了管控Pod好好干活为什么要设置Deployment和ReplicaSet两个层级呢直接让Deployment来管理不可以吗**
回答不清楚但是私以为是因为先有ReplicaSet但是使用中发现ReplicaSet不够满足要求于是又整了一个Deployment**有清楚Deployment和ReplicaSet联系和区别的小伙伴欢迎留言啊**)。
但是从K8S使用者角度来看用户会直接操作Deployment部署服务而当Deployment被部署的时候K8S会自动生成要求的ReplicaSet和Pod。在[K8S官方文档](https://www.kubernetes.org.cn/replicasets)中也指出用户只需要关心Deployment而不操心ReplicaSet
> This actually means that you may never need to manipulate ReplicaSet
> objects: use a Deployment instead, and define your application in the
> spec section.
> 这实际上意味着您可能永远不需要操作ReplicaSet对象直接使用Deployments并在规范部分定义应用程序。
补充说明在K8S中还有一个对象 --- ReplicationController简称RC官方文档对它的定义是
> ReplicationController 确保在任何时候都有特定数量的 Pod 副本处于运行状态。
> 换句话说ReplicationController 确保一个 Pod 或一组同类的 Pod 总是可用的。
怎么样和ReplicaSet是不是很相近在Deployments, ReplicaSets, and pods教程中说“ReplicationController是ReplicaSet的前身”官方也推荐用Deployment取代ReplicationController来部署服务。
### 2.5 Service和Ingress
吐槽下K8S的概念/对象/资源是真的多啊!**前文介绍的Deployment、ReplicationController和ReplicaSet主要管控Pod程序服务那么Service和Ingress则负责管控Pod网络服务**。
我们先来看看官方文档中Service的定义
> 将运行在一组 [Pods](https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/) 上的应用程序公开为网络服务的抽象方法。 使用 Kubernetes您无需修改应用程序即可使用不熟悉的服务发现机制。
> Kubernetes 为 Pods 提供自己的 IP 地址,并为一组 Pod 提供相同的 DNS 名, 并且可以在它们之间进行负载均衡。
翻译下K8S中的服务Service并不是我们常说的“服务”的含义而更像是网关层是若干个Pod的流量入口、流量均衡器。
那么,**为什么要Service呢**
私以为在这一点上,[官方文档](https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/namespaces/)讲解地非常清楚:
> Kubernetes Pod 是有生命周期的。 它们可以被创建,而且销毁之后不会再启动。 如果您使用 Deployment
> 来运行您的应用程序,则它可以动态创建和销毁 Pod。 每个 Pod 都有自己的 IP 地址,但是在 Deployment
> 中,在同一时刻运行的 Pod 集合可能与稍后运行该应用程序的 Pod 集合不同。 这导致了一个问题: 如果一组
> Pod称为“后端”为群集内的其他 Pod称为“前端”提供功能 那么前端如何找出并跟踪要连接的 IP
> 地址,以便前端可以使用工作量的后端部分?
补充说明K8S集群的网络管理和拓扑也有特别的设计以后会专门出一章节来详细介绍K8S中的网络。这里需要清楚一点K8S集群内的每一个Pod都有自己的IP是不是很类似一个Pod就是一台服务器然而事实上是多个Pod存在于一台服务器上只不过是K8S做了网络隔离在K8S集群内部还有DNS等网络服务一个K8S集群就如同管理了多区域的服务器可以做复杂的网络拓扑
此外笔者推荐k8s外网如何访问业务应用对于Service的介绍不过对于新手而言推荐阅读前半部分对于service的介绍即可后半部分就太复杂了。我这里做了简单的总结
**Service是K8S服务的核心屏蔽了服务细节统一对外暴露服务接口真正做到了“微服务”**。举个例子我们的一个服务A部署了3个备份也就是3个Pod对于用户来说只需要关注一个Service的入口就可以而不需要操心究竟应该请求哪一个Pod。优势非常明显**一方面外部用户不需要感知因为Pod上服务的意外崩溃、K8S重新拉起Pod而造成的IP变更外部用户也不需要感知因升级、变更服务带来的Pod替换而造成的IP变化另一方面Service还可以做流量负载均衡**。
但是Service主要负责K8S集群内部的网络拓扑。那么集群外部怎么访问集群内部呢这个时候就需要Ingress了[官方文档](https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/namespaces/)中的解释是:
> Ingress 是对集群中服务的外部访问进行管理的 API 对象,典型的访问方式是 HTTP。 Ingress 可以提供负载均衡、SSL
> 终结和基于名称的虚拟托管。
翻译一下Ingress是整个K8S集群的接入层复杂集群内外通讯。
最后笔者把Ingress和Service的关系绘制网络拓扑关系图如下希望对理解这两个概念有所帮助
![在这里插入图片描述](https://img-blog.csdnimg.cn/62525c9371f84a819e67e8e0c4c8e875.png#pic_center =x400)
### 2.6 namespace 命名空间
和前文介绍的所有的概念都不一样namespace跟Pod没有直接关系而是K8S另一个维度的对象。或者说前文提到的概念都是为了服务Pod的而namespace则是为了服务整个K8S集群的。
那么namespace是什么呢
上[官方文档](https://kubernetes.io/zh/docs/concepts/overview/working-with-objects/namespaces/)定义:
> Kubernetes 支持多个虚拟集群,它们底层依赖于同一个物理集群。 这些虚拟集群被称为名字空间。
翻译一下:**namespace是为了把一个K8S集群划分为若干个资源不可共享的虚拟集群而诞生的。**
也就是说,**可以通过在K8S集群内创建namespace来分隔资源和对象**。比如我有2个业务A和B那么我可以创建ns-a和ns-b分别部署业务A和B的服务如在ns-a中部署了一个deployment名字是hello返回用户的是“hello a”在ns-b中也部署了一个deployment名字恰巧也是hello返回用户的是“hello b”要知道在同一个namespace下deployment不能同名但是不同namespace之间没有影响。前文提到的所有对象都是在namespace下的当然也有一些对象是不隶属于namespace的而是在K8S集群内全局可见的官方文档提到的可以通过命令来查看具体命令的使用办法笔者会出后续的实战文章来介绍先贴下命令
```bash
# 位于名字空间中的资源
kubectl api-resources --namespaced=true
# 不在名字空间中的资源
kubectl api-resources --namespaced=false
```
不在namespace下的对象有
![在这里插入图片描述](https://img-blog.csdnimg.cn/eb01dd40a7984ee1a5cf6e077d73654a.png)
在namespace下的对象有部分
![在这里插入图片描述](https://img-blog.csdnimg.cn/079974ccc763483db47ba40906624345.png)
### 2.7 其他
K8S的对象实在太多了2.1-2.6介绍的是在实际使用K8S部署服务最常见的。其他的还有Job、CronJob等等在对K8S有了比较清楚的认知之后再去学习更多的K8S对象不是难事。
### 写在后面
本文是K8S系列文章第一篇希望能够帮助对K8S不了解的新手快速了解K8S。如果文章中有纰漏非常欢迎留言或者私信指出有理解错误的地方更是欢迎留言或者私信告知。
笔者一边写文章一边查阅和整理K8S资料过程中越发感觉K8S架构的完备、设计的精妙是值得深入研究的K8S大受欢迎是有道理的再次感叹下。
<!--stackedit_data:
eyJoaXN0b3J5IjpbLTc5ODg4ODk0NF19
-->