跳至主要内容

如何在 Docker 中设置和配置 MySQL

学习如何在 Docker 容器中设置和配置 MySQL 数据库。教程涵盖连接 MySQL 服务器、运行 MySQL 客户端连接容器等内容。
· 12分钟 阅读

使用 AI 探索

MySQL 是最受欢迎的关系型数据库工具,市场份额超过 40%。与其竞争对手 PostgreSQL(16%)和 Oracle Database(11%)相比,数据相当亮眼。

MySQL 之所以流行,是因为它简单却强大。以下是它的一些最佳特性:

  • 关系型:遵循关系模型,使用 SQL 管理数据库。
  • 开源(GNU 许可):社区喜欢它,公司也喜欢它。
  • 可扩展:可支撑从小型到企业级的应用。
  • 安全:提供用户认证、访问管理和加密。
  • 高性能:以在处理复杂查询和大数据量时的速度与效率著称。
  • 复制与备份:支持数据复制和备份选项,可用于灾难恢复策略。

在 Docker 容器中使用 MySQL,可以说是天作之合。如果您之前使用过 Docker,那么它的所有优势同样适用于 MySQL Docker 容器:

  • 隔离性与一致性:MySQL 实例将与其他软件和依赖分离,避免潜在冲突。
  • 版本控制:Docker 允许您与 MySQL 一起为整套软件栈做版本化。您可以随时复现环境,便于开发与测试。
  • 可扩展与资源管理:借助 Docker,您可以通过轻松分配更多内存或 CPU 来扩展 MySQL 应用。
  • 依赖管理:Docker 封装您的 MySQL 实例,让您可以管理不同版本,而不影响本机的其他内容。

最重要的是,您的 MySQL 应用可以在任何地方运行,而不仅仅是您的电脑上。

如果您想将 MySQL 与其第二受欢迎的竞争对手进行对比,欢迎查看我们的深度比较文章 PostgreSQL 与 MySQL。

今天,您将学习如何将 MySQL 与 Docker 协同运行的基础知识。让我们开始吧!

先决条件

由于本文聚焦于 MySQL Docker 容器,跟进实践需要满足以下前提:

  • 命令行/终端访问:您需要一个可访问终端的本地环境。如果您在 Colab 等 Jupyter 环境中,请现在切换。
  • 正在运行的 Docker 实例:您应已安装 Docker Desktop(可参考我们的 面向数据科学的 Docker 教程)。完全就绪后,界面左下角会出现绿色小鲸鱼:

image2.png

并且在终端中运行 docker --help 命令不会报错。

  • 具备 Docker 基础:尽管我会讲解文中使用的所有命令,但具备基本的 Docker 理解,会显著提升您从本文获得的收益。
  • SQL:SQL 同理——本文不讲解出现的 SQL 命令,以免偏离主题。如果您的 SQL 技能有些生疏,可在这门 SQL 课程中回顾重点。

下载官方 MySQL Docker 镜像

我们先用下面的命令下载官方 MySQL Docker 镜像:

$ docker pull mysql:latest

docker pull 需要以 image:version 的语法指定镜像名称和版本。使用关键字 latest 将下载最新的稳定版。

如果访问 Docker Hub 上的官方 MySQL 镜像页面,您会看到为不同用途提供的许多版本。

image3.png

例如,以下命令用于下载 v8.2:

$ docker pull mysql:8.2

下载完成后,镜像应会出现在您现有的 Docker 镜像列表中:

image4.png

也可以通过终端列出 Docker 镜像:

$ docker images

image5.png

请记住:Docker 镜像是构建容器的蓝图。就像蓝图能指导建房一样,Docker 镜像包含创建某个应用或服务运行实例所需的全部指令与组件。

如果您有 OOP 背景,可以把 Docker 镜像类比为类(class)。正如一个类能实例化出多个对象,Docker 镜像也能基于它们创建多个容器。

运行与管理 MySQL 服务器容器

现在,让我们基于 mysql 镜像创建第一个容器。使用如下命令:

$ docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=strong_password -d mysql
  • run:创建一个新容器或启动现有容器
  • --name CONTAINER_NAME:为容器命名。名称应简短易读。本例为 test-mysql。
  • -e ENV_VARIABLE=value:-e 标记用于在容器内创建可访问的环境变量。必须设置 MYSQL_ROOT_PASSWORD,以便稍后能在容器中运行 SQL 命令。请务必妥善保存您的强密码(别只记在脑子里)。
  • -d:即 detached,表示让容器在后台运行。若去掉此标签,命令会持续打印日志直到容器停止。
  • image_name:最后一个参数是用于构建容器的镜像名。此处为 mysql。

