近日由于市政电路整改,机房被迫断电。其中有一台ubuntu主机没有手工关机,重新送电后ubuntu主机重启成功。但在ubuntu宿主上用docker安装的mysql动无法启动。
$ docker exec -it mysql57 env LANG=C.UTF-8 /bin/bash
得到
Error response from daemon: Container 40580276ee2f0bf30e59d9ff670977b27856a36ed10b788e3a3fce8f17d7849b is not running
$ docker logs mysql57
Initializing database
Database initialized
MySQL init process in progress...
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
/entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
MySQL init process done. Ready for start up.
对于数据库,最重要的就是数据的安全性要得到保证。
所以必须要确保即使docker容器损坏后,仍然能够拿到mysql存储的数据文件。
因此在初始化docker容器时,只要将数据目录挂载到宿主机上的自定义目录即可。
这里假设我的宿主用户名为study
docker stop mysql57
docker rm mysql57
备份损坏前的数据文件
#进入数据目录的父目录
/home/study/database
#备份文件夹
sudo zip -r MYSQL_DATA.zip MYSQL_DATA
#删除原有的DATA目录
sudo rm -rf MYSQL_DATA
sudo mkdir MYSQL_DATA
sudo chmod -R 755 /home/study/database
这里我在宿主上创建了一个文件夹/home/study/database/MYSQL_DATA作为mysql的数据目录。因此这里要先备份它。
这是我初次安装时创建的一些目录和文件 :
#日志目录
sudo mkdir -p "/home/study/database/logs"
#数据目录
sudo mkdir -p "/home/study/database/MYSQL_DATA"
#配置目录
sudo mkdir -p "/home/study/database/conf"
#创建文件
sudo touch /home/study/database/logs/mysqld-error.log
sudo touch /home/study/database/conf/mysqld.pid
3.重建实例
sudo docker run --name mysql57 -p 3308:3306 -e MYSQL_ROOT_PASSWORD=studyDB -d \
--mount type=bind,src=/home/study/database/logs/mysqld-error.log,dst=/var/log/mysqld.log \
--mount type=bind,src=/home/study/database/MySQL_DATA,dst=/var/lib/mysql mysql/mysql-server:5.7.18
命令解读:
sudo 以管理员身份执行
docker run 是docker容器初始化的命令。
--name mysql57 容器取名为mysql57后期维护用这个名字,相当于给容器ID取个别名。
-p 3308:3306 这里有两个端口3306是容器中mysql进程监听的端口,3308是通过宿主IP来访问数据库时宿主机的端口。相当于将容器中的3306映射到宿主机的3308上。
-e MYSQL_ROOT_PASSWORD=studyDB 指定root帐号的密码
-d 选项是 "detached" 或 "daemon" 的缩写,它的作用是将容器在后台运行,而不是占用当前终端会话。具体来说,它指示Docker将容器作为后台进程启动,然后返回到命令行终端,允许您继续使用该终端而不会阻止在容器上运行的应用程序。
\ 用于将一条很长的命令分成多行来书写。相当于行与行之间的连接符。
--mount type=bind,src=/home/study/database/logs/mysqld-error.log,dst=/var/log/mysqld.log
这一句--mount是挂载宿主文件路径,src是宿主路径,dst是容器中的命令
相当于在docker容器中创建了一个文件软链接,指定此参数后,在容器中往路径/var/log/mysqld.log中写入内容时,实际内容会被写入到宿主的/home/study/database/logs/mysqld-error.log这个文件。
--mount type=bind,src=/home/study/database/MySQL_DATA,dst=/var/lib/mysql
这一句--mount是挂载宿主文件目录路径,src是宿主路径,dst是容器中的命令
相当于在docker容器中创建了一个文件软链接,指定此参数后,在容器中往目录/var/lib/mysql下写入内容时,实际内容会被写入到宿主的/home/study/database/MySQL_DATA目录下。
mysql/mysql-server:5.7.18 这是docker pull拉取的镜像名称,意思是以它为模板运行实例。
以上执行成功后,启动mysql容器:
#启动容器
docker start mysql57
#修改容器重启策略,让它随宿主机开机自启
docker update --restart=always mysql57
进入容器并设置中文支持
#第一步:进入时加环境变量参数env LANG=C.UTF-8
docker exec -it mysql57 env LANG=C.UTF-8 /bin/bash
#第二步:安装vi程序
yum install vi
#第三步:vi /etc/profile 文件尾插入
LANG=en_ZW.utf8
#第四步:配置生效
source /etc/profile
#验证mysql登录
mysql -uroot -pstudyDB --default-character-set=utf8
#退出mysql命令行
quit
#修改mysql配置
vim /etc/my.cnf 添加下面的sql_mode和lower_case_table_names
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
#解析SQL语句时,忽略库表名称大小写
lower_case_table_names=1
#时间为东八区
default-time_zone = "+8:00"
#退出mysql容器
exit
#停止mysql
sudo docker stop mysql57
#进入备份所在目录
cd /home/study/database
#直接解压覆盖所有文件
sudo unzip MYSQL_DATA.zip
#重启mysql
sudo docker start mysql57
#进入容器命令行
docker exec -it mysql57 env LANG=C.UTF-8 /bin/bash
这是在生产环境使用docker后第一次遇到容器损坏的情况。
本次事故能够得到解决主要得益于新技术应用之前做好了风险把控,将Mysql的数据目录映射到宿主的文件夹中。否则一旦容器损坏,后果难以设想。