9. kubernetes 存储卷
[TOC]
本文基于马哥的docker和k8s视频总结, 在此致谢马哥.
k8s上可以用的三种存储卷类型
emptyDir
-
(1)
emptyDir
只在节点本地使用, 且pod删除时存储卷会随之被删除, 用于当临时目录或缓存, 此存储卷可使用节点的内存一个存储卷可以在同一个pod内的多个容器间共享:
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
tier: frontend
annotations:
magedu.com/create-by: "cluster admin"
spec:
containers:
- name: myapp
image: nginx
ports:
- name: http
containerPort: 80
volumeMounts:
- name: html # 挂载名为html的存储卷 (需要使用下面存在的volumes)
mountPath: /usr/share/nginx/html/ # 挂载点路径
# 其他参数: readOnly, subPath, mountPropagation
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
volumeMounts: # 挂载是容器级别的, 哪个容器使用, 哪个容器就要挂载, 不挂载时访问不到数据
- name: html
mountPath: /data/ # 注意两个容器的挂载路径可以不同
command:
- "/bin/sh"
- "-c"
- "while true; done echo $(date) >> /data/index.html; sleep 10; done"
volumes:
- name: html
emptyDir: {} # 可以指定为空, 表示使用默认值(使用硬盘空间, 不限制使用大小)
# medium 指定使用的存储卷设备, 空字符串代表使用硬盘, Memory代表使用内存
# sizeLimit 指定使用的存储卷大小
kubectl apply -f vol-demo1.yml
kubectl exec -it pod-demo -c busybox -- /bin/sh
/ # echo $(date) >> /data/index.html
kubectl exec -it pod-demo -c myapp -- /bin/sh
/ # cat /data/web/html/index.html # 可以在另一个容器中看到共享的数据
kubect get pods -o wide # 查看pod的IP
curl pod_IP
hostPath
- (2)
hostPath
宿主机路径, 将pod上的存储卷与宿主机的目录做映射
apiVersion: v1
kind: Pod
metadata:
name: pod-hostpath-vol
namespace: default
spec:
containers:
- name: myapp
image: nginx:1.14:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
hostPath:
path: /data/pod/volume1/
type: DirectoryOrCreate # 目录不存在时自动创建
mkdir -p /data/pod/volume1/
echo "test hostPath" >> /data/pod/volume1/index.html # 只要节点上有相同内容, 则pod宕了也没关系
kubectl apply -f pod-hostpath-vol.yml
以nfs
为例
- (3) 共享存储, 支持
awsElasticBlockStore, azureDisk, cephfs, glusterfs, gitRepo, nfs, iscsi, rbd
等
# node1(ip为192.168.200.200)作为nfs服务的提供者
yum -y install nfs-utils # 作为nfs共享存储的节点需要安装此包
mkdir /data/volumes -pv
vi /etc/exports
/data/volumes 192.168.0.0/16(rw,no_root_squash)
systemctl start nfs
# node2(ip为192.168.200.201)作为nfs服务的使用者
yum -y install nfs-utils
mount -t nfs 192.168.200.200:/data/volumes /mnt # 一定要进行挂载测试
umount /mnt
vi pod-nfs-vol.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-nfs-vol
namespace: default
spec:
containers:
- name: myapp
image: nginx:1.14:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
nfs:
path: /data/pod/volumes
server:
192.168.200.201
readOnly: false # 默认就是false, 即rw
kubectl apply -f pod-nfs-vol.yml
注: nfs
支持多客户端同时挂载, 支持多客户端的多路读写访问
pvc和pv
pvc
和pv
也是标准的k8s资源
kubectl explain pods.spec.volumes.persistentVolumeClaim
claimName # 必要选项, 指明已创建好的pvc名称
readOnly # default false
kubectl explain pvc.spec
accessModes <[]string># 访问模型, 这里不可随便定义, 有些设备可能不支持某种模型
ReadWriteOnce # 单路读写, 可简写为RWO
ReadOnlyMany # 多路只读, 可简写为ROM
ReadWriteMany # 多路读写, 可简写为RWM
resources # 资源限制, 对应的存储空间至少需要的大小
selecotr # pv可以有标签, pvc上使用selector时表示必须使用哪个pv建立关联关系, 不加selector时自动选择最佳匹配
volumeMode # 后端存储卷的模式, 可以不指定
volumeName # 卷名称, 绑定某个pv, 可以不指定
kubectl explain pv.spec
accessModes <[]string># 访问模型, 这里不可随便定义, 有些设备可能不支持某种模型
ReadWriteOnce # 单路读写, 可简写为RWO
ReadOnlyMany # 多路只读, 可简写为ROM
ReadWriteMany # 多路读写, 可简写为RWM
capacity
创建
pvc
后会去找系统上合适的pv
进行绑定, 如果没有则挂起(pending), 例如pvc
需要使用30G, 而pv
现在最大创建的容量只有20G, 不满足条件, 操作被挂起, 直到满足条件pv
和pvc
是一一对应的关系, 如果某个pv
被pvc
占用了, 则这个pv
不能再被其他pvc
占用, 但一个pvc
可以被多个pod
访问
# node1(ip为192.168.200.200)作为nfs服务的提供者
yum -y install nfs-utils # 作为nfs共享存储的节点需要安装此包
mkdir /data/volumes -pv
vi /etc/exports
/data/volumes/v1 192.168.0.0/16(rw,no_root_squash)
/data/volumes/v2 192.168.0.0/16(rw,no_root_squash)
/data/volumes/v3 192.168.0.0/16(rw,no_root_squash)
/data/volumes/v4 192.168.0.0/16(rw,no_root_squash)
/data/volumes/v5 192.168.0.0/16(rw,no_root_squash)
exportfs -arv
showmount -e
# node2(ip为192.168.200.201)作为nfs服务的使用者
yum -y install nfs-utils
mount -t nfs 192.168.200.200:/data/volumes /mnt # 一定要进行挂载测试
umount /mnt
vi pod-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001 # 定义pv时千万不要定义namespace, 因为pv是集群级别的, 不属于namespace
labels:
name: pv001
spec:
nfs:
path: /data/volumes/v1
server: 192.168.200.200
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: 192.168.200.200
accessModes: ["ReadWriteMany"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: 192.168.200.200
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 20Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/volumes/v4
server: 192.168.200.200
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: 192.168.200.200
accessModes: ["ReadWriteMany", "ReadWriteOnce"]
capacity:
storage: 10Gi
---
kubectl apply -f pod-pv.yml
kubectl get pv
# RECLAIM POLICY 回收策略, 某个pvc绑定了pv, 当pvc被删除后pv内还有数据, 该如何处理?
# Retain 保留数据
# Recycle 回收
# Delete 删除
vi pod-pvc.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: mypvc
namespace: default
spec:
accessModes: ["ReadWriteMany"] # pvc的accessModes必须是pv的子集
resources:
requests: # 要求有多大的存储空间
storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
name: pod-vol-pvc
namespace: default
spec:
containers:
- name: myapp
image: nginx:1.14:alpine
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
volumes:
- name: html
persistentVolumeClaim:
claimName: mypvc
kubeclt apply -f pod-pvc.yml
kubectl get pv # 可查看STATUS, 是否被Bound
kubectl get pvc
特殊类型的存储卷: 用于制作数据中心
配置容器化应用的方式有以下几种:
- (1) 自定义命令行参数
command
args: []
- (2) 把配置文件直接放入基本镜像并重构
- (3) 环境变量
- (3.1) Could Native的应用程序一般可直接通过环境变量加载配置
- 通过
entrypoint
脚本来预处理变量为配置文件中配置信息
- (4) 存储卷
- (4.1)
configmap
: 明文 - (4.2)
secret
: 密文
- (4.1)
configmap
# 创建configmap的方式:
# 第一种: 直接直接用命令行的方式给定
kubectl create configmap nginx-config --from-literal=nginx_port=80 --from-ilteral=server_name=myapp.magedu.com
# --from-literal=key=value 直接用命令行的方式给定
kubectl get cm
kubectl describe cm nginx-config
# 可在显示信息中看到Data (定义的key和value)
# 第二种: 配置文件给定
mkdir configmap
vi www.conf
server {
server_name myapp.magedu.com;
listen 80;
root /data/web/html/;
}
kubectl create configmap nginx-www --from-file=www=./www.conf
# 按这种方式指定, key=www, value=www.conf的文件内容
kubectl create configmap nginx-www --from-file=./www.conf
# 按照这种方式指定, key=文件名(此例中为www.conf), value=www.conf的文件内容
kubectl descirbe cm nginx-www
vi pod-configmap.yml
- 通过
环境变量
的方式向pod传数据:
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-1
namespace: default
labels:
app: myapp
tier: frontend
annotations:
alexti/created-by: "cluster admin"
spec:
containers:
- name: myapp
image: nginx:1.14-alpine
ports:
- name: http
containerPort: 80
env:
- name: NGINX_SERVER_PORT # 变量最好使用下划线
valueFrom:
configMapKeyRef: # 引用configmap获取数据
name: nginx-config
key: nginx_port # nginx_port的值会传递给变量NGINX_SERVER_PORT
optional: true # 如果configmap不存在或者configmap中定义的变量没有你需要使用的key, pod将无法被启动, 可以将这一项的值设置为true, 表示此configmap可以在定义完之后再创建
- name: NGINX_SERVER_NAME
valueFrom:
configMapKeyRef:
name: nginx-conf
key: server_name
optional: true
kubectl apply -f pod-configmap.yml
kubectl exec -it pod pod-demo-1 -- /bin/sh
/ # printenv # 可查看到自定义的变量: NGINX_SERVER_PORT和NGINX_SERVER_NAME
kubectl edit cm nginx-config # 支持编辑
- 通过
存储卷
的方式向pod传数据:
方法一, 使用命令行
创建的configmap
:
vi pod-configmap2.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-2
namespace: default
labels:
app: myapp
tier: frontend
annotations:
alexti/created-by: "cluster admin"
spec:
containers:
- name: myapp
image: nginx:1.14-alpine
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/config.d/
readOnly: true # 不允许容器修改配置文件
volumes:
- name: nginxconf
configMap: # 存储卷类型为configMap
name: nginx-config
kubectl apply -f pod-configmap2.yml
kubectl exec -it pod pod-demo-2 -- /bin/sh
/ # cd /etc/nginx/config.d/
/ # ls # 可以查看到两个文件, 文件名为nginx_port和server_name
kubectl edit cm nginx-config
# 将nginx_port从80改为8080
kubectl exec -it pod pod-demo-2 -- /bin/sh
/ # cat /etc/nginx/config/nginx_port # 此时可以查看到结果为修改后的8080
方法二, 使用创建的配置文件
:
vi pod-configmap3.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-3
namespace: default
labels:
app: myapp
tier: frontend
annotations:
alexti/created-by: "cluster admin"
spec:
containers:
- name: myapp
image: nginx:1.14-alpine
ports:
- name: http
containerPort: 80
volumeMounts:
- name: nginxconf
mountPath: /etc/nginx/conf.d/
readOnly: true # 不允许容器修改配置文件
volumes:
- name: nginxconf
configMap: # 存储卷类型为configMap
name: nginx-www
# 指定items可以只挂载部分键值而不是全部
kubecgtl apply -f pod-configmap3.yml
kubectl get pods
kuebctl exec -it pod-demo-3 -- /bin/sh
/ # cat /etc/nginx/conf.d/www.conf # 可看到使用配置文件定义的配置
/ # nginx -T # 查看nginx加载的配置
kubectl edit cm nginx-www
# 将某个参数修改, 例如listen的值改为8080, 等待一段时间后会发现pod内的配置会随之修改为8080, 但此时配置还未生效, 需要重载配置文件
/ # nginx -s reload
secret
kubectl create secret --help
# 有三种类型
generic # 通用的secret, 一般用于保存密码
tls # 保存私钥和证书
docker-registry # 保存docker-registry认证信息, 连接私有仓库时拉取镜像时使用
kubectl create secret generic mysql-root-password --form-literal=password=MyP@ss123
kubectl get secret
kubectl descirbe secret mysql-root-password # 会发现值不显示
kubectl get secret mysql-root-password -o yaml
echo "经base加密后的密码" | base64 -d # 解码, 可看到密码源码, 说明密码安全性不佳
vi pod-secret-1.yml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo-4
namespace: default
labels:
app: myapp
tier: frontend
annotations:
alexti/created-by: "cluster admin"
spec:
containers:
- name: myapp
image: nginx:1.14-alpine
ports:
- name: http
containerPort: 80
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-root-password
key: password
optional: true
kubectl apply -f pod-secret-1.yml
kubectl exec -it pod-demo-4 -- printenv # 会发现传入的MYSQL_ROOT_PASSWORD在会解密后通过环境变量的方式注入pod