你的位置:首页 > 信息动态 > 新闻中心
信息动态
联系我们

ubernetes Controller

2021/12/17 4:50:15

文章目录

  • 一、什么是Controller
  • 二、 Deployment控制器应用
      • Deploymet 部署应用
      • 使用yaml 文件创建Pod
    • 升级回滚
    • 弹性伸缩
  • 三、Service
    • Service存在的意义
      • 1. 防止Pod失联【服务发现】
      • 2. 定义Pod访问策略【负载均衡】
    • Pod和Service的关系
    • Service常用类型
  • 四、Statefulset
    • 无状态应用
    • 有状态应用
  • 五、DaemonSet
  • 六、 Job和CronJob

一、什么是Controller

Controller是在集群上管理和运行容器的对象,Controller是实际存在的,Pod是虚拟机的

Kubernetes 通常不会直接创建 Pod,而是通过 Controller 来管理 Pod 的。Controller 中定义了 Pod 的部署特性,比如有几个副本,在什么样的 Node 上运行等。为了满足不同的业务场景,Kubernetes 提供了多种 Controller,包括 Deployment、ReplicaSet、DaemonSet、StatefuleSet、Job 等。

Pod和Controller的关系

  • Pod是通过Controller实现应用的运维,比如弹性伸缩,滚动升级等
  • Pod 和 Controller之间是通过label标签来建立关系,同时Controller又被称为控制器工作负载
    在这里插入图片描述

二、 Deployment控制器应用

  • Deployment控制器可以部署无状态应用
  • 管理Pod和ReplicaSet
  • 部署,滚动升级等功能
  • 应用场景:web服务,微服务

Deployment表示用户对K8S集群的一次更新操作。Deployment是一个比RS( Replica Set, RS) 应用模型更广的 API 对象,可以是创建一个新的服务,更新一个新的服务,也可以是滚动升级一个服务。滚动升级一个服务,实际是创建一个新的RS,然后逐渐将新 RS 中副本数增加到理想状态,将旧RS中的副本数减少到0的复合操作。

这样一个复合操作用一个RS是不好描述的,所以用一个更通用的Deployment来描述。以K8S的发展方向,未来对所有长期伺服型的业务的管理,都会通过Deployment来管理。

Deploymet 部署应用

kubectl create deployment web --image=nginx

但是上述部署代码不是很好的进行复用,因为每次我们都需要重新输入代码,所以我们都是通过YAML进行配置
我们可以尝试使用上面的代码创建一个镜像【只是尝试,不会创建】

kubectl create deployment web --image=nginx --dry-run -o yaml > nginx.yaml

得到如下文件

[root@k8s-master ~]# cat 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
[root@k8s-master ~]# kubectl get pod
NAME                  READY   STATUS    RESTARTS   AGE
web-96d5df5c8-6mzxp   1/1     Running   0          38s

由于没有暴露端口,只能在集群内部进行访问,所以我们还需要对外暴露端口

kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1

–port:就是我们内部的端口号
–target-port:就是暴露外面访问的端口号
–name:名称
–type:类型

[root@k8s-master ~]# cat web1.yaml 
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: "2021-12-15T11:49:17Z"
  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-expose
    operation: Update
    time: "2021-12-15T11:49:17Z"
  name: web2
  namespace: default
  resourceVersion: "173489"
  uid: 92701e93-d90f-4d9c-be51-0fba0dd8f6ac
spec:
  clusterIP: 10.1.23.54
  clusterIPs:
  - 10.1.23.54
  externalTrafficPolicy: Cluster
  ports:
  - nodePort: 30394
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  sessionAffinity: None
  type: NodePort
status:
  loadBalancer: {}

让其暴露端口

kubectl expose deployment web --port=80 --type=NodePort --target-port=80 --name=web1 -o yaml > web1.yaml

kubectl apply -f web1.yaml
[root@k8s-master ~]# kubectl get pods,svc
NAME                      READY   STATUS    RESTARTS   AGE
pod/web-96d5df5c8-2cfz9   1/1     Running   0          2m43s

NAME                 TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.1.0.1      <none>        443/TCP        46h
service/web1         NodePort    10.1.20.137   <none>        80:32202/TCP   35s

升级回滚

升级: 服务从低版本升级到高版本,nginx:1.18—nginx-1.20 这就叫应用的升级【升级可以保证服务不中断】
回滚:版本从高版本到底版本,这就叫应用的回滚
弹性伸缩:我们根据不同的业务场景,来改变Pod的数量对外提供服务,这就是弹性伸缩

例如我们部署nginx:1.18 然后创建三个副本,把它升级到1.20

