Kubernetes-3

持久存储卷

K8S提供了三种基于存储的抽象对象,分别是PersistentVloume(PV),StorageClass,PersistentVloumeClaim(PVC),通过这三种类型来支持基础设施和应用之间的分离。

PV:持久存储卷,定义了K8S集群中的可用的存储资源,其中包含了存储资源的实现细节,比如包含NFS等资源的具体设置。

PVC:表示持久存储卷的申请,是通过用户发起对存储资源的请求。申请中只包含请求资源的大小和读写访问模式,不需要关心具体的资源实现细节,K8S会自动为其绑定符合条件的PV。

1.创建PV

[root@master ~]# vi testnfspv.yaml

apiVersion: v1              #创建的资源对象的版本

kind: PersistentVolume      #所要创建的资源对象,在这里是创建的PV

metadata:

  name: testnfspv

spec:                      #具体设置

  capacity:                #PV的容量

    storage: 1Gi           #指定占用的具体存储资源(NFS)的大小

  accessModes:             #定义PV对具体存储资源的访问模式。它下设的属性一共包含三种类型访问模式,分别为

ReadWriteOnce:这个卷可以被单个节点以读写模式挂载;ReadWriteMany:这个卷可以被多个节点以读写模式挂载;ReadOnlyMany:这个卷可以被多个节点以只读的模式挂载

    - ReadWriteMany

  persistentVolumeReclaimPolicy: Recycle    #删除PVC时对于PV资源的回收策略,它下设了三种类型的策略,分别

为:Retain(保留);Recycle(自动回收);Delete(自动删除)

  storageClassName: testnfs   #PV资源的描述性分类,在后续创建PVC时可以引用这个名称来绑定PV

  nfs:                        #表示PV使用NFS服务器作为具体的存储资源

    path: /data/k8snfs/

    server: 192.168.200.11

[root@master ~]# kubectl  apply -f testnfspv.yaml

persistentvolume/testnfspv created

[root@master ~]# kubectl  get pv

NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE

testnfspv   1Gi        RWX            Recycle          Available(资源空闲)           testnfs                 36s

[root@master ~]# kubectl  describe pv testnfspv

Name:            testnfspv

Labels:          <none>

Annotations:     <none>

Finalizers:      [kubernetes.io/pv-protection]

StorageClass:    testnfs

Status:          Available

Claim:          

Reclaim Policy:  Recycle

Access Modes:    RWX

VolumeMode:      Filesystem

Capacity:        1Gi

Node Affinity:   <none>

Message:        

Source:

    Type:      NFS (an NFS mount that lasts the lifetime of a pod)

    Server:    192.168.200.11

    Path:      /data/k8snfs/

    ReadOnly:  false

Events:        <none>

2.创建PVC

[root@master ~]# vi testnfspvc.yaml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: testnfspvc

spec:

  accessModes:

    - ReadWriteMany

  storageClassName: "testnfs"      #表示要引用的PV的资源名称

  resources:                      #定义PVC资源的参数

    requests:                     #设置具体的资源需求

      storage: 500Mi              #表示申请500MiB的资源

[root@master ~]# kubectl  apply -f testnfspvc.yaml

persistentvolumeclaim/testnfspvc created

[root@master ~]# kubectl  get pvc

NAME         STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE

testnfspvc   Bound    testnfspv   1Gi        RWX            testnfs        26s

//Bound代表已经绑定到了符合条件的PV上

[root@master ~]# kubectl  get pv

NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS   REASON   AGE

testnfspv   1Gi        RWX            Recycle          Bound    default/testnfspvc   testnfs                 12m

[root@master ~]# kubectl  describe pvc testnfspvc

Name:          testnfspvc

Namespace:     default

StorageClass:  testnfs

Status:        Bound

Volume:        testnfspv

Labels:        <none>

Annotations:   pv.kubernetes.io/bind-completed: yes

               pv.kubernetes.io/bound-by-controller: yes

Finalizers:    [kubernetes.io/pvc-protection]

Capacity:      1Gi

Access Modes:  RWX

VolumeMode:    Filesystem

Used By:       <none>

Events:        <none>

3.定义Pod并使用PVC引用的资源

[root@master ~]# cat testnfspvcdeployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: testnfspvcdeployment

spec:

  replicas: 2

  selector:

    matchLabels:

      example: testnfspvc

  template:

    metadata:

      labels:

        example: testnfspvc

    spec:

      containers:

      - name: testnfspvc

        image: busybox

        imagePullPolicy: IfNotPresent

        command: ['sh','-c']

        args: ['echo "The host is $(hostname)" >> /dir/dataforpvc; sleep 3600']

        volumeMounts:

        - name: pvcdata

          mountPath: /dir

      volumes:

      - name: pvcdata

        persistentVolumeClaim:

          claimName: testnfspvc

[root@master ~]# kubectl  apply -f testnfspvcdeployment.yaml

deployment.apps/testnfspvcdeployment created

//本案例中所创建存储卷名称为pvcdata,这个名称会被容器中设置的volumeMounts所引用。存储卷的类型时PVC,claimName属性表示引用的PVC名称,这里为 testnfspvc

[root@master ~]# kubectl  get deployment

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE

testnfspvcdeployment       2/2     2            2           21s

[root@master ~]# kubectl  get pod -o wide  |grep testnfspvcdeployment

testnfspvcdeployment-58756f77c5-gpg72      1/1     Running   0                74s     10.244.0.187   master    <none>           <none>

testnfspvcdeployment-58756f77c5-r5vsw      1/1     Running   0                74s     10.244.0.186   master    <none>           <none>

//在上面的案例中,我们观察到pod已经被分布在了master节点上,pvc所绑定的pv引用中nfs服务器的共享目录为 /data/k8snfs/,这时我们可以执行以下命令查看共享目录。

[root@master k8snfs]# cat  dataforpvc

The host is testnfspvcdeployment-58756f77c5-r5vsw

The host is testnfspvcdeployment-58756f77c5-gpg72

//从以上内容可知,目前在nfs服务器端已经同步了pod主机名信息,我们可以通过pod中的命令行执行情况来做一个对比,随机抽取一个pod进入后查看。

[root@master ~]# kubectl exec -it  testnfspvcdeployment-58756f77c5-gpg72 -- /bin/sh

/ # cat /dir/data

data        dataforpvc

/ # cat /dir/dataforpvc

The host is testnfspvcdeployment-58756f77c5-r5vsw

The host is testnfspvcdeployment-58756f77c5-gpg72

//从上面内容可见两条输出信息之技安时相同的,证明我们的pvc创建无误


PV的解绑与回收

在创建pvc时我们已经将资源绑定在了唯一的pv上,如果此时我们在创建一个pvc这时候会发生什么问题?

[root@master ~]# vi testnfspvc2.yaml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: testnfspvc2

