资源控制器以及RS 与 RC 与 Deployment 关联讲解
什么是控制器
Kubernetes 中内建了很多 controller(控制器),这些相当于一个状态机,用来控制 Pod 的具体状态和行为
控制器类型
-
ReplicationController 和 ReplicaSet
-
Deployment
-
DaemonSet
-
StateFulSet
-
Job/CronJob
-
Horizontal Pod Autoscaling
Pod的分类:
自主式 Pod:Pod退出了此类型的Pod不会被创建
控制器管理的Pod:在控制器的生命周期里始终要维持Pod的副本数目
ReplicationController 和 ReplicaSet
ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的 Pod 来替代;而如果异常多出来的容器也会自动回收;
在新版本的 Kubernetes 中建议使用 ReplicaSet 来取代 ReplicationController 。ReplicaSet 跟ReplicationController 没有本质的不同,只是名字不一样,并且 ReplicaSet 支持集合式的 selector;
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义 (declarative) 方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括;
-
定义 Deployment 来创建 Pod 和 ReplicaSet
-
滚动升级和回滚应用
-
扩容和缩容
-
暂停和继续 Deployment
命令式编程:它侧重于于何实现程序,就像我们刚接触编程的时候那样,我们需要把程序的实现过程按照逻辑结果一步步写下来
声明式编程:它侧重于定义想要什么,然后告诉计算机/引擎,让他帮你去实现
串名式编程(Deployment)apply(最优)create命令式 (RS) create(最优) apply
deployment是通过RS管理pod的!
DaemonSet
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod
使用 DaemonSet 的一些典型用法:
-
运行集群存储 daemon,例如在每个 Node 上运行 glusterd 、 ceph
-
在每个 Node 上运行日志收集 daemon,例如 fluentd 、 logstash
-
在每个 Node 上运行监控 daemon,例如 Prometheus Node Exporter、 collectd 、Datadog 代理、
New Relic 代理,或 Ganglia gmond
Job
Job 负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束
(job倾向于以脚本运行方案机制的管理)
CronJob
Cron Job 管理基于时间的 Job,即:
-
在给定时间点只运行一次
-
周期性地在给定时间点运行
也就是cron job通过在特定的时间内循环创建job来实现!
使用前提条件:当前使用的 Kubernetes 集群,版本 >= 1.8(对 CronJob)。对于先前版本的集群,版本 <1.8,启动 API Server时,通过传递选项 --runtime-config=batch/v2alpha1=true 可以开启 batch/v2alpha1API**
典型的用法如下所示:
-
在给定的时间点调度 Job 运行
-
创建周期性运行的 Job,例如:数据库备份、发送邮件
StatefulSet
StatefulSet 作为 Controller 为 Pod 提供唯一的标识。它可以保证部署和 scale 的顺序
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括:
-
稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现
-
稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有
Cluster IP的Service)来实现
-
有序部署,有序扩展,即Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次依次进行(即从0到N-1,在下一个Pod运行之前所有之前的Pod必须都是Running和Ready状态),基于init containers来实现
-
有序收缩,有序删除(即从N-1到0)
有状态服务和无状态服务理解:
无状态服务不会在本地存储持久化数据.多个服务实例对于同一个用户请求的响应结果是完全一致的.这种多服务实例之间是没有依赖关系,比如web应用,在k8s控制器 中动态启停无状态服务的pod并不会对其它的pod产生影响.
-
有状态服务
有状态服务需要在本地存储持久化数据,典型的是分布式数据库的应用,分布式节点实例之
Horizontal Pod Autoscaling
应用的资源使用率通常都有高峰和低谷的时候,如何削峰填谷,提高集群的整体资源利用率,让service中的Pod个数自动调整呢?这就有赖于Horizontal Pod Autoscaling了,顾名思义,使Pod水平自动缩放
HPA不是一个直接的控制器,它可以负责管理这个控制器!
总结:
一般的应用程序比如无状态服务部署在RS和Deployment上面(RC已经退出历史舞台了)
如果是类似守护进程和需要node节点的需要在DaemonSe上面
如果是批处理任务需要在job和cron job上
有状态服务部署在StatefulSet
小小补充:
pod 内部容器网络通信:公用pause容器的网络栈lo网卡 localhost方式互相访问
pod与pod之间网络通信:overlay network
pod与service网络通信:iptables ipvs
RC (ReplicationController )主要的作用就是用来确保容器应用的副本数始终保持在用户定义的副本数 。即如果有容器异常退出,会自动创建新的Pod来替代;而如果异常多出来的容器也会自动回收
Kubernetes 官方建议使用 RS(ReplicaSet ) 替代 RC (ReplicationController ) 进行部署,RS 跟 RC 没有本质的不同,只是名字不一样,并且 RS 支持集合式的 selector
实战:
[root@k8s-master01 ~]# vim rs.yaml
apiVersion
[root@k8s-master01 ~]# vim rs.yaml
[root@k8s-master01 ~]# kubectl create -f rs.yaml
replicaset.apps/frontend created
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-srgmf 1/1 Running 0 40s
frontend-tnv2m 1/1 Running 0 40s
frontend-wk66v 1/1 Running 0 40s
[root@k8s-master01 ~]# kubectl delete pod --all
pod "frontend-srgmf" deleted
pod "frontend-tnv2m" deleted
pod "frontend-wk66v" deleted
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
frontend-4lmsq 0/1 ContainerCreating 0 3s
frontend-6rtf6 0/1 ContainerCreating 0 3s
frontend-g96dl 0/1 ContainerCreating 0 3s
[root@k8s-master01 ~]#
(这就是我们利用资源控制器定义的pod,即使删除后,也会就随机继续创建出来!)
[root@k8s-master01 ~]# kubectl get pod --show-labels(查看一下pod的标签)
NAME READY STATUS RESTARTS AGE LABELS
frontend-4lmsq 1/1 Running 0 2m48s tier=frontend
frontend-6rtf6 1/1 Running 0 2m48s tier=frontend
frontend-g96dl 1/1 Running 0 2m48s tier=frontend
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl label pod frontend-4lmsq tier=frontend1(修改一下其中一个pod的标签)
error: 'tier' already has a value (frontend), and --overwrite is false
[root@k8s-master01 ~]# kubectl label pod frontend-4lmsq tier=frontend1 --overwrite=true
pod/frontend-4lmsq labeled
[root@k8s-master01 ~]# kubectl get pod(这时我们发现pod数量发生了变化)
NAME READY STATUS RESTARTS AGE
frontend-4lmsq 1/1 Running 0 5m14s
frontend-6f9ml 1/1 Running 0 7s
frontend-6rtf6 1/1 Running 0 5m14s
frontend-g96dl 1/1 Running 0 5m14s
[root@k8s-master01 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-4lmsq 1/1 Running 0 5m23s tier=frontend1
frontend-6f9ml 1/1 Running 0 16s tier=frontend
frontend-6rtf6 1/1 Running 0 5m23s tier=frontend
frontend-g96dl 1/1 Running 0 5m23s tier=frontend
[root@k8s-master01 ~]#
(对于k8s来说,很多副本的监控都是以标签为基础的!标签相同的pod则它们都是由一个rs创建出来的)
[root@k8s-master01 ~]# kubectl delete rs --all(删除rs)
replicaset.apps "frontend" deleted
[root@k8s-master01 ~]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
frontend-4lmsq 1/1 Running 0 11m tier=frontend1
我们删除rs后,发现只有新改标签的pod仍在运行!
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController 来方便的管理应用。典型的应用场景包括:
-
定义Deployment来创建Pod和ReplicaSet
-
滚动升级和回滚应用
-
扩容和缩容
-
暂停和继续Deployment
1、部署一个简单的 Nginx 应用
apiVersion
[root@k8s-master01 ~]# kubectl apply -f deployment.yaml --record(--record参数可以记录命令,我们可以很方便的查看每次 revision 的变化)
Flag --record has been deprecated, --record will be removed in the future
error: unable to recognize "deployment.yaml": no matches for kind "Deployment" in version "extensions/v1beta1"
(这里会报版本版本错误,我们用命令查看一下相关的版本)
[root@k8s-master01 ~]# kubectl explain deployment.apiVersion
KIND: Deployment
VERSION: apps/v1
FIELD: apiVersion <string>
DESCRIPTION:
APIVersion defines the versioned schema of this representation of an
object. Servers should convert recognized schemas to the latest internal
value, and may reject unrecognized values. More info:
https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
[root@k8s-master01 ~]# kubectl apply -f deployment.yaml --record
Flag --record has been deprecated, --record will be removed in the future
error: error validating "deployment.yaml": error validating data: ValidationError(Deployment.spec): missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors, turn validation off with --validate=false
[root@k8s-master01 ~]#
(这里还会报一个selector的错误,加一下就可以了selector: matchLabels: app: nginx)
[root@k8s-master01 ~]# kubectl apply -f deployment.yaml --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx-deployment created
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 101s
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-f7ccf9478 3 3 3 110s
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-f7ccf9478-92xjn 1/1 Running 0 4m20s
nginx-deployment-f7ccf9478-98d7c 1/1 Running 0 4m20s
nginx-deployment-f7ccf9478-d49ms 1/1 Running 0 4m20s
[root@k8s-master01 ~]#
(由此我们可以看出Deployment是通过rs来管理pod的)
[root@k8s-master01 ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-f7ccf9478-92xjn 1/1 Running 0 5m43s 10.244.2.14 k8s-node02 <none> <none>
nginx-deployment-f7ccf9478-98d7c 1/1 Running 0 5m43s 10.244.2.15 k8s-node02 <none> <none>
nginx-deployment-f7ccf9478-d49ms 1/1 Running 0 5m43s 10.244.1.14 k8s-node01 <none> <none>
[root@k8s-master01 ~]# curl 10.244.2.14(我们访问一下pod,可以访问到)
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl scale deployment nginx-deployment --replicas=10
deployment.apps/nginx-deployment scaled
[root@k8s-master01 ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-f7ccf9478-2kwtj 1/1 Running 0 18s
nginx-deployment-f7ccf9478-4vhfw 1/1 Running 0 18s
nginx-deployment-f7ccf9478-92xjn 1/1 Running 0 12m
nginx-deployment-f7ccf9478-98d7c 1/1 Running 0 12m
nginx-deployment-f7ccf9478-9ww92 1/1 Running 0 18s
nginx-deployment-f7ccf9478-b8pds 1/1 Running 0 18s
nginx-deployment-f7ccf9478-cbw9r 1/1 Running 0 18s
nginx-deployment-f7ccf9478-d49ms 1/1 Running 0 12m
nginx-deployment-f7ccf9478-j5cjl 1/1 Running 0 18s
nginx-deployment-f7ccf9478-lmxrm 1/1 Running 0 18s
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-f7ccf9478 10 10 10 14m
[root@k8s-master01 ~]#
3、如果集群支持 horizontal pod autoscaling 的话,还可以为Deployment设置自动扩展
kubectl rollout undo deployment/nginx-deployment
4、更新镜像也比较简单
[root@k8s-master01 ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
deployment.apps/nginx-deployment image updated
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 5 5 0 25s
nginx-deployment-f7ccf9478 8 8 8 17m
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 7 7 2 26s
nginx-deployment-f7ccf9478 6 6 6 17m
[
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 8 8 3 27s
nginx-deployment-f7ccf9478 5 5 5 17m
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 9 8 4 28s
nginx-deployment-f7ccf9478 4 4 4 17m
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 10 10 6 29s
nginx-deployment-f7ccf9478 2 3 3 17m
[root@k8s-master01 ~]# kubectl get rs
nginx-deployment-5bfdf46dc6 10 10 7 40s
nginx-deployment-f7ccf9478 1 1 1 18m
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 10 10 10 2m41s
nginx-deployment-f7ccf9478 0 0 0 20m
[root@k8s-master01 ~]#
(我们发现镜像更新后,Deployment的版本也变化了)
5、回滚
[root@k8s-master01 ~]# kubectl rollout undo deployment/nginx-deployment
deployment.apps/nginx-deployment rolled back
[root@k8s-master01 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5bfdf46dc6 0 0 0 8m25s
nginx-deployment-f7ccf9478 10 10 10 25m
更新 Deployment
Deployment 可以保证在升级时只有一定数量的 Pod 是 down 的。默认的,它会确保至少有比期望的Pod数量少 一个是up状态(最多一个不可用)
Deployment 同时也可以确保只创建出超过期望数量的一定数量的 Pod。默认的,它会确保最多比期望的Pod数 量多一个的 Pod 是 up 的(最多1个 surge )
未来的 Kuberentes 版本中,将从1-1变成25%-25%
假如您创建了一个有5个 niginx:1.7.9 replica的 Deployment,但是当还只有3个 nginx:1.7.9 的 replica 创建出来的时候您就开始更新含有5个 nginx:1.9.1 replica 的 Deployment。在这种情况下,Deployment 会立即杀掉已创建的3个 nginx:1.7.9 的 Pod,并开始创建 nginx:1.9.1 的 Pod。它不会等到所有的5个 nginx:1.7.9 的Pod 都创建完成后才开始改变航道
理解:
我们正在创建旧版本的pod,还没有创建完,这时收到创建新版本pod的命令,这时旧版本的pod会立即被杀死,不会等旧版本全部创建完杀死!
kubectl set image deployment/nginx-deployment nginx=nginx:1.91(更新镜像)
kubectl rollout status deployments nginx-deployment(查看更新的状态)
kubectl get pods
kubectl rollout history deployment/nginx-deployment(查看更新的历史版本)
kubectl rollout undo deployment/nginx-deployment(更新镜像回滚)
kubectl rollout undo deployment/nginx-deployment --to-revision=2 (可以使用 --revision参数指定某个历史版本)
kubectl rollout pause deployment/nginx-deployment (暂停 deployment 的更新)
您可以用 kubectl rollout status 命令查看 Deployment 是否完成。如果 rollout 成功完成, kubectl rolloutstatus 将返回一个0值的 Exit Code
deployment "nginx-deployment" successfully rolled out
[root@k8s-master01 ~]# echo $?
0
[root@k8s-master01 ~]#
[root@k8s-master01 ~]# kubectl rollout history deployment/nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
2 kubectl apply --filename=deployment.yaml --record=true
3 kubectl apply --filename=deployment.yaml --record=true
[root@k8s-master01 ~]#
清理 Policy
您可以通过设置 .spec.revisonHistoryLimit 项来指定 deployment 最多保留多少 revision 历史记录。默认的会