[root@k8s-master ~]# cat nginx.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  replicas: 3 # 创建三个副本
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: web
    spec:
      containers:
      - image: nginx:1.18 # 指定版本号
        name: nginx
        resources: {}
status: {}

在这里插入图片描述
升级

kubectl set image deployment web nginx=nginx:1.20

查看,可以看到有一四个副本,一个正在创建,说明是不停服务的升级,当一个副本满足条件后,会替换旧的,依次创建新的,替换旧的
 4

[root@k8s-master ~]# kubectl get pods
NAME                   READY   STATUS              RESTARTS   AGE
web-6695fcb7f9-jg9kk   0/1     ContainerCreating   0          15s
web-7989784f96-h9jmp   1/1     Running             0          26m
web-7989784f96-jqf2g   1/1     Running             0          27m
web-7989784f96-vxdgw   1/1     Running             0          26m

可以看到过程,升级过程始终保持四个,当升级结束后,又恢复到三个副本
在这里插入图片描述
查看docker镜像,可以看到新的1.20也被拉取下来
在这里插入图片描述

查看升级状态
kubectl rollout status deployment web

[root@k8s-master ~]# kubectl rollout status deployment web
deployment "web" successfully rolled out

查看历史版本
kubectl rollout history deployment web

[root@k8s-master ~]# kubectl rollout history deployment web
deployment.apps/web 
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3         <none>

应用回滚: 一般情况下只需要回滚到上一个状态即可
kubectl rollout undo deployment web
同时我们还可以回滚到指定版本

kubectl rollout undo deployment web --to-revision=2

弹性伸缩

弹性伸缩,也就是根据业务要求,通过命令一下创建多个副本

在这里插入图片描述

三、Service

Deployment 只是保证了支撑服务的微服务Pod的数量,但是没有解决如何访问这些服务的问题。一个Pod只是一个运行服务的实例,随时可能在一个节点上停止,在另一个节点以一个新的Pod,IP也是不固定的。因此不能以确定的IP和端口号提供服务。

要稳定地提供服务需要服务发现和负载均衡能力。服务发现完成的工作,是针对客户端访问的服务,找到对应的后端服务实例。在K8S集群中,客户端需要访问的服务就是Service对象。每个Service会对应一个集群内部有效的虚拟IP,集群内部通过虚拟IP访问一个服务。

在K8S集群中,微服务的负载均衡是由kube-proxy实现的。kube-proxy是k8s集群内部的负载均衡器。它是一个分布式代理服务器,在K8S的每个节点上都有一个;这一设计体现了它的伸缩性优势,需要访问服务的节点越多,提供负载均衡能力的kube-proxy就越多,高可用节点也随之增多。与之相比,我们平时在服务器端使用反向代理作负载均衡,还要进一步解决反向代理的高可用问题。

Service存在的意义

Service是Kubernetes最核心概念,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。

1. 防止Pod失联【服务发现】

因为Pod每次创建都对应一个IP地址,而这个IP地址是短暂的,每次随着Pod的更新都会变化,假设当我们的前端页面有多个Pod时候,同时后端也多个Pod,这个时候,他们之间的相互访问,就需要通过注册中心,拿到Pod的IP地址,然后去访问对应的Pod。Service就相当于注册中心,每个Pod创建,都先要到注册中心注册。

2. 定义Pod访问策略【负载均衡】

前端的Pod访问到后端的Pod,中间会通过Service一层,而Service在这里还能做负载均衡,负载均衡的策略有很多种实现策略,例如

  • 随机
  • 轮询
  • 响应比
    在这里插入图片描述

Pod和Service的关系

Pod 和 Service 之间还是根据 label 和 selector 建立关联的 【和Controller一样】

在这里插入图片描述
我们在访问service的时候,其实也是需要有一个ip地址,这个ip肯定不是pod的ip地址,而是 虚拟IP vip

Service常用类型

Service常用类型有三种

  • ClusterIp:集群内部访问
  • NodePort:对外访问应用使用
  • LoadBalancer:对外访问应用使用,公有云
root@k8s-master ~]# kubectl get pod
NAME                   READY   STATUS    RESTARTS   AGE
web-7989784f96-5bk4j   1/1     Running   0          80s
web-7989784f96-mv2dr   1/1     Running   0          80s

[root@k8s-master ~]# kubectl expose deployment web --port=80 --target-port=80 --dry-run -o yaml > service.yaml
W1216 20:58:15.375212   92002 helpers.go:553] --dry-run is deprecated and can be replaced with --dry-run=client.


# servic.yaml文件如下
[root@k8s-master ~]# cat service.yaml 
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
status:
  loadBalancer: {}

如果我们没有做设置的话,默认使用的是第一种方式 ClusterIp,也就是只能在集群内部使用,
我们可以先以它创建Pod测试

