一、回调HOOK
Pod Hook 是由 kubelet 发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。
- PostStart:这个钩子在容器创建后立即执行。但是,并不能保证钩子将在容器ENTRYPOINT之前运行,因为没有参数传递给处理程序。主要用于资源部署、环境准备等。不过需要注意的是如果钩子花费太长时间以至于不能运行或者挂起, 容器将不能达到running状态。
- PreStop:这个钩子在容器终止之前立即被调用。它是阻塞的,意味着它是同步的, 所以它必须在删除容器的调用发出之前完成。主要用于优雅关闭应用程序、通知其他系统等。如果钩子在执行期间挂起, Pod阶段将停留在running状态并且永不会达到failed状态。
如果PostStart或者PreStop钩子失败, 它会杀死容器。所以我们应该让钩子函数尽可能的轻量。当然有些情况下,长时间运行命令是合理的, 比如在停止容器之前预先保存状态 。
1.回调钩子
#1.poststart:启动回调钩子,是在容器启动之后立即执行
apiVersion: apps/v1
kind: Deployment
metadata:
name: lifecycle
spec:
selector:
matchLabels:
app: cycle
template:
metadata:
labels:
app: cycle
spec:
nodeName: gdx2
containers:
- name: nginx
image: nginx
volumeMounts: #定义存储卷
- mountPath: /usr/share/nginx/html #容器内挂载路径
name: lifecycle-data
lifecycle: #生命周期
postStart: #启动回调钩子
exec:
command: #执行命令
- "/bin/bash"
- "-c"
- "echo 'This is Lifecycle' > /usr/share/nginx/html/index.html"
preStop: #结束回调钩子
exec:
command: #执行命令
- "/bin/bash"
- "-c"
- "echo 'This is Lifecycle preStop' > /usr/share/nginx/html/index.html"
volumes: #定义宿主机存储卷
- name: lifecycle-data
hostPath: #存储卷方式
path: /opt/discuz/data #宿主机挂载路径
#2.验证启动回调钩子
[root@k8s-master1 ~]# kubectl get pods -w -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
lifecycle-94b467df6-2grpm 1/1 Running 0 10m 10.244.1.35 gdx2 <none> <none>
[root@k8s-master1 ~]# curl 10.244.1.35
This is Lifecycle
#3.验证结束回调钩子
[root@k8s-master1 ~]# kubectl delete deployments.apps lifecycle
deployment.apps "lifecycle" deleted
[root@k8s-node1 discuz]# cat data/index.html
This is Lifecycle preStop
二、数据持久化
Pod是由容器组成的,而容器宕机或停止之后,数据就随之丢了,那么这也就意味着我们在做Kubernetes集群的时候就不得不考虑存储的问题,而存储卷就是为了Pod保存数据而生的。存储卷的类型有很多,我们常用到一般有四种:emptyDir,hostPath,NFS以及云存储(ceph, glasterfs…)等。
1.emptyDir(不能用来做数据持久化)
#emptyDir:是pod调度到节点上时创建的一个空目录,当pod被删除时,emptydir中数据也随之删除,emptydir常用于容器间分享文件,或者用于创建临时目录。
#实例
#编写配置清单
[root@k8s-master1 ~]# vim emptydir.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: emptydir
spec:
selector:
matchLabels:
app: emptydir
template:
metadata:
labels:
app: emptydir
spec:
containers:
- name: nginx
image: nginx
volumeMounts: #nginx容器挂载目录
- mountPath: /usr/share/nginx/nginx
name: test-emptydir
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
volumeMounts: #MySQL容器挂载目录
- mountPath: /usr/share/nginx
name: test-emptydir
volumes:
- name: test-emptydir
emptyDir: {}
#验证容器间的数据分享
#进入MySQL容器挂载的目录,创建文件
[root@k8s-master1 ~]# kubectl exec -it emptydir-5dc7dcd9fd-zrb99 -c mysql -- bash
root@emptydir-5dc7dcd9fd-zrb99:/# cd /usr/share/nginx/
root@emptydir-5dc7dcd9fd-zrb99:/usr/share/nginx# ls
root@emptydir-5dc7dcd9fd-zrb99:/usr/share/nginx# touch {1..10}
root@emptydir-5dc7dcd9fd-zrb99:/usr/share/nginx# ls
1 10 2 3 4 5 6 7 8 9
root@emptydir-5dc7dcd9fd-zrb99:/usr/share/nginx# exit
#进入nginx挂载的目录查看是否也有创建的文件
[root@k8s-master1 ~]# kubectl exec -it emptydir-5dc7dcd9fd-zrb99 -c nginx -- bash
root@emptydir-5dc7dcd9fd-zrb99:/# cd /usr/share/nginx/nginx/
root@emptydir-5dc7dcd9fd-zrb99:/usr/share/nginx/nginx# ls
1 10 2 3 4 5 6 7 8 9
2.hostpath
hostPath类型则是映射node文件系统中的文件或者目录到pod里。在使用hostPath类型的存储卷时,也可以设置type字段,支持的类型有文件、目录、File、Socket、CharDevice和BlockDevice。
#hostPath类似于docker -v参数,将宿主主机中的文件挂载pod中,但是hostPath比docker -v参数更强大,(Pod调度到哪个节点,则直接挂载到当前节点上)
#实例
#编写配置清单
kind: Deployment
apiVersion: apps/v1
metadata:
name: hostpath
spec:
selector:
matchLabels:
app: hostpath
template:
metadata:
labels:
app: hostpath
spec:
nodeName: k8s-m-01
containers:
- name: nginx
image: nginx
volumeMounts:
- mountPath: /usr/share/nginx/nginx
name: test-hostpath
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
volumeMounts:
- mountPath: /usr/share/nginx
name: test-hostpath
volumes:
- name: test-hostpath
hostPath:
path: /opt/hostpath
type: DirectoryOrCreate
1)hostpath 的type的种类
3.NFS
#NFS
nfs使得我们可以挂载已经存在的共享搭到我们的pod中
和emptydir不同的是,当pod被删除时,emptydir也会被删除。
nfs不会被删除,仅仅是解除挂在状态而已,这就意味着NFS能够允许我们提前对数据进行处理,而且这些数据可以在pod之间互相传递,并且nfs可以同时被多个pod挂载并进行读写。
#1.部署NFS(所有节点)
[root@k8s-master1 ~]# yum install nfs-utils.x86_64 -y
#2.配置
[root@kubernetes-master-01 nfs]# mkdir -p /nfs/v{1..10}
[root@kubernetes-master-01 nfs]# cat > /etc/exports <<EOF
/nfs/v1 172.16.0.0/16(rw,no_root_squash)
/nfs/v2 172.16.0.0/16(rw,no_root_squash)
/nfs/v3 172.16.0.0/16(rw,no_root_squash)
/nfs/v4 172.16.0.0/16(rw,no_root_squash)
/nfs/v5 172.16.0.0/16(rw,no_root_squash)
/nfs/v6 172.16.0.0/16(rw,no_root_squash)
/nfs/v7 172.16.0.0/16(rw,no_root_squash)
/nfs/v8 172.16.0.0/16(rw,no_root_squash)
/nfs/v9 172.16.0.0/16(rw,no_root_squash)
/nfs/v10 172.16.0.0/16(rw,no_root_squash)
EOF
#查看结果
[root@k8s-master1 ~]# exportfs -arv
exporting 172.16.0.0/16:/nfs/v10
exporting 172.16.0.0/16:/nfs/v9
exporting 172.16.0.0/16:/nfs/v8
exporting 172.16.0.0/16:/nfs/v7
exporting 172.16.0.0/16:/nfs/v6
exporting 172.16.0.0/16:/nfs/v5
exporting 172.16.0.0/16:/nfs/v4
exporting 172.16.0.0/16:/nfs/v3
exporting 172.16.0.0/16:/nfs/v2
exporting 172.16.0.0/16:/nfs/v1
#启动nfs(所有节点)
systemctl enable -- now nfs
#3.测试k8s使用nfs
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs
spec:
selector:
matchLabels:
app: nfs
template:
metadata:
labels:
app: nfs
spec:
nodeName: gdx3
containers:
- name: mysql
image: mysql:5.7
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
volumeMounts:
- mountPath: /var/lib/mysql
name: nfs
volumes:
- name: nfs
nfs:
path: /nfs/v1
server: 172.16.1.11
#4.验证nfs挂载
#进入到nfs数据库
[root@k8s-master1 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
emptydir-5dc7dcd9fd-zrb99 2/2 Running 0 9h
nfs-85dff7bb6b-8pgrp 1/1 Running 0 60m
statefulset-test-0 1/1 Running 0 27h
test-6799fc88d8-t6jn6 1/1 Running 0 142m
test-tag 1/1 Running 0 3d15h
wordpress-test-0 2/2 Running 0 26h
[root@k8s-master1 v1]# kubectl exec -it nfs-85dff7bb6b-8pgrp -- bash
root@nfs-85dff7bb6b-8pgrp:/# mysql -u root -p123456
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.33 MySQL Community Server (GPL)
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> create database discuz; #创建一个数据库
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| discuz |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set (0.00 sec)
#到宿主机的挂载目录下查看
[root@k8s-master1 ~]# cd /nfs/v1
[root@k8s-master1 v1]# ll
总用量 188484
-rw-r----- 1 polkitd ssh_keys 56 4月 4 19:06 auto.cnf
-rw------- 1 polkitd ssh_keys 1680 4月 4 19:06 ca-key.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 4月 4 19:06 ca.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 4月 4 19:06 client-cert.pem
-rw------- 1 polkitd ssh_keys 1680 4月 4 19:06 client-key.pem
drwxr-x--- 2 polkitd ssh_keys 20 4月 4 21:07 discuz #数据库目录已经存在
-rw-r----- 1 polkitd ssh_keys 692 4月 4 20:04 ib_buffer_pool
-rw-r----- 1 polkitd ssh_keys 79691776 4月 4 20:04 ibdata1
-rw-r----- 1 polkitd ssh_keys 50331648 4月 4 20:04 ib_logfile0
-rw-r----- 1 polkitd ssh_keys 50331648 4月 4 19:06 ib_logfile1
-rw-r----- 1 polkitd ssh_keys 12582912 4月 4 20:05 ibtmp1
drwxr-x--- 2 polkitd ssh_keys 4096 4月 4 19:06 mysql
drwxr-x--- 2 polkitd ssh_keys 8192 4月 4 19:06 performance_schema
-rw------- 1 polkitd ssh_keys 1680 4月 4 19:06 private_key.pem
-rw-r--r-- 1 polkitd ssh_keys 452 4月 4 19:06 public_key.pem
-rw-r--r-- 1 polkitd ssh_keys 1112 4月 4 19:06 server-cert.pem
-rw------- 1 polkitd ssh_keys 1680 4月 4 19:06 server-key.pem
drwxr-x--- 2 polkitd ssh_keys 8192 4月 4 19:06 sys
#测试删除pod
[root@k8s-master1 discuz]# kubectl delete pods nfs-85dff7bb6b-8pgrp
pod "nfs-85dff7bb6b-8pgrp" deleted
#在回宿主机挂载目录查看discuz数据库目录仍然是存在的
4.PV/PVC
- PersistentVolume(PV)是集群中已由管理员配置的一段网络存储。 集群中的资源就像一个节点是一个集群资源。 PV是诸如卷之类的卷插件,但是具有独立于使用PV的任何单个pod的生命周期。 该API对象捕获存储的实现细节,即NFS,iSCSI或云提供商特定的存储系统 。
- PersistentVolumeClaim(PVC)是用户存储的请求。PVC的使用逻辑:在pod中定义一个存储卷(该存储卷类型为PVC),定义的时候直接指定大小,pvc必须与对应的pv建立关系,pvc会根据定义去pv申请,而pv是由存储空间创建出来的。pv和pvc是kubernetes抽象出来的一种存储资源。
1)PV 的访问模式(accessModes)
模式 | 解释 |
---|---|
ReadWriteOnce(RWO) | 可读可写,但只支持被单个节点挂载。 |
ReadOnlyMany(ROX) | 只读,可以被多个节点挂载。 |
ReadWriteMany(RWX) | 多路可读可写。这种存储可以以读写的方式被多个节点共享。不是每一种存储都支持这三种方式,像共享方式,目前支持的还比较少,比较常用的是 NFS。在 PVC 绑定 PV 时通常根据两个条件来绑定,一个是存储的大小,另一个就是访问模式。 |
2)PV的回收策略(persistentVolumeReclaimPolicy)
策略 | 解释 |
---|---|
Retain | 不清理, 保留 Volume(需要手动清理) |
Recycle | 删除数据,即 rm -rf /thevolume/*(只有 NFS 和 HostPath 支持) |
Delete | 删除存储资源,比如删除 AWS EBS 卷(只有 AWS EBS, GCE PD, Azure Disk 和 Cinder 支持) |
3)PV的状态
状态 | 解释 |
---|---|
Available | 可用 |
Bound | 已经分配给 PVC。 |
Released | PVC 解绑但还未执行回收策略。 |
Failed | 发生错误 |
#创建pv (PV集群级资源)
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv1
spec:
nfs:
path: /nfs/v2
server: 172.16.1.11
capacity:
storage: 20Gi
persistentVolumeReclaimPolicy: Retain #指定pv的回收策略:不清理保留volume
accessModes: #指定pv的访问模式
- "ReadWriteOnce" #可读可写,但只支持单个节点挂载
- "ReadWriteMany" #多路可读可写
#查看pv
[root@k8s-master1 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 20Gi RWO,RWX Retain Available 53s
4)PVC指定使用的PV (PVC名称空间级资源)
#创建PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc1
spec:
accessModes:
- "ReadWriteMany" #此内容要在pv的访问模式中包含
resources:
requests:
storage: "6Gi" #此值要包含在pv的大小内
#再查看pv
[root@k8s-master1 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pv1 20Gi RWO,RWX Retain Bound default/pvc1 29m
#注:此时pv已是绑定pv1的状态
#查看pvc
[root@k8s-master1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
pvc1 Bound pv1 20Gi RWO,RWX 2m42s
三、部署discuz实战(使用pv/pvc管理nfs)
#1.编写配置清单
[root@k8s-master1 discuz]# vim discuz-pv-pvc.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-mysql
spec:
nfs:
path: /nfs/v3
server: 172.16.1.11
capacity:
storage: 20Gi
persistentVolumeReclaimPolicy: Retain
accessModes:
- "ReadWriteOnce"
- "ReadWriteMany"
---
apiVersion: v1
kind: Namespace
metadata:
name: mysql
---
kind: Service
apiVersion: v1
metadata:
name: mysql-svc
namespace: mysql
spec:
ports:
- port: 3306
targetPort: 3306
name: mysql
protocol: TCP
selector:
app: mysql
deploy: discuz
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-mysql-pvc
namespace: mysql
spec:
accessModes:
- "ReadWriteMany"
resources:
requests:
storage: "20Gi"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql-deployment
namespace: mysql
spec:
selector:
matchLabels:
app: mysql
deploy: discuz
template:
metadata:
labels:
app: mysql
deploy: discuz
spec:
nodeName: gdx2
containers:
- name: mysql
image: mysql:5.7
livenessProbe:
tcpSocket:
port: 3306
readinessProbe:
tcpSocket:
port: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "123456"
- name: MYSQL_DATABASE
value: "discuz"
volumeMounts:
- mountPath: /var/lib/mysql
name: mysql-data
volumes:
- name: mysql-data
persistentVolumeClaim:
claimName: pv-mysql-pvc
---
kind: Namespace
apiVersion: v1
metadata:
name: discuz
---
kind: Service
apiVersion: v1
metadata:
name: discuz-svc
namespace: discuz
spec:
clusterIP: None
ports:
- port: 80
targetPort: 80
name: http
selector:
app: discuz
deploy: discuz
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-discuz
spec:
nfs:
path: /nfs/v4
server: 172.16.1.11
capacity:
storage: 20Gi
persistentVolumeReclaimPolicy: Retain
accessModes:
- "ReadWriteOnce"
- "ReadWriteMany"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pv-discuz-pvc
namespace: discuz
spec:
accessModes:
- "ReadWriteMany"
resources:
requests:
storage: "18Gi"
---
kind: Deployment
apiVersion: apps/v1
metadata:
name: discuz-deployment
namespace: discuz
spec:
replicas: 5
selector:
matchLabels:
app: discuz
deploy: discuz
template:
metadata:
labels:
app: discuz
deploy: discuz
spec:
nodeName: gdx2
containers:
- name: php
image: elaina0808/lnmp-php:v6
livenessProbe:
tcpSocket:
port: 9000
readinessProbe:
tcpSocket:
port: 9000
volumeMounts:
- mountPath: /usr/share/nginx/html
name: discuz-data
- name: nginx
image: elaina0808/lnmp-nginx:v9
livenessProbe:
httpGet:
port: 80
path: /
readinessProbe:
httpGet:
port: 80
path: /
volumeMounts:
- mountPath: /usr/share/nginx/html
name: discuz-data
volumes:
- name: discuz-data
persistentVolumeClaim:
claimName: pv-discuz-pvc
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: discuz-ingress
namespace: discuz
spec:
tls:
- hosts:
- www.discuz.cluster.local.com
secretName: discuz-secret
rules:
- host: www.discuz.cluster.local.com
http:
paths:
- backend:
serviceName: discuz-svc
servicePort: 80
#2.部署discuz
[root@k8s-master1 discuz]# kubectl apply -f discuz-pv-pvc.yaml
#将需要的uploa压缩包移动到/nfs/v4
[root@k8s-master1 discuz]# mv Discuz_X3.4_SC_UTF8_20210320.zip /nfs/v4
#解压压缩包
[root@k8s-master1 discuz]# cd /nfs/v4
[root@k8s-master1 v4]# unzip Discuz_X3.4_SC_UTF8_20210320.zip
[root@k8s-master1 v4]# ll
总用量 12048
-rw-r--r-- 1 root root 12330468 4月 7 2021 Discuz_X3.4_SC_UTF8_20210320.zip
drwxr-xr-x 13 root root 4096 3月 22 19:44 upload
[root@k8s-master1 v4]# mv upload/* .
[root@k8s-master1 v4]# ll
总用量 12112
-rw-r--r-- 1 root root 2834 3月 22 19:44 admin.php
drwxr-xr-x 9 root root 135 3月 22 19:44 api
-rw-r--r-- 1 root root 727 3月 22 19:44 api.php
drwxr-xr-x 2 root root 23 3月 22 19:44 archiver
drwxr-xr-x 2 root root 90 3月 22 19:44 config
-rw-r--r-- 1 root root 1040 3月 22 19:44 connect.php
-rw-r--r-- 1 root root 106 3月 22 19:44 crossdomain.xml
drwxr-xr-x 12 root root 178 3月 22 19:44 data
-rw-r--r-- 1 root root 5558 3月 20 10:36 favicon.ico
-rw-r--r-- 1 root root 2245 3月 22 19:44 forum.php
-rw-r--r-- 1 root root 821 3月 22 19:44 group.php
-rw-r--r-- 1 root root 1280 3月 22 19:44 home.php
-rw-r--r-- 1 root root 6472 3月 22 19:44 index.php
drwxr-xr-x 5 root root 64 3月 22 19:44 install
drwxr-xr-x 2 root root 23 3月 22 19:44 m
-rw-r--r-- 1 root root 1025 3月 22 19:44 member.php
-rw-r--r-- 1 root root 2371 3月 22 19:44 misc.php
-rw-r--r-- 1 root root 1788 3月 22 19:44 plugin.php
-rw-r--r-- 1 root root 977 3月 22 19:44 portal.php
-rw-r--r-- 1 root root 582 3月 22 19:44 robots.txt
-rw-r--r-- 1 root root 1155 3月 22 19:44 search.php
drwxr-xr-x 10 root root 168 3月 22 19:44 source
drwxr-xr-x 7 root root 86 3月 22 19:44 static
drwxr-xr-x 3 root root 38 3月 22 19:44 template
drwxr-xr-x 7 root root 106 3月 22 19:44 uc_client
drwxr-xr-x 13 root root 241 3月 22 19:44 uc_server
drwxr-xr-x 2 root root 6 4月 4 18:15 upload
[root@k8s-master1 v4]# chmod -R o+w ../v4 #给所有文件加执行权限
#查看域名
[root@k8s-master1 discuz]# kubectl get ingress -n discuz
NAME CLASS HOSTS ADDRESS PORTS AGE
discuz-ingress <none> www.discuz.cluster.local.com 192.168.12.12 80, 443 4m25s
#查看端口号
[root@k8s-master1 discuz]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller NodePort 10.101.179.113 <none> 80:30655/TCP,443:30480/TCP 3h29m
ingress-nginx-controller-admission ClusterIP 10.98.44.67 <none> 443/TCP 3h29m
#查看pods是否正常启动
[root@k8s-master1 discuz]# kubectl get pods -n discuz
NAME READY STATUS RESTARTS AGE
discuz-deployment-577d4d9b9-2phtj 2/2 Running 0 106m
discuz-deployment-577d4d9b9-g4pv4 2/2 Running 0 106m
discuz-deployment-577d4d9b9-mcptb 2/2 Running 0 106m
discuz-deployment-577d4d9b9-v8hrw 2/2 Running 0 106m
discuz-deployment-577d4d9b9-wcqzn 2/2 Running 0 106m
#3.测试访问如下图