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    .
.

于是这里提出有几个问题

  1. nfs服务端为什么只同步过俩个文件?
  2. 为什么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的资源。

image.png

总结:写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;

你可能感兴趣的:(k8s使用nfs持久存储mysql数据的一次踩坑)