spec:

  accessModes:

    - ReadWriteMany

  storageClassName: "testnfs"      #表示要引用的PV的资源名称

  resources:                      #定义PVC资源的参数

    requests:                     #设置具体的资源需求

      storage: 500Mi              #表示申请500MiB的资源

[root@master ~]# kubectl  apply -f testnfspvc2.yaml

persistentvolumeclaim/testnfspvc2 created

[root@master ~]# kubectl  get pvc

NAME          STATUS    VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE

testnfspvc    Bound     testnfspv   1Gi        RWX            testnfs        3d21h

testnfspvc2   Pending                                         testnfs        16s

//由上述结果可知,新创建的pvc2状态已经时pending,这表示了我们新创建的pvc一致处于挂起的状态,虽然我们之前定义的pv大小为1GiB,后面定义的两个pvc都之申请了500MiB的资源,但是对于PV和PVC来说只能一对一的绑定,不能一对多,所以新的pvc无法找到合适的资源,如果向使用只能在重新创建一个pv或者将之前的pvc解绑。

[root@master ~]# kubectl  delete -f testnfspvcdeployment.yaml    

deployment.apps "testnfspvcdeployment" deleted

[root@master ~]# kubectl  delete  pvc testnfspvc  --force

warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.

persistentvolumeclaim "testnfspvc" force deleted

//在执行删除时,尽可能先删除pod,然后删除pvc,最后删除pv,因为我们之前定义过回收策略,所以在删除时,自动回收资源,清理PVC在PV上写入的内容,此时查看宿主机下的文件,会发现已经被删除了。

[root@master ~]# ll /data/k8snfs/

total 0

//如果自动回收失败,则PVC的STATUS属性将变为Failed,,此时PV暂时无法使用。如果之前设置的PV的回收策略时Retain(保留),那么资源将不会被回收,宿主机的文件依然存在,但是PV的属性变为了Released,并且依然不能重新绑定到其他的PVC。


Storage Class(存储类)

针对于前面的PV和PVC的创建是静态的创建,我们需要指定规定的PV大小,而且PV的创建又是手动创建整个过程会很麻烦。

Kubernetes又提供了一种Storage Class的抽象,来动态的创建PV,Storage Class简化了PV的创建过程,当申请PVC资源的时候,如果匹配到满足条件的Storage Class,就会自动的为PVC创建对应大小的PV并进行绑定

Storage Class是通过存储分配器来动态分配PV,需要注意的是Kubernetes官方内置的存储分配器并不支持NFS,所以我们需要先安装NFS存储分配器。

1.安装NFS存储器

[root@master ~]# git clone https://github.com/kubernetes-incubator/external-storage.git

//利用这种方式需要先进入到external-storage目录下找到nfs-client/deploy目录,然后创建rbac.yaml文件

wget https://github.com/kubernetes-retired/external-storage/blob/master/nfs-client/deploy/rbac.yaml

[root@master deploy]# kubectl create -f  rbac.yaml

[root@master ~]# wget https://raw.githubusercontent.com/Kubernetes-incubator/external-storage/master/nfs-client/deploy/deployment.yaml

[root@master ~]# vi 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: quay.io/external_storage/nfs-client-provisioner:latest

          volumeMounts:

            - name: nfs-client-root

              mountPath: /persistentvolumes

          env:

            - name: PROVISIONER_NAME

              value: fuseim.pri/ifs

            - name: NFS_SERVER

              value: 192.168.200.11

            - name: NFS_PATH

              value: /data/k8snfs

      volumes:

        - name: nfs-client-root

          nfs:

            server: 192.168.200.11

            path: /data/k8snfs

//在env的属性当中PROVISIONER_NAME参数代表了存储器的名称,NFS_SERVER参数代表了之前配置的NFS服务端地址, NFS_PATH代表了NFS共享目录的地址,在volume的属性中,也需要将  server与path改为之前的NFS服务器的地址和共享目录。

[root@master ~]# kubectl  apply -f deployment.yaml

deployment.apps/nfs-client-provisioner created

[root@master ~]# kubectl  get deployment

NAME                       READY   UP-TO-DATE   AVAILABLE   AGE

nfs-client-provisioner     1/1     1            1           5m25s

[root@master ~]# kubectl  get pod |grep nfs

nfs-client-provisioner-849c76dd46-drh2d    1/1     Running   0                5m45s

//从以上结果可知我们的pod和控制器都是正常运行的状态,如果在集群中已经启用了RBAC,则必须要为NFS存储器去授权,可以按照以下步骤进行操作。

[root@master ~]# wget https://github.com/kubernetes-retired/external-storage/blob/master/nfs-client/deploy/class.yaml

[root@master deploy]# vi class.yaml

apiVersion: storage.k8s.io/v1         #API的版本,此处使用的是API的稳定版

kind: StorageClass                  #资源对象

metadata:                         #元数据

  name: managed-nfs-storage

provisioner: fuseim.pri/ifs           #存储器的名称,这边采用的是Deployment控制器中创建的- name: PROVISIONER_NAME参数中指定的

parameters:                        #资源对象的参数,如果archiveOnDelete为false时,与其关联的PVC在删除时,它所绑定的PV不会被存储分配器保留;如果为true则相反

  archiveOnDelete: "false"

[root@master deploy]# kubectl  apply -f class.yaml

storageclass.storage.k8s.io/managed-nfs-storage created

[root@master deploy]# kubectl  get storageclass

NAME                  PROVISIONER      RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE

managed-nfs-storage   fuseim.pri/ifs   Delete          Immediate           false                  26s

[root@master deploy]# kubectl  describe storageclass managed-nfs-storage

Name:            managed-nfs-storage

IsDefaultClass:  No

Annotations:     kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"managed-nfs-storage"},"parameters":{"archiveOnDelete":"false"},"provisioner":"fuseim.pri/ifs"}

Provisioner:           fuseim.pri/ifs

Parameters:            archiveOnDelete=false

AllowVolumeExpansion:  <unset>

MountOptions:          <none>

ReclaimPolicy:         Delete

VolumeBindingMode:     Immediate

Events:                <none>

2.创建PVC

在K8S集群中默认仅用了SelfLink项,所以我们首先要修改api-server的配置,按照下面的方法进行修改

[root@master ~]# cd /etc/kubernetes/manifests/

[root@master manifests]# vi kube-apiserver.yaml

apiVersion: v1

kind: Pod

metadata:

  annotations:

    kubeadm.kubernetes.io/kube-apiserver.advertise-address.endpoint: 192.168.200.11:6443

  creationTimestamp: null

  labels:

    component: kube-apiserver

    tier: control-plane

  name: kube-apiserver

  namespace: kube-system

spec:

  containers:

  - command:

    - kube-apiserver

    ......添加下面红色处

    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key

    - --feature-gates=TTLAfterFinished=true

    - --feature-gates=RemoveSelfLink=false

[root@master manifests]# kubectl  apply -f kube-apiserver.yaml

//等待api-pod运行正常,在创建pvc

[root@master ~]# vi teststoragepvc.yaml

apiVersion: v1

kind: PersistentVolumeClaim

metadata:

  name: teststorageclass

spec:

  accessModes:

    - ReadWriteMany

  storageClassName: "managed-nfs-storage"

  resources:                     

    requests:                    

      storage: 500Mi

[root@master ~]# kubectl  apply -f teststoragepvc.yaml

persistentvolumeclaim/teststorageclass created

[root@master ~]# kubectl  get pvc

NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE

teststorageclass   Bound    pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891   500Mi      RWX            managed-nfs-storage   6s

[root@master ~]# ^C

[root@master ~]# kubectl  get pv

NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                      STORAGECLASS          REASON   AGE

pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891   500Mi      RWX            Delete           Bound       default/teststorageclass   managed-nfs-storage            29s

[root@master ~]# kubectl  describe pv

Name:            pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891

Labels:          <none>

Annotations:     pv.kubernetes.io/provisioned-by: fuseim.pri/ifs

Finalizers:      [kubernetes.io/pv-protection]

StorageClass:    managed-nfs-storage

Status:          Bound

Claim:           default/teststorageclass

Reclaim Policy:  Delete

Access Modes:    RWX

VolumeMode:      Filesystem

Capacity:        500Mi

Node Affinity:   <none>

Message:        

Source:

    Type:      NFS (an NFS mount that lasts the lifetime of a pod)

    Server:    192.168.200.11

    Path:      /data/k8snfs/default-teststorageclass-pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891

    ReadOnly:  false

Events:        <none>

//从标红的位置我们可以看到动态的PV在NFS服务器的目录中创建了一个他的专属子目录

[root@master ~]# vi teststoragedeployment.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

  name: teststoragedeployment

spec:

  replicas: 2

  selector:

    matchLabels:

      example: teststoragedeployment

  template:

    metadata:

      labels:

        example: teststoragedeployment

    spec:

      containers:

      - name: teststoragedeployment

        image: busybox

        imagePullPolicy: IfNotPresent

        command: ['sh','-c']

        args: ['echo "The host is $(hostname)" >> /dir/dataforpvc; sleep 3600']

        volumeMounts:

        - name: pvcdata

          mountPath: /dir

      volumes:

      - name: pvcdata

        persistentVolumeClaim:

          claimName: teststorageclass

[root@master ~]# kubectl  apply -f teststoragedeployment.yaml

deployment.apps/teststoragedeployment created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS        AGE

teststoragedeployment-b7db57c78-65zzc      1/1     Running   0               15s

teststoragedeployment-b7db57c78-cqkhv      1/1     Running   0               15s

[root@master ~]# cat /data/k8snfs/d

data

default-teststorageclass-pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891/

[root@master ~]# cat /data/k8snfs/default-teststorageclass-pvc-f5ca4c79-b080-4f83-a800-653d0a7ab891/dataforpvc

The host is teststoragedeployment-b7db57c78-65zzc

The host is teststoragedeployment-b7db57c78-cqkhv

注意:在删除时也要遵循先删控制器/pod,然后删pvc,在这里我们删除完pvc后会直接将pv动态进行删除,以及PV的专属子目录在主机上也会删除


StatefulSet控制器

提供排序和唯一性保证的特殊Pod控制器,当有部署顺序、持久化数据以及固定网络等相关特殊需求时,可以使用该控制器进行细粒度的控制。

该控制器对于有状态服务(Deployment对应于无状态服务),其功能如下:

  1. 实现稳定的持久化存储:Pod重新调度之后还能访问相同的持久化数据,可基于PVC来实现
  2. 实现稳定的网络标识:Pod重新调度之后其PodName和HostName保持不变,基于无头Service(没有ClusterIPde Service实现)
  3. 实现有序部署、有序伸缩:Pod是有顺序的,在部署或者扩展的时候要依据定义的顺序依次执行(也就是说从第一个到最后一个一次部署,在下一个Pod运行之前所有的Pod都必须处于running或ready状态)
  4. 实现有序收缩、有序删除:从最后一个开始,一次删除至第一个
  5. 无头Service:用于为Pod资源标识符生成可以解析的DNS记录
  6. VolumeClaimTempalte:基于静态或动态的PV供给方式为Pod资源提供专属的固定存储
  7. StatefulSet:管理Pod资源

StatefulSet控制器下的Pod,虽然各个Pod定义是一样的,但是因为数据的不同,所提供的服务是有差异的,分布式存储系统就非常适合StatefulSet控制器,由PodA存储一部分数据并提供相关服务,由Pod B存储另外一部分的数据提供相关服务。在这些场景中每一个有状态的Pod提供的服务是不一样的,所以每一个Pod是不能被取代的,必须是有序的分配而且必须为其分配唯一的标识。Pod名称就是它们唯一的标识符,和Deployment控制器下的Pod不同,即使有状态的Pod发生故障并被重建,Pod名称也会和原来的一模一样。因为各个有状态的Pod也必须要拥有一个唯一的网络标识符一访问具体的某个Pod,,所以采用无头Service,它会给每一个Pod分配唯一的一个DNS名称。

有状态的Pod都会使用到持久存储,众所周知,有状态的Pod最大的特点是每一个Pod中的数据是不一样的,所以各个Pod没有办法使用同一个存储卷。因为每个Pod要拥有自己的专用存储卷,所以这个存储卷的定义并不是在Pod模板中定义的(如果实在Pod模板中定义,那么每个Pod都会用到同一个存储卷),StatefuSet控制器的存储卷配置,而是在StatefuSet控制器模板的VolumeClaimTemplate属性中定义存储卷的申请模板,为每一个Pod生成不同的PVC并且绑定各自的PV,从而使各个Pod拥有各自专用的存储卷。

因为每个Pod都会产生各自专用的PVC以及PV,所以StatefuSet控制器的存储最好通过StorageClass来进行动态创建。Sure,也可通过手动创建各个预设的PV,But会很麻烦。

1.创建控制器&&service

[root@master ~]# cat teststatefulset.yaml

apiVersion: v1

kind: Service

metadata:

  name: teststatefulsetservice

spec:

  selector:

    example: teststateful

  clusterIP: None

  ports:

    - protocol: TCP

      port: 8080

      targetPort: 80

  type: ClusterIP

---

apiVersion: apps/v1

kind: StatefulSet

metadata:

  name: teststatefulset

spec:

  replicas: 3

  serviceName: "teststatefulsetservice"

  selector:

    matchLabels:

      example: teststateful

  template:

    metadata:

      labels:

        example: teststateful

    spec:

      containers:

      - name: pythonservice

        image: python:3.7

        imagePullPolicy: IfNotPresent

        command: ['sh','-c']

        args: ['echo "The host is $(hostname)" >> /dir/data; echo "<p>The host is $(hostname)</p>" >index.html; python -m http.server 80']

        volumeMounts:

        - name: statefuldata

          mountPath: /dir

        ports:

        - name: http

          containerPort: 80

  volumeClaimTemplates:

    - metadata:

        name: statefuldata

      spec:

        accessModes: ["ReadWriteOnce"]

        storageClassName: "managed-nfs-storage"

        resources:

          requests:

            storage: 200Mi

