Kubernetes核心技术-Controller
什么是Controller
Controller是在集群上管理和运行容器的对象,Controller是实际存在的,Pod是虚拟的
Pod和Controller
Pod是通过Controller实现应用的运维,比如弹性伸缩、滚动更新等
Pod和Controller之间是通过label标签来建立关系,同时Controller有称为控制器工作负载
Deployment控制器应用
- Deployment控制器可以部署无状态应用
- 管理Pod和ReplicaSet
- 部署,滚动升级等功能
- 应用场景: web服务,微服务
Deployment表示用户对K8s集群的一次更新操作。Dployment是一个比RS应用模型更广的API对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新RS中副本数增加到理想状态,将旧的副本数减少的0的复合操作。
这样一个符合操作用一个RS是不好描述的,所以用一个更通用的Deployment来描述。以K8s的发展方向,未来对所有长期伺服型的业务的管理,都会通过Deployment来管理。
Deployment部署应用
最简单的部署命令
kubectl create deployment web --image=nginx
但是这个方法不能很好的进行服用,每次都需要重新输入代码,所以一般工作环境中都是通过YAML进行配置
首先我们需要获取一个deployment的yaml文件
kubectl create deployment web --image=nginx --dry-run -o yaml > nginx.yaml
然后会输出一个yaml配置文件nginx.yaml,配置文件如下
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: nginx
name: nginx
resources: {}
status: {}
这里可以看到selector和label就是我们Pod和Controller之间建立关系的桥梁
使用yaml创建Pod
通过刚才的的代码,我们已经获取到了YAML文件,下面使用这个配置文件就可以快速创建Pod了
kubectl apply -f nginx.yaml
但是因为这个方式创建的,我们只能在集群内部访问,所以我们还需要对外暴露端口
kubectl expose deployment web --port=80 --type=NodePort --target-prot=80 --name=web
参数选项:
--port: 服务内部的端口
--target-port:暴露外面访问的端口号
--name:SVC名称
--type:SVC类型
同样也可以导出对应的配置文件
kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web -o yaml > web.yaml
cat web.yaml
apiVersion: v1
kind: Service
metadata:
creationTimestamp: "2021-03-19T02:19:13Z"
labels:
app: web
managedFields:
- apiVersion: v1
fieldsType: FieldsV1
fieldsV1:
f:metadata:
f:labels:
.: {}
f:app: {}
f:spec:
f:externalTrafficPolicy: {}
f:ports:
.: {}
k:{"port":80,"protocol":"TCP"}:
.: {}
f:port: {}
f:protocol: {}
f:targetPort: {}
f:selector:
.: {}
f:app: {}
f:sessionAffinity: {}
f:type: {}
manager: kubectl
operation: Update
time: "2021-03-19T02:19:13Z"
name: web
namespace: default
resourceVersion: "84558"
selfLink: /api/v1/namespaces/default/services/web
uid: 7a222d9c-b90a-4963-b59f-3f59b6b6d951
spec:
clusterIP: 10.108.14.242
externalTrafficPolicy: Cluster
ports:
- nodePort: 31068
port: 80
protocol: TCP
targetPort: 80
selector:
app: web
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
然后通过下面的命令来查看对外暴露的服务端口
kubectl get pod,svc
然后访问对应的url,就可以看到nginx
http://192.168.2.73:31068
升级回滚和弹性伸缩
- 升级:假设从版本为1.14升级到1.15,这就叫应用的升级(升级可以保证服务不中断)
- 回滚:从版本1.15回到1.14,这就叫应用的回滚
- 弹性伸缩:根据不同的业务场景,来改变Pod的数量对外提供服务,这就是弹性伸缩
应用升级和回滚
首先创建一个1.14版本的Pod
apiVersion: apps/v1
kind: Deployment
metadata:
creationTimestamp: null
labels:
app: web
name: web
spec:
replicas: 1
selector:
matchLabels:
app: web
strategy: {}
template:
metadata:
creationTimestamp: null
labels:
app: web
spec:
containers:
- image: nginx:1.14
name: nginx
resources: {}
status: {}
修改yaml文件,指定nginx版本1.14,然后开始创建我们的Pod
kubectl apply -f nginx.yaml
使用下面的命令可以将nginx从1.14升级到1.15
kubectl set image deployment web nginx=nginx:1.15
kubectl get pod
升级的过程
- 首先是开始的nginx1.14版本的Pod在运行,然后1.15版本的在创建
- 然后在1.15版本创建完成后,就会暂停1.14版本
- 最后把1.14版本的Pod移除,完成我们的升级
在下载1.15版本中,容器就处于ContaiersCreating状态,然后下载完成后,就用1.15版本去替换1.14版本,这么做的好处就是升级过程中保证服务不中断。
查看升级状态
下面可以查看升级状态
kubectl rollout status deployment web
查看历史版版本
kubectl rollout history deployment web
应用回滚
我们可以使用下面的命令,完成回滚操作,也就是回滚到上一个版本
kubectl rollout undo deployment web
然后我们可以查看装态
kubectl rollout status deploymnt web
同时我们还可以回滚到指定版本
kubectl rollout undo deployment web --to-version=2
弹性伸缩
弹性伸缩,也就是我们通过命令一下创建多个副本
kubectl scale deployment web --replicas=10
我这里有个问题K8s如何实现金丝雀部署呢?
有状态应用和无状态应用
无状态应用
- 认为Pod都是一样的
- 没有顺序要求
- 不考虑应用在那个node上运行
- 能够进行随意伸缩和扩展
有状态应用
- 让每一个Pod独立
- 让每一个Pod独立,保持Pod启动顺序和唯一性
- 唯一的网络标识符,持久存储
- 有序,比如MySQL的主从
StatefulSet
StatefulSet主要是用来部署有状态应用
对于StatefulSet中的Pod,每个Pod挂自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。
适合StatefulSet的业务包括数据库服务MySQL和PostgreSQL,集群化股那里服务Zookeeper、etcd等有状态服务
StatefulSet的另一种典型应用场景是作为一种比普通容器更稳定的可靠的模拟虚拟机机制。传统的虚拟机正是一种有状态的宠物,运维人员需要不断的维护它,容器刚开始流行时,我们用容器来模拟虚拟机使用,所有状态都保存载容器里,而这已被证明是非常不安全、不可靠的。
使用StatefulSet,Pod仍然可以通过漂移到不同节点提供高可用,而存储也可以通过外挂的存储来提供高可靠性,StatefulSet做的只是将稳定的Pod和确定的存储关联起来保证状态的连续性。
部署有状态应用
无头Service,ClusterIP:none
这里需要使用StatefulSet部署又状态应用
apiVersion: v1
kind: Service
metadata:
labels:
app: nginx
name: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web-statefulset
namespace: default
spec:
serviceName: web
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
查看pod,svc,发现每个pod都有唯一的名称。svchi是无头的servie
kubectl get pod,svc
这里的有状态的约定,肯定不是简单的通过名称来进行约定,而是更加复杂的操作
- Deployment:是有身份的,有唯一标识
- StatefulSet:根据主机名+按照一定规则生成域名
每个pod有唯一的主机名,并且有唯一的域名
- 格式:主机名称.service名称.名称空间.svc.cluster.local.
这里用dig命令和coredns可以让我们的podIP和SVC名称绑定。并且提供负载均衡的能力
yum -y install bind-util
dig -t A nginx.default.svc.cluster.local. @10.244.1.2
dig -t A nginx.default.svc.cluster.local. @10.244.1.3
然后我们会发现statefulset的pod重启以后名字没变,但是ip变了。svc里记录的ip也随之改变了。后面我们就可以使用ingress接口来为我们的无头服务提供访问的方案。
DaemonSet
DaemonSet即后台支撑型服务,主要是用来部署守护进程
长期伺服型和批处理型的核心在业务应用,可能有些节点运行多个同类型业务的Pod,有些节点上又没有这类的Pod运行;而后台支撑型服务的核心关注点在K8s集群中的节点(物理机或者虚拟机),要保证每个节点上都有一个此类型Pod运行。节点可能是所有集群节点,也可能是通过nodeSelector选定的一些特定节点。典型的后台支撑型服务包括:存储、日志和监控等。在每个节点上支撑K8s集群运行的服务。
守护进程在我们每个节点上,运行的是同一个Pod,新加入的节点里面也同样运行在同一个Pod
#ex:这里在每个node节点安装数据采集工具
apiVsersion: apps/v1
kind: DaemonSet
metadata:
name: ds-beat
labels:
app: filebeat
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
containers:
- name: logs
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: varlog
mountPath: /tmp/log
volumes:
- name: varlog
hostPath:
path: /var/log
这里使用volume将本地的/var/log目录挂载到了容器里的/tmp/log
kubectl exec -it ds-beat-cqdjg -- /bin/bash
通过着条命令,就可以看到内部收集的日志信息了
Job和CronJob
一次性任务和定时任务
- 一次性任务:一次执行完成就结束
- 定时任务:周期性执行
Job是K8s中用来控制批处理型任务的API任务。批处理业务与长期伺服业务的主要区别就是批处理业务的运行有头有尾,而长期伺服业务在用户不停止的情况下永远运行。Job管理的Pod根据用户的设置把任务成功完成就自动退出了。成功完成的标志根据不同的spec.completions策略而不同:单Pod型任务有一个Pod成功就标志完成;定数成功性任务保证有N个任务全部成功;工作队列性任务根据应用确定的全局成功而标志成功。
Job
Job也就是一次性任务
apiVersion: batch/v1
kind: Job
metadata:
name: job-test
spec:
template:
spec:
containers:
- name: job-test
image: centos
command: ["echo", "hello world!"]
restartPolicy: Never
backoffLimit: 4
通过下面的命令就可以看到已存在的job和完成任务的pod
kubectl get pod,job
通过查看日志,可以查看到一次性任务的结果
kubectl logs job-test-pgb4k
CronJob
定时任务
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: cron-test
spec:
schedule: '*/1 * * * *'
jobTemplate:
metadata:
name: cron-test
spec:
template:
spec:
containers:
- image: nginx
name: cron-test
args:
- /bin/bash
- -c
- date; echo Hello world
restartPolicy: OnFailure
通过上面的文件查看定时任务
kubectl apply -f cronjob.yaml
查看获取cronjob和pod信息
kubectl get pod,cronjob
通过日志查看
kubectl logs cron-test-1616153340-sh7ks
CronJob是每执行一次就多一个Pod。
RC和RS
RC
Replication Controller简称RC,用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来代替;如果异常多出来得容器也会自动回收。
即使在指定数目为1的情况下,通过RC运行Pod也比较直接运行Pod更加明智,因为RC可以发挥它高可用的能力,保证永远有一个Pod在运行。RC是K8s中较早的技术概念,只适用于长期伺服型的业务类型,比如控制Pod提供高可用的Web服务。
RS
ReplicationSet简称RS,也就是副本控制器,RS是新一代的RC,提供同样高可用的能力,区别主要在于RS后来居上,能够支撑更多类型的匹配模式。副本集对象一般不单独使用,而是作为Deployment的理想状态参数来使用。
终于output完了!!!