一、问题背景:
某个项目的线上环境oracle数据库挂了,同事急匆匆来找我救火。我简单咨询了一些基本情况:线上环境,docker部署,已正常运行半年。由于宿主机的根目录硬盘空间不够,运维的同事想把oracle数据文件迁移至别的硬盘上。但不知什么原因,容器丢失,运维的同事想重建新的oracle容器。
二、分析问题:
第一步就是看操作历史,以便于全面了解同事都做了哪些操作。通过history命令,分析历史操作,得到以下信息:
1.oracle容器实例是于今年4月份创建,容器名为oracle11g,影射端口为1521,未指定挂载卷;
2.oracle11g容器未被删除,但现在通过docker ps -a却找不到;
3.同事将容器目录下的oradata文件夹mv到了另一块硬盘上;
4.宿主机的根目录空间只剩下3个G;
5.同事尝试创建新的oracle容器,并指定挂载mv出来的数据文件;
仅有数据文件是很难把数据库服务跑起来的,故找回容器oracle11g是解决问题的关键。由于同事已经记录了oracle11g容器的ID,于是找到了容器的所在目录:/mnt/docker-data/containers/,发现容器文件还在。
接着分析历史操作,又发现同事改了docker容器目录containers下oracle11g的hostconfig.json文件,于是推断此项操作是导致容器丢失的关键。
于是,将hostconfig.json文件恢复,重新启动docker服务:
# systemctl restart docker
重启成功之后,通过docker ps -a已经可以找到oracle11g这个容器了。
尝试启动oracle11g:
# docker start oracle11g;
启动成功!于是进入容器,检查数据库状态:
# docker exec -it oracle11g bash //进入容器
$ source /home/oracle/.bash_profile //引用环境变量
$ sqlplus / as sysdba //进入数据库实例
> shutdown immediate //关闭数据库
> startup //启动数据库
启动数据库时,报错,提示数据文件需要恢复。此问题是由于同事已将容器中的数据文件/oradata通过mv操作转移到了其它硬盘。
至此,问题已很清楚。以下问题需要得到解决:
1.docker的Root_dir是在宿主机的根目录下,目前可用空间仅3G,需要把docker的数据目录改为有更多硬盘空间的目录:/NET_FS;
2.需要根据现有的oracle11g容器创建新的镜像,以通过挂载的方式引用mv出来的数据文件(也可以把数据文件拷备至容器原有的数据文件所在的位置,但是否可行待验证);
三、解决过程:
先解决第2个问题,根据现有容器创建新的镜像:
# docker export oracle11g /NET_FS/oracle11g_image.tar //导出容器,漫长的等待。
容器导出成功后,由于docker所在的文件系统已无多余空间可用,故再调整docker的Root_dir目录:
# systemctl stop docker //停止docker服务;
# cp -R /mnt/docker-data /NET_FS/lib/docker/ //拷备现有的docker数据文件至新的文件系统
整个docker数据文件约100G,经过漫长的等等之后,拷备完成。接下来修改Root_dir参数:
# vim /etc/docker/daemon.json //添加以下内容
{"data-root": "/NET_FS/lib/docker/docker-data"}
启动docker服务:
# systemctl start docker //启动服务
# docker info |grep Root //检验数据文件目录修改是否生效
# docker ps //查看容器运行状态
# df -h //也可以通过此命令看到docker的目录已经生效
docker服务正常,其它的容器也正常运行。接下来,将刚才导出的容器,导入为新的镜像:
# cat /NET_FS/oracle11g_image.tar |docker import - oracle11g:v3 //导入容器为镜像
# docker images //查看镜像,新的镜像已成功添加。
根据镜像创建新的容器,并挂载指定的oracle数据文件:
# docker run -d --name oracle11g_new -p 1521:1521 -v /NET_FS/oradata /oradata oracle11g:v3 /bin/bash
容器创建成功,接下来进入容器,启动数据库:
# docker exec -it oracle11g_new bash //进入容器
$ source /home/oracle/.bash_profile //引用环境变量
$ sqlplus / as sysdba //进入数据库实例
> shutdown immediate //关闭数据库
> startup //启动数据库
数据库顺利启动!经过业务验证,系统已经恢复,至此故障得到解决。
四、总结与反思:
通过此次故障修复,有以下几点反思:
1.生产环境的一切操作要谨慎,随时准备好回退方案。如本例中,在转移数据库数据文件时,用的是mv,非cp;
2.除非知道自己在做什么,否则最好考虑清楚再下手。本例中容器的hostconfig.json文件被修改后,导致找不到容器,同事以为容器“丢失”;
3.线上环境没有预先规划好资源。本例中docker是直接安装至根目录下的,但根目录只有50G的空间,对于生产环境来说,这个空间肯定是不够用的。
4.宿主机没有使用LVM逻辑卷管理,导致后期扩容困难。
5.运维操作不规范,如没有制定妥善的扩容方案,运维人员操作也存在操作风险。
五、写在最后:
在故障处理期间,相关同事已经做好了数据丢失的心理准备,这种压力是特别大的。但幸好问题得到解决,数据也没有丢失。通过此次事件,我也汲取教训,认真反思和总结,以求工作中避免发生不可挽回的事故。