//此模板分为三个部分的内容,先创建了一个无头Service,名称为“teststatefulsetservice”,它会通过标签选择器关联到各个标签为teststateful的pod上。

然后创建了一个statefulset的模板,定义了三个Pod副本,容器为“Python3.7”的镜像,目的是为了构建服务。在启动容器时会以追加的方式向/data/dir文件写入The host is $(hostname),获取当前Pod名称,/dir目录通过volumeMounts的属性映射到statefuldata的存储卷,在写入文本时会直接写入存储卷。

接下来,执行echo "<p>The host is $(hostname)</p>语句将代码插入到html文件,这样在访问时就知道访问的是哪个Pod,另外通过 python -m http.server 80构建一个简单的Web服务,并且声明服务的端口为80。

后半部分为存储卷的申请模板,内容基本和PVC类似,但需要注意我们这里批量定义了PVC,然后storageclass属性为上一节创建的,requests为storage:200Mi,表示为每一个Pod搜申请200Mi的存储空间。

[root@master ~]# kubectl apply   -f  teststatefulset.yaml

service/teststatefulsetservice unchanged

statefulset.apps/teststatefulset created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS       AGE

teststatefulset-0                          1/1     Running   0              8s

teststatefulset-1                          1/1     Running   0              6s

teststatefulset-2                          1/1     Running   0              5s

//从上述结果可知,在创建的过程中,并且在不同时段去查看pod创建状态,会发现Pod创建顺序是依次创建的,Pod名称和Deployment控制器不一样,名称末尾并没有随机生成字符串,二十按照数字从0依次叠加。

[root@master ~]# kubectl  get statefulset

NAME              READY   AGE

teststatefulset   3/3     6m7s

[root@master ~]# kubectl  describe statefulset teststatefulset

Name:               teststatefulset

Namespace:          default

CreationTimestamp:  Mon, 29 May 2023 23:00:15 -0400

Selector:           example=teststateful

Labels:             <none>

Annotations:        <none>

Replicas:           3 desired | 3 total

Update Strategy:    RollingUpdate

  Partition:        0

Pods Status:        3 Running / 0 Waiting / 0 Succeeded / 0 Failed

Pod Template:

  Labels:  example=teststateful

  Containers:

   pythonservice:

    Image:      python:3.7

    Port:       80/TCP

    Host Port:  0/TCP

    Command:

      sh

      -c

    Args:

      echo "The host is $(hostname)" >> /dir/data; echo "<p>The host is $(hostname)</p>" >index.html; python -m http.server 80

    Environment:  <none>

    Mounts:

      /dir from statefuldata (rw)

  Volumes:  <none>

Volume Claims:

  Name:          statefuldata

  StorageClass:  managed-nfs-storage

  Labels:        <none>

  Annotations:   <none>

  Capacity:      200Mi

  Access Modes:  [ReadWriteOnce]

Events:

  Type    Reason            Age    From                    Message

  ----    ------            ----   ----                    -------

  Normal  SuccessfulCreate  6m33s  statefulset-controller  create Pod teststatefulset-0 in StatefulSet teststatefulset successful

  Normal  SuccessfulCreate  6m31s  statefulset-controller  create Pod teststatefulset-1 in StatefulSet teststatefulset successful

  Normal  SuccessfulCreate  6m30s  statefulset-controller  create Pod teststatefulset-2 in StatefulSet teststatefulset successful

2.PV以及PVC的使用

[root@master ~]# kubectl  get pv,pvc

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                                    STORAGECLASS          REASON   AGE

persistentvolume/pvc-bbf264cc-be7d-4b53-9a7e-ee5c3bb19bb5   200Mi      RWO            Delete           Bound       default/statefuldata-teststatefulset-1   managed-nfs-storage            19m

persistentvolume/pvc-c94269db-3267-4fc3-8727-b8b51afed71a   200Mi      RWO            Delete           Bound       default/statefuldata-teststatefulset-2   managed-nfs-storage            19m

persistentvolume/pvc-fb168ccf-f6e8-43d0-9be7-873396518907   200Mi      RWO            Delete           Bound       default/statefuldata-teststatefulset-0   managed-nfs-storage            19m

persistentvolume/testnfspv                                  1Gi        RWX            Recycle          Available                                            testnfs                        4d18h

NAME                                                   STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE

persistentvolumeclaim/statefuldata-teststatefulset-0   Bound    pvc-fb168ccf-f6e8-43d0-9be7-873396518907   200Mi      RWO            managed-nfs-storage   19m

persistentvolumeclaim/statefuldata-teststatefulset-1   Bound    pvc-bbf264cc-be7d-4b53-9a7e-ee5c3bb19bb5   200Mi      RWO            managed-nfs-storage   19m

persistentvolumeclaim/statefuldata-teststatefulset-2   Bound    pvc-c94269db-3267-4fc3-8727-b8b51afed71a   200Mi      RWO            managed-nfs-storage   19m

//接下来随意挑选出一个PV,查询状态

[root@master ~]# kubectl  describe pv pvc-fb168ccf-f6e8-43d0-9be7-873396518907

Name:            pvc-fb168ccf-f6e8-43d0-9be7-873396518907

Labels:          <none>

Annotations:     pv.kubernetes.io/provisioned-by: fuseim.pri/ifs

Finalizers:      [kubernetes.io/pv-protection]

StorageClass:    managed-nfs-storage

Status:          Bound

Claim:           default/statefuldata-teststatefulset-0

Reclaim Policy:  Delete

Access Modes:    RWO

VolumeMode:      Filesystem

Capacity:        200Mi

Node Affinity:   <none>

Message:        

Source:

    Type:      NFS (an NFS mount that lasts the lifetime of a pod)

    Server:    192.168.200.11

    Path:      /data/k8snfs/default-statefuldata-teststatefulset-0-pvc-fb168ccf-f6e8-43d0-9be7-873396518907

    ReadOnly:  false

Events:        <none>

[root@master ~]# cat /data/k8snfs/default-statefuldata-teststatefulset-0-pvc-fb168ccf-f6e8-43d0-9be7-873396518907/data

The host is teststatefulset-0

The host is teststatefulset-0

3.无头Service的访问

[root@master ~]# kubectl  get svc

NAME                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE

teststatefulsetservice   ClusterIP      None          <none>          8080/TCP       156m

//由于这个Service无法通过集群内外的机器直接访问,因此只有Pod才可以访问,而且需要DNS的形式来进行访问,其具体的形式为{ServiceName}.{Namespace}.svc.{ClusterDomain}

[root@master ~]# vi testpodheadlessservice.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testpodheadlessservice

spec:

  containers:

  - name: testcontainer

    image: docker.io/appropriate/curl

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "The test pod for headless service!"; sleep 3600']

