StatefulSet

Deployment的不足,Deployment不足以覆盖所有的应用编排问题,因为在它看来,一个应用的所有Pod是完全一样的,所有它们之间就没有顺序,也无所谓运行在哪台宿主机上,需要时,Deployment就通过Pod模板创建新的Pod,不需要时就“杀掉”任意一个Pod。

但是在实际场景中,并不是所有应用都满足这样的要求,比如:主从关系,主备关系,还有就是数据存储类应用,多个实例通常会在本地磁盘上保存一份数据,而这些实例一旦被杀掉,即使重建出来,实例与数据之间的对应关系也已经丢失,从而导致应用失败。

这种实例之间有不对等关系,或者有依赖关系的应用,被称为“有状态应用(Stateful Application)”。为了能对“有状态应用”做出支持,Kubernetes在Deployment基础上,扩展出了StatefulSet。

StatefulSet能较好满足一些有状态应用特有的需求:

  • 每个Pod有order序号,会按序号创建、删除、更新Pod。

  • 通过配置headless service,使每个Pod有一个唯一的网络标识(hostname)。

  • 通过配置pvc template,每个Pod有一个独享的pv存储盘。

  • 支持一定数量的灰度发布。

StatefulSet设计

StatefulSet将真实世界里的应用状态,抽象为了两种情况:

拓扑状态:
这种情况是说,应用的多个实例之间不是完全对等的关系,这些应用实例必须按照某些顺序启动,比如某个应用的主节点A要先于B启动,那么当把A和B两个节点删除之后,重新创建出来时,也要是这个顺序才行,并且,新创建出来的A和B必须和原来的A和B的网络标识一样,这样原先的访问者才能使用同样的方法访问到这个新Pod。

存储状态:
这种情况是说,应用的多个实例分别绑定了不同的存储数据,对于这些应用实例来说,Pod A第一次读取到的数据和隔了十分钟之后再次读取到的数据应该是同一份,哪怕在此期间Pod A被重新创建过。

所以,StatefulSet的核心功能就是通过某种方式纪录这些状态,然后在Pod被重新创建时,能够为新Pod恢复这些状态。

Headless Service

Service是Kubernetes项目中用来将一组Pod暴露给外界访问的一种机制,比如,一个Deployment有3个Pod,那么就可以定义一个Service,然后用户只要能访问到这个Service,就能访问到某个具体的Pod。
但是,这个Service是怎么被访问到的呢?

第一种方式:
以Service的VIP(Virtual IP:虚拟IP)方式,比如:当访问192.168.0.1这个Service的IP地址时,它就是一个VIP,在实际中,它会把请求转发到Service代理的具体Pod上。

第二种方式:
就是以Service的DNS方式,在这里又分为两种处理方法:第一种是Normal Service,这种情况下,当访问DNS纪录时,解析到的是Service的VIP;第二种是Headless Service,这种情况下,访问DNS纪录时,解析到的就是某一个Pod的IP地址。

Headless Service不需要分配一个VIP,而是可以直接以DNS纪录的方式解析出被代理Pod的IP地址,这样设计可以使Kubernetes项目为Pod分配唯一“可解析身份”,而有了这个身份之后,只要知道了一个Pod的名字以及它对应的Service的名字,就可以非常确定地通过这些DNS纪录访问到Pod的IP地址。

创建Statefulset:

可以使每个pod有序号
通过headlessservice使每个pod有唯一的网络标识
通过pvctemplate每个pod有独立的pv存储
支持一定数量的灰度发布

创建pv:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv1
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /volume/pv1
    server: 192.168.19.163
   
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv2
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /volume/pv2
    server: 192.168.19.163
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv3
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  nfs:
    path: /volume/pv3
    server: 192.168.19.163

创建statefilset:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  labels:
    app: web
  name: web
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  serviceName: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: web
        image: nginx:alpine
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: aaaa
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: aaaa
    spec:
      accessModes: ["ReadWriteOnce"]
      resources:
        requests:
          storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  selector:
    app: nginx
  ports:
  - port: 80
    protocol: TCP
  clusterIP: None

查看:

[root@k8smaster]# kubectl   get    statefulsets.apps 
NAME   READY   AGE
web    3/3     1m27s

[root@k8smaster]# kubectl    get    pod   -o  wide
NAME    READY   STATUS    RESTARTS   AGE     IP            NODE       NOMINATED NODE   READINESS GATES
web-0   1/1     Running   0          2m16s    10.244.2.11   k8snode2   <none>           <none>
web-1   1/1     Running   0          1m58s   10.244.1.15   k8snode1   <none>           <none>
web-2   1/1     Running   0          1m12s   10.244.1.16   k8snode1   <none>           <none>

