Kubernetes
存储卷管理
临时卷
卷概述
卷是一个抽象化的存储设备
容器中的文件在磁盘上都是临时存放的,这给容器中运行的重要程序带来一些问题
- 当容器奔溃或重启的时候,kubelet会以干净的镜像状态重启容器,容器内的历史数据会丢失
- 当容器被删除(K8S没有停止容器的概念,只有创建、删除),容器内的数据会被一起清理
- 多个容器中有共享文件或目录的需求
Kubernetes支持很多类型的卷
Pod可以同时使用任意数目的卷类型
Pod中的容器在奔溃或重启之后数据都不会丢失
临时卷
临时卷的生命周期与Pod相同,当Pod不存在时,K8S也会销毁临时卷
持久卷
当Pod执行结束或被删除以后,K8S不会销毁持久卷
如何使用卷?
使用卷时,在spec,volumes字段中设置为Pod提供的卷,并在spec,containers下volumeMounts字段中声明在容器中的挂载位置
卷挂载在镜像中指定路径下,Pod配置中的每个容器必须独立指定各个卷的挂载位置
卷不能挂载到其它卷之上,也不能与其它卷有硬链接
emptyDir卷
一种临时卷,本质是一个简单的空目录
当Pod被创建时,emptyDir也会被创建,并且和Pod在该节点上运行期间,一直存在。当Pod被从节点上删除时,emptyDir中的数据也会被永久删除
emptyDir的用途:临时空间,例如缓存服务器、数据统计分析、归并排序
同一个Pod中容器共享数据
统计访问量(案例1)
[root@master ~]# vim myv1.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web1
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: logs
emptyDir: {}
containers:
- name: nginx
image: myos:nginx
volumeMounts:
- name: logs
mountPath: /usr/local/nginx/logs
ports:
- protocol: TCP
containerPort: 80
- name: log
image: myos:v2009
volumeMounts:
- name: logs
mountPath: /logdata
command: ["/bin/bash"]
args:
- -c
- |
while true;do
awk '{IP[$1]++}END{for(i in IP)print(i,IP[i])}' /logdata/access.log
sleep 60
done
[root@master ~]# kubectl apply -f myv1.yaml
pod/web1 created
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web1 2/2 Running 0 59s 10.244.3.50 node-0003
[root@master ~]# curl -s http://10.244.3.50
[root@master ~]# curl -s http://10.244.3.50
[root@master ~]# curl -s http://10.244.3.50
Nginx is running !
[root@master ~]# kubectl logs web1 -c log
10.244.0.0 3
configMap卷
一种临时卷
configMap提供了向Pod注入配置数据的方法,允许你将配置文件与镜像分离,使容器化的应用具有可移植性
configMap在使用之前需要先创建它,configMap不是用来保存大量数据的,在其中保存的数据不得超过1M
configMap的用途:定义临时环境变量
修改各种配置文件的参数,数据库的地址,用户名密码等
设置容器变量
# 使用变量创建 configMap
[root@master ~]# kubectl create configmap mycm1 --from-literal=x=123 --from-literal=y=456
configmap/mycm1 created
# 查看 configMap
[root@master ~]# kubectl get configmaps
NAME DATA AGE
kube-root-ca.crt 1 2d5h
mycm1 1 54s
# 引用 configMap 设置环境变量
[root@master ~]# vim myv2.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web2
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
envFrom:
- configMapRef:
name: mycm1
[root@master ~]# kubectl apply -f myv2.yaml
pod/web2 created
[root@master ~]# kubectl exec -it web2 -- /bin/bash
[root@web1 html]# echo ${x},${y}
123,456
配置系统时区
[root@master ~]# vim myv2.yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
name: timezone
data:
TZ: "Asia/Shanghai"
---
apiVersion: v1
kind: Pod
metadata:
name: web2
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
envFrom:
- configMapRef:
name: timezone
[root@master ~]# kubectl delete -f myv2.yaml
pod "web2" deleted
[root@master ~]# kubectl apply -f myv2.yaml
configmap/timezone created
pod/web2 created
[root@master ~]# kubectl exec -it web2 -- /bin/bash
[root@web2 html]# date +%T
配置Nginx解析PHP
# 拷贝 5/public/info.php 到 master 主机,创建测试页面
[root@master ~]# mkdir webphp
[root@master ~]# echo "Hello Nginx ." >webphp/info.html
[root@master ~]# cp info.php webphp/
# 把目录做 configMap
[root@master ~]# kubectl create configmap website --from-file=webphp
configmap/website created
# 修改 nginx 配置文件,并做成 ConfigMap
[root@master ~]# kubectl cp web2:/usr/local/nginx/conf/nginx.conf ./nginx.conf
[root@master ~]# vim nginx.conf
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
[root@master ~]# kubectl create configmap webconf --from-file=nginx.conf
configmap/webconf created
[root@master ~]# kubectl get configmaps
NAME DATA AGE
timezone 1 73m
webconf 1 5s
website 2 4m18s
修改Pod配置文件
[root@master ~]# vim myv2.yaml
---
kind: ConfigMap
apiVersion: v1
metadata:
name: timezone
data:
TZ: "Asia/Shanghai"
---
apiVersion: v1
kind: Pod
metadata:
name: web2
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: myphp
configMap:
name: website
- name: webconf
configMap:
name: webconf
containers:
- name: nginx
image: myos:nginx
volumeMounts:
- name: myphp
mountPath: /usr/local/nginx/html/myphp
- name: webconf
subPath: nginx.conf
mountPath: /usr/local/nginx/conf/nginx.conf
ports:
- protocol: TCP
containerPort: 80
envFrom:
- configMapRef:
name: timezone
- name: php
image: myos:phpfpm
volumeMounts:
- name: myphp
mountPath: /usr/local/nginx/html/myphp
envFrom:
- configMapRef:
name: timezone
[root@master ~]# kubectl delete -f myv2.yaml
pod "web2" deleted
[root@master ~]# kubectl apply -f myv2.yaml
pod/web2 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web2 2/2 Running 0 7s 10.244.3.13 node-0003
[root@master ~]# curl http://10.244.3.13/myphp/info.php
<pre>
Array
(
[REMOTE_ADDR] => 10.244.0.0
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /info.php
)
php_host: web2
1229
保护敏感数据(案例2)
# 修改 nginx.conf 配置文件,启用认证
[root@master ~]# vim nginx.conf
location ~ ^/myphp/.+\.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
auth_basic "Website Admin";
auth_basic_user_file "/usr/local/nginx/conf/webauth";
}
[root@master ~]# kubectl delete configmaps webconf
configmap "webconf" deleted
[root@master ~]# kubectl create configmap webconf --from-file=nginx.conf
configmap/webconf created
# 修改 configmap 之后重建 Pod
[root@master ~]# kubectl delete -f myv2.yaml
configmap "timezone" deleted
pod "web2" deleted
[root@master ~]# kubectl apply -f myv2.yaml
configmap/timezone created
pod/web2 created
# 创建认证文件
[root@master ~]# kubectl exec -it web2 -c nginx -- /bin/bash
[root@web2 html]# yum install -y httpd-tools
[root@web2 html]# htpasswd -nbm admin 123456 >/usr/local/nginx/conf/webauth
[root@web2 html]# exit
# 访问验证
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web2 2/2 Running 0 100s 10.244.2.20 node-0002
[root@master ~]# curl http://10.244.2.20/myphp/info.html
Nginx is running !
[root@master ~]# curl http://10.244.2.20/myphp/info.php
<html>
<head><title>401 Authorization Required</title></head>
<body>
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.17.6</center>
</body>
</html>
[root@master ~]# curl -u admin:123456 http://10.244.2.20/myphp/info.php
<pre>
Array
(
[REMOTE_ADDR] => 127.0.0.1
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /myphp/info.php
)
php_host: web
1229
secret卷
一种临时卷
secret类似于configMap但专门用于保存机密数据
在设置secret的data字段时,所有键值都必须是经过base64编码的字符串
secret用途:为容器配置环境变量
挂载配置文件/目录到容器
由kubelet在为Pod拉取镜像时使用(需要登录的仓库)
[root@master ~]# kubectl create secret generic mysecret --from-literal=username=admin --from-literal=password=123456
secret/mysecret created
[root@master ~]# kubectl get secrets
NAME TYPE DATA AGE
default-token-qw9b9 kubernetes.io/service-account-token 3 5d1h
mysecret Opaque 2 54s
[root@master ~]# kubectl get secrets mysecret -o yaml
apiVersion: v1
data:
password: MTIzNDU2
username: YWRtaW4=
kind: Secret
metadata:
creationTimestamp: "2022-09-03T09:51:10Z"
name: mysecret
namespace: default
resourceVersion: "288864"
uid: fec7e9bc-f957-40b5-ab7a-0382c75c3224
type: Opaque
Pod 映射 secret
[root@master ~]# vim myv3.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web3
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
envFrom:
- secretRef:
name: mysecret
[root@master ~]# kubectl apply -f myv3.yaml
pod/web3 created
[root@master ~]# kubectl exec -it web3 -- /bin/bash
[root@web3 html]# echo ${username},${password}
admin,123456
[root@master ~]# kubectl delete -f myv3.yaml
pod "web3" deleted
[root@master ~]# kubectl delete secrets mysecret
secret "mysecret" deleted
为案例2配置用户名密码
# 生成加密 base64 数据
[root@master ~]# kubectl exec -it web2 -c nginx -- /bin/bash
[root@web2 html]# yum install -y httpd-tools
[root@web2 html]# htpasswd -nbm admin 123456 |base64
YWRtaW46JGFwcjEkdGJqOXJISUckdk9DRFpDaFZJUHl0ZHdGSXl1Qm91MAoK
[root@web2 html]# exit
# 使用 secret 设置密码
[root@master ~]# vim myv2.yaml
---
kind: Secret
apiVersion: v1
metadata:
name: myauth
type: Opaque
data:
webauth: YWRtaW46JGFwcjEkdGJqOXJISUckdk9DRFpDaFZJUHl0ZHdGSXl1Qm91MAoK
---
kind: ConfigMap
apiVersion: v1
metadata:
name: timezone
data:
TZ: "Asia/Shanghai"
---
apiVersion: v1
kind: Pod
metadata:
name: web2
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: myphp
configMap:
name: website
- name: webconf
configMap:
name: webconf
- name: webauth
secret:
secretName: myauth
items:
- key: webauth
path: webauth
mode: 0644
containers:
- name: nginx
image: myos:nginx
volumeMounts:
- name: myphp
mountPath: /usr/local/nginx/html/myphp
- name: webconf
subPath: nginx.conf
mountPath: /usr/local/nginx/conf/nginx.conf
- name: webauth
subPath: webauth
mountPath: /usr/local/nginx/conf/webauth
ports:
- protocol: TCP
containerPort: 80
envFrom:
- configMapRef:
name: timezone
- name: php
image: myos:phpfpm
volumeMounts:
- name: myphp
mountPath: /usr/local/nginx/html/myphp
envFrom:
- configMapRef:
name: timezone
[root@master ~]# kubectl delete pod web2
pod "web2" deleted
[root@master ~]# kubectl apply -f myv2.yaml
configmap/timezone created
secret/myauth created
pod/web2 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web2 2/2 Running 0 4s 10.244.3.22 node-0003
[root@master ~]# curl -u admin:123456 http://10.244.3.22/myphp/info.php
<pre>
Array
(
[REMOTE_ADDR] => 10.244.0.0
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.29.0
[REQUEST_URI] => /myphp/info.php
)
php_host: web2
1229
持久卷
hostPath卷
hostPath卷的本质是使用本地设备,例如磁盘,分区、目录、Socket、CharDevice、BlockDevice等hostPath卷的可用性取决于底层节点的可用性,如果节点变得不健康,那么hostPath卷也将不可被访问
hostPath卷里面的数据不会随着Pod技术而消失
#配置相同的Pod,可能在不同的节点上表现不同,因为不同节点上映射的文件内容不同
[root@master ~]# vim myv5.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web5
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: mydata
hostPath:
path: /var/log
type: DirectoryOrCreate
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
volumeMounts:
- name: mydata
mountPath: /log
[root@master ~]# kubectl apply -f myv5.yaml
pod/web5 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web5 1/1 Running 0 4s 10.244.2.28 node-0002
[root@master ~]# kubectl exec -it web5 -- /bin/bash
# 在不同的预节点显示的数据不同
[root@web5 data]# cat /log/messages
... ...
# 创建的数据可以永久保存,即使 Pod 被删除也不会丢失
[root@web5 data]# echo "hello world" >/log/myfile.txt
[root@master ~]# kubectl delete -f myv5.yaml
pod "web5" deleted
[root@node-0002 ~]# cat /var/log/myfile.txt
hello world
NFS卷
NFS是持久卷
NFS卷的内容在删除Pod时会被卸载(umount),而不是被删除NFS卷可以在不同节点的Pod共享数据
NFS卷的用途:NFS最大的功能就是在不同节点的不同Pod中共享读写数据,本地NFS客户端可以透明的读写位于远端NFS服务器的文件,就像访问本地文件一样
搭建NFS服务器
# 搭建 NFS 服务
[root@registry ~]# yum install -y nfs-utils
[root@registry ~]# mkdir -m 0777 /var/webroot
[root@registry ~]# echo "This is NFS server" >/var/webroot/index.html
[root@registry ~]# echo -e "/var/webroot\t*(rw)" >/etc/exports
[root@registry ~]# systemctl enable --now nfs
# 在 master 上验证服务
[root@master ~]# yum install -y nfs-utils
[root@master ~]# showmount -e registry
Export list for registry:
/var/webroot *
# 在所有节点安装 NFS 模块
[root@node-0001 ~]# yum install -y nfs-utils
[root@node-0002 ~]# yum install -y nfs-utils
[root@node-0003 ~]# yum install -y nfs-utils
搭建NFS服务器
[root@master ~]# vim myv6.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web6
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: website
nfs:
server: registry
path: /var/webroot
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
volumeMounts:
- name: website
mountPath: /usr/local/nginx/html
[root@master ~]# kubectl apply -f myv6.yaml
pod/web6 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web6 1/1 Running 0 3s 10.244.1.18 node-0001
[root@master ~]# curl http://10.244.1.18/
This is NFS server
# 清理实验 Pod
[root@master ~]# kubectl delete -f myv6.yaml
pod "web6" deleted
PV/PVC
PV的全称是Persistent Volume,是持久卷
PVC的全称是PersistentVolumeClaim,是持久卷声明
PV/PVC的用途:存储的管理是一个与计算实例的管理完全不同的话题。管理员希望能提供一种通用的API来完成Pod对卷的部署管理与使用。PV/PVC就是为了满足这种需求而诞生的,PV/PVC的引入使集群具备了存储的逻辑抽象能力
持久卷(PV)
[root@master ~]# vim pv.yaml
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-local
spec:
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
capacity:
storage: 30Gi
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /var/weblog
type: DirectoryOrCreate
---
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-nfs
spec:
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
- ReadOnlyMany
- ReadWriteMany
capacity:
storage: 20Gi
persistentVolumeReclaimPolicy: Retain
nfs:
server: registry
path: /var/webroot
[root@master ~]# kubectl apply -f pv.yaml
persistentvolume/pv-local created
persistentvolume/pv-nfs created
[root@master ~]# kubectl get persistentvolume
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv-local 30Gi RWO Retain Available 2s
pv-nfs 20Gi RWO,ROX,RWX Retain Available 2s
持久卷声明(PVC)
[root@master ~]# vim pvc.yaml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc1
spec:
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 18Gi
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc2
spec:
volumeMode: Filesystem
accessModes:
- ReadWriteMany
resources:
requests:
storage: 15Gi
[root@master ~]# kubectl apply -f pvc.yaml
persistentvolumeclaim/pvc1 created
persistentvolumeclaim/pvc2 created
[root@master ~]# kubectl get persistentvolumeclaims
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc1 Bound pv-local 30Gi RWO 8s
pvc2 Bound pv-nfs 20Gi RWO,ROX,RWX 8s
Pod 调用 PVC
[root@master ~]# cat myv7.yaml
---
apiVersion: v1
kind: Pod
metadata:
name: web7
spec:
terminationGracePeriodSeconds: 0
restartPolicy: Always
volumes:
- name: logdata
persistentVolumeClaim:
claimName: pvc1
- name: website
persistentVolumeClaim:
claimName: pvc2
containers:
- name: nginx
image: myos:nginx
ports:
- protocol: TCP
containerPort: 80
volumeMounts:
- name: logdata
mountPath: /usr/local/nginx/logs
- name: website
mountPath: /usr/local/nginx/html
[root@master ~]# kubectl apply -f myv7.yaml
pod/web7 created
[root@master ~]# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
web7 1/1 Running 0 19s 10.244.1.20 node-0001
[root@master ~]# curl http://10.244.1.20/
This is NFS server
[root@master ~]# kubectl delete -f myv7.yaml
pod "web7" deleted
[root@node-0001 ~]# cat /var/weblog/access_log
10.244.0.0 - - [27/Jun/2022:02:00:12 +0000] "GET / HTTP/1.1" 200 19 "-" "curl/7.29.0"
10.244.0.0 - - [27/Jun/2022:02:00:14 +0000] "GET / HTTP/1.1" 200 19 "-" "curl/7.29.0"