[root@master ~]# kubectl  apply -f testpodheadlessservice.yaml

pod/testpodheadlessservice created

[root@master ~]# kubectl  exec -it testpodheadlessservice -- /bin/sh

/ # nslookup  teststatefulsetservice.default.svc.cluster.local

nslookup: can't resolve '(null)': Name does not resolve

Name:      teststatefulsetservice.default.svc.cluster.local

Address 1: 10.244.1.108 teststatefulset-0.teststatefulsetservice.default.svc.cluster.local

Address 2: 10.244.1.110 teststatefulset-2.teststatefulsetservice.default.svc.cluster.local

Address 3: 10.244.1.109 teststatefulset-1.teststatefulsetservice.default.svc.cluster.local

//总共返回了三个地址,然后K8S又为每一个Pod地址创建了对应的专属域名,访问这些域名就可以访问指定的Pod,当然也可通过无头Service的总域名来访问服务

/ # curl  teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-0</p>

/ # curl  teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-0</p>

/ # curl  teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-1</p>

/ # curl  teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-2</p>

/ # curl  teststatefulsetservice.default.svc.cluster.local

//以上这种访问方式对于Deployment控制器是没有问题的,但是对于StatefulSet控制器是不行的,因为每个Pod提供的服务是不一样的,所以在调用时需要指定哪一个Pod提供服务。

在无头Service中,每一个Pod会生成一个专属的域名,其访问格式为{PodName}.{ServiceName}.{Namespace}.svc.{ClusterDomain},每个域名通过DNS查询都可以解析出Pod的IP地址,如下:

Name:      teststatefulset-0.teststatefulsetservice.default.svc.cluster.local

Address 1: 10.244.1.108 teststatefulset-0.teststatefulsetservice.default.svc.cluster.local

//要访问有不同有状态Pod提供的服务,只需要访问专属域名,如下:

/ # curl  teststatefulset-0.teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-0</p>

/ # curl  teststatefulset-1.teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-1</p>

/ # curl  teststatefulset-2.teststatefulsetservice.default.svc.cluster.local

<p>The host is teststatefulset-2</p>

4.pod重建

接下来模拟Pod重建的场景

[root@master ~]# kubectl  delete  pod teststatefulset-1

pod "teststatefulset-1" deleted

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS        RESTARTS       AGE

teststatefulset-0                          1/1     Running       0              178m

teststatefulset-1                          1/1     Terminating   0              178m

teststatefulset-2                          1/1     Running       0              178m

//因为在之前的副本数量中定义Pod为3,表示会保留三个稳定的副本,所以Pod会重建,下面的内容我们可以看到Pod重建之后的状态和名称是一模一样的,IP地址会有变化,但不会影响服务。

[root@master ~]# kubectl  get pod  -o wide

NAME                                       READY   STATUS    RESTARTS       AGE     IP             NODE      NOMINATED NODE   READINESS GATES

teststatefulset-0                          1/1     Running   0              3h2m    10.244.1.108   worker2   <none>           <none>

teststatefulset-1                          1/1     Running   0              3m11s   10.244.1.111   worker2   <none>           <none>

teststatefulset-2                          1/1     Running   0              3h2m    10.244.1.110   worker2   <none>           <none>

//执行下述命令输出Pod专属的存储卷中文件的内容,查看是否仍然调用同一个存储

[root@master ~]# cat /data/k8snfs/default-statefuldata-teststatefulset-1-pvc-bbf264cc-be7d-4b53-9a7e-ee5c3bb19bb5/data

The host is teststatefulset-1

The host is teststatefulset-1

The host is teststatefulset-1

//因为在之前的Pod定义这个Pod启动时会一追加的方式向文件中写入数据,所以Pod重建之后会在写一条数据。因为重建后的P;od使用的还是同一个PVChePV,所以仍然在同一个文件上进行编辑。查询出来会有三条文本内容,其中两条是第一次创建时写入的,另外一条时重建时写入的。

5.控制器的伸缩与更新

和Depolyment控制器一样,它也可以实现动态伸缩,我们只需要更改配置中的replicas属性然后执行应用即可。但是与Depolyment控制器不一样的地方在于Pod更新也是有序的,跟创建一样。在扩容时,后续新增的Pod会从前往后依次创建,创建完成后才开始进行下一个Pod创建,在缩容的时候,在缩容时会先从编号大的Pod开始从后往前依次删除,完全删除完成后才开始进行下一个Pod的删除。

该控制器也有两种更新策略,可以模板中通过spec.updateStrategy属性进行设置。

第一种是OnDelete更新策略,这是默认向后兼容的更新策略,使用这种更新策略更新StatefulSet模板后,只有在手动删除旧的Pod之后才会新建新的Pod。

第二种更新策略RollingUpdate,在更新该控制器的模板后,旧的Pod将被终止哦,并且以受控的方式自动新建Pod,但是和Deployment控制之间有一些席位的差异,如下:

  1. StatefulSet控制器是有序的,更新的顺序会从编号最大的Pod到最小的Pod依次进行更新,在更新之前不会立即删除旧的Pod,会等到新的Pod创建完毕并且处于Running状态,才会替换并删除旧的Pod
  2. 该控制器拥有独有的更新属性,spec.updateStrategy.rollingUpdate.partition。这种方式类似于金丝雀部署,如果将.partition设置为4,只有编号大于或者等于4的Pod才会更新,编号小于.partition的Pod将不会更新,如果已经更新的Pod通过验证,则在将.partition的值改为0,更新其余的Pod即可。

配置存储卷

K8S还包含一些存储卷,他们之间不是用来进行容器间的交互或者Pod之间的数据共享,而是用于向各个Pod的容器中注入配置信息的,在使用方式上大同小异,Pod可以通过环境变量或者存储卷访问这些配置信息。

目前的这类的存储卷主要分为三种:

  1. ConfigMap:传递普通的配置信息
  2. Secret:传递敏感的、加密的配置信息
  3. DownwardAPI:可以传递Pod和容器自身的运行信息

一.ConfigMap

在企业的运营中,一般会有多个部署环境,如开发环境、测试环境、预发布环境、生产环境等等,每一种环境的配置不同。如果在Pod模板信息中直接配置,会比较难管理,而且每个环境都需要准备不同的模板。

利用ConfigMap可以解耦部署与配置之间的关系,只需要在各个环境中的机器上预先完成不同的配置即可,也就是配置ConfigMap。对于同一个应用部署,Pod模板无需变化,只需要将明文编写的配置设置为对ConfigMap的引用,就可以降低环境管理和管理的复杂度。

ConfigMap是以键值对的方式来存储配置信息的。

[root@master ~]# vi testconfigmap1.yaml

apiVersion: v1

kind: ConfigMap

metadata:

  name: testconfigmap

data:

  exampleHostName: www.testk8s.com

  exampleBusinessMode: testMode

[root@master ~]# kubectl  apply -f testconfigmap1.yaml

configmap/testconfigmap created

