Kubernetes入门实验:volume

369 阅读6分钟

k8s volume 实验。
注:本文为笔者实验记录。

环境

# kubectl get node
NAME              STATUS     ROLES    AGE   VERSION
edge-node         Ready      <none>   15m   v1.17.0
edge-node2        Ready      <none>   16m   v1.17.0
ubuntu            Ready      master   67d   v1.17.0

volume

技术总结

一个pod内多个容器,可通过emptyDir实时临时共享,如进行即时数据通信。为跨节点共享,可用 nfs 。
busybox镜像(其它类似)时区为UTC,可挂载/etc/localtime。以保证时间正确。
有些程序依赖库太多,可直接挂载主机lib目录。

创建pv和pvc,其meta名称不同。使用的pod指定pvc(注:pod使用的是pvc),自动匹配到pv(pv和pvc的匹配机制暂不清楚,有资料说根据容量匹配,待议)。

pvc不合适多个副本的情况,因为多副本会读写同一文件。实际用到什么场合,待议。

在pv指定的目录,最好先创建并且保证权限正常。使用nfs时,如没有创建目录,pod会创建失败。

常见类型

emptyDir

yaml文件。一个pod有2个容器,创建临时挂载目录(无须指定在主机哪个目录),两容器可相互访问,pod消失后,挂载目录不存在。

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx
    image: latelee/lidch
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - mountPath: /test111
      name: empty-volume
    ports:
    - name: http
      containerPort: 80
      hostIP: 0.0.0.0
      hostPort: 80
      protocol: TCP
    - name: https
      containerPort: 443
      hostIP: 0.0.0.0
      hostPort: 443
      protocol: TCP
  - name: busybox
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test222
      name: empty-volume
  volumes:
  - name: empty-volume
    emptyDir: {}

创建:

kubectl apply -f nginx-pod.yaml

验证:

kubectl exec -it nginx-pod -c busybox sh
echo "from busybos" > /test222/foo
exit

kubectl exec -it nginx-pod -c nginx sh
cat /test111/foo  // 输出:from busybos
exit

即:两容器有各自的挂载目录,目录名不同,但内容共享。

hostPath

与上类似,但挂载的目录,会映射到主机(实际是节点主机)目录,容器之间共享,容器被删除,文件保留。但下次pod若调度其它节点,数据不存在。此法与节点主机相关。

busybox-pod.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod
  labels:
    app: busybox
spec:
  containers:
  - name: busybox1
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test111
      name: host-volume
  - name: busybox2
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test222
      name: host-volume
  volumes:
  - name: host-volume
    hostPath:
      path: /data
      type: DirectoryOrCreate

测试步骤同上,2容器分别写文件。

kubectl apply -f busybox-pod.yaml 

kubectl exec -it busybox-pod -c busybox1 sh

kubectl exec -it busybox-pod -c busybox1 sh

kubectl delete -f busybox-pod.yaml 

当删除 pod 后,登陆节点机器,查看目录/data,可见文件还在。

多目录挂载示例busybox-pod1.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod1
  labels:
    app: busybox
spec:
  containers:
  - name: busybox1
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test111
      name: host-volume
    - mountPath: /etc/localtime
      name: time-zone
  volumes:
  - name: host-volume
    hostPath: 
      path: /data
  - name: time-zone
    hostPath: 
      path: /etc/localtime

注1:如静态程序运行,直接挂载lib。或操作硬件的程序,直接挂载/dev目录。
注2:本例映射时间文件,可与前面对比。kubectl exec -it busybox-pod -c busybox1 date

NFS

要点:指定一台主机做NFS服务(本例为master),在其上安装服务。集群各节点安装nfs客户端。
此法固定了挂载目录,不随调度而变化。

安装并配置nfs。

sudo apt-get install nfs-kernel-server -y
vim /etc/exports
/nfs  *(rw,no_root_squash,no_all_squash,sync)

sudo /etc/init.d/nfs-kernel-server restart

mount -t nfs -o nolock 192.168.0.102:/nfs /mnt/nfs

节点需要支持nfs格式挂载。

sudo apt-get install nfs-common -y

否则提示:

wrong fs type, bad option, bad superblock on 192.168.0.102:/nfs,missing codepage or helper program, or other error

busybox-nfs.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod
  labels:
    app: busybox
spec:
  containers:
  - name: busybox1
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test111
      name: nfs-volume
  - name: busybox2
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test222
      name: nfs-volume
  volumes:
  - name: nfs-volume
    nfs:
      server: 192.168.0.102
      path: /nfs

测试:

# kubectl exec -it busybox-pod -c busybox1 sh
/ # echo "bbb" > /test111/bbb
/ # exit
# cat /nfs/bbb 
bbb

