7、存储抽象
pod如果挂掉,在其他的机器启动新pod,原来pod的数据是无法迁移到新机器的;所以使用单独的存储层来解决。
将节点上的文件或目录挂载到pod上,此时该目录会变成持久化存储目录,即使Pod被删除后重启,也可以重新加载到该目录,该目录下的文件不会丢失。
nfs卷能将NFS(网络文件系统)挂载到你的pod中,不像emptyDir那样会在删除pod的同时也会被删除,nfs卷的内容在删除pod时会被保留,卷只是被卸载。这意味这nfs卷可以被预先填充数据,并且这些数据可以在pod之间共享。
环境准备
1、所有节点
#所有机器安装
yum install -y nfs-utils
2、主节点
#nfs主节点
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
mkdir -p /nfs/data
systemctl enable rpcbind --now
systemctl enable nfs-server --now
#配置生效
exportfs -r
exportfs
3、从节点
showmount -e 192.168.183.134 #master的ip地址
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir -p /nfs/data
#挂载到主节点的目录
mount -t nfs 192.168.183.134:/nfs/data /nfs/data
在master节点执行
# 写入一个测试文件
echo "hello nfs server" > /nfs/data/test.txt
然后看从节点,已经看到了同步过来的文件text.txt
4、原生方式数据挂载
先创建目录/nfs/data/nginx-pv
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 1
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
server: 192.168.183.134
path: /nfs/data/nginx-pv
kubectl apply -f nfs-mount.yaml #执行
发现挂载的pod
/usr/share/nginx/html/index.html 内容和外面/nfs/data/nginx-pv/index.html 一模一样
5、HostPath的使用
apiVersion: v1
kind: Pod
metadata:
name: test-volume-pd
spec:
containers:
- image: nginx
name: nginx-volume
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
path: /data
type: DirectoryOrCreate
kubectl apply -f test-volume-pd.yaml #执行
在work1 的/data目录下创建touch index.html ,内容为空
kubectl exec -it test-volume-pd -- sh #主节点进入到pod中
从主节点写入,然后去work1看下/data目录下的内容,已经同步过来了
然后work1写入
再去主节点的pod内看下内容,发现内容也同步过来了
6、EmptyDir
主要用于一个pod中不同的Container共享数据使用的,由于只是在pod内部使用,因此与其他volume比较大的区别是,当pod如果被删除了,那么emnptyDir也会被删除。不能做持久化存储
存储介质可以是任意类型,如SSD,磁盘或者网络存储。可以将emptyDir.medium设置为Memory,让k8s使用tmpfs(内存支持文件系统), 速度比较快,但是重启tmpfs节点时,数据会被清除,且设置的大小会计入到Container的内存限制中。
1、PV&PVC
上面挂载的方式有一个问题 :
1.pod如果删除,那么外面目录/nfs/data目录下的内容并不会被清理掉
2.pod使用的存储空间没有限制
PV:持久卷(Persistent Volume),将应用需要持久化的数据保存到指定位置
PVC:持久卷声明(Persistent Volume Claim),申明需要使用的持久卷规格
当用户创建一个pvc对象洪湖,主节点会检测新的pvc对象,并且寻找与之匹配的pv卷,找到pv卷后将二者绑定在一起
如果找不到对应的pv,则需要看pvc是否设置storageClass来决定是否动态创建pv,若没有配置,pvc就会一直处于未绑定状态,直到有与之匹配的pv后才会申领绑定关系。pod没绑定之前是无法启动的。
pod一旦使用pvc绑定pv后,为了保护数据,避免数据丢失问题,pv对象会受到保护,在系统内无法被删除。
1、创建pv池
静态供应
#nfs主节点
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03
创建PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m
spec:
capacity:
storage: 10M
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/01
server: 192.168.183.134
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02-1gi
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/02
server: 192.168.183.134
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
path: /nfs/data/03
server: 192.168.183.134
kubectl apply -f pv.yaml执行
2、PVC创建与绑定
创建PVC
vi pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs
发现申请成功
还可以删除pvc 再重新申请
创建Pod绑定PVC vi pod-pvc.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-pvc
name: nginx-deploy-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deploy-pvc
template:
metadata:
labels:
app: nginx-deploy-pvc
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc
kubectl exec -it nginx-deploy-pvc-64747758f9-4sxnf -- /bin/ba
StorageClass
2、ConfigMap
抽取应用配置,并且可以自动更新
1、redis示例
1、把之前的配置文件创建为配置集
vi redis.conf
appendonly yes
# 创建配置,redis保存到k8s的etcd;
kubectl create cm redis-conf --from-file=redis.conf
这个配置集configmap,存储在k8s的etcd中;这样就把刚才的配置文件做成了k8s的配置集
kubectl get cm redis-conf -oyaml
精简后如下
apiVersion: v1
data: #data是所有真正的数据,key:默认是文件名 value:配置文件的内容
redis.conf: |
appendonly yes
kind: ConfigMap
metadata:
name: redis-conf
namespace: default
只要增加immutable:true 就把这个configMap设置为不可变
2、创建Pod
vi redis.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
command:
- redis-server
- "/redis-master/redis.conf" #指的是redis容器内部的位置
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-conf
items:
- key: redis.conf
path: redis.conf
执行上面的redis配置
kubectl apply -f redis.yaml
已经创建好了redis的pod
进到redis的pod里面看配置内容
也可以在外面编辑配置集内容
kubectl edit configmap redis-conf
增加了一行
此时再进入容器看,增加的配置已经同步
3、检查默认配置
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET appendonly
127.0.0.1:6379> CONFIG GET requirepass
requirepass的配置 需要等重启后才能生效
4、修改ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
5、检查配置是否更新
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
127.0.0.1:6379> CONFIG GET maxmemory-policy
检查指定文件内容是否已经更新
修改了CM。Pod里面的配置文件会跟着变
配置值未更改,因为需要重新启动 Pod 才能从关联的 ConfigMap 中获取更新的值。
原因:我们的Pod部署的中间件自己本身没有热更新能力
3、Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
kubectl create secret docker-registry leifengyang-docker \
--docker-username=leifengyang \
--docker-password=Lfy123456 \
--docker-email=xxxxxxx@qq.
##命令格式
kubectl create secret docker-registry regcred \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: leifengyang/guignginx:v1.0
imagePullSecrets:
- name: leifengyang-docker
4、CronJob 高级调度
在k8s中周期性运行计划任务,与linux中的crontab相同
注意点:cronjob执行的时间是controller-manager的时间,所以一定要确保controller-manager的时间是准确的
创建一个 名为my-cronjob的Kubernetes CronJob定时任务,使用 busybox 镜像作为容器镜像,执行每分钟一次的定时任务,任务是打印当前日期和休眠10秒钟
apiVersion: batch/v1
kind: CronJob
metadata:
creationTimestamp: null
name: my-cronjob
spec:
jobTemplate:
metadata:
creationTimestamp: null
name: my-cronjob
spec:
template:
metadata:
creationTimestamp: null
spec:
terminationGracePeriodSeconds: 0
containers:
- command:
- sh
- -c
- date;sleep 10
image: busybox
imagePullPolicy: IfNotPresent
name: my-cronjob
resources: {}
restartPolicy: OnFailure
schedule: '*/1 * * * *'
status: {}
kubectl apply -f crontab.yaml #执行
可以看到每分钟都启动一个cronjob的pod执行,执行完成后变成completed
5、初始化容器 initContainer
6、污点和容忍
污点:是标注在节点上的,在一个节点打上污点以后,k8s会认为尽量不要将pod调度到该节点上,除非该pod上面表示可以容忍该污点,且一个节点可以打多个污点。此时则需要该pod容忍所有污点才会被调度该节点。
kubectl taint node work1 key=value:NoSchedule #打上污点
kubectl taint node work1 key=value:NoSchedule- #移除污点
NoExecute的含义
Equal的用法
Exists的用法
下面实战打污点
kubectl taint node work1 memory=low:NoSchedule
kubectl describe node work1 #查看work1的详细信息
可以看到node被打上了污点
master节点原本就打上了污点,所以不能调度
如果打污点
kubectl taint node work1 memory=low:No
可以看见驱逐的现象,删掉污点后,pod调度运行恢复正常
在deployment的yaml配置中,增加容忍的配置,重新执行
就可以发现node2又开始运行pod了
如果使用Exists配置,就不需要value了,配置key即可
7、亲和力
下面看一个亲和力的yaml配置
优先调度到weight:50的
pod亲和力:将与指定pod亲和力匹配的pod部署在同一节点
pod反亲和力:根据策略,尽量不部署到一起