Docker 镜像构建优化与 MySQL 主从集群容器化部署
Docker 镜像构建优化涉及多阶段构建、缓存利用及 .dockerignore 配置,CMD 与 ENTRYPOINT 组合使用可提升灵活性。MySQL 主从同步包含全同步、异步、半同步等模式,通过 Docker Compose 可实现一主二从集群的快速部署与数据一致性保障。

Docker 镜像构建优化涉及多阶段构建、缓存利用及 .dockerignore 配置,CMD 与 ENTRYPOINT 组合使用可提升灵活性。MySQL 主从同步包含全同步、异步、半同步等模式,通过 Docker Compose 可实现一主二从集群的快速部署与数据一致性保障。

对应 Dockerfile:
FROM centos:7
ENV VERSION 1.0
RUN sed -i.bak \
-e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.ustc.edu.cn/centos-vault/centos|g' \
/etc/yum.repos.d/CentOS-Base.repo
WORKDIR /src
COPY demo.c .
RUN yum makecache && yum install -y gcc
RUN gcc demo.c -o demo && \
rm -f demo.c && \
yum remove -y gcc
CMD ["/src/demo"]
执行构建命令:
docker build -t my-cpp-image .
等待镜像制作完成并运行。
ENTRYPOINT 和 CMD 均用于定义容器启动时执行的命令。若镜像未设置这两个指令,运行时会报错。
Dockerfile 中后写的指令会覆盖同类型的前置指令。用户运行容器时可通过命令行参数覆盖 Dockerfile 中的 CMD,但 ENTRYPOINT 需用 --entrypoint 强制覆盖。
CMD echo "hello"):命令通过 /bin/sh -c 启动,导致主进程 PID 非 1,无法正常接收信号(如优雅终止容器)。CMD ["echo", "hello"]):直接运行命令,PID 为 1,支持信号转发,强烈推荐使用。ENTRYPOINT 定义固定执行命令,CMD 提供默认参数。最终命令为拼接形式:<ENTRYPOINT> <CMD>,运行时可覆盖 CMD 参数。
如果 Dockerfile 出现两次 CMD 或 ENTRYPOINT,后面的指令会覆盖前面的指令。手动输入参数也会覆盖 CMD。
Shell 模式下启动后容器主进程是 /bin/sh。Exec 模式下主进程是对应命令,PID 为 1。
CMD 做参数,ENTRYPOINT 做命令,实时修改 CMD,实现解耦性;两者相互配合,使得操作更加灵活。
Docker 是 C/S 架构。构建镜像时,客户端会把当前目录所有文件打包发送给服务端,这个包叫做 build context。用 .dockerignore 文件可以忽略不需要的文件(如日志、缓存),让镜像更小更安全。
构建命令:
docker build -t image-name .
一句话总结:build context 是客户端发给服务端的'材料包',用 .dockerignore 过滤掉多余文件。
测试显示,忽略 txt 结尾的文件后,启动后发现只有指定文件,无 txt 结尾的文件,说明 ignore 成功。
Docker 镜像构建的三种方式:
结论:直接用第三种(多阶段构建),高效又省事!
演示:
一个 Dockerfile,先编译 C 程序,再把生成的可执行文件拷贝到小镜像里运行。
之前是默认一个 centos 的镜像同时编译运行等操作,下载了很多相关包文件没有清理干净。
下面采取多级构建:
最后采取的是一个非常小的镜像源作为最终镜像(真正 build 的最后镜像以最后一个为主,其他中间镜像都会被清除);因此对应只需要对应程序的镜像就可以采取多级构建,把对应的 exe 只需要放在一个能跑程序的小镜像里即可(如 busybox)。
总结:
多阶段构建可以很好的解决镜像的层次多,体积大,部署时间长、维护性低等问题;我们编译使用的软件,都没有打到我们的运行态的软件里面,所以可以变得更小。
docker build --no-cache=true 命令选项来完全禁用缓存,但合理利用缓存能极大提升构建效率。例子:
这里的镜像只在 COPY 开始到以上有改变,因此再次构建镜像的时候下面的镜像就可以复用。
比如在频繁更改代码来编译程序:
这样更改就可以减少对应安装软件的频繁安装,直接复用上面的层。
演示:
还是以之前的 c++ 镜像制作为例:
这里发现很多都复用了之前构建的镜像的内容。
下面因为代码频繁更改,可以把对应的安装过程搞到上面,复用下对应缓存:
这里发现改了顺序时间更长了;因为之前的那一次完全复用缓存。
然后这一次从跑到 yum 这里发现上面的层就不同了;因此地下的复用(看到的就是过程的 cached 效果);然后下面重新构建。
下面测试下更改源代码效果:
可以发现现在比第一次快;可以看出先跑到更改层;然后发现之前的层都没动,直接复用之前的;然后更改层上面的重新构建(这里其实对应的重新安装软件也是比较耗时间的)。
总结:
因此对应镜像构建的过程中;尽量让它不变化的放一起,变化的放一起都在上层;让它尽量能复用之前的缓存层;加快构建镜像的速度。
在 docker-compose.yml 里写 build,就能直接编译镜像,不用手动敲命令。
两种方式进行 docker-compose.yml 使用:
成功位于不同位置的 dockerfile 进行构建镜像,但是不启动。
一句话总结:主库将写操作记入 binlog,从库的 IO 线程取、SQL 线程执行,最终实现数据同步。
那什么是 binlog?
MySQL 的 binlog 是记录数据库写操作(增删改)的日志,主要用于数据同步和恢复。它有三种记录模式:
now() 主从同步就可能会出问题)一句话:用速度和可用性换绝对的数据一致。
一句话:主库追求自身处理速度和响应能力,牺牲了数据的强一致性(比如主在同步过程,自己写了但是正在写从的时候挂了)。
一句话:半同步是异步和全同步的折衷方案,用部分性能换取比异步更好的一致性,但不如全同步可靠。
好处:数据更安全(主从一致),解决了'幻读'问题。
代价:比纯异步慢一点(因为要等从库回信)。
一句话:主库等一个从库确认后才算成功,保证了数据不丢不错。
一句话:所有写操作必须经过共识层审批,确保所有节点按相同顺序执行,最终实现多主数据同步。
一主一从
一个主库配一个从库,最基本、最常用的备份与读写分离架构。
一个主库配多个从库,显著提高系统的读性能,是扩展读能力的标准做法。
多个主库的数据同步到一个从库,用于将多个数据库备份到一台高性能存储服务器。
两个主库互为主从,任何一方的修改都会同步到另一方,实现双向同步。
从库再作为其他从库的主库,减轻主库压力,避免主库连接过多而性能下降(比如对应分析数据库,时长进行读操作,不追求性能,此时就可以把它作为以从为主的从库)。
所有形式都是为了实现数据备份、读写分离、提升性能和可用性。
下面基于一下流程进行搭建:
首先看下对应目录:
构建主库的 dockerfile(默认初始化,故无需 copy 对应 sql 脚本):

