news 2026/10/1 18:07:23

MariaDB容器化部署实战:从Docker Compose到备份恢复全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MariaDB容器化部署实战:从Docker Compose到备份恢复全指南

最近好几个朋友问我同一个问题:MariaDB 到底怎么部署才省心?我手里同时管着几套业务库,既有早期在物理服务器上硬装的二进制实例,也有后来全部迁移到容器里的集群,用下来的感受很直接——容器化部署 MariaDB 是当前个人项目、中小团队和微服务架构里性价比最高的方案之一。它把“装包、配置、启停、迁移”这些重复劳动压缩到一个 compose 文件里,三分钟能拉起一个规范实例,半小时能搭完一套带定时备份的完整环境。

这篇文章会围绕容器化部署 MariaDB 的完整链路展开:镜像选型、持久化设计、初始化机制、docker compose 实战、备份恢复、常见坑排查,全程用我实际维护过的配置和踩过的坑说话。适合正在用 yum 或源码硬装数据库、或者第一次打算把数据库塞进容器的朋友,看完可以直接照着操作。

1. 为什么把 MariaDB 装进容器:镜像选型与总体思路

1.1 容器化部署到底解决了什么问题

很多人对“数据库上容器”的第一反应是:容器不适合跑有状态服务。这个观点在我早期刚接触 Docker 时也认同,但后来实际维护了几个容器化数据库实例之后,想法改变了。问题的关键不在于“能不能跑”,而在于“怎么设计持久化和运维流程”。设计得当的情况下,容器化带来的优势非常明显。

先看传统部署方式的问题。二进制安装要下载安装包、解决 glibc 和 libaio 这些依赖、手动初始化数据目录、写 systemd 服务文件;yum 安装虽然省去依赖问题,但版本往往偏老,升级时还容易把系统里的其他组件搞乱。更要命的是环境不一致:开发机上好好的配置,到测试机上因为路径不同、用户不同、参数不同,又要重新调一遍。

容器化把这些问题一次性封装掉了。官方镜像里已经包含了 MariaDB 运行所需的全部依赖和默认配置,宿主机只需要有 Docker 引擎。开发、测试、生产三套环境拉同一个镜像、跑同一份 compose 文件,行为完全一致。迁移也简单,数据目录挂载在外部,容器随便删随便重建,数据不丢。

我用一张表来对比三种方式的差别:

对比项二进制安装yum/apt 包管理容器化
环境一致性差,依赖手工处理一般,受系统版本影响好,镜像自带全部依赖
部署时间10-30 分钟5-15 分钟1-3 分钟
升级回滚麻烦,需停服替换依赖仓库版本改 tag 即可来回切换
隔离性与系统共享运行环境与系统共享运行环境独立进程和文件系统
迁移难度高,需重复安装配置中低,数据目录拷走即可

当然容器化也有代价,比如多了一层 Docker 的故障排查链路、需要额外理解镜像和容器的生命周期。但从团队协作和交付效率来看,这点代价完全值得。

1.2 镜像选型:官方 mariadb 镜像的版本与 tag

镜像选择是第一步,也是最容易被忽视的一步。Docker Hub 上搜 MariaDB 会看到两个主流镜像:mariadb(官方)和bitnami/mariadb(Bitnami 打包)。我优先推荐官方镜像,原因有三个:更新及时、文档齐全、Docker Hub 上直接标注了版本支持周期。

官方镜像的 tag 选择有讲究。MariaDB 从 11.4 开始进入新的 LTS 节奏,11.4 是长期支持版,官方维护到 2029 年;11.5、11.6 这些是滚动发布版,功能新但维护周期短。生产环境我建议锁定 LTS 版本的具体小版本号,比如mariadb:11.4.4,而不是用mariadb:11.4甚至mariadb:latest。锁定精确版本号能保证每次部署拿到的镜像完全一致,配合镜像仓库的 digest 校验,出问题时可追溯。

还有一点要注意架构问题。官方镜像同时发布 amd64 和 arm64 两个架构的版本,树莓派、飞腾等 ARM 设备上直接拉同 tag 就能跑,不需要额外处理交叉编译。这一点比二进制安装方便太多——二进制包经常只提供 x86 版本,ARM 环境得自己编译,非常痛苦。

2. 核心细节拆解:数据持久化、配置与初始化机制

