Fork me on GitHub

k8s存储数据卷

k8s存储

  • 在容器中的磁盘文件是短暂的,当容器挂掉时候,k8s会将它重启,而重启后容器文件会丢失,并且有的pod会有多容器进行文件交互。为了解决这个问题,k8s引入数据卷概念。
  • k8s中Volume提供在容器中挂在外部存储的能力。
  • Pod需要设置卷来源(spec.volume)和挂载点(spec.containers.volumeMounts)两个信息后才可以使用相应的Volume
  • 常用数据卷:
本地:hostPath, emptyDir
网络:NFS, Ceph, GlusterFS
公有云:AWS EBS
k8s资源: configmap, secret

1.存储数据卷

1.1emptyDir

  • 是一个临时存储卷。与pod生命周期绑定一起,如果pod删除卷也会被删除

  • 主要应用:pod中容器之间数据共享(比如一个容器负责写,一个容器负责读的场景)。

  • 示例:

    # 在pod 中启动2个容器一个读一个写
    apiVersion: v1
    kind: Pod
    metadata:
      name: volume1
    spec:
      containers:
      - name: write
        image: centos
        command: ["bash", "-c", "for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
        volumeMounts:
          - name: data
            mountPath: /data
      - name: read
        image: centos
        command: ["bash", "-c", "tail -f /data/hello"]
        volumeMounts:
          - name: data
            mountPath: /data
      volumes:
      - name: data
        emptyDir: {}
    # 如有启动异常可执行
    [root@k8s-master ~]# kubectl logs <pod name> -c <容器name>
    # 通过exec在容器执行shell命令,查看写的执行状态
    kubectl exec volume1 -c write -- tail /data/hello
    # 通过如下命令可以查看刚才部署的pod跑在哪个节点上
    kubectl get pods -o wide
    # 到相应节点过滤查看容器
    docker ps | grep volume1
    #刚才设置数据共享目录在宿主机
    /var/lib/kubelet/pods/<NAME 的ID>/volumes/kubernetes.io~empty-dir/data/hello 
    

1.2Hostpath

  • 挂载node文件系统(pod所在节点)上文件或者目录到pod中的容器。

  • 应用场景:pod中容器需要访问宿主机文件(比如应用程序读取宿主机的物理资源,日志)

  • 示例:

    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-hostpath
    spec:
      containers:
      - name: busybox
        image: busybox
        args:
        - /bin/sh
        - -c
        - sleep: 36000
        volumeMounts:
        - name: data
          mountPath: /data# 挂载容器中/data下
      volumes:
      - name: data
        hostPath:
          path: /tmp# 挂载宿主机的/tmp下
          type: Directory
    
    # 进入容器往容器/data下新增文件
    kubectl exec -it pod-hostpath -- sh
    touch hahat.txt
    # 查看pod运行的节点
    kubectl get pods -o wide
    # 在node01节点上查看/tmp目录下,可以查看新创建的haha.txt
    

1.3NFS

  • 网络存储卷,NFS提供对NFS挂载支持,可以自动将NFS共享路径挂载到Pod中。

  • 准备一台服务器安装NFS,注意:每个Node上都要安装nfs-utils:需要让节点pod挂载共享目录,需要linux支持nfs内部协议的模块

    yum install -y nfs-utils
    
    vi /etc/exports
    	/ifs/kubernetes *(rw,no_root_squash)
    	# /ifs/kubernetes 指定暴漏目录
    	# * 表示暴漏的网段为所有,也可以设置
    	# rw,no_root_squash 表示权限
    # 创建文件夹
    	mkdir -p /ifs/kubernetes
    # 启动
    	
    	systemctl start nfs
    	systemctl enable nfs
    # 测试nfs是否能用,另一台机器
    mount -t nfs 172.16.215.141:/ifs/kubernetes /mnt
    cd /mnt
    
    
    mount -t nfs 172.16.215.141:/ifs/kubernetes /mnt
    cd /mnt
    touch 111.txt
    # 查看nfs服务器/ifs/kubernetes下是否存在111.txt
    
    # 卸载nfs命令: mount /mnt/
    

1.4 ConfigMap

  • 创建ConfigMap后,数据实际会存储在k8s中etcd,然后通过创建pod时引用该数据。

  • 应用场景:应用程序配置文件

  • pod使用configmap数据有两种方式:

    1.变量注入
    2.数据卷挂载
    
  • 示例:

    [root@k8s-master ~]# vi configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: configmap-demo
    data:# 定义键值方式变量
      a: "123"
      b: "456"
      # 定义多行变量
      redis.properties: | 
        port: 6379
        host: 192.168.31.10
    # 将configmap保存到k8中etcd中
    [root@k8s-master ~]# kubectl apply -f configmap
    
    [root@k8s-master ~]# kubectl get configmap
    NAME               DATA   AGE
    configmap-demo     3      7s
    
    
    # 定义一个pod
    
    apiVersion: v1
    kind: Pod
    metadata: 
      name: configmap-demo-map
    spec:
      containers:
        - name: demo
          image: nginx
          # 变量注入
          env:
            - name: ZZZ# 自定义变量
              value: "zzz"
            - name: ABCD# 变量名字
              valueFrom:
                configMapKeyRef:
                  name: configmap-demo# 来自于configmap
                  key: a
            - name: CDEF
              valueFrom: 
                configMapKeyRef:
                  name: configmap-demo
                  key: b
          # 数据卷挂载
          volumeMounts:
          - name: config
            mountPath: "/config"# 存放容器中/config目录下
            readOnly: true
      volumes:
        - name: config
          configMap:
            name: configmap-demo
            items:
            - key: "redis.properties"# key与对应configmap.yaml对应
              path: "redis.properties"# 保存在容器中路径
    # 执行pod
    [root@k8s-master ~]# kubectl apply -f pod-configmap.yaml
    # 进入容器
    [root@k8s-master ~]# kubectl exec -it configmap-demo-map -- bash
    
    # 验证数据卷挂载
    root@configmap-demo-map:/# cat config/redis.properties
    port: 6379
    host: 192.168.31.10
    
    # 验证变量注入
    root@configmap-demo-map:/# echo $CDEF
    456
    

1.5 Secret

  • 与ConfigMap类似,区别于Secret主要存储敏感数据,所有数据要经过base64编码。
  • 应用场景:凭据
  • kubectl create secret 支持三种数据类型
docker-registry: 存储镜像仓库认证信息
generic:从文件,目录或者字符串创建,例如存储用户名,密码
tls:存储证书,例如HTTPS证书
  • 示例
[root@k8s-master ~]# echo -n 'admin' | base64
[root@k8s-master ~]# echo -n '1f2d1e2e67df' | base64
[root@k8s-master ~]# vi secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: db-user-pass
type: Opaque
data:
  username: YWRtaW4=
  password: MWYyZDFlMmU2N2Rm

# 应用
[root@k8s-master ~]# kubectl apply -f secret.yaml 
# 查看secret
[root@k8s-master ~]# kubectl get secret
NAME                                 TYPE                                  DATA   AGE
db-user-pass                         Opaque                                2      12s
# 创建一个pod
[root@k8s-master ~]# vi pod-secret.yaml
apiVersion: v1
kind: Pod
metadata:
  name: secret-demo-pod
spec:
  containers:
    - name: demo
      image: nginx
      # 变量注入
      env:
        - name: USER
          valueFrom:
            secretKeyRef:
              name: db-user-pass
              key: username
        - name: PASS
          valueFrom:
            secretKeyRef:
              name: db-user-pass
              key: password
      # 数据卷方式
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
    - name: config
      secret:
        secretName: db-user-pass
        items:
        - key: username
          path: my-username
# 应用:
[root@k8s-master ~]# kubectl apply -f pod-secret.yaml 
# 进入pod中
[root@k8s-master ~]# kubectl exec -it secret-demo-pod -- bash
# 变量注入方式验证
root@secret-demo-pod:/# echo $USER
admin
root@secret-demo-pod:/# echo $PASS
1f2d1e2e67df
# 数据卷方式验证
root@secret-demo-pod:/# cat /config/my-username
admin

2.pv和pvc管理存储

  • PersistentVolume(PV):对存储资源创建和使用的抽象,使得存储作为集群中的资源管理。

  • PersistentVolumeClaim(PVC): 让用户不需要关系具体的Volume实现细节。

  • 示例

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: deply-pvc
  name: deploy-pvc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: deploy-pvc
  strategy: {}
  template:
    metadata:
      labels:
        app: deploy-pvc
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
      volumes:
      - name: data
        persistentVolumeClaim:# 卷资源pvc
          claimName: my-pvc# 申请空间pvc名字
---
# pvc分配的存储资源
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
# 此时创建pod处于Pending状态 查看pod详情
kubectl describe pod deploy-pvc-6994b7ff4b-k8wgb
# Events报错:
Warning  FailedScheduling  7m27s  default-scheduler  0/2 nodes are available: 2 pod has unbound immediate PersistentVolumeClaims.
# 表示PVC没有绑定PV,需要创建一个PV
# 创建的PV,指定存储的资源
vi pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv00001
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ifs/kubernetes
    server: 172.16.215.141
# 应用:挂载存储
kubectl apply -f pv.yaml
# 此时刚才创建的pvc开始创建,运行。如何查看pv与pvc绑定
kubectl get pv,pvc

NAME                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
persistentvolume/pv00001   1Gi        RWX            Retain           Bound    default/my-pvc                           96s

NAME                           STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/my-pvc   Bound    pv00001   1Gi        RWX                           15m

# 可以看到pv与pvc已经进行绑定
  • 当创建多个pv为保证多个pv之间数据隔离,会在nfs上创建多个目录
/ifs/
└── kubernetes
    ├── pv00001
    ├── pv00002
    └── pv00003
  • 此时pv.yaml应该如下定义多个yaml块
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv00001
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ifs/kubernetes/pv00001
    server: 172.16.215.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv00002
spec:
  capacity:
    storage: 2Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ifs/kubernetes/pv00002
    server: 172.16.215.141
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv00003
spec:
  capacity:
    storage: 3Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /ifs/kubernetes/pv00003
    server: 172.16.215.141
  • 当又创建一个应用。
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: deply-pvc
  name: deploy-pvc2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: deploy-pvc
  strategy: {}
  template:
    metadata:
      labels:
        app: deploy-pvc
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: my-pvc2
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc2
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1.5Gi
  • 此时通过kubectl get pvc
[root@k8s-master ~]# kubectl get pvc
NAME      STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
my-pvc    Bound    pv00001   1Gi        RWX                           32m
my-pvc2   Bound    pv00002   2Gi        RWX                           2m12s
# 可以看到创建第一个和第二个应用分别绑定了pv00001和pv00002
  • PV生命周期
accessModes:访问模式
	AccessModes是用来对PV进行访问模式的设置,用于描述用户应用对存储资源访问权限,访问权限包括下面几种。
		ReadWriteOnce(RWO): 读写权限,但是只能被单个节点挂载
		ReadOnlyMany(ROX): 只读权限,可以被多个节点挂载
		ReadWriteMany(RWX): 读写权限,可以被多个节点挂载
RECLAIM POLICY(回收策略)
	通过 kubectl get pv 命令,查看RECLAIM POLICY列,目前有3种策略
		Retain(保留):保留数据,需要管理员手工清理数据
		Recycle(回收):清除PV中的数据,效果相当于rm -rf
		Delete(删除): 与PV相连后端存储同时删除
STATUS 状态
	表示一个PV生命周期状态。
		Available(可用): 表示可用状态,还未被任何PVC绑定
		Bound(已绑定): 表示PV已经被PVC绑定
		Released(已释放): PVC被删除,但是资源还未被集群重新声明
		Failed(失败): 表示该PV的自动回收失败
  • PV与PVC常见问题
1.PV与PVC之间关系?
	一个PV对应一个PVC
2.PV与PVC怎么匹配?
	根据存储空间,访问模式进行匹配
3.容器匹配策略是什么样的?
	匹配最接近的PV容量,如果满足不了Pod会处于pending状态
4. 存储空间(1Gi,2Gi,...)字段限制使用容量?
	这个字段主要用于做匹配,实际的使用限制取决于后端存储。
  • 现在我们在使用PV为静态供给,需要k8s工程师创建一大堆PV供开发者使用。PV静态供给维护成本过高,通过StorageClass动态进行PV供给可减少维护成本。

3.PV动态供给(StorageClass)

  • 基于NFS实现PV动态供给流程图

  • NFS外部资源调配

  • GitHub复制文件class.yaml,deployment.yaml,rbac.yamlyaml文件下载地址

    • class.yaml 用于存储类
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: managed-nfs-storage
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
    parameters:
      archiveOnDelete: "false"
    
    • deployment.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nfs-client-provisioner
      labels:
        app: nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: default
    spec:
      replicas: 1
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app: nfs-client-provisioner
      template:
        metadata:
          labels:
            app: nfs-client-provisioner
        spec:
          serviceAccountName: nfs-client-provisioner
          containers:
            - name: nfs-client-provisioner
              image: lizhenliang/nfs-subdir-external-provisioner:v4.0.1
              volumeMounts:
                - name: nfs-client-root
                  mountPath: /persistentvolumes
              env:
                - name: PROVISIONER_NAME
                  value: k8s-sigs.io/nfs-subdir-external-provisioner
                - name: NFS_SERVER
                  value: 172.16.215.141# NFS服务器IP
                - name: NFS_PATH
                  value: /ifs/kubernetes# 共享目录
          volumes:
            - name: nfs-client-root
              nfs:
                server: 172.16.215.141# NFS服务器IP
                path: /ifs/kubernetes# 挂载容器的目录
    
    • rbac.yaml为了连接k8s的api进行授权
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: default
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: nfs-client-provisioner-runner
    rules:
      - apiGroups: [""]
        resources: ["nodes"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["persistentvolumes"]
        verbs: ["get", "list", "watch", "create", "delete"]
      - apiGroups: [""]
        resources: ["persistentvolumeclaims"]
        verbs: ["get", "list", "watch", "update"]
      - apiGroups: ["storage.k8s.io"]
        resources: ["storageclasses"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["events"]
        verbs: ["create", "update", "patch"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: run-nfs-client-provisioner
    subjects:
      - kind: ServiceAccount
        name: nfs-client-provisioner
        # replace with namespace where provisioner is deployed
        namespace: default
    roleRef:
      kind: ClusterRole
      name: nfs-client-provisioner-runner
      apiGroup: rbac.authorization.k8s.io
    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: default
    rules:
      - apiGroups: [""]
        resources: ["endpoints"]
        verbs: ["get", "list", "watch", "create", "update", "patch"]
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: default
    subjects:
      - kind: ServiceAccount
        name: nfs-client-provisioner
        # replace with namespace where provisioner is deployed
        namespace: default
    roleRef:
      kind: Role
      name: leader-locking-nfs-client-provisioner
      apiGroup: rbac.authorization.k8s.io
    
  • 目录结构

    nfs-external-rpovisioner/
    ├── class.yaml
    ├── deployment.yaml
    └── rbac.yaml
    
  • 应用

    kubectl apply -f .
    
  • 查看存储类

    [root@k8s-master nfs-external-rpovisioner]# kubectl get sc
    NAME                  PROVISIONER                                   RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
    managed-nfs-storage   k8s-sigs.io/nfs-subdir-external-provisioner   Delete          Immediate           false                  10s
    
  • 查看pod

    [root@k8s-master nfs-external-rpovisioner]# kubectl get pods
    NAME                                      READY   STATUS              RESTARTS   AGE
    nfs-client-provisioner-6f5bf84fc9-srrf8   0/1     Running   0          50s
    
  • 创建一个deployment看是否能动态供给

    # storageClassName 设置存储类名字,通过 kubectl get sc 获取存储类的名字。
    vi deploy-storageclass.yaml 
    
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        app: deply-pvc
      name: deploy-storageclass
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: deploy-pvc
      strategy: {}
      template:
        metadata:
          labels:
            app: deploy-pvc
        spec:
          containers:
          - image: nginx
            name: nginx
            resources: {}
            volumeMounts:
            - name: data
              mountPath: /usr/share/nginx/html
          volumes:
          - name: data
            persistentVolumeClaim:
              claimName: my-sc
    ---
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: my-sc
    spec:
      storageClassName: "managed-nfs-storage"
      accessModes:
        - ReadWriteMany
      resources:
        requests:
          storage: 1.5Gi
    
  • 创建pod

    [root@k8s-master ~]# kubectl apply -f deploy-storageclass.yaml 
    
    
  • 在NFS服务器172.16.215.141可以看到/ifs/kubernetes目录下有default-my-sc-pvc-d94fb9a6-d6ed-4511-9077-18487bfd1985可以知道自动创建一个目录,这个目录就是PV动态供给创建目录

  • 我们进入一个容器内

    kubectl exec -it deploy-storageclass-7584589f8c-ltqg4 bash
    
    cd /usr/share/nginx/html/
    # 创建一个文件
    touch 1.txt
    # 此时查看NFS服务器上的default-my-sc-pvc-d94fb9a6-d6ed-4511-9077-18487bfd1985目录下也多了一个文件1.txt
    
  • 动态供给分配的存储资源,是看你pod要求分配的是多少存储资源。

  • 需要知道是动态存储的类不是一对一关系,可以重复使用,它就好像提供一个接口一样,重复调用。

4.有状态应用部署:StatefulSet控制器

  • Deployment控制器设计原则:管理所有pod一模一样,提供同一个服务,不需要考虑多副本之间的关系是否有独立存储,也不考虑在哪台Node运行,可随意扩容和缩容,这种应用称为‘无状态’,例如web服务。

  • 在实际场景中,这并不能满足所有应用,尤其是分布式应用,会部署多个实例,这些实例之间往往有依赖关系,例如:主从关系,主备关系,这种应用称为‘有状态’,例如MySQL主从,Etcd集群。

  • StatefulSet

    • 用于部署有状态应用

    • 解决pod独立生命周期,保持pod启动顺序和唯一性。

      1.稳定,唯一网络标识符,持久存储
      2.有序, 优雅的部署和扩展,删除和终止。
      3.有序,滚动更新
      
    • 应用场景:分布式应用,数据库集群

  • 稳定的网络ID

    • 使用Headless Service (相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份。并且添加ServiceName字段指定StatefulSet控制器要使用这个Headless Service。DNS解析名称:. , .svc.cluster.local
  • 稳定的存储

    • StatefulSet存储卷使用VolumeClaimTemplate创建,称为卷申请模版,当StatefulSet使用VolumeClaimTemplate创建一个PV(PersistentVolume)时,同样也会为每个pod分配并创建一个编号的PVC
  • 如部署一个MySQL主从:

    • 主从实例启动顺序
    • 主从实例数据目录唯一
    • 从连接主实例需要指定IP或主机名
  • 这里拿nginx做实例,部署statefulSet

# 新增一个statefulSet的基本模版yaml文件
[root@k8s-master ~]# kubectl create deployment sts --image=nginx --dry-run=client -o yaml > sts.yaml

# 暴漏一个service
[root@k8s-master ~]# kubectl expose deployment deploy-pvc --port=80 --target-port=80 --dry-run=client -o yaml > svc.yaml

# 编写demployment的service为StatefulSet






# vi sts.yaml
apiVersion: apps/v1
kind: StatefulSet#设置StatefulSet控制器
metadata:
  labels:
    app: sts
  name: sts
spec:
  serviceName: "sts"# 指定serviceName,用户指定Headless Service
  replicas: 2
  selector:
    matchLabels:
      app: sts
  template:
    metadata:
      labels:
        app: sts
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: {}
        volumeMounts:# 定义挂载目录
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:# volumeClaimTemplates 为每个pod分配独立pv。只支持StatefulSet
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]#单pod读写模式,一个pvc只能被一个pod独享,
      storageClassName: "managed-nfs-storage"# 存储类,为上面提前设置好的。
      resources:
        requests:
          storage: 1Gi
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: sts
  name: sts
spec:
  clusterIP: None# Headless Service是将clusterIP置为None,因为是一个有状态的service。
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: sts


# 应用
kubectl apply -f sts.yaml

# kubectl get pods 可以看到,pod进行有序的启动(部署)
sts-0                                    1/1     Running   0          10m
sts-1                                    1/1     Running   0          9m53s

# 为每个pod分配稳定身份
[root@k8s-master ~]# kubectl get ep
NAME                                          ENDPOINTS                                                        AGE
sts                                           10.244.85.204:80,10.244.85.205:80                                25m


[root@k8s-master ~]# kubectl get svc
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)        AGE
sts          ClusterIP   None           <none>        80/TCP         27m



# 创建一个沙箱
[root@k8s-master ~]# kubectl run -it --rm --image=busybox:1.28.4 -- sh
# deploy-nfs 通过 CLUSTER-IP 进行解析
/ # nslookup deploy-nfs
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
# 而sts并没有 CLUSTER-IP 通过pod IP进行解析
/ # nslookup sts
Server:    10.96.0.10
Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local

Name:      sts
Address 1: 10.244.85.205 sts-0.sts.default.svc.cluster.local
Address 2: 10.244.85.204 sts-1.sts.default.svc.cluster.local
  • 当我们对sts.yaml进行升级时候比如nginx版本升级更高版本
# 重新apply
kubectl apply -f sts.yaml
# 升级的顺序是从后向前升级,也就是先sts-1再sts-0
  • StatefulSet和Deployment区别
主要是身份区别:
	域名
	主机名
	存储(PVC)
  • 总结
1如果是不需额外数据依赖或者状态维护的部署,或者replicas是1,优先考虑使用Deployment;
2如果单纯的要做数据持久化,防止pod宕掉重启数据丢失,那么使用pv/pvc就可以了;
3如果要打通app之间的通信,而又不需要对外暴露,使用headlessService即可;
4如果需要使用service的负载均衡,不要使用StatefulSet,尽量使用clusterIP类型,用serviceName做转发;
5如果是有多replicas,且需要挂载多个pv且每个pv的数据是不同的,因为pod和pv之间是 一 一对应的,如果某个pod挂6掉再重启,还需要连接之前的pv,不能连到别的pv上,考虑使用StatefulSet
6能不用StatefulSet,就不要用
posted @ 2021-06-04 23:19  是阿凯啊  阅读(626)  评论(0编辑  收藏  举报