如果命令返回一长串字符(容器 ID),说明容器已启动。您可以用 docker ps 查看其状态:

image6.png

请记住:Docker 容器是功能强大的操作系统“仿真环境”。除了运行 MySQL,您还可以在容器内完成任何通常在电脑终端中进行的任务。

要进入容器内的终端,可使用:

$ docker exec -it container_name bash

这会启动一个 bash 会话。

在本机连接 MySQL 服务器容器

所有 MySQL 容器都会启动一个MySQL 服务器,它包含用于用 SQL 创建和管理数据库的一切。同时,容器也带有用于连接服务器的MySQL 客户端,让我们可以运行 SQL 查询。客户端其实就是 mysql 终端命令的“好听名字”。我们在 test-mysql 的终端里试用它:

1. 打开 test-mysql 的 bash 终端:

$ docker exec -it test-mysql bash

2. 以 root 用户连接客户端:

$ mysql -u root -p
Enter password: ...
mysql>

我们使用 -u 指定用户名(root),并加上 -p 在提示时输入密码。

image1.gif

也可以在容器外连接 MySQL 服务器。例如,您可以在主机上手动安装 MySQL 客户端进行连接。

在 Windows 上安装 MySQL 及其客户端,可参照官方 MySQL 安装指南。

Mac 上可用 Homebrew:

$ brew install mysql

Linux 或 WSL2(我个人的选择)上可使用 sudo:

$ sudo apt update
$ sudo apt install mysql-client

安装完成后,如果容器正在运行,请先停止并移除:

$ docker stop test-mysql
test-mysql
$ docker rm test-mysql

接下来,我们将通过映射端口的方式重新启动容器:

$ docker run -d --name test-mysql -e MYSQL_ROOT_PASSWORD=strong_password -p 3307:3306 mysql

该命令的作用如下:

  • -p 3307:3306:将容器的 3306 端口(MySQL 默认端口)映射到本地 3307 端口。也就是说,发往您本地 3307 端口的流量会被转发到容器内的 3306 端口,您的 MySQL 服务器将通过该端口可达。
  • -d:再次以分离模式运行容器。
  • --name test-mysql:继续使用容器名 "test-mysql"。
  • -e MYSQL_ROOT_PASSWORD=strong_password:再次为 MySQL 服务器设置 root 密码。
  • mysql:指定要运行的 Docker 镜像,即官方 MySQL 镜像。

终端输出新容器 ID 后,我们可以查看端口映射:

$ docker port test-mysql
3306/tcp -> 0.0.0.0:3307

映射成功!现在,您可以在本机上通过端口 3307 使用 mysql 客户端连接服务器:

$ mysql --host=127.0.0.1 --port=3307 -u root -p
Enter password:

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 8
Server version: 8.2.0 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates…

配置 MySQL 容器

您可以通过配置文件对 MySQL 容器进行大量设置。该文件通常存放在容器的以下目录之一:

  • /etc/mysql/
  • /etc/mysql/conf.d
  • /etc/mysql/mysql.conf.d

不同镜像的目录可能不同。但配置文件的标准文件名与扩展名为 my.cnf。如果在上述任一目录都不存在该文件,说明该容器需要自定义配置文件。我们的 test-mysql 容器正是这种情况:

$ ls /etc/mysql/conf.d/ # Returns no output

遇到这种情况,我们需要谨慎地按以下步骤操作:

1. 停止并移除容器:

$ docker stop test-mysql; docker rm test-mysql

2. 在本地(您的机器上)创建一个空配置文件:

$ sudo mkdir -p /etc/docker/test-mysql # Create a dir
$ sudo touch /etc/docker/test-mysql/my.cnf # Create a config file inside dir

3. 通过关联这两个空的 .cnf 文件来重启容器:

$ docker run \
   --name test-mysql \
   -v /etc/docker/test-mysql:/etc/mysql/conf.d \
   -e MYSQL_ROOT_PASSWORD=strong_password \
   -d mysql

这里我们使用了一个新标签:-v,即 volume。该标签用于在容器与本机之间关联目录。在计算机科学术语中,这个过程称为挂载。

因此,在上面的命令中,我们将本地的 /etc/docker/test-mysql 目录挂载到容器的 /etc/mysql/conf.d 目录。这样会同步两个目录的内容。在任一目录所做的更改都会体现在两边。

通过挂载,我们可以在本机编辑 my.cnf 文件,从而更改 Docker 容器的配置。更棒的是,即使容器被停止或移除,修改过的配置仍会保存在本机,可重复使用。

那么,完成这一步之后,可以修改哪些配置?答案取决于您的使用场景。我们将在下文介绍。

