k8s使用nfs持久存储mysql数据的一次踩坑
准备
首先确保nfs服务端搭建成功。由于资源限制,我们的nfs服务器和k8s集群不在同一局域网内,所以k8s中pv使用公网ip连接nfs,且nfs服务器的带宽为10M。
- 创建nfs pv
apiVersion: v1
kind: PersistentVolume
metadata:
name: mysql-nfs
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Recycle
nfs:
path: /mysql-data
server: 39.105.232.177
- 创建pvc
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: mysql-pvc
namespace: laravel
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
- 查看pv和pvc的状态
pv属于bound状态
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
mysql-nfs 10Gi RWO Recycle Bound laravel/mysql-pvc 16d
pvc也属于bound状态
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pvc Bound mysql-nfs 10Gi RWO 16d
如果没有使用storageclass,pv和pvc通过相同的
storage
存储大小和accessModes
访问策略俩个元素来实现自动绑定。可以看到图中pv和pvc已经自动绑定。
- 创建mysql的deployment
使用的 harbor.maigengduo.com/laravel/mysql5.7镜像是基于docker官方的mysql:5.7镜像build的,mysql的data目录为/var/lib/mysql。
kind: Deployment
apiVersion: extensions/v1beta1
metadata:
name: mysql
namespace: laravel
labels:
name: mysql
annotations:
reloader.stakater.com/auto: "true"
spec:
replicas: 1
selector:
matchLabels:
name: mysql
template:
metadata:
labels:
name: mysql
spec:
containers:
- name: mysql
image: harbor.maigengduo.com/laravel/mysql5.7:202007071543
ports:
- name: mysql-port
containerPort: 3306
protocol: TCP
imagePullPolicy: Always
env:
- name: MYSQL_ROOT_PASSWORD
value: root
volumeMounts:
- name: mysql-pvc
mountPath: "/var/lib/mysql"
restartPolicy: Always
volumes:
- name: mysql-pvc
persistentVolumeClaim:
claimName: mysql-pvc
部署完之后我开始认为,容器内的/var/lib/mysql目录下的数据会‘直接同步’
到nfs服务端的/mysql-data目录下,注意:这里是我认为的,后面会验证我还是年轻啊,哈哈。
但是发现,容器内的数据文件并没有同步到nfs服务端,nfs服务端的共享目录只看到俩个文件,分别为ibdata1和ib_logfile0,而且导致mysql服务不可用,最严重的时候直接导致了整个k8s的pod都处于pendding状态了。
为了确定问题,我将容器内别的目录(目录大小比较小)重新挂载到nfs上,发现是可以正常同步的,证明是/var/lib/mysql目录特殊,特殊点有俩个,第一个该目录的用户和所属组都是mysql,第二点是该目录比较大。
root@mysql-85bc98b4d9-gg4q2:/var/lib# ls -l
total 32
drwxr-xr-x 1 root root 4096 Aug 14 2019 apt
drwxr-xr-x 1 root root 4096 Aug 14 2019 dpkg
drwxr-xr-x 2 root root 4096 Mar 28 2019 misc
drwxr-xr-x 6 mysql mysql 4096 Jul 24 01:10 mysql
drwxrwx--- 2 mysql mysql 4096 Aug 14 2019 mysql-files
drwxr-x--- 2 mysql mysql 4096 Aug 14 2019 mysql-keyring
drwxr-xr-x 2 root root 4096 Aug 12 2019 pam
drwxr-xr-x 1 root root 4096 Aug 12 2019 systemd
root@mysql-85bc98b4d9-gg4q2:/var/lib/mysql# du -sh
422M .
.
于是这里提出有几个问题
- nfs服务端为什么只同步过俩个文件?
- 为什么mysql服务会不可用?为什么严重时整个k8s中的pod都处于pendding状态了呢?
带着上面的俩个问题,多次实验首先发现了下面这个问题
nfs服务端共享文件夹权限问题
现象:nfs服务端的共享目录/mysql-data原本的用户和所属组都是root,如下
[root@iZ2zebwwgp62jma838rfc4Z /]# ls -l
drwxr-xr-x 6 root root 4096 Jul 24 09:10 mysql-data
但是当部署deployment后,也就是客户端挂载后,服务端的共享目录/mysql-data的用户变为了polkitd,用户组变成了input,如下
[root@iZ2zebwwgp62jma838rfc4Z /]# ls -l
drwxr-xr-x 6 polkitd input 4096 Jul 24 09:10 mysql-data
为什么呢?感觉有点不正常。
- 首先查看容器内的/var/lib/mysql目录的权限,看到该目录所属用户和用户组都为mysql
root@mysql-85bc98b4d9-gg4q2:/var/lib# ls -l
total 32
drwxr-xr-x 1 root root 4096 Aug 14 2019 apt
drwxr-xr-x 1 root root 4096 Aug 14 2019 dpkg
drwxr-xr-x 2 root root 4096 Mar 28 2019 misc
drwxr-xr-x 6 mysql mysql 4096 Jul 24 01:10 mysql
然后查看用户为mysql的相关信息,发现用户myql所属id为999,所属组id也为999
root@mysql-85bc98b4d9-gg4q2:/var/lib# cat /etc/passwd | grep mysql
mysql:x:999:999::/home/mysql:
- 查看宿主机上用户id为999的信息,发现用户id为999的用户为polkitd。
[root@iZ2zebwwgp62jma838rfc4Z /]# cat /etc/passwd | grep 999
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
继续查看用户组id为999的组名,发现用户组id为999的组名为input。
[root@iZ2zebwwgp62jma838rfc4Z /]# cat /etc/group | grep 999
input:x:999:
到这里你肯定明白了宿主机上共享目录的权限怎么变成用户为polkitd,用户组变成了input。
- 总结
宿主机使用volume映射到容器内时,宿主机和容器内的文件或文件夹的权限是相同的,准备的说是用户id和用户组id是相同的。
解决
似乎上面那个现象对我们上面提的俩问题并没有什么帮助,但是上面那个现象是真实存在的,我们必须搞清楚。接下来进入正题。。。
- nfs服务端为什么只同步过俩个文件?
刚开始时这个问题真的很棘手,后来静下来想想,这个目录大小将近500M,是不是目录太大的问题,同步需要时间呢?所以并不是只同步过来俩个文件,而是正在同步中
,接下来验证这个猜想。
首先在宿主机的共享目录下查看文件夹大小,发现为100M
[root@iZ2zebwwgp62jma838rfc4Z mysql-data]# du -sh
100M .
在过2秒查看一遍,发现大小变为101M
[root@iZ2zebwwgp62jma838rfc4Z mysql-data]# du -sh
101M .
此时真的验证了我们的猜想,nfs服务端的数据是正在同步中
,只是nfs的写速度真的很慢,让我们以为就同步过来俩个文件,被表象所迷惑。
同步速度慢主要有几个原因,首先io同步就是耗时的,其次nfs服务器和k8s不在一个局域网内,然后nfs服务器的带宽也很低,最主要的还是nfs服务写速度真的很慢。
- 为什么mysql服务会不可用?为什么严重时整个k8s中的pod都处于pendding状态了呢?
写io是很耗cpu的
,更何况这种大量复制。既然服务不可用了,我们使用top命令查看下k8s worker节点机器的各项性能,如下图。发现nfs在同步过程有一个nginx的command的进程cpu竟然达到了99%,us的cpu达到了23.5%,sy的cpu达到了48.6%,很显然,io同步时消耗了大量的cpu,导致mysql服务不可用了,而k8s的pod都会占用宿主机的cpu的资源的,如果宿主机的cpu资源不够pod所申明的cpu,pod将会重新构建,进而进入pod的生命周期中的pendding状态,所有pod都在争抢宿主机cpu的资源。
总结:写io是很耗cpu资源,为了k8s集群服务的可用性,我们需要将k8s的node节点的cpu调大点。
如果你了解k8s resource,你就会知道,
只有当节点拥有足够满足 Pod 内存请求的内存和cpu请求的cpu时,才会将 Pod 调度至节点上运行
,显然上面这种情况消耗了大量的cpu,导致pod都调度不到节点上,以至于处于pendding状态。可以看到我们上面的mysql deployment中并没有设置resource相关cpu和memory配置,pod默认limit为节点的所有cpu个memory。当nfs数据复制时,将大量消耗pod内的cpu,以至于node节点的cpu被消耗完,这是出现这个问题的根本原因,体现了pod设置resource资源的重要性,不然某个pod类似我们的这种情况将会消耗光节点的所有资源。
上面俩个问题解决后,等到mysql的数据文件全部同步到nfs上时,理应mysql服务和其他服务都能正常访问了,但是并没有预期的那么好,又出现了下面这个问题。。
mysql connection is not allowed
在集群外连接mysql时报以下错误。
rHost '172-17-208-115.calico-typha.kube-system.svc.cluster.local' is
not allowed to connect to this MySQL serverConnection closed by foreign host.
- 解决
这个原因是因为索要链接的mysql数据库只允许其所在的服务器连接,需要在mysql服务器上设置一下允许的ip权限
grant all privileges on *.* to 'root'@'%' identified by 'root';
flush privileges;