关键概念

为了管理有状态的服务而存在(有顺序号的Pod)

有状态服务

StatefulSet是有状态的集合,管理有状态的服务,它所管理的Pod的名称不能随意变化。数据持久化的目录也是不一样,每一个Pod都有自己独有的数据持久化存储目录。比如MySQL主从、redis集群等。

无状态服务

RC、Deployment、DaemonSet都是管理无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的。个体对整体无影响,所有pod都是共用一个数据卷的,部署的tomcat就是无状态的服务,tomcat被删除,在启动一个新的tomcat,加入到集群即可,跟tomcat的名字无关。

Headless Service

用来定义pod网路标识,生成可解析的DNS记录。

在用statefulset管理pod时要求pod名称必须是有序的 ,每一个pod不能被随意取代,pod重建后pod名称还是一样的。

因为pod IP是变化的,所以要用Pod名称来识别,pod名称是pod唯一性的标识符,必须持久稳定有效。这时候要用到无头服务,它可以给每个Pod一个唯一的名称。

Headless service不分配clusterIP,headless service可以通过解析service的DNS,返回所有Pod的dns和ip地址 (statefulSet部署的Pod才有DNS),普通的service,只能通过解析service的DNS返回service的ClusterIP。

# 1.headless service会为service分配一个域名
<service name>.$<namespace name>.svc.cluster.local

# 2.StatefulSet会为关联的Pod保持一个不变的Pod Name
Pod的名字格式为$(StatefulSet name)-$(pod序号)

# 3.StatefulSet会为关联的Pod分配一个dnsName
$<Pod Name>.$<service name>.$<namespace name>.svc.cluster.local
## 【扩展】全质量域名:FQDN
Fully Qualified Domain Name
即全限定域名:同时带有主机名和域名的名称
FQDN = Hostname + DomainName
如 主机名是 master
域名是 baidu.com
FQDN= master.baidu.com

## K8s中资源的全局FQDN格式:
Service_NAME.NameSpace_NAME.Domain.LTD.
Domain.LTD.=svc.cluster.local

VolumeClaimTemplate

有状态应用的持久化存储模板,有状态应用要求主从机器的持久化存储卷不能够是共享的(独立存储空间)。

statefulset定义中的每一个pod都不能使用同一个存储卷,这就需要使用volumeClainTemplate,当在使用statefulset创建pod时,volumeClainTemplate会自动生成一个PVC,从而请求绑定一个PV每一个pod都有自己专用的存储卷

资源清单解释

# kubectl explain statefulset.spec
podManagementPolicy	<string>       #pod管理策略
replicas	<integer>              #副本数
revisionHistoryLimit	<integer>  #保留的历史版本
selector	<Object> -required-    #标签选择器,选择它所关联的pod
serviceName	<string> -required-    #headless service的名字【VIP】
template	<Object> -required-    #生成pod的模板
updateStrategy	<Object>           #更新策略
volumeClaimTemplates	<[]Object> #存储卷申请模板【VIP】

# kubectl explain statefulset.spec.template
同deployment

示例

# 【1】创建存储类
vim statefulset-class.yaml
kubectl apply -f statefulset-class.yaml
kubectl get sc

# 【2】创建service和deploy
vim statefulset-test-myapp.yaml
kubectl apply -f statefulset-test-myapp.yaml

## 查看结果
# kubectl get statefulset
NAME   READY   AGE
web    0/2     105s

# kubectl get service
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes   ClusterIP   10.96.0.1        <none>        443/TCP          4d4h
nginx        ClusterIP   None             <none>        80/TCP           2m12s

# kubectl get pods -o wide
NAME                               READY   STATUS    RESTARTS   AGE   IP              NODE       NOMINATED NODE   READINESS GATES
web-0                              1/1     Running   0          12m   10.244.30.104   worker02   <none>           <none>
web-1                              1/1     Running   0          12m   10.244.30.105   worker02   <none>           <none>