[root@master ~]# kubectl  get configmap

NAME               DATA   AGE

testconfigmap      2      30s

[root@master ~]# kubectl  describe configmap testconfigmap

]Name:         testconfigmap

Namespace:    default

Labels:       <none>

Annotations:  <none>

Data

====

exampleBusinessMode:

----

testMode

exampleHostName:

----

www.testk8s.com

BinaryData

====

Events:  <none>

//以上内容是ConfigMap的详细信息,可以查看到我们的键值对信息,后续在Pod中即可引用,下面是ConfigMap的两种引用方式。

1.环境变量的引用方式

ConfigMap可以通过设置环境变量或者命令行参数的形式进行引用,首先定义模板文件:

[root@master ~]# vi testconfigmap2.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testconfigmap2

spec:

  containers:

  - name: containerenv

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "EnvParaHostName: ${EnvParaHostName} EnvParaBusinessMode: ${EnvParaBusinessMode}" prientenv grep EnvPara ; sleep 3600']

    env:

      - name: EnvParaHostName

        valueFrom:

          configMapKeyRef:

            name: testconfigmap

            key: exampleHostName

      - name: EnvParaBusinessMode

        valueFrom:

          configMapKeyRef:

            name: testconfigmap

            key: exampleBusinessMode

//上述的模板通过valueFrom、configMapKeyRef、name、key等属性,我们可以指定具体要引用的那些环境变量。重点是在env的属性中,我们先定义了环境变量的名称分别为EnvParaHostName、EnvParaBusinessMode。和之前的环境变量不同的地方在于,这里是通过valueFrom属性来定义,表示环境变量的值来自外部引用,关键字是onfigMapKeyRef表示从ConfigMap中引用;configMapKeyRef.name属性表示要引用的ConfigMap的名称,而configMapKeyRef.key表示要引用的键值对的键名,它的值会映射到环境变量上。

在容器的参数中,首先会通过命令行直接输出定义的参数,然后通过$ print env |grep EnvPara输出Pod中包含的关键字。

[root@master ~]# kubectl  apply -f testconfigmap2.yaml

pod/testconfigmap2 created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS        AGE

testconfigmap2                             1/1     Running   0               8s

//pod运行正常,接下来我们需要查看pod输出信息

[root@master ~]# kubectl  logs testconfigmap2

EnvParaHostName: www.testk8s.com EnvParaBusinessMode: testMode prientenv grep EnvPara

//从上述信息中可以看到我们的环境变量已经被成功引用,但是在有些时候ConfigMap的键值会非常多,如果一个个的配置到Pod中会非常麻烦,所以K8S还提供了一种简易方式,将ConfigMap中的键值对直接配置到Pod中。

[root@master ~]# cat testconfigmap3.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testconfigmap3

spec:

  containers:

  - name: containerenv3

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['printenv |grep test ; sleep 3600']

    envFrom:

      - configMapRef:

          name: testconfigmap

//我们在这个模板中,是直接使用envFrom属性,表示整个环境都是从外部环境引用,引用方式是configMapRef。

[root@master ~]# kubectl  apply -f testconfigmap3.yaml

pod/testconfigmap3 created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS        AGE

testconfigmap3                             1/1     Running   0               18s

[root@master ~]# kubectl  logs testconfigmap3

HOSTNAME=testconfigmap3

exampleHostName=www.testk8s.com

exampleBusinessMode=testMode

//从上述内容可以查看,对于testconfigmap中的内容全部引用完毕。

2.存储卷引用方式

因为ConfigMap本身就是一种特殊的存储卷,so 也可以利用存储卷的方式配置到Pod中,不同于环境变量的方式,这种引用方式会将每个键值对都转换成对应的实体文件。

[root@master ~]# vi testconfigmap4.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testconfigmap4

spec:

  containers:

  - name: containervolume

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "files:"; ls /config/allvalues; sleep 3600']

    volumeMounts:

    - name: volumeconfig

      mountPath: /config/allvalues

  volumes:

  - name: volumeconfig

    configMap:

      name: testconfigmap

//本文件创建的存储卷名称为volumeconfig,这个名称会被容器设置的存储卷引用。存储卷的类型是configmap,name的属性是testconfigmap。创建的容器名为containervolume会引用volumeconfig存储卷,并将其映射到容器的/config/allvalues目录下,然后通过ls命令输出/config/allvalues下的所有文件

[root@master ~]# kubectl  apply -f testconfigmap4.yaml

pod/testconfigmap4 created

[root@master ~]# kubectl  get pod

NAME                                       READY   STATUS    RESTARTS        AGE

testconfigmap2                             1/1     Running   0               25m

testconfigmap3                             1/1     Running   0               12m

testconfigmap4                             1/1     Running   0               13s

[root@master ~]# kubectl  logs testconfigmap4

files:

exampleBusinessMode

exampleHostName

//从以上内容中可以看出,Pod成功引用了ConfigMap中的键值,并将其对应为实体文件,接下来进入pod中查看,如下:

[root@master ~]# kubectl  exec -it testconfigmap4  -- /bin/sh

/ # cat /config/allvalues/exampleHostName

www.testk8s.com

/ # cat /config/allvalues/exampleBusinessMode

testMode


Secret

Secret对应的三种类型:

(1)OpaqueSecret:使用base64的格式进行比那吗,用来存储密码

(2)ImagePullSecret:用来存储私有的Dcoker Registry的认证信息

(3)ServiceAccountSecret:主要用来访问K8S API。会被Service Account进行引用。在ServiceAccount创建的时候,K8S会默认创建对应的Secret。如果Pod使用了ServiceAccount,则对应的Secret会自动挂载到pod的/run/secrets/Kubernetes.io/serviceaccount目录下

一.OpaqueSecret

此类型与ConfigMap的定义方式和使用方式类似,都是使用的键值对形式,但是区别在于,这种类型中的各个键对应的值必须要经过base64格式进行编码才能配置。

接下来举一个简单的例子,使用该类型存储自定的用户名和密码,用户名为superuser,密码为abc12345,接下来我们要先对用户名和密码进行编码,命令如下:

[root@master ~]# echo  -n "superuser" | base64

c3VwZXJ1c2Vy

[root@master ~]# echo  -n "abc12345" | base64

YWJjMTIzNDU=

//上述结果中产生的字符串信息均为用户名和密码的编码结果

[root@master ~]# vi testsecret.yaml

apiVersion: v1

kind: Secret

metadata:

  name: testsecret

type: Opaque

data:

  username: c3VwZXJ1c2Vy

  password: YWJjMTIzNDU=

//在这个模板中资源对象类型为Secret,名字为testsecret,并且包含了两个键值对,分别为刚才编码之后的值

[root@master ~]# kubectl  apply -f testsecret.yaml

secret/testsecret created

[root@master ~]# kubectl  get secret

NAME                                 TYPE                                  DATA   AGE

testsecret                           Opaque                                2      15s

[root@master ~]# kubectl  describe secret testsecret

