DaemonSet 的使用

通过该控制器的名称我们可以看出它的用法:Daemon,就是用来部署守护进程的,DaemonSet用于在每个kubernetes节点中将守护进程的副本作为后台进程运行,说白了就是在每个节点部署一个Pod副本。当节点加入到kubernetes集群中,Pod会被调度到该节点上运行,当节点从集群只能够被移除后,该节点这个Pod也会被移除,当然,如果我们删除DaemonSet所有和这个对象相关的Pods都会被删除。

在哪种情况下我们会需要用到这种业务场景呢? 其实这种场景还是比较普通的,比如:

  • 集群存储守护程序,如glusterdceph要部署在每个节点上以提供持久性存储。
  • 节点监视守护进程,如Prometheus监控集群,可以在每个节点上运行一个node-exporter进程来收集监控节点的信息;
  • 日志收集守护程序,如filebeat,logstash在每个节点上运行以收集容器的日志

这里需要特别说明的一个就是关于DaemonSet运行的Pod的调度问题,正常i情况下,Pod运行在哪个节点上是有Kubernetes的调度器策略来决定的,然而,由DaemonSet控制器创建的pod实际上提前已经确定了在哪个节点上了(Pod创建时指定了.spec.nodeName),所以:

  • DaemonSet并不关心一个节点的 unshedulable字段
  • DaemonSet可以创建Pod,即使调度器还没有启动,这点非常重要。

下面我们直接使用一个示例来演示下,在每个节点上部署一个Nginx Pod: nginx.yaml

kind: DaemonSet
apiVersion: apps/v1
metadata:
  name: nginx-ds
  labels:
    k8s-app: nginx
spec:
  selector:
    matchLabels:
      k8s-app: nginx
  template:
    metadata:
      labels:
        k8s-app : nginx
    spec:
      containers:
      - image: nginx:1.7.9
        name: nginx
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443

然后我们可以观察下Pod是否被分布到了每个节点上:

[root@master01 nginx]# kubectl get pods -o wide

StatefulSet 的使用

在学习StatefulSet这种控制器之前,我们就得先弄明白一个概念:什么是有状态服务?什么是无状态服务?

  • 无状态服务(Stateless Service) : 该服务运行的实例不会在本地存储需要持久化的数据,并且多个实例对于同一个请求响应的结果是完全一致的,比如前面我们讲解的Wordpress实例,我们是不是可以同时启动多个实例,但是我们访问任意一个实例得到的结果都是一样的吧? 因为它唯一需要持久化的数据是存储在MySQL数据库中的,所以我们可以说Wordpress这个应用是无状态服务,但是MySQL数据库就不是了,因为他需要把数据持久化到本地。
  • 有状态服务(Stateful Service):就和上面的概念是对立的了,该服务运行的实例需要在本地存储持久化数据,比如上面的MySQL数据库,你现在运行在节点A,那么他的数据就存储在节点A上面的,如果这个时候你把服务迁移到节点B 去的话,那么就没有之前的数据了,因为他需要去对应的数据目录里恢复数据,而此时没有任何数据。

    现在对有状态和无状态有一定的认识了把,比如我们常见的WEB应用,是通过session来保持用户的登录状态的,如果我们将session持久化到节点上,那么该应用就是一个有状态的服务了,因为我现在登录进来你把我的session持久化到节点A上了,下次我登录的时候可能就会将请求路由到节点B上去了,但是节点B上根本就没有我当前的session数据,我们会把这类WEB应用改成无状态的服务,怎么改?

    session数据存入一个公共的地方,比如redis里面,是不是就可以了,对于一些客户端请求API的情况 ,我们就不使用session来保持用户状态,改成用token也是可以的。

无状态服务利用我们前面的Deployment或者RC都可以很好的控制,对应有状态服务,需要考虑的细节就要多很多了,容器化应用程序最困难的任务之一,就是设计有状态分布式组件的部署体系结构。由于无状态组件可能没有预定义的启动顺序、集群要求、点对点TCP连接、唯一的网络标识符、正常的启动和终止要求等,因此可以很容易的进行容器化。诸如数据库,大数据分析系统,分布式key/value存储和message brokers 可能有复杂的分布式体系结构,都可能会用到上述功能。为此kubernetes引入了StatefulSet资源来支持这种复杂的需求。

StatefulSet类似于ReplicaSet,但是它可以处理Pod的启动顺序,为保留每个Pod的状态设置唯一标识,同时具有以下功能:

  • 稳定的、唯一的网络标识符
  • 稳定的、持久化的存储
  • 有序的、优雅的部署和缩放
  • 有序的、优雅的删除和终止
  • 有序的、自动滚动更新

创建StatefulSet

接下来我来演示下StatefulSet对象的使用方法,在开始之前,我们先准备两个1G的存储卷(pv),后面会发PV和pvc的使用方法,这里先不讲解。

pv001.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv001
  labels:
    release: stable
spec:
  capacity:
    storage: 1Gi
  accessModes:
  - ReadWriteOnce
  persistentVolumeReclaimPolicy: Recycle
  hostPath:
    path: /tmp/data

另外一个只需要把 name 改成 pv002即可,然后创建:

[root@master01 StatefulSet]# kubectl apply -f .
persistentvolume/pv001 created
persistentvolume/pv002 created

[root@master01 StatefulSet]# kubectl get pv
NAME    CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
pv001   1Gi        RWO            Recycle          Available                                   13s
pv002   1Gi        RWO            Recycle          Available                                   13s

可以看到成功创建了两个 PV对象,状态是:Available。

然后我们使用StatefulSet来创建一个 Nginx 的 Pod,对于这种类型的资源,我们一般是通过创建一个Headless Service类型的服务来暴露服务,将clusterIP设置为None就是一个无头的服务:(statefulset-demo.yaml)

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
    role: stateful

---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  selector:
    matchLabels:
      app: nginx
      role: stateful
  template:
    metadata:
      labels:
        app: nginx
        role: stateful
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1Gi

注意上面的 YAML 文件中和volumeMounts进行关联的是一个新的属性:volumeClaimTemplates,该属性会自动声明一个 pvc 对象和 pv 进行管理:

检查 Pod 的顺序索引

对于一个拥有 N 个副本的 StatefulSet,Pod 被部署时是按照 {0..N-1}的序号顺序创建的。在第一个终端中我们可以看到如下的一些信息:

[root@master01 nginx]# kubectl get pods -w 
NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          71s
web-1   1/1     Running   0          69s
请注意在 web-0 Pod 处于 Running 和 Ready 状态后 web-1 Pod 才会被启动。
[root@master01 nginx]# kubectl exec -it web-0 bash
root@web-1:/# echo "123" > /usr/share/nginx/html/index.html 
#node节点的数据 
[root@node01 data]# cat /tmp/data/index.html 
123
#看下删除服务之后还在吗
[root@master01 nginx]# kubectl delete -f statefulset-demo.yaml 
service "nginx" deleted
statefulset.apps "web" deleted

[root@node01 ~]# cat /tmp/data/index.html 
123

#千万不要去删除pvc 和pv 或者释放绑定其他的实例