用 Docker 部署一个带 MySQL 的小站:从 0 到 可访问
这篇文章是写给未来自己的 Docker + MySQL 部署速记,用尽量直白的方式把从安装 Docker 到应用连上数据库这一整套流程走一遍。
一、为什么要用 Docker 跑 MySQL?
在本地或服务器上安装 MySQL,有几种常见方式:
- 直接在系统里安装(
apt install mysql-server、安装包下一路下一步等) - 用各种图形化软件自带的数据库(比如某些集成环境)
- 用 Docker 拉一个 MySQL 容器跑起来(可以理解成在一台“虚拟小机器”里跑 MySQL)
我更倾向于用 Docker,主要有几个原因:
- 环境干净:不用在系统里装一堆服务,删起来也干净。
- 版本可控:想用哪个 MySQL 版本在
docker pull mysql:8.0里写清楚就行。 - 迁移简单:换一台机器,只要装好 Docker,命令一跑环境就起来了。
- 和应用解耦:应用挂了、数据库挂了都是独立的,互不污染。
后文会从“什么都没有”的状态开始,依次完成:
- Docker 安装好
- MySQL 容器跑起来
- 数据能够持久化(重启容器不丢)
- 应用(或者本地工具)能连上这个 MySQL。
做到这四步,基本就能支撑一个小项目的数据库需求。
二、准备工作:安装 Docker
1. Windows / macOS
如果你用的是 Windows 10/11 或 macOS,最省心的方法是直接装 Docker Desktop(以 Windows 为例):
- 打开浏览器,搜索 “Docker Desktop Windows 2026”
- 在官方页面下载安装包(注意是
docker.com相关域名) - 安装时基本一路下一步,安装完成后重启电脑
- 打开 Docker Desktop,等它状态变成
Running或者小鲸鱼图标稳定
安装完成后,打开终端(PowerShell / Terminal),执行:
docker versiondocker info能看到版本信息就说明安装成功。
2. Linux
Linux 发行版比较多,这里以常见的 Debian / Ubuntu 系为例:
sudo apt updatesudo apt install ca-certificates curl gnupg -y
# 添加 Docker 官方 GPG key 和源(略去具体细节)# 安装 Docker Enginesudo apt install docker-ce docker-ce-cli containerd.io -y
sudo systemctl enable dockersudo systemctl start docker安装完成后同样用 docker version 确认即可。
三、用 Docker 拉起一个 MySQL 容器
1. 拉取 MySQL 镜像
先拉一个 MySQL 8 的官方镜像:
docker pull mysql:8.0拉取完成后,可以用:
docker images看到类似 mysql 8.0 ... 的一行就说明拉取成功。
2. 第一次运行 MySQL 容器(最简单版本)
下面是一个最小可运行的示例命令:
docker run --name my-mysql \ -e MYSQL_ROOT_PASSWORD=your_root_password \ -p 3306:3306 \ -d mysql:8.0参数解释:
--name my-mysql:给容器取个名字,后面好操作。-e MYSQL_ROOT_PASSWORD=...:设置 root 用户密码,这是必须的。-p 3306:3306:把宿主机的 3306 端口映射到容器的 3306 端口,便于外部连接。-d:后台运行。mysql:8.0:使用刚才拉下来的 MySQL 8.0 镜像。
启动之后,用:
docker ps看到 my-mysql 处于 Up 状态,就说明 MySQL 已经在容器里跑起来了。
不过,这个最简单版本没有数据持久化,也只有 root 账户,离生产环境还差一截,下面来补全。
四、给 MySQL 加上数据卷:防止数据丢失
在 Docker 的世界里,有一个非常重要的概念叫 volume(数据卷),用来把容器内部的数据映射 / 挂载到宿主机,可以粗略理解成“专门留给容器用的一块硬盘区域”。这样,即使容器被删掉,只要卷还在,数据就还在。
MySQL 容器默认会把数据写到 /var/lib/mysql 目录,我们要做的,就是把这个目录挂载到宿主机上的一个真实文件夹。
1. 创建一个数据目录
比如在宿主机上先创建一个目录:
mkdir -p ~/docker-data/mysqlWindows 下可以用类似:
mkdir C:\docker-data\mysql2. 用数据卷重新运行 MySQL
如果之前已经启动过一个名为 my-mysql 的容器,建议先把它停掉并删除:
docker stop my-mysqldocker rm my-mysql然后用挂载卷的方式重新跑:
docker run --name my-mysql \ -e MYSQL_ROOT_PASSWORD=your_root_password \ -e MYSQL_DATABASE=app_db \ -e MYSQL_USER=app_user \ -e MYSQL_PASSWORD=app_user_password \ -v ~/docker-data/mysql:/var/lib/mysql \ -p 3306:3306 \ -d mysql:8.0在这个命令里,我们比之前多做了几件事:
-v ~/docker-data/mysql:/var/lib/mysql:把容器的/var/lib/mysql挂到宿主机目录,实现数据持久化。-e MYSQL_DATABASE=app_db:启动时自动创建一个名为app_db的数据库。-e MYSQL_USER=app_user+-e MYSQL_PASSWORD=...:自动创建一个普通用户,适合作为应用连接使用。
这样一来,即使你把 my-mysql 这个容器删了,再用同样的数据卷重新启动一个新的 MySQL 容器,之前的表和数据也都还在。
五、进入容器里看一眼 MySQL
要直接在容器里执行几条 SQL、确认数据库是否正常工作,可以进入容器内部:
docker exec -it my-mysql bash进入容器后,使用 MySQL 自带的命令行客户端:
mysql -u root -p输入刚才设置的 MYSQL_ROOT_PASSWORD,登录成功后就能看到熟悉的 MySQL 提示符。
可以简单测一下:
SHOW DATABASES;USE app_db;CREATE TABLE test ( id INT PRIMARY KEY AUTO_INCREMENT, content VARCHAR(255));INSERT INTO test (content) VALUES ('hello docker mysql');SELECT * FROM test;确认没问题后,输入:
exitexit第一次是退出 MySQL,第二次是退出容器的 shell。
六、从宿主机或开发工具连接这个 MySQL
现在 MySQL 容器已经把 3306 端口映射到了宿主机,可以直接用各种工具连上去:
- 数据库可视化工具:如 Navicat、TablePlus、DBeaver 等
- 应用程序:Node.js、Java、Go、Python 等后端服务
假设你的 Docker 跑在本机上,连接信息大致如下:
- 主机(Host):
127.0.0.1或localhost - 端口(Port):
3306 - 用户名(User):
app_user - 密码(Password):
app_user_password - 数据库名(Database):
app_db
在可视化工具里把这些填上,测试连接通过即可开始用 GUI 管理表和数据。
如果是 Node.js 应用,可以用 mysql2 举个简单例子:
npm install mysql2import mysql from "mysql2/promise";
const pool = mysql.createPool({ host: "127.0.0.1", port: 3306, user: "app_user", password: "app_user_password", database: "app_db",});
async function testConnection() { const [rows] = await pool.query("SELECT NOW() as now"); console.log(rows);}
testConnection().catch(console.error);只要控制台里能打印出当前时间,说明和 Docker 里的 MySQL 已经连通了。
七、用 docker-compose 管理 MySQL(以及未来的应用)
如果只部署一个 MySQL,用 docker run 还算简单。但一旦出现:
- 应用容器
- 数据库容器
- 可能还有 Redis、Nginx 等
命令一多就很难维护,这时可以用 docker-compose 统一管理。
1. 写一个最简单的 docker-compose.yml
在你的项目根目录(或者专门的部署目录)创建一个名为 docker-compose.yml 的文件:
version: "3.9"
services: mysql: image: mysql:8.0 container_name: my-mysql restart: always environment: MYSQL_ROOT_PASSWORD: your_root_password MYSQL_DATABASE: app_db MYSQL_USER: app_user MYSQL_PASSWORD: app_user_password ports: - "3306:3306" volumes: - ./mysql-data:/var/lib/mysql command: - --default-authentication-plugin=mysql_native_password - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci相较于直接使用命令行,这里做了几件事:
- 把之前命令行里的参数转成 YAML 配置,清晰可读。
- 增加了
restart: always,让容器在服务重启后自动拉起。 - 用
./mysql-data做数据卷,方便和项目一起管理。 - 通过
command显式设置字符集,为中文内容存储打好基础。
在这个 docker-compose.yml 同级目录下运行:
docker compose up -d容器就会按照配置自动创建并启动。
查看状态:
docker compose ps如果要停止服务,可以执行:
docker compose down注意:默认 down 不会删掉卷里的数据(除非你加了 -v)。
2. 把你的应用也写进 compose
以后如果你的项目也用 Docker 方式部署,可以直接在 services 下面再加一个服务:
app: build: . container_name: my-app depends_on: - mysql environment: DB_HOST: mysql DB_PORT: 3306 DB_USER: app_user DB_PASSWORD: app_user_password DB_NAME: app_db ports: - "8080:8080"这里有一个关键点需要注意:
- 在同一个
docker-compose网络里,服务之间可以通过 服务名 互相访问,所以DB_HOST不再是127.0.0.1,而是mysql。
以后要启动整套服务,只需要一句命令:
docker compose up -d八、几件容易踩坑但很关键的小事
1. 端口被占用
如果你启动容器时报错类似 “Bind for 0.0.0.0:3306 failed: port is already allocated”,说明本机 3306 已经被其他程序占用。
大致的解决思路:
- 查一下是谁占用了 3306(Windows 下可以用资源监视器,Linux 用
lsof -i:3306等)。 - 停掉本机自带的 MySQL 服务,完全改用 Docker 里的。
- 或者在 Docker 这边改一个宿主机端口,比如:
ports: - "3307:3306"连接时用宿主机端口 3307 即可。
2. 权限/读写问题
在 Linux 上,如果你把数据卷挂到某些权限控制比较严格的目录,有时候会遇到读写权限问题,导致 MySQL 启不起来。
比较通用的经验做法:
- 用普通用户有权限的目录,比如
/home/youruser/docker-data/mysql。 - 或者为该目录设置合适的权限:
sudo chown -R youruser:youruser /home/youruser/docker-data/mysql3. 字符集和乱码
如果你要存中文内容,一定记得把 MySQL 的字符集设成 utf8mb4,否则可能会出现一些隐蔽问题,比如:
- 表创建时默认不是 utf8mb4
- 表情符号/部分字符插入失败
用 docker-compose 的方式,可以统一在 command 里配置:
command: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_unicode_ci已经创建的表,如果字符集不对,可以后续用 ALTER TABLE 改。
九、简单回顾:从 0 到 可以用
最后简单整理一下本文做的事情:
- 安装 Docker / Docker Desktop,让机器具备跑容器的能力。
- 拉取 MySQL 官方镜像:
docker pull mysql:8.0。 - 用
docker run启动一个 MySQL 容器,确认可以运行。 - 给 MySQL 挂上卷,把
/var/lib/mysql映射到宿主机目录,实现数据持久化。 - 通过
docker exec进入容器,直接在 MySQL 里创建数据库和表,确认一切正常。 - 从宿主机或者应用代码里,使用正确的主机、端口和账号连接到容器里的 MySQL。
- 用
docker-compose把配置写进一个文件里,以后一句命令就能启动完整的服务。
目的只是保留一套自己踩过坑之后沉淀出来的流程,方便以后再部署带 MySQL 的小项目时少查文档、少走弯路,也希望能顺便帮你省点试错时间。
十、如果要放到真正的服务器上,我会怎么做?
最后补充一点更贴近“上线”的思路,给整篇笔记收个尾,也方便以后自己查阅。
-
先在本地把 docker-compose 跑顺。
所有服务(应用、MySQL、缓存、Nginx 等)都写在一个docker-compose.yml里,确保在本地一句docker compose up -d就能跑起来,并且各个服务之间的网络配置是正确的。 -
服务器上只做三件事:装 Docker、拉代码、改配置。
- 安装 Docker / Docker Compose(新版本已经合并成
docker compose)。 - 从 Git 仓库把项目拉到服务器上。
- 根据服务器环境,调整
.env或docker-compose.yml里的少量配置(比如端口、域名、密码)。
- 安装 Docker / Docker Compose(新版本已经合并成
-
把所有敏感信息挪到环境变量或
.env文件里。
开发阶段可能直接把MYSQL_ROOT_PASSWORD、DB_PASSWORD写在docker-compose.yml里,上服务器之后更推荐的做法是:- 新建
.env文件(不要提交到 Git 仓库)。 - 把密码、密钥、连接串等写到
.env里。 - 在
docker-compose.yml里用${VAR_NAME}的形式引用。
- 新建
-
做好备份和监控的最低配置。
即使用的是 Docker 里的 MySQL,也一定要定期备份数据,比如:- 写一个简单的备份脚本,用
mysqldump把数据导出到宿主机目录。 - 再配合 crontab,让它每天/每周自动执行一次。
- 最起码在重要更新前,手动备份一份,这一步永远不会多余。
- 写一个简单的备份脚本,用
-
用 Nginx(或其他反向代理)把流量引到应用容器。
当你的应用也跑在 Docker 里时,可以:- 用另一个 Nginx 容器做反向代理,通过域名访问。
- 或者用宿主机上的 Nginx 转发请求到 Docker 网络里的应用容器。
- MySQL 通常不会直接对公网开放,而是只允许应用容器访问,或者只对特定的 IP 段开放。
-
保留一份“最小可用”的部署文档。
本文其实已经是一个雏形,但你可以在自己的仓库里再写一份更贴近你项目的 README:- 如何在新机器上从零开始部署。
- 所有需要的环境变量列表。
- 常见错误(比如端口冲突、权限问题)以及解决方式。
当这些东西都跑通之后,再看 Docker + MySQL 部署,你可能会发现它不再是一个“神秘的黑盒”,而只是你工具箱里一套相对顺手的流程而已。等未来你要再加上 Redis、消息队列,甚至是整套 CI/CD,只需要在现在这套基础上继续往前“加一层楼”就行了。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!