k8s pod 挂载数据卷
挂载基本数据卷有以下几种
emptyDir:kube给创建空目录 不会保存数据 pod删除 数据也会删除,一般用于应用运行时所需要的临时目录
apiVersion: v1
kind: Pod
metadata:
name: volume-emptydir
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports: #设置容器暴露端口
- name: nginx-port #设置暴露端口名 唯一
containerPort: 80 #暴露端口 pod内唯一
protocol: TCP
volumeMounts: #将logs-volume挂载到nginx容器中,对应的目录为 /var/log/nginx
- name: logs-volume
mountPath: /var/log/nginx
subPath: log1 # 在logs-volume里建立子目录 用于隔离不同容器存储的数据
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"] #初始化命令,动态读取指定文件中内容
volumeMounts: # 将logs-volume挂载到容器对应目录 /logs
- name: logs-volume
mountPath: /logs
subPath: log2
volumes: #声明数据卷 volume, name为数据卷名 类型为emptyDir
- name: logs-volume
emptyDir: {}
HostPath: 可将数据持久化到主机,绑定到主机的目录上,数据存储在node节点
apiVersion: v1
kind: Pod
metadata:
name: volume-hostpath
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports: #设置容器暴露端口
- name: nginx-port #设置暴露端口名 唯一
containerPort: 80 #暴露端口 pod内唯一
protocol: TCP
volumeMounts: #将logs-volume挂载到nginx容器中,对应的目录为 /var/log/nginx
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"] #初始化命令,动态读取指定文件中内容
volumeMounts: # 将logs-volume挂载到容器对应目录 /logs
- name: logs-volume
mountPath: /logs
volumes: #声明数据卷 volume, name为数据卷名 类型为hostPath
- name: logs-volume
hostPath:
path: /root/logs
type: DirectoryOrCreate #目录存在就使用不存在就创建后使用
type类型说明:
DirectoryOrCreate :目录存在就使用 不存在创建在使用
Directory: 目录必须存在
File: 文件必须存在
Socket : unix 套接字必须存在
CharDevice 字符设备必须存在
BlockDevice 块设备必须存在
NFS : 网络文件存储系统,可以搭建一台NFS服务器 将pod上的数据直接挂载到NFS上 可实现共享数据存储 解决HostPath只能存储在pod所在节点的问题
#安装nfs服务 提供nfs服务的主机
yum install nfs-utils -y
#准备共享目录
mkdir /root/data/nfs -pv
#将共享目录以可读可写的权限暴露给192.168.140.0/24网段中所有主机
#nfs默认读取配置文件
vim /etc/exports
#增加配置 给这个网段主机增加读写权限 不需要root登录
/root/data/nfs 192.168.140.0/24 (rw,no_root_squash)
#启动nfs服务
systemctl start nfs
#所有需要加入nfs的节点都要安装nfs 不需要启动nfs
yum install nfs-utils -y
创建pod
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports: #设置容器暴露端口
- name: nginx-port #设置暴露端口名 唯一
containerPort: 80 #暴露端口 pod内唯一
protocol: TCP
volumeMounts: #将logs-volume挂载到nginx容器中,对应的目录为 /var/log/nginx
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","tail -f /logs/access.log"] #初始化命令,动态读取指定文件中内容
volumeMounts: # 将logs-volume挂载到容器对应目录 /logs
- name: logs-volume
mountPath: /logs
volumes: #声明数据卷 volume, name为数据卷名 类型为hostPath
- name: logs-volume
nfs:
server: 192.168.140.3 #nfs服务器地址
path: /root/data/nfs #共享文件路径
configmap 存储配置信息 直接把配置文件挂载到容器中 容器可直接访问此配置信息
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap
namespace: test
data: #配置内容 键值对形式
info: | #键 下边都是值 也就是直接存储的数据
username: admin
password: 123456
对应pod
apiVersion: v1
kind: Pod
metadata:
name: pod-configmap
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts: # 将configmap挂载到目录
- name: config
mountPath: /configmap/config
volumes: # 引用configmap
- name: config
configMap:
name: configmap #对应configmap名称
#查看配置
kubectl describe cm -n test
#还可动态修改配置信息 自动更新无需重启pod
kubectl edit cm configmap -n test
#进入pod查看配置
kubectl exec -it pod-configmap -n test /bin/sh
可以从configMap数据生成环境变量
pod内设置
#使用configmap创建环境变量
apiVersion: v1
kind: Pod
metadata:
name: cm-test-pod
spec:
restartPolicy: Never
containers:
- name: cm-test
image: busybox
command: ["/bin/sh", "-c", "env | grep APP"]
env:
- name: APPLOGLEVEL
valueFrom:
configMapKeyRef:
name: cm-appconfig #使用的configmap名称
key: apploglevel #configmap中定义的key
- name: APPDATADIR
valueFrom:
configMapKeyRef:
name: cm-appconfig #使用的configmap名称
key: appdatadir #configmap中定义的key
configMap的yaml
#pod使用config-map里的数据设置env
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-appconfig
data: #配置内容 键值对形式
apploglevel: info
appdatadir: /var/logs
从Kubernetes v1.6开始,引入了一个新的字段 envFrom ,实现在Pod环境内将ConfigMap(也可用于Secret资源对象)中所定义的key=value自动生成为环境变量
#envFrom 直接生成环境变量
apiVersion: v1
kind: Pod
metadata:
name: cm-envfrom-pod
spec:
containers:
- name: test-container
image: busybox
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: cm-appconfig
restartPolicy: Never
容器获取pod信息方式
#容器内获取pod信息,即容器内获取yaml文件配置信息
apiVersion: v1
kind: Pod
metadata:
name: dapi-envars-fieldref
spec:
containers:
- name: test-container
image: busybox
command: ["sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_NODE_NAME MY_POD_NAME MY_POD_NAMESPACE;
printenv MY_POD_IP MY_POD_SERVICE_ACCOUNT;
sleep 10;
done;
env:
- name: MY_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: MY_POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
restartPolicy: Never
容器内获取容器配置信息 通过DownwardAPI 获取
#通过DownwardAPI 将容器信息设置为环境变量
apiVersion: v1
kind: Pod
metadata:
name: dapi-envars-resourcefieldref
spec:
containers:
- name: test-container
image: busybox
command: ["sh", "-c"]
args:
- while true; do
echo -en '\n';
printenv MY_CPU_REQUEST MY_CPU_LIMIT;
printenv MY_MEM_REQUEST MY_MEM_LIMIT;
sleep 10;
done;
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
env:
- name: MY_CPU_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.cpu
- name: MY_CPU_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.cpu
- name: MY_MEM_REQUEST
valueFrom:
resourceFieldRef:
containerName: test-container
resource: requests.memory
- name: MY_MEM_LIMIT
valueFrom:
resourceFieldRef:
containerName: test-container
resource: limits.memory
restartPolicy: Never
**通过volume挂载方式 downwardAPI获取容器和pod配置信息 **
#通过DownwardAPI 将容器和pod信息挂载到容器内部
apiVersion: v1
kind: Pod
metadata:
name: dapi-volume-resourcefieldref
labels:
zone: us-est-coast
cluster: test-cluster1
rack: rack-22
annotations:
build: two
builder: john-doe
spec:
containers:
- name: test-container
image: busybox
resources:
requests:
memory: "32Mi"
cpu: "125m"
limits:
memory: "64Mi"
cpu: "250m"
command: ["sh", "-c"]
args:
- while true; do
echo -en '容器在运行\n';
sleep 10;
done;
volumeMounts:
- name: podinfo
mountPath: /etc/podinfo
volumes:
- name: podinfo
downwardAPI:
items: # 根据items的path生成文件 使用items 可以自定义目录名 否则以KEY为文件名 绑定到容器目录里 configMap也如此使用
- path: "labels" #path 自定义文件名路径名
fieldRef: #绑定pod信息
fieldPath: metadata.labels
- path: "annotations"
fieldRef:
fieldPath: metadata.annotations
- path: "cpu_limit"
resourceFieldRef:
containerName: test-container
resource: limits.cpu
restartPolicy: Never
secret密文形式存储敏感信息通过base64编码存储 容器访问时会自动解码用法与configmap类似
创建base64加密字符串
echo 'admin' | base64
echo '123456' | base64
创建secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: secret
type: Opaque
data:
username: YWRtaW4=
password: MTIzNDU2
查看
#查看
k get secret
#查看详细
k describe secret secret
pod引用
apiVersion: v1
kind: Pod
metadata:
name: pod-secret
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts:
- name: secret-config
mountPath: /secret/config
volumes:
- name: secret-config
secret:
secretName: secret #对应secret名
查看
#进入pod查看 pod会自动解码base64
k exec -it pod-secret bash
高级存储(静态pv) 使用pv :pv是存储的抽象
pod直接绑定pv pv 在绑定nfs 让用户与底层存储隔离
还可以设置pod使用资源大小
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
capacity:
storage: 3Gi #该volume的总容量
accessModes:
- ReadWriteMany # 该volume可以被多个node上的pod挂载使用且都具有读写权限
persistentVolumeReclaimPolicy: Retain #该valume使用后被release之后的回收策略 也就是说pod被删除后的回收数据策略
nfs:
path: /root/data/nfs
server: 192.168.140.3
#查看pv
kubectl get pv -o wide
pvc 就是pod对pv的申请使用 系统自动匹配通过pvc申请空间的大小来匹配pv
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
namespace: test
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi #需要使用容量大小
#查看pvc
kubectl get pvc -n test
pod 挂载到pvc
apiVersion: v1
kind: Pod
metadata:
name: volume-pvc
namespace: test
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do echo pod1 >> /root/out.txt;sleep 10;done;"] #初始化命令,动态读取指定文件中内容
volumeMounts: # 将volume挂载到容器对应目录
- name: volume
mountPath: /root/
volumes: #声明数据卷 volume, name为数据卷名 类型为pvc
- name: volume
persistentVolumeClaim:
claimName: pvc1 #挂载的pvc名称
readOnly: false #是否只读
动态创建pv 通过创建StorageClass就像动态创建PV的模板,为创建pv对象提供必要的参数
要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner(制备器),这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
注意:StorageClass一旦被创建,就无法修改,如需修改,只能删除重建
先kubectl delete -f storage-class.yaml 在创建
storageClass模板
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-disk
# (存储分配器):用来决定使用哪个卷插件分配 PV,该字段必须指定。
可以指定内部分配器,也可以指定外部分配器指 定使用什么分配器来分配存储空间 由于使用minikube环境 所有使用minikube字段分配器 分配本地磁盘
provisioner: k8s.io/minikube-hostpath
# 卷绑定模式:该volumeBindingMode字段控制何时应该发生卷绑定和动态配置。未设置时,默认使用“立即”模式。
# 该Immediate模式指示一旦创建 PersistentVolumeClaim,就会发生卷绑定和动态供应。对于拓扑受限且无法从集群中的所有节点全局访问的存储后端,将在不知道 Pod 调度要求的情况下绑定或配置 PersistentVolume。这可能会导致不可调度的 Pod。
# 集群管理员可以通过指定模式来解决此问题,该WaitForFirstConsumer模式将延迟 PersistentVolume 的绑定和配置,直到创建使用 PersistentVolumeClaim 的 Pod。PersistentVolume 将根据 Pod 的调度约束指定的拓扑进行选择或配置
# 默认使用Immediate
volumeBindingMode: Immediate
# 回收策略
# Retain – 手动回收
# Recycle – 需要擦除后才能再次使用
# Delete – 当用户删除对应的 PersistentVolumeClaim 时,动态配置的 volume 将被自动删除
reclaimPolicy: Delete
基于nfs的storageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "false" #删除pv的时候,pv的内容是否要备份
查看命令:
#创建
k apply -f storage-class.yaml
#查看
k get storageclass
#简写
k get sc
#查看详情
k describe storageclass csi-disk
创建pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: disk-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 25Gi
storageClassName: csi-disk #使用storageClass模板创建pv
创建pod
apiVersion: v1
kind: Pod
metadata:
name: storage-pod
namespace: test
spec:
containers:
- name: nginx
image: nginx:1.79
ports:
- containerPort: 80
volumeMounts:
- name: disk-pvc
mountPath: /data
volumes:
- name: disk-pvc
persistentVolumeClaim:
claimName: disk-pvc #指定pvc名称
以上是通过minikube制备器创建的storageClass
下边是完整的 基于nfs创建的storageClass示例:
- 创建Service Account,这是用来管控NFS Provisioner 在k8s集群中运行的权限
rbac方式认证,授权 这里主要测试storageclass 直接 给Provisioner 以最高权限cluster-admin权限
# rbac.yaml:#唯一需要修改的地方只有namespace,根据实际情况定义
apiVersion: v1
kind: ServiceAccount # 创建一个账户,主要用来管理NFS provisioner在k8s集群中运行的权限
metadata:
name: nfs-client-provisioner
namespace: default
---
kind: ClusterRoleBinding # 集群角色绑定
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects: # 角色绑定对象
- kind: ServiceAccount
name: nfs-client-provisioner
namespace: default
roleRef:
kind: ClusterRole # 哪个角色
name: cluster-admin #k8s集群中最高权限的角色
apiGroup: rbac.authorization.k8s.io
2.创建storageClass 跟 创建NFS provisioner(制备器)
# nfs-provisioner.yaml
# 先创建NFS provisioner
apiVersion: apps/v1
kind: Deployment # 部署nfs-client-provisioner
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
namespace: default #与RBAC文件中的namespace保持一致
spec:
replicas: 1
strategy: # 指定更新策略 执行删除完毕一个创建一个
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner # 指定serviceAccount!
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 # 配置provisioner的Name
value: diy-nfs-storage # 确保该名称与 StorageClass 资源中的provisioner名称保持一致
- name: NFS_SERVER #绑定的nfs服务器
value: 192.168.140.131
- name: NFS_PATH #绑定的nfs服务器目录
value: /root/data/nfs #上边安装nfs服务器时的共享目录
volumes: # 申明nfs数据卷
- name: nfs-client-root
nfs:
server: 192.168.140.131
path: /root/data/nfs #上边安装nfs服务器时的共享目录
在创建strageClass
# 创建NFS资源的StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass # 创建StorageClass
metadata:
name: managed-nfs-storage
provisioner: diy-nfs-storage #这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
parameters:
archiveOnDelete: "false"
3.创建pod,申请PVC进行测试
# 申明一个PVC,指定StorageClass
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-claim
# annotations: #如果低版本使用注解绑定
# 通过annotations注解,和storage-class进行关联,为什么不使用storageClassName,因为版本比较低
# 这里指定的名字就是上面创建的StorageClass的名字,让它帮我们创建PV
#volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
storageClassName: managed-nfs-storage #绑定storageClass
如果pvc一直pending状态 查看制备器pod 报如下异常
k logs -f nfs-client-provisioner-6fb86fbbbc-72j7g
E0905 15:08:26.103331 1 controller.go:1004] provision "default/test-claim" class "managed-nfs-storage": unexpected error getting claim reference: selfLink was empty, can't make reference
原因如下:
如果是 v1.20 版本以上 apiserver 默认禁止使用 selfLink,需要手动配置- --feature-gates=RemoveSelfLink=false 开启。
修改kube-apiserver.yaml 文件:
[root@master nfs]# cat /etc/kubernetes/manifests/kube-apiserver.yaml
containers:
- command:
- kube-apiserver
- --advertise-address=192.168.25.100
- --feature-gates=RemoveSelfLink=false # 添加这条信息
- --allow-privileged=true
systemctl restart kubelet重启 kubelet 服务,然后查看 PVC,PV 信息,可以看到 PVC 申领 PV 卷成功。
注意: 如果不成功,仍然报这个错
可以使用 kubectl get pod -n kube-system 查看 kube-apiserver 是否启动成功
创建pod测试
apiVersion: v1
kind: Pod
metadata:
name: storage-pod
namespace: default
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: nfs-pvc
mountPath: /var/log/nginx
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: test-claim #指定pvc名称