[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP   2d23h
web          ClusterIP   10.1.9.114   <none>        80/TCP    12s

[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.1.0.1     <none>        443/TCP   2d23h
web          ClusterIP   10.1.9.114   <none>        80/TCP    12s

测试集群内部访问,可以返回nginx页面

[root@k8s-node1 ~]# curl 10.1.9.114
<!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>

我们可以添加一个type字段,用来设置我们的service类型

[root@k8s-master ~]# cat service.yaml 
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: web
  name: web
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: web
  type: NodePort
status:
  loadBalancer: {}

[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
kubernetes   ClusterIP   10.1.0.1       <none>        443/TCP        2d23h
web          NodePort    10.1.216.155   <none>        80:31594/TCP   18s

然后我们就可以用10.1.216.155:31594 方式,在集群外部访问

四、Statefulset

Statefulset主要是用来部署有状态应用

对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续以它的状态提供服务。

无状态应用

我们原来使用 deployment,部署的都是无状态的应用,那什么是无状态应用?

  • 认为Pod都是一样的
  • 没有顺序要求
  • 不考虑应用在哪个node上运行
  • 能够进行随意伸缩和扩展

有状态应用

上述的因素都需要考虑到

  • 认为每个Pod独立的
  • Pod启动顺序
  • 唯一的网络标识符,持久存储

有序,比如mysql中的主从
适合StatefulSet的业务包括数据库服务MySQL 和 PostgreSQL,集群化管理服务Zookeeper、etcd等有状态服务

StatefulSet的另一种典型应用场景是作为一种比普通容器更稳定可靠的模拟虚拟机的机制。传统的虚拟机正是一种有状态的宠物,运维人员需要不断地维护它,容器刚开始流行时,我们用容器来模拟虚拟机使用,所有状态都保存在容器里,而这已被证明是非常不安全、不可靠的。

使用StatefulSet,Pod仍然可以通过漂移到不同节点提供高可用,而存储也可以通过外挂的存储来提供 高可靠性,StatefulSet做的只是将确定的Pod与确定的存储关联起来保证状态的连续性。

[root@k8s-master ~]# cat service1.yaml 
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None # 必须为无头service
  selector:
    app: nginx

apiVersion: apps/v1
kind: StatefulSet  # 声明有状态
metadata:
  name: nginx-statefulset
  namespace: default
spec:
  serviceName: nginx
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:latest
        name: nginx
        ports:
          - containerPort: 80

创建Pod

kubectl apply -f service1.yaml 

在这里插入图片描述
在这里插入图片描述特点:

  1. 每个pod都有唯一的名称
  2. 无头的service

这里有状态的约定,肯定不是简简单单通过名称来进行约定,而是更加复杂的操作,statefulset:根据主机名 + 按照一定规则生成域名

每个pod有唯一的主机名,并且有唯一的域名
格式:主机名称.service名称.名称空间.svc.cluster.local
举例:nginx-statefulset-0.default.svc.cluster.local

五、DaemonSet

DaemonSet 即后台支撑型服务,主要是用来部署守护进程

长期伺服型和批处理型的核心在业务应用,可能有些节点运行多个同类业务的Pod,有些节点上又没有这类的Pod运行;而后台支撑型服务的核心关注点在K8S集群中的节点(物理机或虚拟机),要保证每个节点上都有一个此类Pod运行。节点可能是所有集群节点,也可能是通过 nodeSelector选定的一些特定节点。典型的后台支撑型服务包括:存储、日志和监控等。在每个节点上支撑K8S集群运行的服务。

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。当有节点加入集群时,也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

[root@k8s-master ~]# cat service2.yaml 
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: ds-test
  namespace: default
  labels:
    app: filebeat

spec:
  selector:
    matchLabels:
      app: filebeat
  template:
    metadata:
      labels:
        app: filebeat
    spec:
      containers:
        - name: logs
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: varlog
              mountPath: /tmp/log
      
      volumes:
        - name: varlog
          hostPath:
            path: /var/log

运行

kubectl apply -f service3.yaml

在这里插入图片描述
在这里插入图片描述

六、 Job和CronJob

一次性任务 和 定时任务

一次性任务:一次性执行完就结束
定时任务:周期性执行
Job是K8S中用来控制批处理型任务的API对象。批处理业务与长期伺服业务的主要区别就是批处理业务的运行有头有尾,而长期伺服业务在用户不停止的情况下永远运行。Job管理的Pod根据用户的设置把任务成功完成就自动退出了。成功完成的标志根据不同的 spec.completions 策略而不同:单Pod型任务有一个Pod成功就标志完成;定数成功行任务保证有N个任务全部成功;工作队列性任务根据应用确定的全局成功而标志成功。