Name:         testsecret

Namespace:    default

Labels:       <none>

Annotations:  <none>

Type:  Opaque

Data

====

password:  8 bytes       //两个键值对并未使用明文展示

username:  9 bytes

[root@master ~]# kubectl  get secret testsecret -o yaml

apiVersion: v1

data:

  password: YWJjMTIzNDU=

  username: c3VwZXJ1c2Vy

kind: Secret

metadata:

  annotations:

    kubectl.kubernetes.io/last-applied-configuration: |

      {"apiVersion":"v1","data":{"password":"YWJjMTIzNDU=","username":"c3VwZXJ1c2Vy"},"kind":"Secret","metadata":{"annotations":{},"name":"testsecret","namespace":"default"},"type":"Opaque"}

  creationTimestamp: "2023-05-31T01:00:17Z"

  name: testsecret

  namespace: default

  resourceVersion: "833622"

  selfLink: /api/v1/namespaces/default/secrets/testsecret

  uid: 2769805a-82ab-42b7-9980-a450bea8470b

type: Opaque

//从上述的信息可知,使用-o yaml的方式一下就可以查出我们配置的键值,所以这个方式一点也不安全,只要稍微解码即可获取原始值,接下来我们进行解码,如下:

[root@master ~]# echo  "c3VwZXJ1c2Vy" | base64 --decode

superuser

[root@master ~]# echo  "YWJjMTIzNDU=" | base64 --decode

abc12345

//Secret创建完成之后就可以在Pod中进行引用了,其引用方式和ConfigMap的方式大同小异,接下来分别说一下两种引用方式。

【环境变量的方式】

[root@master ~]# vi testsecretpod1.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testsecretpod

spec:

  containers:

  - name: containerforenv

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "EnvParaUserName: ${EnvParaUserName} EnvParaPassword: ${EnvParaPassword}" printenv grep EnvPara; sleep 3600']

    env:

      - name: EnvParaUserName

        valueFrom:

          secretKeyRef:

            name: testsecret

            key: username

      - name: EnvParaPassword

        valueFrom:

          secretKeyRef:

            name: testsecret

            key: password

//上述的模板通过valueFrom、secretKeyRef、name、key等属性,我们可以指定具体要引用的那些环境变量。重点是在env的属性中,我们先定义了环境变量的名称分别为EnvParaUserName、EnvParaPassword。通过valueFrom属性来定义,表示环境变量的值来自外部引用,关键字是secretKeyRef表示从secret中引用;secretKeyRef.name属性表示要引用的secret的名称,而secretKeyRef.key表示要引用的键值对的键名,它的值会映射到环境变量上。

[root@master ~]# kubectl  apply -f testsecretpod1.yaml

pod/testsecretpod created

[root@master ~]# kubectl  get pod  |grep testsecret

testsecretpod                              1/1     Running   0               36s

[root@master ~]# kubectl  logs testsecretpod

EnvParaUserName: superuser EnvParaPassword: abc12345 printenv grep EnvPara

//从上述信息中,我们可以看到secret中设置的键值被成功引用,在secret中设置的键值也是非常多,单个形式配置会很麻烦,K8S也为它提供了简易的方式,来将多个键值配置到Pod,命令如下:

[root@master ~]# cat testsecretpod2.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testsecretpod2

spec:

  containers:

  - name: containerforenv

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['printenv   ; sleep 3600']

    envFrom:

      - secretRef:

          name: testsecret

//此模板直接使用envFrom的属性,代表整个环境从外部文件引用;引用方式为secretRef,代表从secret中引用,- secretRef.name代表secret的名字

[root@master ~]# kubectl  apply -f testsecretpod2.yaml

pod/testsecretpod2 created

[root@master ~]# kubectl  get pod |grep testsecret

testsecretpod                              1/1     Running   0                 9m49s

testsecretpod2                             1/1     Running   0                 22s

[root@master ~]# kubectl  logs testsecretpod2

username=superuser

password=abc12345

【存储卷引用方式】

Secret本身也是一种特殊的存储卷,所以也可以通过存储卷的方式进行配置到Pod中,不同于环境变量的引用方式,它也会把每个键值对都转换成对应的实体文件。

[root@master ~]# vi testsecretvolume.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testsecretvolume

spec:

  containers:

  - name: containervolume

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "files:"; ls /secret/allvalues; sleep 3600']

    volumeMounts:

    - name: volumesecret

      mountPath: /secret/allvalues

  volumes:

  - name: volumesecret

    secret:

      secretName: testsecret

//本文件创建的存储卷名称为volumesecret,这个名称会被容器设置的存储卷引用。存储卷的类型是secret,secretName的属性是testsecret。创建的容器名为containervolume会引用volumesecret存储卷,并将其映射到容器的/secret/allvalues目录下,然后通过ls命令输出/secret/allvalues下的所有文件

[root@master ~]# kubectl  apply -f testsecretvolume.yaml

pod/testsecretvolume created

[root@master ~]# kubectl  get pod |grep testsecretvolume

testsecretvolume                           1/1     Running   0               19s

[root@master ~]# kubectl  logs testsecretvolume

files:

password

Username

//从以上结果可知,在容器的映射目录下分别存放了两个文件,我们可以进入这个Pod中查看这两个文件的信息

[root@master ~]# kubectl  exec -it testsecretvolume -- /bin/sh

/ # cat /secret/allvalues/

..2023_05_31_02_05_54.985248978/  password

..data/                           username

/ # cat /secret/allvalues/username

superuser/ #

/ # cat /secret/allvalues/password

abc12345/

//从以上信息可知,两个文件的内容是secret中各个键对应的值,而且这些值已经被解码成了明文


ImagePullSecret(仅作参考)

此类型主要用来存储私有Dcoker Registry的认证信息,在设置Pod模板时,如果需要从私有仓库中拉取镜像,可以设置imagePullSecret属性为此类型的Secret,以作为仓库的登陆密钥。

[root@master ~]# kubectl  create secret  docker-registry myregistrykey --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_PASSWORD

secret/myregistrykey created

//在这个案例中我们以命令行的方式创建了一个名为myregistrykey的Secret,在创建时需要将自己的DOCKER_REGISTRY_SERVER、DOCKER_USER、DOCKER_PASSWORD、DOCKER_PASSWORD设置为对应环境中的值,也可以使用读取文件的方式来进行创建,比如:

# kubectl  create secret docker-registry myregistrykey --from-file="./dockercfg"

//上述命令执行完毕后可以使用下面命令输出该secret的yaml内容,在改内容中data字段下包含了一串字符串,这串内容就是编码之后的值,可以对该字符串进行解码,使其采用明文的形式展示出来,可以使用下面的命令

[root@master ~]# kubectl  get secret

NAME                                 TYPE                                  DATA   AGE

default-token-r9kpb                  kubernetes.io/service-account-token   3      20d

myregistrykey                        kubernetes.io/dockerconfigjson        1      35s

