Skip to content

MySQL Chef 集成

MySQL Chef 集成的优势

自动化部署

  • 一键部署MySQL服务器
  • 标准化部署流程,确保环境一致性
  • 支持多环境部署(开发、测试、生产)
  • 减少部署时间和人力成本

配置管理

  • 集中管理MySQL配置
  • 配置变更可追踪、可回滚
  • 确保所有MySQL实例配置一致
  • 支持配置的版本控制

扩展性

  • 轻松扩展MySQL集群
  • 支持动态添加和移除节点
  • 自动化处理节点加入和退出
  • 适应业务增长需求

可靠性

  • 减少人为错误
  • 自动化监控和修复
  • 快速恢复故障节点
  • 提高系统可用性

准备工作

安装 Chef

bash
# 安装 Chef Workstation(用于编写和测试Cookbook)
wget https://packages.chef.io/files/stable/chef-workstation/21.10.640/el/7/chef-workstation-21.10.640-1.el7.x86_64.rpm
sudo rpm -ivh chef-workstation-21.10.640-1.el7.x86_64.rpm

# 验证安装
chef --version

设置 Chef 服务器

  1. 安装 Chef 服务器
  2. 创建管理员账户
  3. 创建组织
  4. 下载配置文件

配置 Chef 客户端

bash
# 在目标服务器上安装 Chef 客户端
sudo rpm -Uvh https://packages.chef.io/files/stable/chef/17.10.0/el/7/chef-17.10.0-1.el7.x86_64.rpm

# 注册 Chef 客户端
chef-client -S https://chef-server.example.com/organizations/myorg -k /etc/chef/myorg-validator.pem -N mysql-server-01

MySQL Cookbook 编写

目录结构

mysql-cookbook/
├── Berksfile
├── chefignore
├── metadata.rb
├── README.md
├── recipes/
│   ├── default.rb
│   ├── install.rb
│   ├── configure.rb
│   ├── service.rb
│   └── replication.rb
├── templates/
│   └── default/
│       ├── my.cnf.erb
│       └── mysql_repo.erb
├── attributes/
│   └── default.rb
└── spec/
    ├── spec_helper.rb
    └── recipes/
        └── default_spec.rb

attributes/default.rb

ruby
# MySQL 版本
default['mysql']['version'] = '8.0'

# MySQL 配置
default['mysql']['config'] = {
  'mysqld' => {
    'bind-address' => '0.0.0.0',
    'port' => 3306,
    'datadir' => '/var/lib/mysql',
    'socket' => '/var/lib/mysql/mysql.sock',
    'pid-file' => '/var/run/mysqld/mysqld.pid',
    'log-error' => '/var/log/mysqld.log',
    'innodb_buffer_pool_size' => '128M',
    'max_connections' => 151,
    'skip-name-resolve' => true
  }
}

# MySQL 根密码
default['mysql']['root_password'] = 'secure_password'

# MySQL 复制配置
default['mysql']['replication'] = {
  'enable' => false,
  'role' => 'master', # master or slave
  'master_host' => '',
  'master_user' => 'repl',
  'master_password' => 'repl_password',
  'master_log_file' => '',
  'master_log_pos' => 0
}

recipes/install.rb

ruby
# 安装 MySQL 仓库
template '/etc/yum.repos.d/mysql-community.repo' do
  source 'mysql_repo.erb'
  mode '0644'
  variables(version: node['mysql']['version'])
  action :create
end

# 安装 MySQL 服务器
package 'mysql-community-server' do
  version node['mysql']['version'] + '*'
  action :install
end

recipes/configure.rb

ruby
# 创建 MySQL 配置文件
template '/etc/my.cnf' do
  source 'my.cnf.erb'
  mode '0644'
  variables(config: node['mysql']['config'])
  action :create
  notifies :restart, 'service[mysqld]', :delayed
end

# 初始化 MySQL(仅第一次运行)
execute 'initialize mysql' do
  command 'mysqld --initialize-insecure --user=mysql --datadir=/var/lib/mysql'
  creates '/var/lib/mysql/mysql'
  action :run
  notifies :start, 'service[mysqld]', :immediate
end

# 设置根密码
execute 'set root password' do
  command <<-EOF
    mysql -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '#{node['mysql']['root_password']}';"
    mysql -u root -p'#{node['mysql']['root_password']}' -e "FLUSH PRIVILEGES;"
  EOF
  action :run
  not_if "mysql -u root -p'#{node['mysql']['root_password']}' -e 'SELECT 1;'"
end

recipes/service.rb

ruby
# 启用并启动 MySQL 服务
service 'mysqld' do
  action [:enable, :start]
end

templates/default/my.cnf.erb

erb
[mysqld]
<% node['mysql']['config']['mysqld'].each do |key, value| %>
<%= key %> = <%= value %>
<% end %>

# 复制配置
<% if node['mysql']['replication']['enable'] %>
<% if node['mysql']['replication']['role'] == 'master' %>
log-bin = mysql-bin
server-id = <%= node['ipaddress'].split('.').last %>
<% else %>
server-id = <%= node['ipaddress'].split('.').last %>
relay-log = relay-bin
read-only = 1
<% end %>
<% end %>

MySQL 复制配置

recipes/replication.rb

ruby
# 仅在启用复制时执行
return unless node['mysql']['replication']['enable']

if node['mysql']['replication']['role'] == 'master'
  # 创建复制用户
  execute 'create replication user' do
    command <<-EOF
      mysql -u root -p'#{node['mysql']['root_password']}' -e "CREATE USER '#{node['mysql']['replication']['master_user']}'@'%' IDENTIFIED WITH mysql_native_password BY '#{node['mysql']['replication']['master_password']}';"
      mysql -u root -p'#{node['mysql']['root_password']}' -e "GRANT REPLICATION SLAVE ON *.* TO '#{node['mysql']['replication']['master_user']}'@'%';"
      mysql -u root -p'#{node['mysql']['root_password']}' -e "FLUSH PRIVILEGES;"
    EOF
    not_if "mysql -u root -p'#{node['mysql']['root_password']}' -e "SELECT 1 FROM mysql.user WHERE User='#{node['mysql']['replication']['master_user']}' AND Host='%';""
  end
else
  # 配置从库
  execute 'configure slave' do
    command <<-EOF
      mysql -u root -p'#{node['mysql']['root_password']}' -e "CHANGE MASTER TO \
        MASTER_HOST='#{node['mysql']['replication']['master_host']}', \
        MASTER_USER='#{node['mysql']['replication']['master_user']}', \
        MASTER_PASSWORD='#{node['mysql']['replication']['master_password']}', \
        MASTER_LOG_FILE='#{node['mysql']['replication']['master_log_file']}', \
        MASTER_LOG_POS=#{node['mysql']['replication']['master_log_pos']};"
      mysql -u root -p'#{node['mysql']['root_password']}' -e "START SLAVE;"
    EOF
    not_if "mysql -u root -p'#{node['mysql']['root_password']}' -e 'SHOW SLAVE STATUS\G' | grep -q 'Slave_IO_Running: Yes'"
  end
end

测试和部署

测试 Cookbook

bash
# 安装依赖
berks install

# 语法检查
chef exec rake syntax

# 运行测试
chef exec rspec spec/

# 使用 Test Kitchen 测试
kitchen create
kitchen converge
kitchen verify
kitchen destroy

部署到生产环境

bash
# 上传 Cookbook 到 Chef 服务器
berks upload

# 在节点上运行 Chef 客户端
chef-client

# 或者通过 Knife 命令在多个节点上运行
knife ssh 'role:mysql' 'sudo chef-client' -x username -P password

最佳实践

版本控制

  • 使用 Git 管理 Cookbook 代码
  • 定期提交变更
  • 使用标签管理版本
  • 支持回滚到之前的版本

环境隔离

  • 为不同环境创建独立的环境文件
  • 使用角色和环境管理配置差异
  • 避免在生产环境中直接测试

安全管理

  • 加密敏感数据(使用 Chef Vault)
  • 定期更新 MySQL 版本和补丁
  • 限制 MySQL 访问权限
  • 启用审计日志

监控和告警

  • 集成监控工具(如 Prometheus、Grafana)
  • 设置性能指标告警
  • 监控复制状态
  • 监控磁盘空间和资源使用率

版本差异

MySQL 5.7 与 8.0 的 Chef 配置差异

特性MySQL 5.7MySQL 8.0
认证插件mysql_native_password(默认)caching_sha2_password(默认)
配置文件支持 my.cnf支持 my.cnf
初始化方式mysqld --initializemysqld --initialize-insecure
复制支持传统复制和 GTID 复制支持传统复制和 GTID 复制,增强了 GTID 功能
密码策略较弱更强,支持密码过期、复杂度要求

Chef 版本差异

Chef 版本特性
Chef 12支持基本的 Cookbook 开发
Chef 14引入 Custom Resources,改进了模板系统
Chef 16增强了安全性,改进了错误处理
Chef 17支持 Ruby 3.0,改进了测试框架

常见问题(FAQ)

Q1: 如何处理 MySQL 版本升级?

A1: 使用 Chef 进行 MySQL 版本升级时,建议按照以下步骤进行:

  1. 在测试环境中测试升级过程
  2. 备份生产环境数据
  3. 更新 Cookbook 中的 MySQL 版本属性
  4. 逐步升级生产环境节点
  5. 验证升级后的功能和性能

Q2: 如何管理多个 MySQL 实例?

A2: 可以通过以下方式管理多个 MySQL 实例:

  1. 使用不同的角色(role)定义不同的实例配置
  2. 使用环境(environment)管理不同环境的配置差异
  3. 使用数据袋(data bag)存储实例特定的配置
  4. 使用自定义资源(custom resource)简化多实例管理

Q3: 如何处理 MySQL 配置变更?

A3: 处理 MySQL 配置变更时,建议:

  1. 在 Cookbook 中更新配置属性
  2. 上传更新后的 Cookbook 到 Chef 服务器
  3. 在节点上运行 Chef 客户端应用变更
  4. 监控变更后的系统性能
  5. 如有问题,回滚到之前的配置版本

Q4: 如何集成 MySQL 监控?

A4: 可以通过以下方式集成 MySQL 监控:

  1. 使用 Chef 安装和配置监控代理(如 Node Exporter、MySQL Exporter)
  2. 在 Cookbook 中添加监控配置
  3. 集成到监控系统(如 Prometheus + Grafana)
  4. 设置告警规则

Q5: 如何确保 Chef 部署的安全性?

A5: 确保 Chef 部署安全性的方法包括:

  1. 使用 Chef Vault 加密敏感数据
  2. 限制 Chef 服务器的访问权限
  3. 定期更新 Chef 版本和补丁
  4. 监控 Chef 服务器的日志
  5. 使用 HTTPS 保护 Chef 服务器通信

Q6: 如何处理 Chef 客户端运行失败?

A6: 处理 Chef 客户端运行失败时,建议:

  1. 查看 Chef 客户端的运行日志
  2. 检查 Cookbook 代码中的错误
  3. 在测试环境中重现问题
  4. 修复问题并测试
  5. 重新在生产环境中运行 Chef 客户端

Q7: 如何实现 MySQL 高可用性?

A7: 使用 Chef 实现 MySQL 高可用性的方法包括:

  1. 配置主从复制
  2. 集成高可用性解决方案(如 MHA、Pacemaker + Corosync)
  3. 使用 Chef 自动化故障转移
  4. 监控集群状态
  5. 定期测试故障转移流程

Q8: 如何管理 MySQL 用户和权限?

A8: 使用 Chef 管理 MySQL 用户和权限的方法包括:

  1. 在 Cookbook 中定义用户和权限
  2. 使用模板或自定义资源创建用户
  3. 定期更新密码和权限
  4. 审计用户权限
  5. 遵循最小权限原则

Q9: 如何处理 MySQL 备份?

A9: 使用 Chef 处理 MySQL 备份的方法包括:

  1. 在 Cookbook 中配置备份策略
  2. 使用备份工具(如 mysqldump、xtrabackup)
  3. 自动化备份任务
  4. 验证备份的完整性
  5. 定期测试恢复流程

Q10: 如何扩展 Chef 管理的 MySQL 集群?

A10: 扩展 Chef 管理的 MySQL 集群的方法包括:

  1. 添加新节点到 Chef 服务器
  2. 为新节点分配角色和环境
  3. 运行 Chef 客户端部署 MySQL
  4. 配置复制(如果是从库)
  5. 验证新节点的功能和性能