想要获得 Docker 认证吗?请查看我们的Docker 认证指南!

应该配置哪些选项?

尽管 MySQL Docker 容器的默认配置适用于许多常见场景,但为优化性能、安全性和资源使用,您应当调整某些设置。以下是最常见的一些配置项:

性能

  • innodb_buffer_pool_size:决定分配给 InnoDB 缓冲池的内存大小,缓冲池会缓存常用数据以加快读取。增大该值可提升读密集型负载的性能,但会占用更多内存。
  • query_cache_size:控制查询缓存的大小,存储已执行的查询以加快重复执行。增大该值有助于提升重复性查询的性能,但会占用更多内存,对高度动态的查询可能效果不佳。
  • thread_pool_size:决定服务器可处理的最大并发连接数。根据预期流量调整该值可优化资源利用并防止瓶颈。

安全

  • bind-address:限制 MySQL 服务器仅监听特定网络接口,阻止未授权来源的访问。
  • mysql_bind_host:允许将 MySQL 服务器绑定到特定 IP 地址,而非监听所有接口。
  • validate_password_policy:启用更严格的密码要求,以提升安全性。

资源利用

  • max_connections:控制允许的最大并发连接数。适当调整可避免资源耗尽,确保服务器高效运行。
  • innodb_file_per_table:将每个 InnoDB 表存储在单独文件中,可能提升性能,但会增加存储占用。
  • innodb_io_capacity:设置存储系统的预估 IOPS(每秒输入/输出操作数),以便引擎优化缓冲池使用与磁盘操作。

其他常见修改

  • character_set_server:设置服务器的默认字符集,确保数据编码和处理一致。
  • collation_server:决定字符数据排序与比较所使用的默认校对规则。
  • log_bin:启用服务器活动的二进制日志,有助于故障排查与复制。

要查看完整的配置选项列表,可以运行以下命令:

$ docker run -it --rm mysql:tag --verbose --help

您可以使用任意文本编辑器编辑 .cnf 文件。语法如下:

[mysqld]
max_connections=200
other_params=value
...

如何持久化 MySQL Docker 容器中的数据

将 MySQL 容器中的数据持久化至关重要,原因包括:

  • 数据持久性:停止或移除容器时,所有数据(包括数据库)都会丢失。将数据与容器解耦可确保随时可访问。
  • 在容器之间共享数据:将数据从容器中分离,允许多个容器访问同一份数据,从而避免数据重复,简化使用相同数据的项目之间的同步。
  • 可移植性与备份:持久化的数据易于独立备份与共享,可为数据丢失或误删提供可靠的恢复途径。
  • 更好的性能与可扩展性:将常用数据存放在 SSD 等持久化存储上,相比依赖通常较慢的容器可写层,可提升应用性能。

流程与我们已经见过的类似——创建一个卷并将其挂载到容器中存储数据的位置。步骤如下:

1. 创建一个卷:

$ docker volume create test-mysql-data

volume create 命令会在本地文件系统上为该卷创建专用存储。卷被挂载后,所有容器数据都将与其关联。

2. 挂载该卷后重启容器:

$ docker stop test-mysql; docker rm test-mysql
$ docker run \
   --name test-mysql \
   -v test-mysql-data:/var/lib/mysql \
   -e MYSQL_ROOT_PASSWORD=strong_password \
   -d mysql

这次的语法为:-v volume_name:directory_in_container。按照 MySQL 镜像文档,所有创建的卷都应挂载到 /var/lib/mysql 目录。

现在,在 test-mysql 中创建的任何数据库或表都会在本地持久化,即使容器被停止或移除也不受影响。

最终命令

在本文中,我们的 docker run 命令经历了多次演进。现在,让我们把所有变体整合成一个最终“总命令”。我们需要再次停止并移除容器,同时移除卷以便从头开始:

$ docker stop test-mysql; docker rm test-mysql
$ docker volume rm test-mysql-data

下面是最终的总命令:

$ docker run \
   --name final-mysql \
   -e MYSQL_ROOT_PASSWORD=strong_password \
   -p 3307:3306 \
   -v /etc/docker/test-mysql:/etc/mysql/conf.d \
   -v final-mysql-data:/var/lib/mysql \
   -d mysql

该命令会将我们之前的本地 my.cnf 文件挂载到目标位置,同时创建并挂载名为 final-mysql-data 的新卷。

使用 Docker Compose 管理复杂的 MySQL 部署

对于涉及多个容器的高级场景(例如将 MySQL 与其他服务一起运行,如 Web 服务器或应用后端),Docker Compose 通过单个配置文件定义和管理多容器应用,从而简化流程。