nfs-client-provisioner-token-j2csg   kubernetes.io/service-account-token   3      44h

testsecret                           Opaque                                2      145m

[root@master ~]# kubectl  get secret myregistrykey -o yaml

apiVersion: v1

data:

  .dockerconfigjson: eyJhdXRocyI6eyJET0NLRVJfUkVHSVNUUllfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX1BBU1NXT1JEIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0=

kind: Secret

metadata:

  creationTimestamp: "2023-05-31T03:25:26Z"

  name: myregistrykey

  namespace: default

  resourceVersion: "850444"

  selfLink: /api/v1/namespaces/default/secrets/myregistrykey

  uid: d8763d6a-aae2-4568-9a9f-74c50fdbf923

type: kubernetes.io/dockerconfigjson

[root@master ~]# echo  "eyJhdXRocyI6eyJET0NLRVJfUkVHSVNUUllfU0VSVkVSIjp7InVzZXJuYW1lIjoiRE9DS0VSX1VTRVIiLCJwYXNzd29yZCI6IkRPQ0tFUl9QQVNTV09SRCIsImVtYWlsIjoiRE9DS0VSX1BBU1NXT1JEIiwiYXV0aCI6IlJFOURTMFZTWDFWVFJWSTZSRTlEUzBWU1gxQkJVMU5YVDFKRSJ9fX0=" | base64 --decode

{"auths":{"DOCKER_REGISTRY_SERVER":{"username":"DOCKER_USER","password":"DOCKER_PASSWORD","email":"DOCKER_PASSWORD","auth":"RE9DS0VSX1VTRVI6RE9DS0VSX1BBU1NXT1JE"}}}

//Secret创建完成后,就可以在Pod中引用,将Secret名称配置到spec.imagePullSecrets属性中即可,模板如下:

[root@master ~]# vi testsecretimagePullSecret.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testsecretimagePullSecret

spec:

  containers:

    - name: testcontainer

      image: mydocker/myapp:v1

  imagePullSecrets:

    - name: myregistrykey

DownWard API

主要作用是向Pod中运行的容器暴露Pod自身的信息,DownWardapi允许容器在不使用K8S客户端或者API Server的情况下获取有关自身或集群的信息。

在目前的版本中DownWardAPI可以获取大量的信息,下面列出可同时通过环境变量或存储卷获取的信息:

【使用FieldRef属性可获取的信息】

● metadata.name:Pod名称

● metadata.namespace:Pod的命名空间

● metadata.uid:Pod的UID

● metadata.labels[‘{KEY}’]:Pod的标签{KEY}值

● metadata.annottations[‘{KEY}’]:Pod注解{KEY}的值

【使用resourceFieldRef属性可获取的信息】

如果你没有给容器指定CPU或者内存限制,则DownWardAPI获取节点上CPU和内存默认可分配的值

● limits.cpu:容器的CPU限制

● requests.cpu:容器的CPU请求

● limits.memory:容器的内存限制

● requests.memory:容器的内存请求

● limits.ephemeral-storage:容器的临时存储限制

● requests.ephemeral-storage:容器的临时存储请求

【使用FieldRef属性批量可获取的信息】

● metadata.labels:所有的Pod标签,格式为label-key=”escaped-label-value”,每行一个标签

●metadata.annottations:所有Pod的注解,格式为annottation-key=”escaped-annottation-value”每行一个注解

【只能通过环境变量获得的信息】

● status.podIP:Pod的IP地址

● spec.serviceAccountName:Pod的ServiceAccount名称

● spec.nodeName:节点名称

● status.hostIP:节点的IP

1.【环境变量引用方式】

DownWardAPI可以采用设置环境变量和命令行参数的形式进行引用

[root@master ~]# cat testpodfordownward.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testpodfordownward

spec:

  containers:

  - name: containerenv

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "EnvParaPodName: ${EnvParaPodName} EnvParaPodIP: ${EnvParaPodIP}  EnvParaNodeName: ${EnvParaNodeName}"; printenv |grep EnvPara; sleep 3600']

    env:

      - name: EnvParaPodName

        valueFrom:

          fieldRef:

            fieldPath: metadata.name

      - name: EnvParaPodIP

        valueFrom:

          fieldRef:

            fieldPath: status.podIP

      - name: EnvParaNodeName

        valueFrom:

          fieldRef:

            fieldPath: spec.nodeName

[root@master ~]# kubectl  apply -f testpodfordownward.yaml

pod/testpodfordownward created

[root@master ~]# kubectl  get pod |grep testpodfordownward

testpodfordownward                         1/1     Running   0               21s

[root@master ~]# kubectl  logs testpodfordownward

EnvParaPodName: testpodfordownward EnvParaPodIP: 10.244.2.10  EnvParaNodeName: worker1

EnvParaPodName=testpodfordownward

EnvParaPodIP=10.244.2.10

EnvParaNodeName=worker1

2.【通过存储卷的方式引用】

因为DownWard API本身就是一种特殊的存储卷,so 也可以利用存储卷的方式配置到Pod中,这种引用方式会将每个键值对都转换成对应的实体文件。

[root@master ~]# cat testpodforvolume.yaml

apiVersion: v1

kind: Pod

metadata:

  name: testpodforvolumedownward

spec:

  containers:

  - name: containerforvolume

    image: busybox

    imagePullPolicy: IfNotPresent

    command: ['sh','-c']

    args: ['echo "files:"; ls /config/alldownward; sleep 3600']

    volumeMounts:

    - name: volumedownward

      mountPath: /config/alldownward

  volumes:

  - name: volumedownward

    downwardAPI:

      items:

      - path: "PodName"

        fieldRef:

            fieldPath: metadata.name

      - path: "PodUID"

        fieldRef:

            fieldPath: metadata.uid

      - path: "PodNameSpace"

        fieldRef:

            fieldPath: metadata.namespace

//本文件创建的存储卷名称为volumedownward,这个名称会被容器设置的存储卷引用。存储卷的类型是downwardAPI,分别引用了metadata.name、metadata.uid、metadata.namespace,分别将其命名为到指定路径的PodName、PodNameSpace、PodUID。创建的容器名为containervolume会引用volumeconfig存储卷,并将其映射到容器的/config/alldownward目录下,然后通过ls命令输出/config/alldownward下的所有文件

[root@master ~]# kubectl apply -f  testpodforvolume.yaml

pod/testpodforvolumedownward created

[root@master ~]# kubectl get pod   |grep testpodforvolume

testpodforvolumedownward                   1/1     Running   0                32s

[root@master ~]# kubectl  logs testpodforvolumedownward

files:

PodName

PodNameSpace

PodUID

[root@master ~]# kubectl  exec -it testpodforvolumedownward -- /bin/sh

/ # cat /config/alldownward/PodName

testpodforvolumedownward/ #

/ # cat /config/alldownward/PodNameSpace

/ # cat /config/alldownward/PodUID

d5fa0630-8c4c-4f61-8ab4-563484c7d85a/ #

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值