lmk123 / blog

个人技术博客,博文写在 Issues 里。
https://github.com/lmk123/blog/issues
623 stars 35 forks source link

在服务器 build docker image 时服务器会卡死的问题分析及解决方案 #109

Open lmk123 opened 2 years ago

lmk123 commented 2 years ago

在分析问题之前,先说说我是怎么在服务器上更新我的后端应用的。

我在服务器上安装了 docker,当我在本地修改了代码之后,我会将代码传送到服务器里,然后在服务器里用代码 build 出 docker image 并重新生成 container。

起初,这种方式运行的很好,但随着我 build 的次数越来越多,我能明显感觉到每次 build image 的时间变得越来越久,从一开始的 20 秒,到后来的 10 分钟,而到上一次的时候,过了半小时都没有 build 成功。

镜像 build 的过程其实就只是用 yarn install 安装了项目依赖,而且也确认不是网络原因,因为从 yarn install 的日志来看,模块很快就下载好了,但卡在了 Building fresh moudes [4/4] 这一步。

而且,build 过程中还出现了 ssh 无法连接的情况,最终只能重启服务器,但这个问题也导致我无法再发布新的代码了。

从云服务器后台可以看到,在 build 过程中,除了硬盘读IOPS硬盘IO繁忙比率,其它指标都是正常的。这俩指标的曲线都到顶了,其中硬盘IO繁忙比率直接冲到了 100%。

总结一下此问题的特点:

解决这个问题的办法有两种:

由于不知道出现问题的原因,所以目前来看最好的办法就是在本地 build 镜像,然后上传到服务器并导入。

这个过程还是蛮简单的,只涉及到三条命令:

但是,这一过程却出现了问题。

第一次尝试时,上面三条命令一切正常,但是当我用导入的镜像生成 container 运行的时候报错了:exec user process caused: exec format error。谷歌了一下找到了原因:我的开发机是 Macbook Air M1,CPU 是 arm,但服务器是 x86-64 的。

所以,普通的 docker image build 是不行了,得用 docker buildx build 来打包支持多架构的镜像。https://docs.docker.com/desktop/multi-arch/

导出我用的是 docker buildx build -o type=tar,dest=out.tar --platform=linux/amd64 .,但导入的时候用 docker image load 会报错:open /var/lib/docker/tmp/docker-import-837327978/bin/json: no such file or directory

简单 google 了下之后,改为用 docker image import 导入了 tar,但是作为 container 跑起来之后又报错了:No command specified——然而我的 Dockerfile 里明明写了 CMD 的 :joy:

到这里我觉得这问题一时半会儿是解决不了了,就决定找个其它时间再尝试。

此问题已解决,见 https://github.com/lmk123/docker-buildx-test

由于尝试过程中产生了很多没有用的 image,我决定清理一下,正好以前 build 过的代码镜像也一直没清理过,占用了很多硬盘空间,于是我运行了 docker image prune,然而这个命令运行了 3 分钟了没有任何反应,像极了 build image 时的表现,于是我赶紧上云服务器后台确认了一下指标,发现硬盘IO繁忙比率冲到了 82%,但是没到 100%,而且 ssh 也能正常连上去。大概 5 分钟后,命令运行完成了。

我突然想到,会不会是因为一直没清理 image 导致的这个问题?于是我又重新尝试了在服务器里 build image,结果居然 20 秒就好了,就像我第一次 build 时那样快 :joy:

到这里问题可以说圆满解决了,但是我仍然不明白为什么没有清理的 image 会导致这个问题 :joy: