本文以容器形式部署了开源自动化运维工具 Ansible,基于自带的 MySQL 管理模块编排了 playbook 配置文件,最终实现 MySQL 数据库备份的目标。选择容器而非直接安装的部署形式,可以避免对系统环境的污染,使运维工作开展更加高效和灵活。
MySQL 数据库备份技术和相关方案已经非常成熟,本文不做赘述和展开。在实际场景中,数据库不可能脱离业务单独存在;因此对于备份等运维操作来说,应当在运维平台统一的调度下发起或实施,Ansible 作为近年来流行的自动化运维工具,可以定位于运维平台的核心来使用。
Ansible简介
关于 Ansible 的介绍,公开渠道可以查阅到大量资料,公众号此前也有文章专门介绍,本文不再浪费篇幅铺开。简单来说,Ansible 是一个基于Python语言开发的运维工具,由于没有客户端依赖,在管理成本方面较其他产品有显著优势;Ansible 基于模块工作,通过系统自带、客户编写、和第三方模块,可以满足各种管理任务,本文使用 mysql_db 数据库模块实现了备份功能。
环境准备
笔者对红帽系统比较熟悉,原本想直接通过 yum 命令安装 ansible,但是从实际工作角度出发,一方面要维护非联网环境中 yum 源,另一方面 ansible 需要连带安装大量依赖包,易对系统造成“污染”,因此并不推荐 yum 直接安装。根据 Ansible 的官方文档,使用 mysql_db 模块需要安装 MySQL 客户端和其他一些工具,这些对于操作系统本身也非必要。基于以上考虑,笔者最终采用构建自定义 docker 镜像的方式部署 Ansible。除了克服以上弊端外,镜像制作完成后可以方便地移植到任意安装 docker 的环境中,无需兼顾环境因素。本文使用 debian11 的官方镜像作为底座和中科大的软件源,Dockerfile 文件定义如下:
FROM debian:latest
RUN sed -i 's/deb.debian.org/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \
&& apt-get update -y \
&& apt-get upgrade -y \
&& apt-get install ansible -y \
&& apt-get install sshpass -y \
&& apt-get install pip -y \
&& apt-get install libmysql++-dev -y \
&& apt-get install default-mysql-client -y \
&& apt-get autoclean
RUN pip3 install mysqlclient
RUN mkdir -p /etc/ansible/
CMD ["/bin/bash"]
使用 docker 编译后,导出的镜像约 900MB,安装的 ansible 版本为 2.10.8。使用该镜像部署的容器启动后检查输出如下图。
mysql_db模块
该模块用于实现 MySQL 库级别的管理,提供 CREATE、DROP、DUMP、IMPORT 四种功能。本文通过把 state 设置为 dump,实现调用 mysqldump 工具完成备份,mysql_db 模块备份功能可能用到的主要输入参数说明如下:
connect_timeout integer | The connection timeout when connecting to the MySQL server. Default: 30 |
dump_extra_args string added in 0.1.0 of community.mysql | Provide additional arguments for mysqldump. Used when state=dump only, ignored otherwise. |
encoding string | Encoding mode to use, examples include utf8 or latin1_swedish_ci, at creation of database, dump or importation of sql script. Default: “” |
force boolean added in 0.1.0 of community.mysql | Continue dump or import even if we get an SQL error. Used only when state is dump or import. Choices:
|
hex_blob boolean added in 0.1.0 of community.mysql | Dump binary columns using hexadecimal notation. Choices:
|
ignore_tables list / elements=string | A list of table names that will be ignored in the dump of the form database_name.table_name. Default: [] |
login_host string | Host running the database. In some cases for local connections the login_unix_socket=/path/to/mysqld/socket, that is usually /var/run/mysqld/mysqld.sock, needs to be used instead of login_host=localhost. Default: “localhost” |
login_password string | The password used to authenticate with. |
login_port integer | Port of the MySQL server. Requires login_host be defined as other than localhost if login_port is used. Default: 3306 |
login_user string | The username used to authenticate with. |
master_data integer added in 0.1.0 of community.mysql | Option to dump a master replication server to produce a dump file that can be used to set up another server as a slave of the master. 0 to not include master data. 1 to generate a ‘CHANGE MASTER TO’ statement required on the slave to start the replication process. 2 to generate a commented ‘CHANGE MASTER TO’. Can be used when state=dump. Choices:
Default: 0 |
name aliases: db list / elements=string / required | Name of the database to add or remove. name=all may only be provided if state is dump or import. List of databases is provided with state=dump, state=present and state=absent. If name=all it works like –all-databases option for mysqldump (Added in 2.0). |
quick boolean | Option used for dumping large tables. Choices:
|
restrict_config_file boolean added in 0.1.0 of community.mysql | Read only passed config_file. When state is dump or import, by default the module passes config_file parameter using --defaults-extra-file command-line argument to mysql/mysqldump utilities under the hood that read named option file in addition to usual option files. If this behavior is undesirable, use yes to read only named option file. Choices:
|
single_transaction boolean | Execute the dump in a single transaction. Choices:
|
skip_lock_tables boolean added in 0.1.0 of community.mysql | Skip locking tables for read. Used when state=dump, ignored otherwise. Choices:
|
state string | The database state. Choices:
|
target path | Location, on the remote host, of the dump file to read from or write to. Uncompressed SQL files (.sql) as well as bzip2 (.bz2), gzip (.gz) and xz (Added in 2.0) compressed files are supported. |
playbook编排
playbook 是 Ansible 用于配置、部署、和管理被控节点的剧本,给被控节点列出的一系列 to-do-list。剧本在执行过程中按照编排定义,执行一个或多个 task,实现目标主机完成指定任务,达到预期的状态。笔者编写了一个简单的 playbook,配置了一个task调用 mysql_db 模块实现备份目标,需要注意的是 hosts 建议设定为127.0.0.1,表示 ansible 所在容器本身,yml 文件具体如下:
---
- hosts: 127.0.0.1
tasks:
- name: "mysql dump test"
mysql_db:
login_host: 192.168.43.51
login_user: root
login_password: ******
state: dump
name: test
target: /tmp/test_{{ ansible_date_time.date }}.gz
执行该 playbook 的过程和结果如下图所示:
PLAYBOOK: bak.yml *********************************************************
1 plays in bak.yml
PLAY [127.0.0.1] *********************************************************
TASK [Gathering Facts] *********************************************************
task path: /bak.yml:2
ok: [127.0.0.1]
META: ran handlers
TASK [mysql dump test] *********************************************************
task path: /bak.yml:4
redirecting (type: modules) ansible.builtin.mysql_db to community.mysql.mysql_db
[WARNING]: The value "********" (type int) was converted to "'********'" (type string). If this does not look like what you expect, quote the entire value to
ensure it does not change.
changed: [127.0.0.1] => {"changed": true, "db": "test", "db_list": ["test"], "executed_commands": ["/usr/bin/mysqldump --user=root --password=******** --host=192.168.43.51 --port=3306 test --quick | /bin/gzip > /tmp/test_2022-05-06.gz"], "msg": ""}
META: ran handlers
META: ran handlers
PLAY RECAP *********************************************************
127.0.0.1 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
总结和展望
本文使用容器形式实现 Ansible 轻量化安装部署的尝试,旨在更好地发挥 Ansible 在运维管理中的积极作用,Ansible 模块化的属性可以帮助运维人员摆脱复杂的技术而更好地专注于运维场景本身。笔者仅实现了 MySQL 备份一个场景,在企业级规模运维管理中,要实现更复杂的运维场景,做好模块管理还是有必要部署 Ansible Tower。笔者也会持续开展 Ansible Tower对应的开源产品AWX应用研究。
作者简介:曹杰,中国结算上海分公司高级经理,从事系统运维管理工作。