以下是一个用于 MySQL 容器的基础 docker-compose.yml 示例:

version: '3.9'
services:
  db:
    image: mysql:8.3.0
    container_name: mysql-db
    environment:
      MYSQL_ROOT_PASSWORD: strong_password
      MYSQL_DATABASE: example_db
      MYSQL_USER: user
      MYSQL_PASSWORD: user_password
    ports:
      - "3306:3306"
    volumes:
      - db_data:/var/lib/mysql
      - ./mysql-config:/etc/mysql/conf.d
volumes:
  db_data:

使用 Docker Compose 的步骤:

  • 创建 docker-compose.yml 文件:将配置文件保存在您的项目目录中。
  • 启动服务:运行以下命令启动文件中定义的所有服务:
docker-compose up -d
  • 停止服务:完成后关闭服务:
docker-compose down

Docker Compose 对 MySQL 的好处:

  • 配置更简化:在单个文件中管理 MySQL 配置、端口与卷。
  • 更易扩展:轻松扩展数据库,或将其与应用栈中的其他服务集成。
  • 数据持久化:在容器重启间自动管理卷,确保数据持久化。

在管理多个环境(如开发、预发布和生产)或与团队协作时,使用 Docker Compose 尤其有帮助。

结语

本文介绍了在 Docker 容器中运行与管理 MySQL 数据库的关键要点。我们学习了如何下载与设置 MySQL 镜像、在容器内启动 MySQL 服务器、如何修改容器并通过卷实现自定义配置与数据持久化。

若想进一步学习,推荐以下资源:

感谢阅读!

FAQs

Can I use Docker Compose to manage multiple MySQL containers?

可以。Docker Compose 是管理多个 Docker 容器(包括 MySQL)的优秀工具。您可以在 docker-compose.yml 文件中定义 MySQL 服务配置,从而用一条命令启动、停止并管理多个服务。

How do I upgrade MySQL to a newer version in a Docker container?

要在 Docker 容器中升级 MySQL,您需要先拉取新版本的 MySQL Docker 镜像,然后用该新镜像重新创建容器。升级前请确保已备份数据。

Can I run multiple MySQL containers on the same host?

可以,您可以在同一主机上运行多个 MySQL 容器。每个容器都必须通过 -p 选项在主机上分配唯一端口,以避免端口冲突。

What are the security best practices for running MySQL containers?

安全最佳实践包括:在没有完善安全措施的情况下,不要将 MySQL 容器暴露在公网;使用强密码;定期更新 Docker 与 MySQL 镜像;对密码等敏感信息使用 Docker secrets。

How can I automate the backup of MySQL databases in Docker?

您可以在主机上创建一个定时任务(cron job),使用 docker exec 在容器内运行 mysqldump。或者,您也可以使用 Docker 卷来持久化数据,并直接在主机上执行备份。

Can I connect to the MySQL Docker container from another container?

可以。只要确保两个容器位于同一 Docker 网络上,就可以从另一个容器进行连接。连接时可以使用该容器的名称作为主机名。

How do I troubleshoot connection issues with my MySQL container?

可通过以下方式排查连接问题:检查容器是否正在运行(docker ps),验证端口映射(docker port),检查网络配置,并确保容器内的 MySQL 服务器已配置为接受来自主机或其他容器的连接。

Is it possible to use a custom MySQL configuration file without mounting it from the host?

可以,您可以在容器内创建自定义配置文件。不过,更常见的做法是从主机进行挂载,便于管理与持久化。

How can I monitor the performance of my MySQL container?

您可以使用 mysqladmin 等工具监控 MySQL 专属指标,使用 Docker 内置的统计命令(docker stats),或使用 Prometheus 等第三方监控方案,配合 Docker 与 MySQL 的导出器。

What should I do if my MySQL Docker container crashes?

如果容器崩溃,首先使用 docker logs <container_name> 查看日志以定位错误。确保配置与环境变量正确,并确认不存在资源(CPU、内存)限制。重启容器并监控其运行状况。

Bexruz (Bex) Tuychiev

作者

Bexruz (Bex) Tuychiev

我是一名数据科学内容创作者,拥有超过 2 年的经验,并在 Medium 上拥有较大的读者群。我喜欢用略带讽刺的笔调撰写有关 AI 和机器学习的深度文章——毕竟总得想点办法让这些内容不那么枯燥。我已发表 130 多篇文章,并制作了一门 DataCamp 课程,另有一门正在筹备中。我的内容已被超过 500 万人次阅读,其中有 2 万人在 Medium 和 LinkedIn 上成为关注者。 

主题