持久化

PV:将存储(如主机磁盘、云盘)抽象为k8s的存储单元,以便使用。(存疑:一个命名空间只能有一个PV?)。
创建PV后,是静态概念,即一直在那里。需要使用PVC注册并使用。

pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv1
  labels:
    storage: nfs
spec:
  accessModes: ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany"] # 支持多模式,可能好些
  #accessModes:
  #  - ReadWriteMany
  capacity:
    storage: 200Mi
  volumeMode: Filesystem
  persistentVolumeReclaimPolicy: Retain # 值 delete Recycle Retain
  nfs:
    server: 192.168.0.102
    path: /nfs1
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv2
spec:
  capacity:
    storage: 100Mi # 5Gi
  accessModes: ["ReadWriteOnce", "ReadWriteMany", "ReadOnlyMany"]
  #accessModes:
  #  - ReadWriteMany
  nfs:
    server: 192.168.0.102
    path: /nfs2

pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc1
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 20Mi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc2
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi

注:metadata.name需要注意命名,后续要使用。
(疑问:pvc如何匹配pv?)

创建

kubectl apply -f pv.yaml
kubectl delete -f pv.yaml

kubectl apply -f pvc.yaml
kubectl delete -f pvc.yaml

查看创建的pv:

kubectl get pv
NAME      CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv1   200Mi      RWO,ROX,RWX    Retain           Available                                   17s
nfs-pv2   100Mi      RWX            Retain           Available                                   3m

创建的pvc:

NAME       STATUS   VOLUME    CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc1   Bound    nfs-pv2   100Mi      RWX                           3s
nfs-pvc2   Bound    nfs-pv1   200Mi      RWO,ROX,RWX                   3s

注:似乎根据请求的容器来申请的,

busybox-pvc.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pvc
  labels:
    app: busybox
spec:
  containers:
  - name: busybox1
    image: latelee/busybox
    imagePullPolicy: IfNotPresent
    command: ["sh", "-c", "sleep 3600"]
    volumeMounts:
    - mountPath: /test111
      name: host-volume
  volumes:
  - name: host-volume
    persistentVolumeClaim:
      claimName: nfs-pvc2 # 请求的PVC,必须存在
kubectl apply -f busybox-pvc.yaml 
kubectl exec -it busybox-pvc -c busybox1 df
kubectl delete -f busybox-pvc.yaml 

redis实例redis-pvc.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: redis-pvc
  labels:
    app: redis-pvc
spec:
  containers:
  - name: redis-pod
    image: redis:alpine
    imagePullPolicy: IfNotPresent
    # command: # 不需要
    volumeMounts:
    - mountPath: /data  # 这是redis的存储目录
      name: pvc-volume
  volumes:
  - name: pvc-volume
    persistentVolumeClaim:
      claimName: nfs-pvc2 # 请求的PVC,必须存在

写数据:

# kubectl exec -it redis-pvc sh
/data # redis-cli 
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set who "latelee"
OK
127.0.0.1:6379> set email "li@latelee.or"
OK
127.0.0.1:6379> BGSAVE
Background saving started
127.0.0.1:6379> exit
/data # exit

nginx服务挂载:

apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
   app: nginx
spec:
  replicas: 3 # tells deployment to run 2 pods matching the template
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: latelee/lidch
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
        volumeMounts:
        - name: www
          subPath: html1 # 设置子目录,专用于本服务
          mountPath: /usr/share/nginx/html
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: nfs-pvc2

---

apiVersion: v1
kind: Service # 指定为service
metadata:
  labels:
    run: nginx
  name: nginx
  namespace: default
spec:
  ports:
  - port: 88 # 对外为88端口
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer

实验小记: 创建,获取对应的service地址,访问之,出现403(此为正常,因为nfs-pvc2即/nfs1/html1没有index.html),写一文件即可正常访问。(要等待片刻)

问题及小测试

1、
没有pv,但创建了pvc。pvc请求的容量超过pv容器。提示:

no persistent volumes available for this claim and no storage class is set

先创建2个PV,再创建2个PVC,查看分配成功后,再删除一个PV。此时PV正在被占用,删除时为 Terminating 状态。当再删除绑定的pvc时,pv继续删除至成功。

创建一个pod,写入数据,超过PV和PVC规定容量。似乎也能成功。

dd if=/dev/zero of=null.bin count=3000 bs=102400

2、
先删除pvc,再删除pv。否则pv无法删除。

3、

mount.nfs: access denied by server while mounting 192.168.0.102:/nfs3

1、目录不存在;2、没有导出该目录。