如何通过SaltStack与mysql-formula管理两个MySQL实例?
我之前在折腾mysql-formula多实例部署的时候,也碰到过和你一模一样的问题——明明部署了两个实例,却没法同时引用它们的配置,应用那边拿不到连接信息急得跳脚。别担心,大概率是咱们对formula的多实例逻辑没摸透,咱们一步步来捋清楚:
1. 先把Pillar的多实例配置捋顺
mysql-formula默认是单实例逻辑,但它原生支持多实例,核心就是通过mysql:server:instances这个pillar节点来定义所有实例。你现在把配置拆成了db1-host.sls和db2-host.sls,很可能导致目标主机只拿到了其中一个实例的配置,没法同时识别两个。
建议把两个实例的配置合并到一个pillar文件(比如pillar/mysql/multi-instances.sls),结构如下:
mysql: server: instances: db1: port: 3306 datadir: /var/lib/mysql/db1 socket: /var/run/mysqld/db1.sock bind_address: 0.0.0.0 # 其他你需要的配置,比如skip_name_resolve、max_connections等 db2: port: 3307 datadir: /var/lib/mysql/db2 socket: /var/run/mysqld/db2.sock bind_address: 0.0.0.0
然后在pillar/top.sls里确保目标主机能拿到这个完整的多实例pillar:
base: 'db-host': # 你的MySQL主机的minion ID或匹配规则 - mysql.multi-instances
2. 调整Salt状态文件适配多实例
默认的mysql.server模块已经支持多实例部署,你只需要在salt/MySQL/init.sls里循环处理每个实例就行,不用硬编码单实例配置:
include: - mysql.server # 循环启动并管理所有MySQL实例 {% for instance_name, instance_config in salt['pillar.get']('mysql:server:instances', {}).items() %} mysql_server_{{ instance_name }}: mysql_server.running: - name: {{ instance_name }} - config: {{ instance_config }} - enable: True - require: - pkg: mysql_server {% endfor %}
这样执行状态后,formula会自动为每个实例生成独立的配置文件(比如/etc/mysql/my.cnf.d/db1.cnf)和systemd服务(比如mysql@db1.service),两个实例不会互相干扰。
3. 让应用获取数据库连接配置
应用需要的连接信息(主机、端口、用户名密码等),可以通过两种方式传递:
方式一:直接从Pillar读取(适合应用和MySQL在同一主机或应用主机能拿到MySQL的pillar)
在应用的状态文件里,通过pillar获取实例的配置,渲染到应用的配置文件中:
my_app_config: file.managed: - name: /etc/my_app/config.ini - source: salt://my_app/templates/config.ini.j2 - template: jinja - context: db1_host: {{ grains['fqdn'] }} # 或者直接写IP db1_port: {{ salt['pillar.get']('mysql:server:instances:db1:port') }} db1_user: {{ salt['pillar.get']('mysql:server:instances:db1:user:app_user') }} # 如果在pillar里定义了用户 db2_host: {{ grains['fqdn'] }} db2_port: {{ salt['pillar.get']('mysql:server:instances:db2:port') }}
方式二:用Salt Mine收集实例信息(适合应用和MySQL在不同主机,且不想把MySQL的pillar暴露给应用主机)
先在MySQL主机的状态文件里配置Mine,发布实例信息:
# 在MySQL主机的sls里添加 mine_functions: mysql_instances: - function: pillar.get - args: - mysql:server:instances
然后在应用主机的状态文件里,通过Mine获取MySQL主机的实例信息:
{% set mysql_host_instances = salt['mine.get']('db-host', 'mysql_instances', tgt_type='glob') %} {% set db1_config = mysql_host_instances.values()|first.get('db1', {}) %} {% set db2_config = mysql_host_instances.values()|first.get('db2', {}) %} my_app_config: file.managed: - name: /etc/my_app/config.ini - source: salt://my_app/templates/config.ini.j2 - template: jinja - context: db1_host: 'db-host' # MySQL主机的minion ID或IP db1_port: {{ db1_config.get('port', 3306) }} db2_host: 'db-host' db2_port: {{ db2_config.get('port', 3307) }}
4. 常见坑点排查
- 确认pillar的top.sls没有只分配单个实例的pillar给主机,要确保主机拿到完整的
instances配置; - 检查两个实例的端口、socket、datadir有没有冲突,冲突会导致实例启动失败;
- 用
systemctl status mysql@db1.service和systemctl status mysql@db2.service验证实例是否正常运行; - 如果应用拿不到配置,检查应用主机是否有读取MySQL pillar或Mine数据的权限(Salt的权限控制)。
内容的提问来源于stack exchange,提问作者jma

