ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

VMware虚拟机CentOS7中用Docker安装MySQL完整实操指南

VMware虚拟机CentOS7中用Docker安装MySQL完整实操指南 最近好几个做后端的朋友都在折腾同一件事在自己电脑的虚拟机里搭一套CentOS7再用Docker把MySQL跑起来。这个组合在开发环境、学习场景里实在太常见了不管是模拟生产、练手Linux还是想给团队统一一套数据库环境几乎都绕不过它。这篇内容就把我从零开始在VMware虚拟机里装好CentOS7之后装Docker、再装MySQL的完整过程写清楚包括每个命令为什么要这么写、中间会踩哪些坑适合刚接触Linux的开发者也适合已经被“docker安装mysql失败”折磨过几次的运维新手。我的习惯是先把结论放前面这套东西并不难难点全在看不见的细节上比如网络通不通、yum源能不能用、端口有没有暴露、数据有没有挂载出来。下面按我实际操作的顺序来写跟着走一遍能少走很多弯路。1. 动手前先把三件事想清楚1.1 为什么是“虚拟机 CentOS7 Docker MySQL”这套组合先从选型讲起。很多人拿到一台虚拟机就急着装MySQL但我建议你先花两分钟搞清楚“为什么这么搭”因为后面遇到问题时这些判断能帮你快速定位到底出在哪个环节。虚拟机解决的是“折腾不坏宿主机”的问题。你可以在里面随便装系统、乱配服务、反复删了重来最多打个快照就回滚了对Windows或macOS本体没有任何影响。而且虚拟机的网络模式尤其是NAT模式相当于给你一个独立的局域网环境非常适合练习数据库端口映射、防火墙这些操作。CentOS7是服务器场景里的“老熟人”。虽然它已经进入了维护周期的尾声但大量线上服务器、公司内部文档、培训机构教材都还在用它。对想进运维或后端岗位的人来说熟悉CentOS7的yum、systemd、firewalld这套操作目前依然是刚需。Docker在这里的价值可以用一句话概括让MySQL以“可复制的黑盒”方式运行。传统rpm安装MySQL也不是不行但你会遇到依赖冲突、多版本切换困难、卸载不干净、配置文件散落各处等问题。用Docker的话镜像拉下来直接跑删了重来只损失容器本身数据通过数据卷保存在外部底层系统始终干干净净。我经常拿装修来类比rpm安装像自己买材料请工人Docker像直接租了一套精装房家具家电都给你配好你只管拎包入住。这套组合还有一个隐藏好处方便模拟“本地和服务端一致”的环境。你在虚拟机里调好的这套MySQL配置将来可以直接照搬到云服务器或者同事的机器上只要大家用的都是CentOS7 Docker行为就基本一致不会再出现“我本地能跑你本地跑不了”的尴尬。1.2 解决CentOS7上网和yum源的“第一道坎”很多人兴致勃勃装完CentOS7敲了个yum install -y vim结果卡了半天最后超时。这时候你去看多半是网络没通或者默认yum源慢到发指。先说网络。虚拟机里CentOS7最常见的网络故障就是“ping不通百度”。我用VMware举例排查顺序基本是固定的先看虚拟机的网络模式是不是NAT。在VMware里选中虚拟机右键设置网络适配器选“NAT模式”。NAT模式下虚拟机通过宿主机上网对新手最友好桥接模式反而容易因为路由器限制而连不上。进系统后执行ip addr看网卡有没有分配到IP。如果只有一个lo回环地址没有ens33或eth0的IP说明网卡没起来。CentOS7里可以执行systemctl restart network重启网络服务或者ifup ens33手动拉起网卡。能ping通网关但ping不通外网大概率是DNS问题。修改/etc/resolv.conf加一行nameserver 223.5.5.5阿里DNS或者nameserver 8.8.8.8再测ping -c 4 www.baidu.com。如果你以后建容器、拉镜像DNS不对几乎一定失败。注意/etc/resolv.conf在某些情况下会被NetworkManager覆盖如果改了又变回去去/etc/sysconfig/network-scripts/ifcfg-ens33里把DNS1223.5.5.5加上再重启网络。网络通了之后立刻换国内yum源。CentOS7默认源在国外下载速度经常只有几十KB换源之后的体验是质的飞跃。操作很简单# 先备份原源文件 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak # 下载阿里云CentOS7源 curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo # 清缓存并重建 yum clean all yum makecache顺手把常用软件包装上后面都会用到yum install -y vim net-tools wget curl这里有个细节必须提醒如果你的虚拟机是刚装好的最小化系统可能连curl都没有。那就换个思路把repo文件里的地址记下来直接在宿主机浏览器下载Centos-7.repo再通过共享文件夹或者拖拽方式放进虚拟机。别笑我真的见过有人在最小化系统里卡在这一步卡了半小时。2. 安装Docker三种来源怎么选装完必做的三件事2.1 官方源、国内镜像源、离线rpm我为什么选国内镜像源Docker在CentOS7上的安装方式常见的有三种CentOS自带yum源里的老版本Docker、Docker官方源、国内镜像源以及内网环境的离线rpm包。先避开一个坑直接用yum install docker装出来的通常是Docker 1.13版本太老很多新特性不支持跑MySQL虽然能用但后续管理起来麻烦。所以不建议这个方式。Docker官方源download.docker.com/linux/centos/docker-ce.repo是最权威的但国内服务器或虚拟机访问它经常超时尤其是刚配好的虚拟机网络质量本来就一般不建议把时间耗在这里。我的选择是直接用阿里云的Docker社区版源速度快、稳定配置方式也不复杂。如果你在内网或者离线环境那就只能用离线rpm包。去能联网的机器上下载docker-ce、docker-ce-cli、containerd.io等几个rpm拷进去用rpm -ivh按依赖顺序安装或者yum localinstall *.rpm自动解决依赖。这个方案我没展开细讲因为对新手来说先保证能联网才是王道。阿里云源的安装命令是这样# 安装依赖工具 yum install -y yum-utils device-mapper-persistent-data lvm2 # 添加阿里云docker-ce源 yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 安装docker-ce yum install -y docker-ce docker-ce-cli containerd.ioyum-config-manager来自yum-utils所以顺序不能乱先装工具再添加repo。安装过程如果看到一堆依赖被自动处理就说明源正常工作。2.2 启动服务、配置加速器、免sudo一个都不能少Docker安装好之后不要急着拉MySQL镜像先做三件收尾工作。第一启动Docker并设置开机自启systemctl start docker systemctl enable dockerenable这一步很重要否则虚拟机重启后Docker不会自动启动容器自然也起不来。检查是否成功systemctl status docker第二配置镜像加速器。这一步解决的是“拉镜像慢”的问题。Docker默认从Docker Hub拉镜像国内网络环境经常慢到无法接受。修改/etc/docker/daemon.json{ registry-mirrors: [ https://你个人加速器地址.mirror.aliyuncs.com ] }加速器地址需要自己去阿里云容器镜像服务控制台查看每个人绑定的地址不同。修改后重启Dockersystemctl daemon-reload systemctl restart docker docker info | grep -A5 Registry Mirrors能看到加速器列表就说明生效了。第三把当前用户加进docker组省得每次敲命令都要加sudousermod -aG docker $USER newgrp docker这里注意newgrp docker之后当前终端临时生效如果你用的是SSH连接可能需要退出重登一下。加完之后直接docker version测试能输出就说明没问题。个人经验过去我图省事经常直接顶着root用户操作Docker后来发现生产环境里这种习惯很危险。容器里有漏洞就等于宿主机被突破了一定不要用root身份跑日常命令。现在加docker组这个动作已经是我的新环境初始化标配。3. MySQL版本和容器启动参数拆解3.1 5.7还是8.0先给项目“体检”再选版本MySQL镜像选择是很多人纠结的地方其实核心就两个版本5.7和8.0。我见过太多人上来就docker pull mysql:latest结果拉下来是8.0项目里的老代码用的还是5.7的方言连接驱动也是旧版启动一通报错。反过来新项目用5.7也不是不行但以后迟早要面临升级迁移。先看个对比对比项MySQL 5.7MySQL 8.0默认认证插件mysql_native_passwordcaching_sha2_password老客户端兼容性很好老客户端可能连不上性能表现稳定扎实整体更强优化器进步明显窗口函数、CTE不支持支持JSON能力基础完善官方维护状态已过常规维护期持续维护所以我的建议很明确如果你是跟着教程学、在虚拟机上练手、或者跑老项目直接用5.7具体点可以写mysql:5.7.44锁一个大版本里相对新的子版本避免遇到历史bug如果你是新项目、新团队又不依赖老驱动直接8.0。有一点必须强调不要用latest标签。这个标签指向的版本会变今天拉的是8.0.x过几个月再拉一次可能变成8.x.y配置文件、默认行为都可能不一样你的生产环境不应该建立在“不确定”之上。指定精确版本号或者至少指定大版本是容器化部署的基本素养。3.2 docker run 参数逐个拆开看选好版本后真正决定成败的是docker run的参数。我第一次跑MySQL时随手写了个最简单的命令结果数据全在容器里容器一删全没了。后来才老老实实把每个参数搞明白。先看我平时用的完整命令docker run -d \ --name mysql57 \ -p 3306:3306 \ -e MYSQL_ROOT_PASSWORDYourStrongPass123 \ -e MYSQL_ROOT_HOST% \ -e TZAsia/Shanghai \ -v mysql_data:/var/lib/mysql \ -v /opt/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf \ --restartalways \ mysql:5.7.44逐个拆开讲-d是后台运行不加的话终端会被MySQL日志刷屏而且CtrlC会把容器停掉。--name mysql57是给容器起名字后面所有docker exec、docker logs、docker stop都靠这个名字来定位比用容器ID方便得多。-p 3306:3306是端口映射。宿主机3306端口映射到容器内3306端口外部程序通过虚拟机IP加3306就能连到MySQL。这里多说一句生产环境不要把端口暴露到所有网卡上否则宿主机上任何进程都能访问后面6.3节会专门讲怎么收口。-e MYSQL_ROOT_PASSWORD是设置MySQL root密码这是官方镜像的初始化机制。在容器首次启动时它会自动执行初始化脚本把这个环境变量里的值作为root密码写入数据库。环境变量属于进程级别的配置容器停止后这个值还存在但删除容器重来就失效了所以密码别只写在命令行里最好配合环境变量文件使用。-e MYSQL_ROOT_HOST%是允许root从任意主机远程登录。不加这个的话默认root可能只能从容器内部连接你在宿主机或者Navicat里根本连不上。%表示所有IP练手和学习阶段用这个最省事生产环境建议把它换成具体的IP网段。-e TZAsia/Shanghai是把容器时区设置成东八区避免MySQL的时间和宿主机时间差8个小时。虽然MySQL内部也有时区变量但容器时区不对的话很多事情都会莫名其妙。-v mysql_data:/var/lib/mysql是核心中的核心。这行把MySQL的数据目录挂载到Docker的命名卷mysql_data上。MySQL的所有库表文件都写在/var/lib/mysql下如果不挂载出来数据就存在容器可写层里容器被删除时数据跟着没。挂载之后哪怕容器删了重建数据依然在新容器挂载同一卷就能无缝接续。命名卷的位置在宿主机/var/lib/docker/volumes/mysql_data/_data比直接在宿主机指定一个路径更规范。-v /opt/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf是配置文件挂载。官方镜像默认会读取/etc/mysql/conf.d/下的配置文件我们把自己准备好的my.cnf放进去就可以自定义字符集、排序规则、时区参数等。这样改配置不用重新build镜像直接改宿主机文件重启容器即可。--restartalways是设置容器自动重启策略。虚拟机重启后Docker会跟着启动这个参数能保证Docker一启动就把MySQL容器带起来不用你手动一个个docker start。mysql:5.7.44是镜像标签前面已经说了锁死版本。这里我再补一个细节如果不想用外部配置文件也可以在docker run命令末尾直接追加参数docker run ... mysql:5.7.44 \ --character-set-serverutf8mb4 \ --collation-serverutf8mb4_unicode_ci这两种方式效果一样。我习惯用配置文件因为以后调整参数时不用翻bash历史记录直接vim改文件就行。4. 完整跑通从拉镜像到远程连接4.1 启动容器先看懂初始化日志参数都确认没问题后开始拉镜像docker pull mysql:5.7.44网络正常情况下几秒钟就能拉完。如果卡住不动大概率是加速器没生效或者网络还没完全打通先回头检查。拉完镜像后把3.2节的docker run命令老老实实执行一遍然后立刻看日志docker logs mysql57这一步很多人会跳过我建议一定看。MySQL官方镜像首次启动时会做初始化动作初始化数据目录、创建系统表、设置root密码。日志里会有一条类似mysqld: ready for connections或者port: 3306的记录看到这个说明初始化完成可以开始连接了。如果你在日志里看到[ERROR] [MY-000000] ...之类的报错先别急着到处搜按下面顺序快速自查端口被占用了netstat -tlnp | grep 3306然后把宿主机上占用3306的进程停掉或者把映射端口改成3307。数据目录已经有残留数据docker rm mysql57清掉再重新run或者换一个新卷名。密码策略太弱报错官方镜像默认有密码校验策略太简单的密码会被拒绝尽量用大小写字母加数字加特殊符号的组合。4.2 进容器授权再让Navicat连上来容器启动完成后先进入容器内部测试连接docker exec -it mysql57 mysql -uroot -p输入刚才设置的密码能进入MySQL命令行就说明服务正常。此时跑一句SELECT VERSION();如果输出5.7.44环境和版本都没问题。接下来验证远程连接能力。虽然我们设置了MYSQL_ROOT_HOST%但稳妥起见还是手动确认一下授权SELECT user, host FROM mysql.user WHERE userroot;如果看到root对应的host为%说明远程登录已经放开了。如果还是localhost则手动补一条授权GRANT ALL PRIVILEGES ON *.* TO root% IDENTIFIED BY 你的密码; FLUSH PRIVILEGES;在宿主机上用MySQL客户端测一下宿主机没装mysql客户端的话可以用Python的pymysql或者直接开Navicatmysql -h 虚拟机IP -P 3306 -uroot -p看到密码输入提示就说明网络链路通了。Navicat这类GUI工具的连接方式也一样主机填虚拟机IP端口3306用户名root密码填设置好的那个。提醒在真正的生产环境不建议直接用root远程连数据库。更规范的做法是新建一个业务专用账号只授权具体的库。但就虚拟机练手这个场景来说root直连能省去很多麻烦先把流程跑通了再谈安全加固。5. 踩坑实录安装和连接MySQL的常见问题5.1 docker安装MySQL失败的几种典型报错我在折腾这些环境时见过最多的报错大概有下面几种整理成速查表报错特征大概率原因解决办法manifest for mysql:xxx not found镜像tag不存在先docker search mysql或去Docker Hub确认版本号port is already allocated宿主机3306被其他程序占用netstat -tlnp查占用换映射端口或停掉占用进程ERROR: Got permission denied当前用户不在docker组重新登出登录或用sudo dockerError response from daemon: pull access denied镜像名拼错或私有仓库未登录检查docker login和镜像名容器启动秒退日志写着initialize specified but the data directory has files数据目录已经有数据和本次初始化冲突换一个空的数据卷或者删掉残留数据从经验来看新手最容易忽略的还是数据目录冲突。比如你第一次docker run时挂载了mysql_data:/var/lib/mysql初始化好后不满意想重新跑于是docker rm容器但卷还在。第二次run时又指定同一个卷新容器发现里面有旧数据就又不会执行初始化脚本结果密码跟你环境变量里设置的不一样连不上。这种情况其实不是故障是官方镜像的初始化规则在起作用数据目录有数据就跳过初始化。解决办法很简单把卷清空或者换一个新卷名。5.2 容器起来了却连不上先查这三处容器状态明明是Up但宿主机或者Navicat就是连不上这个问题出现频率极高。我一般按“防火墙、监听、认证”三处顺序排查。第一防火墙。CentOS7默认开着firewalld如果你没放行3306端口外部连接会被直接拒绝# 查看当前防火墙状态 systemctl status firewalld # 放行3306 firewall-cmd --permanent --add-port3306/tcp firewall-cmd --reload # 确认放行结果 firewall-cmd --list-ports也有人图省事直接systemctl stop firewalld但我建议别这么干。你将来还要跑Nginx、Redis、其他项目一次性把规则配好比彻底关闭安全得多。练习环境关了倒无所谓就怕形成习惯到生产环境也随手关防火墙那就真要出事了。第二监听地址。容器里MySQL的默认监听地址其实是0.0.0.0因为Docker端口映射需要它监听在容器内所有网卡上否则映射不会生效。如果你看到某个教程让你去容器里改bind-address127.0.0.1大概率会把自己的连接搞挂这个操作千万别随意做。第三认证方式。最容易翻车的地方。MySQL 8.0默认使用caching_sha2_password加密方式而老版本的Navicat、Python的pymysql、某些旧JDBC驱动只认mysql_native_password结果就是“密码明明是对的但连接失败”。如果实在不想换客户端可以执行ALTER USER root% IDENTIFIED WITH mysql_native_password BY 你的密码; FLUSH PRIVILEGES;但这只是临时方案生产环境还是尽量用新客户端去适配caching_sha2_password。这里还顺便说一下热词里那个频繁出现的“mysql ssl连接错误”。很多客户端默认会尝试SSL加密连接如果MySQL端SSL配置和客户端不匹配就会报SSL connection error。开发环境里最简单的处理就是在连接串里把SSL关掉比如JDBC连接最后加useSSLfalseallowPublicKeyRetrievaltrue。生产环境反过来必须开启SSL并保证证书链路完整这是安全底线不能为了省事牺牲。5.3 容器一删数据全没挂载和自启一起检查“MySQL数据丢失”是容器化数据库最容易被吐槽的点但绝大多数时候不是Docker的问题而是使用方式的问题。我见过一个真实案例同事在服务器上用docker run mysql跑了一周的业务数据然后嫌端口不对直接docker rm -f mysql重建结果跑完命令才反应过来数据全没了。原因就是他没有做任何卷挂载数据全写在容器可写层里。容器删除后这层数据也被一起清理了。解决办法前面已经提到就是-v mysql_data:/var/lib/mysql这行参数。但这里还有个隐藏坑-v后面写的卷名如果没创建过Docker会自动创建这点很方便可是如果你换了一台机器或者把Docker的数据目录整体备份恢复命名卷的丢失概率很高。所以我后来更推荐直接把数据放到宿主机明确的目录下比如-v /opt/mysql/data:/var/lib/mysql这样数据位置一目了然备份的时候直接压缩/opt/mysql目录就行不用去Docker卷目录里翻。自动重启策略也要一起检查。很多人虚拟机重启后MySQL容器没跟着起来第一反应是MySQL坏了其实只是重启策略没配。补一下docker update --restartalways mysql575.4 时区、中文乱码和性能焦虑这几个问题听起来不致命但会让人很烦。时区问题典型表现是MySQL里NOW()返回的时间和宿主机差了8小时。容器启动时设置了-e TZAsia/Shanghai一般就能解决但如果你对时区敏感比如业务要统计凌晨的数据最好在MySQL里再确认一下SELECT NOW(); SELECT global.time_zone;如果global.time_zone还是00:00可以在my.cnf里加default-time-zone 08:00然后重启容器。中文乱码问题十有八九是字符集没设对。MySQL默认的utf8实际上是utf8mb3只能存三字节的字符一些生僻字、emoji表情根本存不进去。所以从建库开始就该统一使用utf8mb4。如果你的容器已经跑起来了可以在my.cnf里配置[mysqld] character-set-serverutf8mb4 collation-serverutf8mb4_unicode_ci然后重启容器。已经存在的库和表还要单独改一遍ALTER DATABASE 你的库名 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; ALTER TABLE 你的表名 CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;性能焦虑这块我见过很多人在虚拟机里给MySQL分配大量内存和CPU其实没必要。虚拟机本身性能就比物理机差一截MySQL容器初期用默认配置完全够真遇到慢查询先看SQL语句和索引别急着加资源。6. 上线前的最后几道工序6.1 开机自启、资源上限都配好MySQL容器稳定跑起来只是第一步想要它“省心”长期跑还需要做几个小配置。开机自启已经讲过了--restartalways或docker update --restartalways mysql57必须配上。这样虚拟机一启动Docker自动起来MySQL也会跟着拉起。我遇到过不少虚拟机重启后忘配这个参数数据库起不来业务方疯狂反馈问题的场景。资源限制这个容易被忽略。虚拟机的内存是固定的如果你同时跑了MySQL、Nginx、Redis好几个容器某个容器出现内存泄漏就可能把宿主机拖垮。Docker其实支持给容器设上限# 限制内存最多2GCPU最多2核 docker update --memory 2g --cpus 2 mysql57docker stats可以实时查看容器资源占用建议定期看一眼尤其是刚上线那几天能直观发现有没有异常。6.2 定时备份MySQL别再裸奔数据库不备份等于把全部身家放在一个没有气囊的车里。虽然是用Docker跑的MySQL但备份方式其实和普通MySQL差不多。最简单的逻辑备份用mysqldump。在宿主机上直接执行docker exec mysql57 sh -c exec mysqldump --single-transaction -uroot -p$MYSQL_ROOT_PASSWORD --all-databases /opt/mysql/backup/all_$(date %F).sql这条命令会把所有数据库导成一个SQL文件--single-transaction保证导出过程中不锁业务表。密码通过环境变量$MYSQL_ROOT_PASSWORD从容器里取不需要明文写在命令里。恢复的时候反过来docker exec -i mysql57 sh -c exec mysql -uroot -p$MYSQL_ROOT_PASSWORD /opt/mysql/backup/all_2025-01-01.sql定时备份推荐用crontab。编辑 crontabcrontab -e加一行每天凌晨3点执行0 3 * * * docker exec mysql57 sh -c exec mysqldump --single-transaction -uroot -p$MYSQL_ROOT_PASSWORD --all-databases /opt/mysql/backup/all_$(date \%F).sql 21注意crontab里%需要转义成\%否则会被当成换行符。备份文件建议保留最近7天或30天再写个find命令清理旧文件find /opt/mysql/backup -name *.sql -mtime 7 -exec rm {} \;这套流程虽然朴素但真到了误删数据、容器损坏的时候能救命的往往就是这么简单的备份。6.3 端口暴露范围收一收之前为了练手方便我在docker run里写的是-p 3306:3306意思是宿主机所有网卡都暴露3306端口。如果虚拟机设置了桥接网络相当于局域网里其他机器也能直接访问这个数据库只要密码被爆破就是事故。生产环境或者长期使用的虚拟机建议把端口绑定到指定IP比如只允许本机访问-p 127.0.0.1:3306:3306这样只有宿主机能连接外部机器完全访问不到。如果应用也在同一台虚拟机上跑这个方案完全够用。如果确实需要远程访问再放开到具体内网IP-p 192.168.1.100:3306:3306这个细节看似无关紧要但它是判断你有没有“容器安全”意识的一个重要分界线。6.4 写在最后一点个人建议这套环境我前前后后搭过不下十遍每次都能踩到一两个新的小坑。最近一次帮朋友排查时发现他装完Docker没配镜像加速器拉MySQL镜像用了四十分钟还以为自己网速不行其实换个镜像源一分钟就完事。我自己最大的体会是Docker装MySQL本身不难难的是想清楚数据存哪里、配置怎么改、重启之后会发生什么。把这三个问题想明白了后面基本一马平川。如果你也在虚拟机上第一次折腾这套装环境强烈建议装好CentOS7后先打个快照后面随便造造坏了秒回滚。镜像拉下来、容器跑起来、远程连上来之后再回头做一遍那几道“收尾工序”您的MySQL环境就很扎实了。
返回列表