俩从库的 dockerfile(需要手动同步):

对应的从的初始化 sql:

对应的总的 docker-compose 文件:
services:
mysql-master:
build:
context: ./
dockerfile: ./master/Dockerfile-master
image: mysqlmaster:v1.0
restart: always
container_name: mysql-master
volumes:
- ./master/var/lib/mysql:/var/lib/mysql
ports:
- 9306:3306
environment:
MYSQL_ROOT_PASSWORD: root
privileged: true
command: ['--server-id=1','--log-bin=mysql-bin','--binlog-ignore-db=mysql','--binlog_cache_size=256M','--binlog_format=mixed','--lower_case_table_names=1','--character-set-server=utf8','--collation-server=utf8_general_ci']
mysql-slave:
build:
context: ./
dockerfile: ./slave/Dockerfile-slave
image: mysqlslave:v1.0
restart: always
container_name: mysql-slave
volumes:
- ./slave/var/lib/mysql:/var/lib/mysql
ports:
-
[,,,,]
[,,,,]
这里对应的 master 的密码用户都是 root;然后在两个从的初始化 sql 中都设置了用户名和密码都是 root。
下面熟悉了之前的 docker compose 配置参数后;这里就值介绍对应 command 了:
主节点 (mysql-master) 参数
--server-id=1
--log-bin=mysql-bin
--binlog-ignore-db=mysql
mysql 的变更,避免不必要的同步。--binlog_format=mixed
从节点 (mysql-slave, mysql-slave2) 参数
--server-id=2 / --server-id=3
--relay-log=slave-relay-bin
--lower_case_table_names=1
--character-set-server=utf8
--collation-server=utf8_general_ci
下面同规格 docker compose 进行镜像生成:
等待很长时间。
成功构建。
成功构建好容器。
进入主从 mysql 中。
通过下面的指令进行主从查看:
SHOW MASTER STATUS\G
SHOW SLAVE STATUS\G
下面进行插入数据看是否同步:
主库插入:
mysql> create database db1;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| db1 |
| mysql |
| performance_schema |
| sys |
+--------------------+
5 rows in set(0.00 sec)
mysql> use db1;
Database changed
mysql> insert into t1 values("zs",1),("lm",2);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+------+------+|
| name | age ||
+------+------+|
| zs
lm
( sec)
mysql
从库查看:
发现同步成功。
至此可以看到我们搭建的 mysql 集群已经能够正常进行工作。
本篇通过 Dockerfile 多阶段构建大幅精简镜像体积,利用缓存机制提升构建效率;深入解析 MySQL 主从复制五大模式,并完成一主二从集群实战。掌握 ENTRYPOINT+CMD 组合、.dockerignore 过滤等技巧,实现容器化部署的高性能与高可用。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
在线格式化和美化您的 SQL 查询(它支持各种 SQL 方言)。 在线工具,SQL 美化和格式化在线工具,online
解析 INSERT 等受限 SQL,导出为 CSV、JSON、XML、YAML、HTML 表格(见页内语法说明)。 在线工具,SQL转CSV/JSON/XML在线工具,online
CSV 与 JSON/XML/HTML/TSV/SQL 等互转,单页多 Tab。 在线工具,CSV 工具包在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online