2.1 数据持久化:volume 与 bind mount 的取舍

容器是“临时”的,这个特性决定了容器化部署数据库的第一原则:数据必须存放在容器外部。否则docker rm一执行,整库数据就跟着容器一起消失了。MariaDB 官方镜像的工作目录是/var/lib/mysql,我们要做的就是把宿主机目录或 Docker 卷挂载到这个位置。

Docker 提供了两种挂载方式:named volume(命名卷)和 bind mount(绑定挂载)。命名卷由 Docker 管理,宿主机上的实际路径隐藏在/var/lib/docker/volumes/下,适合不想关心数据具体存放在哪里的场景;绑定挂载直接把宿主机某个目录映射进去,比如/data/mariadb:/var/lib/mysql,路径一目了然,方便备份和审计。

实际项目中我更偏向绑定挂载,因为能直接用 rsync、tar 等宿主机工具操作数据文件。但有一个坑必须提前说:目录权限。容器内的 mysql 用户 UID 是999,如果挂载的宿主机目录权限是root:root,容器启动时会报chown失败或者直接拒绝写入。解决办法是在创建目录后执行:

mkdir -p /data/mariadb chown -R 999:999 /data/mariadb

如果你的宿主机开启了 SELinux,还需要给目录打上container_file_t标签,或者挂载时加:z后缀。之前我在 CentOS 上部署,反复启动失败,docker logs里全是Permission denied,排查半天才发现是 SELinux 拦的,加上:z之后立刻就通了。

2.2 自定义配置:my.cnf 的两种挂载姿势

MariaDB 官方镜像的默认配置存放在/etc/mysql/下,主配置文件/etc/mysql/my.cnf里通过!includedir引入了/etc/mysql/conf.d/和/etc/mysql/mariadb.conf.d/两个目录。自定义配置的最佳做法是不修改主配置文件,而是在 conf.d 目录里放一个独立文件。

有两种挂载方式。第一种是把宿主机上的整个配置目录挂载进去覆盖默认目录:

volumes: - ./conf.d:/etc/mysql/conf.d

第二种是只挂载单个文件:

volumes: - ./my-custom.cnf:/etc/mysql/conf.d/custom.cnf

第二种方式更常用,因为不会因为宿主机和容器目录结构不一致导致配置丢失。我习惯在宿主机上建一个conf.d目录,里面放custom.cnf,所有自定义参数都写在这个文件里。有一点要提醒:不要挂载到/etc/mysql/my.cnf覆盖主配置。官方镜像的主配置里还包含 socket 路径、pid 文件路径等关键设定,覆盖后很容易因为路径不一致导致容器启动失败。

下面是一份我常用的 MariaDB 配置片段:

[mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci max_connections = 500 innodb_buffer_pool_size = 1G skip-name-resolve slow_query_log = 1 slow_query_log_file = /var/log/mysql/slow.log long_query_time = 2

skip-name-resolve这个参数值得多说一句。它让 MariaDB 不再对客户端 IP 做反向 DNS 解析,能明显降低连接建立时间。如果应用是内网域名访问,建议开启;但如果权限表里用了主机名授权,开了它就会导致授权不生效,需要根据场景取舍。

2.3 环境变量初始化:root 密码、数据库与用户的一次性设置

官方镜像支持通过环境变量在首次启动时完成初始化,这是容器化部署和传统部署差异最大的地方。传统方式装完数据库要手动执行mysql_secure_installation设 root 密码、删匿名用户,容器化方案把这些工作全部内置了。

核心环境变量有这几个:

环境变量作用示例
MARIADB_ROOT_PASSWORD设置 root 用户密码MyRootPass123
MARIADB_DATABASE自动创建数据库myapp
MARIADB_USER自动创建应用用户myapp_user
MARIADB_PASSWORD设置应用用户密码MyAppPass456
MARIADB_ROOT_HOST允许 root 从哪些主机连接%或localhost
MARIADB_AUTO_UPGRADE启动时自动执行升级脚本1

这条机制只在数据目录为空的情况下生效。如果挂载目录里已经有数据,比如从旧实例迁移过来的数据文件,容器启动时会跳过初始化,环境变量里的密码、数据库设置都不会生效。这个机制经常让人产生困惑——第一次启动时密码明明设了,第二次重建容器后密码却不认了,其实是因为数据目录已初始化,环境变量被忽略了。

关于 root 密码有两点实际建议。第一,生产环境不要把密码直接写进 compose 文件或 docker run 命令里,至少用.env文件配合 compose 的变量替换,更稳妥的方式是交给密钥管理服务。第二,MARIADB_ROOT_HOST不要轻易设成%,允许 root 远程登录意味着攻击面扩大,绝大多数场景下 root 只在容器内使用就够了,应用连接走专门创建的业务账号。

2.4 字符集、排序规则与时区

中国传统企业应用里最常遇到的问题就是中文乱码,而 MariaDB 容器默认字符集是latin1,不是utf8mb4。如果不在初始化时指定字符集,建表时又没有显式声明,插入中文就会变成一堆???或者报Incorrect string value错误。

在配置文件中加上前面那段character-set-server和collation-server就能解决服务端字符集问题。但还要注意连接层的字符集。客户端连接时最好在连接串里加characterEncoding=utf8(Java)或charset=utf8mb4(Go、Python),否则服务端配置对了,客户端传过来的还是 latin1,照样乱码。

时区是另一个高频问题。官方镜像默认时区是 UTC,在宿主机东八区的情况下,容器里执行SELECT NOW()会比北京时间慢 8 小时。除了在数据列里用TIMESTAMP类型会造成显示偏差外,定时任务、日志时间戳全部会跟着乱。解决方式是在容器环境变量里加:

environment: - TZ=Asia/Shanghai

有些应用连接数据库时还会在连接串里指定serverTimezone=Asia/Shanghai,这个要和服务端保持一致,否则 JDBC 驱动在计算时间偏移时可能算出奇怪的结果。

3. 实操过程:docker compose 部署完整流程

3.1 准备工作:目录结构与端口规划

在实际部署前,先把目录结构规划好。我的习惯是在项目根目录下建一个mariadb/目录,里面区分配置和数据:

mariadb/ ├── docker-compose.yml ├── .env ├── conf.d/ │ └── custom.cnf └── data/

.env文件存放密码等敏感信息,不提交到 git 仓库;conf.d放自定义配置;data是数据目录。这样的分层一眼就能看出每个路径的职责。

端口规划也要提前想清楚。默认情况下 MariaDB 监听 3306,宿主机如果已经有了一个 MySQL 实例占用 3306,容器映射就会失败。映射到自定义端口本身没有性能损失,但应用连接串、防火墙策略都要跟着改。我的建议是:如果是全新环境用默认 3306,端口越一致越省心;如果宿主机已有其他数据库服务,映射到 3307 这类端口,同时在.env里写清楚端口变量,避免到处硬编码。

3.2 docker-compose.yml 完整配置逐行解读

直接给一份我目前在生产环境使用的 compose 配置,基于 Docker Compose v2 语法:

services: mariadb: image: mariadb:11.4.4 container_name: mariadb restart: unless-stopped environment: TZ: Asia/Shanghai MARIADB_ROOT_PASSWORD: ${MARIADB_ROOT_PASSWORD} MARIADB_DATABASE: ${MARIADB_DATABASE} MARIADB_USER: ${MARIADB_USER} MARIADB_PASSWORD: ${MARIADB_PASSWORD} ports: - "3306:3306" volumes: - ./data:/var/lib/mysql - ./conf.d:/etc/mysql/conf.d healthcheck: test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"] interval: 10s timeout: 5s retries: 5 start_period: 30s logging: driver: json-file options: max-size: "10m" max-file: "3"

逐项说明几个关键配置。

image固定到精确小版本11.4.4,避免后期拉取时 tag 漂移。restart: unless-stopped保证服务器重启后容器自动拉起,这是容器化运维的基本配置,比 systemd 的enable更方便。ports映射的"3306:3306"表示宿主机 3306 映射到容器 3306,如果宿主机端口冲突,改成"3307:3306"即可。

healthcheck是容易被忽略但特别有用的配置。官方镜像自带healthcheck.sh脚本,支持--connect和--innodb_initialized两种检查模式。--connect验证能够建立数据库连接,--innodb_initialized验证 InnoDB 是否完成初始化。加了这一项后,docker compose ps会显示healthy状态,编排工具也能基于健康状态做依赖判断,避免应用在数据库还没就绪时就启动。

logging配置限定了容器日志大小,max-size: "10m"和max-file: "3"意味着日志超过 10MB 会自动轮转,最多保留 3 个历史文件。很多线上事故都是日志无限增长把磁盘打满导致的,这个配置能提前防住。

对应.env文件内容如下:

MARIADB_ROOT_PASSWORD=change_this_root_password MARIADB_DATABASE=myapp MARIADB_USER=myapp_user MARIADB_PASSWORD=change_this_app_password

3.3 启动服务与验证步骤

配置写好后,启动就只有三条命令:

docker compose up -d docker compose ps docker compose logs -f

up -d会在后台拉取镜像并创建容器。第一次启动时由于要初始化数据目录,可能需要十几秒到一分钟,之后再看ps状态应该显示Up和healthy。logs -f可以实时观察启动过程,如果看到类似MariaDB init process done. Ready for start up的日志,说明初始化完成。

接下来验证数据库是否可用。进入容器执行 MySQL 客户端命令:

docker exec -it mariadb mysql -uroot -p

输入 root 密码后,依次执行几个 SQL 检查状态:

SELECT VERSION(); SHOW VARIABLES LIKE 'character_set_server'; SHOW VARIABLES LIKE 'time_zone'; SELECT NOW();

预期看到版本是11.4.4,字符集是utf8mb4,时区是+08:00(或者Asia/Shanghai)。如果NOW()返回的是 UTC 时间,说明TZ环境变量没生效。

从宿主机外部连接测试,要确认客户端工具装了 MySQL/MariaDB 客户端:

mysql -h 127.0.0.1 -P 3306 -u myapp_user -p

能连上并且SELECT DATABASE();返回myapp就说明网络映射和数据库初始化都正常。

3.4 用户与权限管理实战

容器化初始化时通过环境变量创建的用户,默认只有对MARIADB_DATABASE指定库的完整权限。这个设计很好,因为应用用户只需要操作自己的业务库,不该有全局管理权限。

实际项目中,应用用户往往需要更多权限,比如多个库的读写权限、或者只读账号供报表系统使用。这时就要手动创建用户并授权。进入容器后执行:

CREATE USER 'report_user'@'%' IDENTIFIED BY 'report_password'; GRANT SELECT ON myapp.* TO 'report_user'@'%'; FLUSH PRIVILEGES;

这里有个权限与安全的小细节。'report_user'@'%'表示允许从任何主机连接,适合应用所在网段不固定的情况;如果应用服务器 IP 固定,建议精确到 IP,比如'report_user'@'10.0.0.5',能显著缩小攻击面。另外,FLUSH PRIVILEGES在通过 SQL 语句修改授权时不是必须的,因为 grant 语句会立即生效,但如果直接改 mysql.user 表则需要执行。

关于 root 远程访问,我的态度一直是不开。容器内使用 root 做运维操作足够,远程管理走应用账号或跳板机更安全。很多人第一次装数据库习惯用 root 去连可视化工具,这个习惯在容器化环境里建议改掉,否则一旦 root 密码泄露,权限是全部的。

4. 日常运维:备份恢复、资源限制与版本升级

4.1 定时备份:容器内 mysqldump + 宿主机 cron

数据库容器化之后,备份方案也要跟着容器化。最简单的模式是:宿主机上写一个备份脚本,通过docker exec进入容器执行mysqldump,把备份文件输出到宿主机目录。

先说mysqldump的参数选择。对于 InnoDB 表,推荐加--single-transaction,它基于事务一致性快照备份,备份过程中不会锁表,业务写入不受影响。再加--quick避免备份大表时把所有数据读入内存。完整命令:

docker exec mariadb mysqldump -uroot -p"$MARIADB_ROOT_PASSWORD" \ --single-transaction --quick --default-character-set=utf8mb4 \ --databases myapp > /backup/myapp_$(date +%Y%m%d_%H%M%S).sql

有一点要注意:--databases参数会在备份文件里包含CREATE DATABASE和USE语句,恢复时不需要手动建库;如果去掉它,恢复时先得手动创建数据库。两种方式都能用,但恢复脚本要对得上。

定时任务放到宿主机 crontab 里:

0 2 * * * /opt/scripts/backup_mariadb.sh

备份脚本里除了执行 dump,还要做保留策略。比如只保留最近 7 天备份:

find /backup -name "myapp_*.sql" -mtime +7 -delete

很多备份方案只做 dump 不验证,等到真要恢复时才发现备份文件是坏的。我个人的习惯是每个星期从最新备份里挑一个,在临时容器里恢复一遍,验证能正常启动,这样心里才有底。

4.2 数据恢复操作与注意事项

恢复操作用mysql客户端把 SQL 文件导入目标库即可:

docker exec -i mariadb mysql -uroot -p"$MARIADB_ROOT_PASSWORD" < /backup/myapp_20250101_020000.sql

这里用-i保持标准输入打开,否则管道重定向的文件内容进不到容器里的 mysql 进程。很多人在这一步踩坑:直接在宿主机执行docker exec mariadb mysql ... < backup.sql,忘记加-i,结果命令执行了但库里没数据。

恢复前的一个重要检查项是:备份文件是用的--databases还是逐库导出。如果是逐库导出,文件里没有建库语句,导入前要先手动执行:

CREATE DATABASE IF NOT EXISTS myapp DEFAULT CHARACTER SET utf8mb4;

另外建议在恢复前先停掉应用写入,或者至少把要覆盖的库先备份一下。逻辑备份恢复不是增量同步,它会把现有数据完全覆盖,导入过程中如果应用还在写,可能出现部分新数据被旧备份覆盖的混乱状态。

4.3 资源限制与健康检查配置

容器默认是不限制 CPU 和内存的,但数据库这种资源大户如果不设上限,容易引发宿主机资源被占满。Compose 配置里加资源限制:

deploy: resources: limits: cpus: "2.0" memory: 2G

这段配置在 Docker Compose v2 中可以直接使用。限制内存尤其重要,因为 InnoDB 的缓冲池会在启动时占掉一部分内存,多个容器叠加后可能直接把宿主机的内存耗尽。如果内存不够,容器启动时会报无法初始化 buffer pool 的错误,极难排查。

healthcheck配置在前面已经提到过,这里再补一个细节:start_period: 30s是给容器的“宽限期”,在启动后的这段时间内健康检查失败不会触发unhealthy状态,避免因为初始化耗时较长被误判。

4.4 版本升级与数据目录兼容性

容器化升级数据库版本非常便利:改镜像 tag、重启容器,两步完成。但有两个前提必须满足。

第一,升级前必须做完整备份。逻辑备份用mysqldump,如果数据量较大,建议先做物理备份,直接复制挂载的数据目录。物理备份最好在停库状态下复制,保证文件一致性。

第二,小版本升级可以跨版本,大版本升级要谨慎。MariaDB 官方镜像在检测到数据目录版本低于镜像版本时,会自动执行升级脚本,前提是设置MARIADB_AUTO_UPGRADE=1。但这个自动升级不是万能的,跨大版本(比如 10.6 升到 11.4)建议先在测试环境验证一遍。

升级步骤示例:

docker compose down # 修改 docker-compose.yml 中的 image 版本 docker compose pull docker compose up -d docker compose logs -f

日志里出现Upgrade completed之类的输出说明升级成功。降级则要非常谨慎,如果升级过程中数据目录的格式已经改变,直接降级可能导致实例无法启动。所以在确认新版本稳定前,原始版本的数据目录备份一定不要删除。

5. 常见问题与排查技巧实录

5.1 容器重启后数据全丢

这是容器化部署数据库最常见的事故,我早期吃过一次大亏。场景是这样的:用docker run起了一个 MariaDB,正常运行了一个月,某次服务器重启后容器没有自动恢复,直接docker rm重建,结果数据全没了。原因很简单:没有挂载数据卷,数据文件存在容器可写层里,容器一删,数据跟着消失。

排查容器是否挂了数据卷,用一条命令就能看清楚:

docker inspect mariadb | grep -A 5 Mounts

如果Mounts里没有映射到宿主机目录或命名卷,说明数据就在容器内部。这种情况下,在容器还没删之前立刻把数据文件复制出来:

docker cp mariadb:/var/lib/mysql /backup/mariadb-data

复制出来的数据目录可以直接挂载到新容器上,前提是版本兼容。预防措施就是写 compose 文件时永远带上./data:/var/lib/mysql这条挂载,并严格遵循“先挂载后启动”的顺序。

5.2 中文乱码与 emoji 显示异常

中文乱码的排查路径一般是:先看服务端字符集,再看客户端连接字符集,最后看表字段字符集。三层缺一不可。

排查 SQL 如下:

SHOW VARIABLES LIKE 'character%'; SHOW CREATE TABLE myapp.users\G

如果服务端已经设置utf8mb4,但某张表创建时用的是latin1或utf8mb3,需要单独转换:

ALTER TABLE myapp.users CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

还有一种隐蔽情况:索引字段长度超出限制。utf8mb4下 varchar(255) 的唯一索引需要 1020 字节,如果使用的是utf8mb3(即 utf8)创建的表,转成 utf8mb4 后可能报Specified key was too long。解决办法是调整字段长度,或者把索引列改成前缀索引。

应用侧连接串同样要检查。Java 的连接串推荐加characterEncoding=utf8&connectionCollation=utf8mb4_unicode_ci,Python 的pymysql默认用的就是 utf8mb4,一般问题不大。最蹊跷的一个坑是:启动容器时没加TZ,时间不对导致某个应用依赖时间戳排序的功能出现错乱,表面看起来数据没问题,但查询顺序反了,这也是环境变量不完整引发的问题。

5.3 容器启动失败:权限、端口占用、内存不足

启动失败的排查流程比较固定。第一步看日志:

docker logs --tail 50 mariadb

常见错误不外乎三类。

第一类是权限错误,日志里出现chown: changing ownership of '/var/lib/mysql/...': Permission denied。这是因为宿主机挂载目录的属主不是 UID 999。解决方案就是前面提到的chown -R 999:999 /data/mariadb,或者挂载时加:z处理 SELinux。

第二类是端口占用,日志显示Can't start server: Bind on TCP/IP port: Address already in use。先查宿主机端口占用:

ss -ltnp | grep 3306

确认有别的进程占用后,改 compose 里的端口映射即可,这种问题不需要重启机器。

第三类是内存不足,日志可能显示InnoDB: Error allocating ...或Out of memory。这种情况把配置里的innodb_buffer_pool_size调小一些,比如从 1G 改为 256M,Deploy 的资源限制也要同步检查,确保memory限制高于 buffer pool 加上其他开销的总和。

5.4 从外部无法连接数据库

容器内部连数据库正常,宿主机外部连不上,这个问题多数出在三个层面:端口映射、监听地址、防火墙。

先检查端口映射:

docker compose ps

确认PORTS列显示0.0.0.0:3306->3306/tcp,如果显示只有3306/tcp而没有映射,说明 compose 里 ports 没配。再检查容器内监听地址:

docker exec mariadb ss -ltnp | grep 3306

正常应该监听0.0.0.0:3306。如果监听在127.0.0.1,需要在配置里加:

[mysqld] bind-address = 0.0.0.0

最后检查防火墙。很多云服务器默认只放行部分端口,需要额外放行 3306。注意,千万不要把防火墙直接关了来“快速解决”,数据库端口暴露到公网本身就是高危行为,建议只对应用服务器所在的内网网段开放。

5.5 时区慢 8 小时

时间不对最典型的表现是:宿主机执行date显示北京时间,容器里执行SELECT NOW()却显示 UTC 时间。原因就是容器继承了宿主机的/etc/localtime但设置的环境变量TZ不存在。

容器化部署的解决方式是在 compose 的environment里加TZ: Asia/Shanghai。创建容器后还想补救的话,可以这样进入容器设置:

docker exec -it mariadb bash ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime echo "Asia/Shanghai" > /etc/timezone

注意,改了容器的/etc/localtime后重启容器可能被重置,所以最稳妥的方式还是在环境变量层面解决。某些应用场景下,数据库时间没问题,客户端却显示不对,这是应用连接串里没指定时区,像 JDBC 需要在 URL 后加serverTimezone=Asia/Shanghai。

5.6 日志无限增长导致磁盘满

数据库容器运行一段时间后,日志文件可能占据大量磁盘空间,来源有两类:容器日志和数据库日志。容器日志由 Docker 管理,前面已经在 compose 里配置了logging轮转,这里不再重复。

数据库自身的日志更隐蔽。MariaDB 默认开启了二进制日志(binlog),用于主从复制和时间点恢复,但单机模式下如果没有及时清理,binlog 会越积越多。建议在配置里设置过期时间:

[mysqld] expire_logs_days = 7 max_binlog_size = 100M

MariaDB 10.6 之后更推荐用binlog_expire_logs_seconds,单位是秒。慢查询日志如果开启并且长期不清理,也会膨胀,但通常量级不如 binlog 大。排查磁盘占用时,进入容器执行:

du -sh /var/lib/mysql/*

看到mysql-bin.000001这类文件名,就知道 binlog 在占据了。清理方式执行PURGE BINARY LOGS BEFORE NOW() - INTERVAL 7 DAY;,不建议直接删文件,否则有可能让 master 找不到对应位置。

结尾:一些实际维护中的体会

跑到这里,一套容器化 MariaDB 的部署、运维、排障链路就完整了。我个人在实际操作中的体会是:容器化部署数据库这件事,难点从来不在“起一个容器”,而在于把持久化、配置、备份、升级这些生命周期问题想在容器之下。数据卷一定要规划在前,健康检查一定要配上,备份脚本一定要先验证一次恢复流程。

最后再分享一个小技巧:每次要动数据库前,不管改配置还是升级版本,先执行一次备份,再执行一条命令:

docker compose down && docker compose up -d

这套流程我在多个环境反复用过,基本能覆盖大家会遇到的大部分场景。MariaDB 的容器化生态已经相当成熟,官方镜像的维护和文档质量都很靠谱,放心大胆地把数据库迁进容器,只要把持久化和备份设计到位,稳定性和运维效率都能上一个台阶。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 18:06:42

MySQL数据库入门全攻略:从安装部署到实战避坑

拿MySQL入门数据库&#xff0c;是很多开发者和运维同学绕不开的第一步。这篇文章我不打算按教科书方式讲理论&#xff0c;而是直接以“先装起来、跑起来、用起来”为主线&#xff0c;从头梳理MySQL是什么、能做什么、适合谁&#xff0c;以及在实际部署和日常操作中会被反复踩到…

作者头像 李华
网站建设 2026/10/1 18:06:31

鸿蒙多设备适配:Flutter Flex控件响应式布局实战与避坑指南

去年把一款电商App从安卓侧迁移到鸿蒙&#xff0c;第一轮UI走查就翻车了&#xff1a;同样的布局代码&#xff0c;安卓上看着没问题&#xff0c;到了鸿蒙的小折叠屏和横屏车机上&#xff0c;顶部榜单和底部操作栏直接挤成一片。排查到最后&#xff0c;问题几乎全部集中在Flex控件…

作者头像 李华
网站建设 2026/10/1 18:05:40

子类对父类的方法重写:概念、规则与实战避坑

子类对父类的方法重写&#xff1a;概念、规则与实战避坑不管你是准备课程设计答辩、应付期末考试&#xff0c;还是刚入行写业务代码&#xff0c;方法重写&#xff08;Override)都是面向对象绕不过去的坎。我见过太多答辩现场&#xff0c;学生能把“重写是对父类方法的重新实现”…

作者头像 李华
网站建设 2026/10/1 18:05:11

BqLog环形队列与自适应数据总线设计解析

1. 这不是普通日志组件&#xff0c;是王者荣耀后台扛住百万并发写入的“数据减压阀”BqLog这个名字&#xff0c;在游戏开发圈子里已经不算陌生。但真正让我在项目复盘会上拍大腿说“原来还能这么干”的&#xff0c;不是它功能多全&#xff0c;而是它在王者峡谷每秒涌进30万条操…

作者头像 李华
网站建设 2026/10/1 18:04:38

后见之明:从项目复盘的认知偏差到HER算法的学习机制

先别急着把"hindsight"翻译成"事后诸葛亮"就划走。这个词在中文语境里经常被当成一句调侃&#xff0c;但放在项目复盘、技术选型甚至产品迭代的语境里&#xff0c;它其实是一整套非常实用的决策改进框架。我最早接触hindsight是在一次大规模系统重构的复盘…

作者头像 李华
网站建设 2026/10/1 18:04:29

从零手搓AI工程:手写神经网络与反向传播实战指南

1. 从零手搓AI工程&#xff1a;为什么我不建议你直接调包第一次看到ai-engineering-from-scratch这个项目名&#xff0c;我脑子里蹦出来的画面是&#xff1a;一个人坐在终端前&#xff0c;从矩阵乘法开始&#xff0c;一行一行把 Transformer 敲出来&#xff0c;中间不碰任何高层…

作者头像 李华