# kubectl get pvc
NAME          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
www-web-0     Bound    pvc-2c9fe659-2b05-45ab-ae04-d438b0fc8579   50M        RWO            nfs-web        29s
# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                 STORAGECLASS   REASON   AGE
pvc-2c9fe659-2b05-45ab-ae04-d438b0fc8579   50M        RWO            Delete           Bound       default/www-web-0     nfs-web                 27s

#查看pod主机名
for i in 0 1; do kubectl exec web-$i -- sh -c 'hostname';done 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-web
provisioner: example.com/nfs
apiVersion: v1
kind: Service
metadata: 
  name: nginx
  labels:
     app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata: 
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 2
  template:
    metadata: 
     labels:
       app: nginx
    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"]
      storageClassName: "nfs-web"
      resources:
        requests: 
          storage: 1Gi
## 通过对pod主机名执行nslookup,可以检查它们在集群内部的DNS地址
kubectl exec -it web-1 -- /bin/bash
apt-get update
apt-get install dnsutils -y

## 解析Pod的IP (展示Pod的IP)
nslookup web-0.nginx.default.svc.cluster.local 

Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	web-0.nginx.default.svc.cluster.local
Address: 10.244.30.104

## 解析Service的IP(会把绑定的Pod的IP解析出来)
nslookup nginx.default.svc.cluster.local

Server:		10.96.0.10
Address:	10.96.0.10#53

Name:	nginx.default.svc.cluster.local
Address: 10.244.30.105
Name:	nginx.default.svc.cluster.local
Address: 10.244.30.104

## 查看详细信息
dig -t A nginx.default.svc.cluster.local @10.96.0.10

在这里插入图片描述

## 【扩展-1】dig的使用 
dig -t A nginx.default.svc.cluster.local @10.96.0.10
格式如下:  
@来指定域名服务器 
A 为解析类型 ,A记录
-t 指定要解析的类型 
A记录:  A记录是解析域名到IP
## 【扩展-2】service 和headless service区别
vim deploy-service.yaml 

kubectl get svc

NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
springboot   NodePort    10.111.145.211   <none>        8081:31180/TCP   3d5h

# 进入到web-1的pod
kubectl exec -it web-1 -- /bin/bash

# 解析的是service的ip地址
nslookup my-nginx.default.svc.cluster.local

Name:      springboot.default.svc.cluster.local
Address 1: 10.111.145.211 springboot.default.svc.cluster.local
apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  type: ClusterIP
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    run: my-nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  selector:
    matchLabels:
      run: my-nginx
  replicas: 2
  template:
    metadata:
      labels:
        run: my-nginx
    spec:
      containers:
      - name: my-nginx
        image: busybox
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        command:
          - sleep
          - "3600"

字段详述

apiVersion: v1   #定义api版本
kind: Service    #定义要创建的资源:service
metadata: 
  name: nginx    #定义service的名字
  labels:
     app: nginx  #service的标签
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None  #创建一个没有ip的service
  selector:
    app: nginx     #选择拥有app=nginx标签的pod
---
apiVersion: apps/v1
kind: StatefulSet
metadata: 
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"     #headless service的名字
  replicas: 2              #副本数
  template:                #定义pod的模板
    metadata: 
     labels:
       app: nginx
    spec: 
      containers:
      - name: nginx
        image: nginx
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:      #存储卷申请模板
  - metadata:
      name: www
    spec:
      accessModes: ["ReadWriteOnce"]
storageClassName: "nfs-web"  #指定从哪个存储类申请pv
      resources:
        requests: 
          storage: 1Gi       #需要1G的pvc,会自动跟符合条件的pv绑定

动态扩缩容、滚动更新

基本同deployment一致

### 修改replicas 和 image字段
## 方式一:编辑本地的yaml文件
vim <sts.yaml>
kubectl apply -f <sts.yaml>

## 方式二:直接编辑statefulset资源
kubectl edit sts <sts-name>

## 查看
kubectl get pods -o wide
kubectl describe pods web-0
Logo

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

更多推荐