技术标签: k8s 基础篇 kubernetes
一个 Pod 被创建出来,不管是由你直接创建,还是由其他工作负载控制器(Workload Controller)自动创建,经过调度器调度以后,就永久地“长”在某个节点上了,直到该 Pod 被删除,或者因为资源不够被驱逐,抑或由于对应的节点故障导致宕机等。因此单独地用一个 Pod 来承载业务,是没办法保证高可用、可伸缩、负载均衡等要求,而且 Pod 也无法“自愈”。
这时我们就需要在 Pod 之上做一层抽象,通过多个副本(Replica)来保证可用 Pod 的数量,避免业务不可用。在介绍 Kubernetes 中对这种抽象的实现之前,我们先来看看应用的业务类型。
有状态服务 VS 无状态服务
一般来说,业务的服务类型可分为无状态服务和有状态服务。举个简单的例子,像打网络游戏这类的服务,就是有状态服务,而正常浏览网页这类服务一般都是无状态服务。其实判断两种请求的关键在于,两个来自相同发起者的请求在服务器端是否具备上下文关系。
有状态服务和无状态服务分别有各自擅长的业务类型和技术优势,在 Kubernetes 中,分别有不同的工作负载控制器来负责承载这两类服务。
这篇文章,我们先介绍 Kubernetes 中的无状态工作负载。
Kubernetes 中各个对象的 metadata 字段都有 label(标签)和 annotation(注解) 两个对象,可以用来标识一些元数据信息。不论是 label 还是 annotation,都是一组键值对,键值不允许相同。
为了让这种抽象的对象可以跟 Pod 关联起来,Kubernetes 使用了labelSelector来跟 label 进行选择匹配,从而达到这种松耦合的关联效果。
$ kubectl get pod -l label1=value1,label2=value2 -n my-namespace
比如,我们就可以通过上述命令,查询出 my-namespace 这个命名空间下面,带有标签label1=value1
和label2=value2
的 pod。label 中的键值对在匹配的时候是“且”的关系。
Kubernetes 中有一系列的工作负载可以用来部署无状态服务。在最初,Kubernetes 中使用了ReplicationController来做 Pod 的副本控制,即确保该服务的 Pod 数量维持在特定的数量。为了简洁并便于使用,ReplicationController通常缩写为“rc”,并作为 kubectl 命令的快捷方式,例如:
$ kubectl get rc -n my-namespace
如果副本数少于预定的值,则创建新的 Pod。如果副本数大于预定的值,就删除多余的副本。因此即使你的业务应用只需要一个 Pod,你也可以使用 rc 来自动帮你维护和创建 Pod。
随后社区开发了下一代的 Pod 控制器 ReplicaSet(可简写为 rs) 用来替代 ReplicaController。虽然 ReplicaController 目前依然可以使用,但是社区已经不推荐继续使用了。这两者的功能和目的完全相同,但是 ReplicaSet 具备更强大的基于集合的标签选择器,这样你可以通过一组值来进行标签匹配选择。目前支持三种操作符:in
、notin
和exists
。
例如,你可以用environment in (production, qa)
来匹配 label 中带有environment=production
或environment=qa
的 Pod。
同样你也可以使用tier notin (frontend,backend)
来匹配 label 中不带有tier=frontend
或tier=backend
的 Pod。
或者你可以用 partition来匹配 label 中带有 partition 这个 key 的 Pod。
了解了标签选择器,我们就可以通过如下的 kubectl 命令查找 Pod:
kubectl get pods -l environment=production,tier=frontend
或者使用:
kubectl get pods -l 'environment in (production),tier in (frontend)'
虽然 Replicaset 可以独立使用,但是为了能够更好地协调 Pod 的创建、删除以及更新等操作,我们都是直接使用更高级的 Deployment来管理 Replicaset,社区也是一直这么定位和推荐的。比如一些业务升级的场景,使用单一的 ReplicaController 或者 Replicaset 是无法实现滚动升级的诉求,至少需要定义两个该对象才能实现,而且这两个对象使用的标签选择器中的 label 至少要有一个不相同。通过不断地对这两个对象的副本进行增减,也可以称为调和(Reconcile),才可以完成滚动升级。这样使用起来不方便,也增加了用户的使用门槛,极大地降低了业务发布的效率。
[root@k8s-master ~]# kubectl rollout undo deployment/web
deployment.apps/web rolled back
[root@k8s-master ~]# kubectl get replicaset -w
NAME DESIRED CURRENT READY AGE
web-6c8f6b7f84 3 3 3 29m
web-7cc58d88d9 0 0 0 63m
web-7cc58d88d9 0 0 0 64m
web-7cc58d88d9 1 0 0 64m
web-6c8f6b7f84 1 3 3 30m
web-7cc58d88d9 1 0 0 64m
web-7cc58d88d9 3 0 0 64m
web-6c8f6b7f84 1 3 3 30m
web-6c8f6b7f84 1 1 1 30m
web-7cc58d88d9 3 1 0 64m
web-7cc58d88d9 3 1 0 64m
web-7cc58d88d9 3 3 0 64m
web-7cc58d88d9 3 3 1 64m
web-6c8f6b7f84 0 1 1 30m
web-6c8f6b7f84 0 1 1 30m
web-7cc58d88d9 3 3 2 64m
web-6c8f6b7f84 0 0 0 30m
web-7cc58d88d9 3 3 3 64m
^C[root@k8s-master ~]# kubectl get replicaset
NAME DESIRED CURRENT READY AGE
web-6c8f6b7f84 0 0 0 30m
web-7cc58d88d9 3 3 3 64m
通过 Deployment,我们就不需要再关心和操作 ReplicaSet 了。
Deployment、ReplicaSet 和 Pod 这三者之间的关系见上图。通过 Deployment,我们可以管理多个 label 各不相同的 ReplicaSet,每个 ReplicaSet 负责保证对应数目的 Pod 在运行。
我们来看一个定义 Deployment 的例子:
[root@k8s-master ~]# cat deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-demo
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
version: v1
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
我们这里定义了副本数spec.replicas
为 3,同时在spec.selector.matchLabels
中设置了app=nginx
的 label,用于匹配spec.template.metadata.labels
的 label。我们还增加了version=v1
的 label 用于后续滚动升级做比较。
我们将上述内容保存到deploy-demo.yaml
文件中。
注意,spec.selector.matchLabels
中写的 label 一定要能匹配得了spec.template.metadata.labels
中的 label。否则该 Deployment 无法关联创建出来的 ReplicaSet。
然后我们通过下面这些命令,便可以在命名空间 demo 中创建名为 nginx-deployment-demo 的 Deployment。
[root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/nginx-deployment-demo created
[root@k8s-master ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-demo-675745c9cd-5q65l 1/1 Running 0 2m30s app=nginx,pod-template-hash=675745c9cd,version=v1
nginx-deployment-demo-675745c9cd-kktkv 1/1 Running 0 2m30s app=nginx,pod-template-hash=675745c9cd,version=v1
nginx-deployment-demo-675745c9cd-xbtgs 1/1 Running 0 2m30s app=nginx,pod-template-hash=675745c9cd,version=v1
创建完成后,我们可以查看自动创建出来的 rs。(ReplicaSet )
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-demo-675745c9cd 3 3 3 4m10s
[root@k8s-master ~]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment-demo 3/3 3 3 6m6s
接下来我们用 kubectl describe deployment
了解更详细的信息。
[root@k8s-master ~]# kubectl describe deployment nginx-deployment-demo
NewReplicaSet: nginx-deployment-demo-675745c9cd (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 7m32s deployment-controller Scaled up replica set nginx-deployment-demo-675745c9cd to 3
这里告诉我们创建了一个 ReplicaSet nginx-deployment-demo-675745c9cd,Events
是 Deployment 的日志,记录了 ReplicaSet 的启动过程。
通过上面的分析,也验证了 Deployment 通过 ReplicaSet 来管理 Pod 的事实。接着我们将注意力切换到 nginx-deployment-demo-675745c9cd,执行 kubectl describe replicaset
:
[root@k8s-master ~]# kubectl describe replicaset nginx-deployment-demo-675745c9cd
Controlled By: Deployment/nginx-deployment-demo
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 10m replicaset-controller Created pod: nginx-deployment-demo-675745c9cd-xbtgs
Normal SuccessfulCreate 10m replicaset-controller Created pod: nginx-deployment-demo-675745c9cd-5q65l
Normal SuccessfulCreate 10m replicaset-controller Created pod: nginx-deployment-demo-675745c9cd-kktkv
Controlled By
指明此 ReplicaSet 是由 Deployment nginx-deployment
创建。Events
记录了三个副本 Pod 的创建。接着我们来看 Pod,执行 kubectl get pod
:
[root@k8s-master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-demo-675745c9cd-5q65l 1/1 Running 0 16m
nginx-deployment-demo-675745c9cd-kktkv 1/1 Running 0 16m
nginx-deployment-demo-675745c9cd-xbtgs 1/1 Running 0 16m
两个副本 Pod 都处于 Running
状态,用 kubectl describe pod
查看更详细的信息:
[root@k8s-master ~]# kubectl describe pod nginx-deployment-demo-675745c9cd-5q65l
Controlled By: ReplicaSet/nginx-deployment-demo-675745c9cd
[root@k8s-master ~]# kubectl describe pod nginx-deployment-demo-675745c9cd-kktkv
Controlled By: ReplicaSet/nginx-deployment-demo-675745c9cd
[root@k8s-master ~]# kubectl describe pod nginx-deployment-demo-675745c9cd-xbtgs
Controlled By: ReplicaSet/nginx-deployment-demo-675745c9cd
Controlled By
指明此 Pod 是由 ReplicaSet nginx-deployment-demo-675745c9cd
创建。Events
记录了 Pod 的启动过程。如果操作失败(比如 image 不存在),也能在这里查看到原因。
总结一下这个过程:
用户通过 kubectl
创建 Deployment。
Deployment 创建 ReplicaSet。
ReplicaSet 创建 Pod。
从上图也可以看出,对象的命名方式是:子对象的名字
= 父对象名字
+ 随机字符串或数字
。
现在我们试着做下镜像更新看看。更改spec.template.metadata.labels
中的version=v1
为version=v2
,同时更新镜像nginx:1.14.2
为nginx:1.19.2
。
你可以直接通过下述命令来直接更改:
$ kubectl edit deploy nginx-deployment-demo
也可以更改deploy-demo.yaml
这个文件:
[root@k8s-master ~]# cat deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-demo
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
version: v2
spec:
containers:
- name: nginx
image: nginx:1.19.2
ports:
- containerPort: 80
然后运行这些命令:
[root@k8s-master ~]# kubectl apply -f deployment.yml
deployment.apps/nginx-deployment-demo configured
这个时候,我们来看看 ReplicaSet 有什么变化:
[root@k8s-master ~]# kubectl get rs -w
NAME DESIRED CURRENT READY AGE
nginx-deployment-demo-675745c9cd 3 3 3 28m
#下面为执行apply之后的状态
nginx-deployment-demo-f6bf65976 1 0 0 0s
nginx-deployment-demo-f6bf65976 1 0 0 0s
nginx-deployment-demo-f6bf65976 1 1 0 0s
nginx-deployment-demo-f6bf65976 1 1 1 41s
nginx-deployment-demo-675745c9cd 2 3 3 30m
nginx-deployment-demo-f6bf65976 2 1 1 41s
nginx-deployment-demo-675745c9cd 2 3 3 30m
nginx-deployment-demo-675745c9cd 2 2 2 30m
nginx-deployment-demo-f6bf65976 2 1 1 41s
nginx-deployment-demo-f6bf65976 2 2 1 41s
nginx-deployment-demo-f6bf65976 2 2 2 110s
nginx-deployment-demo-675745c9cd 1 2 2 31m
nginx-deployment-demo-f6bf65976 3 2 2 110s
nginx-deployment-demo-675745c9cd 1 2 2 31m
nginx-deployment-demo-675745c9cd 1 1 1 31m
nginx-deployment-demo-f6bf65976 3 2 2 111s
nginx-deployment-demo-f6bf65976 3 3 2 111s
nginx-deployment-demo-f6bf65976 3 3 3 113s
nginx-deployment-demo-675745c9cd 0 1 1 31m
nginx-deployment-demo-675745c9cd 0 1 1 31m
nginx-deployment-demo-675745c9cd 0 0 0 31m
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-demo-675745c9cd 1 1 1 31m
nginx-deployment-demo-f6bf65976 3 3 2 113s
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-demo-675745c9cd 0 0 0 33m
nginx-deployment-demo-f6bf65976 3 3 3 3m52s
可以看到,这个时候自动创建了一个新的 rs 出来:nginx-deployment-demo-f6bf65976。一般 Deployment 的默认更新策略是 RollingUpdate,即先创建一个新的 Pod,并待其成功运行以后,再删除旧的。
还有一个更新策略是Recreate,即先删除现有的 Pod,再创建新的。关于 Deployment,我们还可以设置最大不可用(maxUnavailable)和最大增量(maxSurge),来更精确地控制滚动更新操作。
我建议你使用默认的策略来保证可用性。后面 Deployment 控制器会不断对这两个 rs 进行调和,直到新的 rs 副本数为 3,老的 rs 副本数为 0。
我们可以通过如下命令,能够观察到 Deployment 的调和过程。
[root@k8s-master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
nginx-deployment-demo-675745c9cd-5q65l 1/1 Running 0 28m
nginx-deployment-demo-675745c9cd-kktkv 1/1 Running 0 28m
nginx-deployment-demo-675745c9cd-xbtgs 1/1 Running 0 28m
#apply之后产生的
nginx-deployment-demo-f6bf65976-bwjlk 0/1 Pending 0 0s
nginx-deployment-demo-f6bf65976-bwjlk 0/1 Pending 0 0s
nginx-deployment-demo-f6bf65976-bwjlk 0/1 ContainerCreating 0 0s
nginx-deployment-demo-f6bf65976-bwjlk 0/1 ContainerCreating 0 2s
nginx-deployment-demo-f6bf65976-bwjlk 1/1 Running 0 41s
nginx-deployment-demo-675745c9cd-xbtgs 1/1 Terminating 0 30m
nginx-deployment-demo-f6bf65976-s5j6v 0/1 Pending 0 0s
nginx-deployment-demo-f6bf65976-s5j6v 0/1 Pending 0 0s
nginx-deployment-demo-f6bf65976-s5j6v 0/1 ContainerCreating 0 0s
nginx-deployment-demo-675745c9cd-xbtgs 1/1 Terminating 0 30m
nginx-deployment-demo-675745c9cd-xbtgs 0/1 Terminating 0 30m
nginx-deployment-demo-f6bf65976-s5j6v 0/1 ContainerCreating 0 2s
nginx-deployment-demo-675745c9cd-xbtgs 0/1 Terminating 0 30m
nginx-deployment-demo-675745c9cd-xbtgs 0/1 Terminating 0 30m
nginx-deployment-demo-f6bf65976-s5j6v 1/1 Running 0 69s
nginx-deployment-demo-675745c9cd-kktkv 1/1 Terminating 0 31m
nginx-deployment-demo-f6bf65976-t5hc4 0/1 Pending 0 1s
nginx-deployment-demo-f6bf65976-t5hc4 0/1 Pending 0 1s
nginx-deployment-demo-f6bf65976-t5hc4 0/1 ContainerCreating 0 1s
nginx-deployment-demo-675745c9cd-kktkv 1/1 Terminating 0 31m
nginx-deployment-demo-f6bf65976-t5hc4 0/1 ContainerCreating 0 2s
nginx-deployment-demo-675745c9cd-kktkv 0/1 Terminating 0 31m
nginx-deployment-demo-f6bf65976-t5hc4 1/1 Running 0 3s
nginx-deployment-demo-675745c9cd-5q65l 1/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-kktkv 0/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-kktkv 0/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-5q65l 1/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-5q65l 0/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-5q65l 0/1 Terminating 0 31m
nginx-deployment-demo-675745c9cd-5q65l 0/1 Terminating 0 31m
[root@k8s-master ~]# kubectl get pod -l version=v2,app=nginx
NAME READY STATUS RESTARTS AGE
nginx-deployment-demo-f6bf65976-bwjlk 1/1 Running 0 11m
nginx-deployment-demo-f6bf65976-s5j6v 1/1 Running 0 10m
nginx-deployment-demo-f6bf65976-t5hc4 1/1 Running 0 9m19s
Kubernetes 中这些高阶的抽象对象,都是通过标签选择器来控制 Pod 的。有了 Deployment 这个高级对象,我们可以很方便地完成无状态服务的发布、更新升级,无须多余的人工参与,就能保证业务的高可用性。这也是 Kubernetes 迷人之处——声明式 API。
文章浏览阅读1k次。3、内连接要求相等的分量,不一定是公共属性,自然连接要求相等的分量必须是公共属性;自然外连接分为自然左外连接和自然右外连接.匹配条件也是由系统自动指定.在MySQL中,可通过求左外连接与右外连接的合集来实现全外连接。自然内连接其实就是内连接,这里的匹配条件是由系统自动指定.2、内连接不把重复的属性除去,自然连接要把重复的属性除去;4、内连接不把重复的属性除去,自然连接要把重复的属性除去。–自然内连接 natural inner join。1、自然连接一定是内连接,内连接不一定是自然连接;_sql注入join连接
文章浏览阅读1w次,点赞7次,收藏37次。英文原文链接:https://www.pyimagesearch.com/2018/08/20/opencv-text-detection-east-text-detector/提醒:作者实现的python的文本检测基于OpenCV的官方C ++示例;在将其转换为Python时遇到了一些麻烦。首先,Python中没有Point2f 和RotatedRect函数,因此,无法100..._python east
文章浏览阅读211次。<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>表格</title> <style> table{/*为页面中所有table标签添加样式*/ border: black 1px solid; width: 800px;/*设置表格宽度*/ margin: 0 auto;/*设置表格水平居中*/ bord_html中关于表格所有的标签
文章浏览阅读680次。Kerberos技术实践_kerberos_patch 1.0
文章浏览阅读515次。@Test public void testHighLightingQuery() throws SolrServerException, IOException{ // 初始化solrj服务 HttpSolrServer server = new HttpSolrServer("http://localhost:8080/solr/c..._sql query highlighting
文章浏览阅读542次。微信扫码观看全套Excel、Word、PPT视频作者:徐少寒来源:徐少寒(id:ixushaohan)截图、录屏和制作GIF是每一位职场办公人员必备的基础技能,因此,今天小编给大家科普六款工具大大提高你的工作效率。1截图工具日常用的截图除了QQ截图、桌面版微信截图、浏览器自带的截图功能外,相信还有不少人没有用过Snipaste和FSCapture。▍SnipasteSnipaste..._电脑后台截屏软件
文章浏览阅读2.1k次。FileReader:读取文件内容1.readAsText():读取文本文件(可以使用Txt打开的文件),返回文本字符串,默认编码是UTF-82.readAsBinaryString():读取任意类型的文件。返回二进制字符串。这个方法不是用来读取文件展示给用户看,而是存储文件。例如:读取文件的内容,获取二进制数据,传递给后台,后台接收了数据之后,再将数据存储3.readAsDataURL():读取文件获取一段以data开头的字符串,这段字符串的本质就是DataURL.DataURL是一种将文件(这个文_filereader读取文件内容
文章浏览阅读179次。UML关系关联关系即两个类互相包含,使用双向箭头表示 依赖关系即方法参数上的依赖,使用虚线箭头表示,其中箭头指向部分 聚合关系即部分与整体之间的关系,如类A中有属性值为B,使用 菱形空心箭头表示其中空心端为整体组合关系也是部分与整体之间的关系,与聚合关系的区别在于组合中部分单独存在没有意义,部分需要依赖于整体才能存在,使用菱形实心箭头表示其中实心端为整体 泛化关系即..._音乐网站排行uml图
文章浏览阅读3.9k次。今天要打开struts.xml文件时莫名其妙报错,试了几种方法都没用:后来用了一下方式打开:鼠标放在待打开xml文件,点击右键,然后选择open with。。。选择MyEclipse Struts2 configeditor即可!
文章浏览阅读547次。一直以为打印乘法口诀要用两个for循环,今天发现用一个for循环就能达到同样的效果,java代码如下://打印乘法口诀public class multiTable { //主函数 public static void main(String[] args) { // 一个for循环,两个参数实现了循环的嵌套效果 for (int i = 1, j = 1; j <= 9;_java从键盘输入一个1到之间的数,如若输入6则打印六六乘法表
文章浏览阅读2k次。本文转自:https://www.cnblogs.com/Jtianlin/p/4339931.htmlhttp://www.cnblogs.com/Rosanna/p/3446557.html使文件立刻生效命令:/sbin/sysctl -p/proc/sys目录下存放着大多数内核参数,并且可以在系统运行时进行更改,不过重新启动机器就会失效。/etc/sysctl.conf是一个允许..._大量time_wait,导致resin 请求进不
文章浏览阅读1.2w次,点赞12次,收藏77次。springboot后端部署1.前提条件 可执行的springboot源码文件,Linux服务器,写好的vue前端项目2.执行步骤 a. 打开springboot项目中的配置文件application.yaml b.配置服务器端口号 c.将springboot后端项目打包d.在springboot文件中找到刚才对应的jar包e.使用xshell上传到本地服务器(在想要存放对应文件目录中使用rz或者直接拖动文件复制到Linux的当前文件夹下)后端传输完毕VUE的前端部署_springboot vue 不安装nginx