[root@k8smaster statefilset]# kubectl    get  pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                STORAGECLASS   REASON   AGE
pv1    1Gi        RWO            Retain           Bound       default/aaaa-web-1                           3m16s
pv2    1Gi        RWO            Retain           Bound       default/aaaa-web-0                           3m16s
pv3    1Gi        RWO            Retain           Bound       default/aaaa-web-2                           3m16s

对StatefulSet 所使用的镜像进行升级,然后再次查看状态:

[root@k8smaster# kubectl   set   image   statefulset   web  web=nginx:mainline

再次查看:

[root@k8smaster statefilset]# kubectl    get     statefulsets.apps   -o  wide
NAME   READY   AGE   CONTAINERS   IMAGES
web    3/3     11m   web          nginx:mainline
[root@k8smaster statefilset]# kubectl   get    pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                STORAGECLASS   REASON   AGE
pv1    1Gi        RWO            Retain           Bound       default/aaaa-web-1                           13m
pv2    1Gi        RWO            Retain           Bound       default/aaaa-web-0                           13m
pv3    1Gi        RWO            Retain           Bound       default/aaaa-web-2  

规律总结

匹配Pod name(网络标识)的模式为:(statefulset名称)-(序号),比如上面的示例:nginx-web-0,nginx-web-1,nginx-web-2。

  • StatefulSet为每个Pod副本创建了一个DNS域名,这个域名的格式为:$(podname).(headless server name)。
  • StatefulSet使用Headless服务来控制Pod的域名,这个域名的FQDN为:(servicename).(namespace).svc.cluster.local,其中,“cluster.local”指的是集群的域名。
  • 根据volumeClaimTemplates为每个Pod创建一个pvc,pvc匹配模式为:(volume_name)-(pod_name),比如上面的volumeMounts.name=www-storage,Pod name=nginx-web-[0-2],因此创建出来的PVC是www-storage-nginx-web-0、www-storage-nginx-web-1、www-storage-nginx-web-2。
  • 删除Pod不会删除其pvc,删除pvc将自动释放pv。

StatefulSet的启停顺序:

  • 有序部署:部署StatefulSet时,如果有多个Pod副本,它们会被顺序地创建(从0到N-1)。
  • 有序删除:当Pod被删除时,它们被终止的顺序是从N-1到0。
  • 有序扩展:当对Pod执行扩展操作时,与部署一样,它前面的Pod必须都处于Running和Ready状态。

StatefulSet Pod管理策略:

在v1.7以后,通过允许修改Pod排序策略,同时通过.spec.podManagementPolicy字段确保其身份的唯一性。

  • OrderedReady:上述的启停顺序,默认设置。
  • Parallel:告诉StatefulSet控制器并行启动或终止所有Pod,并且在启动或终止另一个Pod之前不等待前一个Pod变为Running and Ready或完全终止。

Ingress

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。
为了使外部的应用能够访问集群内的服务,在Kubernetes目前提供了以下几种方案:

  • NodePort
  • LoadBalancer
  • Ingress

Ingress组成

  • Ingress controller
    将新加入的Ingress转化成Nginx的配置文件并使之生效。

  • Ingress服务
    将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可。

Ingress工作原理

Ingress controller通过和Kubernetes api交互,动态的去感知集群中ingress规则变化,然后读取它,按照自定义的规则,就是写明了哪个域名对应哪个service,生成一段nginx配置,再写到nginx-ingress-controller的Pod里,这个Ingress controller的Pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,然后reload一下使配置生效,以此达到域名分配置和动态更新的问题。

所有节点下载 https://github.com/kubernetes/ingress-nginx

docker    load   -i    ingress28.tar

master 修改 yaml 文件:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx- ingress -controller
  namespace: ingress -nginx
  labels:
    app. kubernetes . io/name: ingress -nginx
    app . kubernetes . io/part-of: ingress -nginx
spec:
  replicas: 1
  selector:
    matchLabels :
      app . kubernetes . io/name: ingress -nginx
      app. kubernetes . io/part-of: ingress -nginx
  template:
    metadata:
      labels:
        app. kube rnetes . io/name: ingress -nginx
        app. kubernetes . io/part-of: ingress -nginx
      annotations :
        prometheus. io/port: "10254"
        prometheus . io/scrape: "true"
    spec :
      hostNetwork: true           ## 添加此行
      # wait upto five minutes for. the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx- ingress -serviceaccount
      nodeSelecto r:
        kubernetes.10/os: linux
      containers :
        - name: nginx- ingress -controller

master主机编写 yaml 文件:

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  labels:
    app: ingress-nginx
  namespace: ingress-nginx
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP
  - name: https
    port: 443
    targetPort: 443
    protocol: TCP
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