《UNIX/Linux系统管理技术手册-读书笔记-第二十三章

配置管理

1. 配置管理概述

1.1 什么是配置管理

概念 说明 能做什么
配置管理(CM) 以代码形式描述系统期望状态,自动化实现服务器配置 替代“雪花服务器”,实现可重现、可审计、可版本控制的基础设施
声明式 vs 过程式 声明式:描述“要达到什么状态”;过程式:描述“要执行哪些步骤” 声明式更简洁,CM系统自动处理执行细节
幂等性(Idempotence) 重复执行同一操作,系统状态不变 可安全反复运行CM代码,无需担心副作用
基础设施即代码 基础设施配置存储在版本控制系统中 可追溯变更历史,支持代码审查和回滚

CM系统的核心操作

  • 创建/删除用户账户
  • 安装/卸载软件包
  • 同步配置文件(模板化)
  • 重启服务
  • 执行任意shell命令
  • 创建云服务器实例
  • 管理数据库账户

1.2 配置管理的危险(重要)

风险 说明
禁止手动修改 一旦CM托管,手动修改即退化为雪花服务器,造成状态漂移
陡峭学习曲线 所有CM系统都有学习成本,建议先在虚拟实验室练习
基础设施开销 大规模站点需专用服务器运行CM工作负载
系统间术语差异 不同CM系统概念相同但命名不同(见表23.2),知识迁移需重新学习

2. 配置管理核心要素

概念 说明
操作(Operation) 最小配置单元(如package install nginxservice start nginx
参数(Parameter) 操作的输入值(如软件包名、服务名)
变量(Variable) 命名过的值,用于参数化和模板填充
事实数据(Fact) CM系统自动收集的目标主机信息(OS类型、IP地址、内存等)
处理程序(Handler) 响应特定事件的操作(如配置文件变更后重启服务)
绑定(Binding) 将操作集合与特定主机/主机组关联
操作集(Bundle) 完成特定功能的操作集合(如“安装并配置Web服务器”)
环境(Environment) 隔离的配置世界(开发/测试/生产),支持分阶段部署

2.1 各CM系统术语对照表(表23.2)

通用概念 Ansible Salt Puppet Chef
操作 task state resource resource
操作类型 module function resource type, provider provider
操作列表 tasks states class, manifest recipe
绑定 playbook top file classification run list
控制主机 control master master server
客户机 host minion agent, node node
客户组 group nodegroup role
变量 variable variable parameter, variable attribute
事实数据 fact grain fact automatic attribute
处理程序 handler requisite notify notifies
操作集 role formula module cookbook
操作集仓库 Galaxy GitHub Forge Supermarket

3. 主流CM系统对比

3.1 一览表(表23.1扩展)

系统 实现语言 配置格式 模板引擎 守护进程(服务器/客户端) 首次发布
Ansible Python YAML Jinja2 ❌ 无(仅SSH) 2012
Salt Python YAML Jinja2 ✅ 可选/可选 2011
Puppet Ruby 自定义DSL ERB ✅ 可选/可选 2005
Chef Ruby Ruby DSL ERB ✅ 有/有 2009

市场份额:Puppet最老(2005)→ 用户量最大;Ansible和Salt增长最快;Chef在企业级场景受青睐。

3.2 架构差异(关键决策点)

对比维度 Ansible Salt Puppet Chef
无服务器模式 ✅ 默认(仅需SSH) ✅ 支持(SSH模式) ❌ 需master ✅ 支持(chef-solo)
性能 较慢(SSH往返) 快速(ZeroMQ/消息总线) 中等 中等
配置语言 YAML + Jinja YAML + Jinja 自定义Ruby DSL Ruby DSL
学习曲线 高(需熟悉Ruby)
大规模扩展 需调优 ✅ 原生支持 有瓶颈(已知Lyft等迁移案例) ✅ 分层架构支持
加密配置 ✅ ansible-vault(内建) ❌ 无内建 ❌ 无内建 ❌ 无内建
Windows支持
模块/操作集仓库 Ansible Galaxy GitHub Formulas Puppet Forge Chef Supermarket

3.3 各系统点评

Ansible(推荐小型到中型环境):

  • 最大优势:无服务器守护进程,仅需SSH+Python,配置简洁
  • ✅ ansible-vault提供内建加密
  • ❌ 大规模部署时速度明显慢于Salt
  • ❌ 手动管理客户端清单(无自动注册)

Salt(推荐大规模、云原生环境):

  • ✅ 速度快(消息总线架构),原生支持云集成
  • ✅ minion自动注册,配置语法一致性强
  • ✅ 可无服务器运行(SSH模式)
  • ❌ 依赖Jinja较重,文档组织较差
  • ❌ 无内建加密方案(需外部工具)

Puppet(市场份额最大但呈下降趋势):

  • ✅ 用户基数大,模块丰富,有免费WebGUI
  • ❌ 历史包袱重,配置语言不直观
  • ❌ 大规模场景存在master瓶颈

Chef(适合已有Ruby经验的企业):

  • ✅ 功能完备,强健,可扩展,支持AIX
  • ❌ 学习曲线最陡,企业级复杂度高
  • ❌ “非Chef场景”慎选——若<100台服务器,其他系统更轻量

4. YAML(配置语言基础)

特性 说明
本质 JSON的另一种语法(人类可读性更好)
列表 - item1(破折号+空格)
散列 key: value
多行字符串 `
变量插值 {{ variable }}(Ansible/Salt的Jinja扩展)

YAML陷阱

  • 缩进必须用空格(不能用Tab)
  • 布尔值(yes/notrue/false)自动转换
  • {{开头的值需加引号(某些情况下)

5. Ansible核心知识

5.1 架构与安装

组件 说明
控制主机 运行Ansible的机器(无需在受管节点安装agent
受管节点要求 ✅ SSH访问 + ✅ Python 2/3 + ✅ sudo权限
配置文件 /etc/ansible/ansible.cfg(系统级)或~/.ansible.cfg(用户级)
清单(Inventory) /etc/ansible/hosts(默认),列出受管主机

安装

1
2
3
4
5
6
7
8
# RHEL/CentOS(需启用EPEL)
sudo yum install ansible

# Ubuntu/Debian
sudo apt install ansible

# 或通过pip
pip install ansible

性能优化ansible.cfg):

1
2
[ssh_connection]
pipelining = true   # 大幅提升SSH执行速度

5.2 清单(Inventory)与分组

静态清单示例/etc/ansible/hosts):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 未分组主机
client-four.example.com

[webservers]
client-one.example.com
client-two.example.com

[dbservers]
client-one.example.com
client-three.example.com

# 主机变量
new-client.example.com ansible_user=ansible

# FreeBSD客户端(指定Python路径)
freebsd.example.com ansible_python_interpreter=/usr/local/bin/python

动态清单:可执行脚本输出JSON → 从云API动态获取主机列表(如ec2.py自动根据AWS标签分组)。

5.3 模块与任务

常用模块

模块 功能 示例
package 软件包管理 package: name=nginx state=present
service 服务管理 service: name=nginx state=started enabled=yes
copy 复制文件 copy: src=file dest=/path/file mode=0644
template 模板渲染(Jinja2) template: src=file.j2 dest=/path/file
user / group 用户/组管理 user: name=john groups=sudo append=yes
file 文件/目录属性 file: path=/dir state=directory mode=0755
lineinfile 文件行管理 lineinfile: path=/etc/hosts line="127.0.0.1 localhost"
shell / command 执行命令 shell: "df -h"
setup 收集事实数据 ansible new-client -m setup
group_by 动态分组 group_by: key={{ ansible_os_family }}

任务示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
- name: 安装Nginx
  package:
    name: nginx
    state: present

- name: 启动Nginx
  service:
    name: nginx
    state: started
    enabled: yes

5.4 变量与事实数据

变量类型 定义位置 优先级
主机变量 host_vars/hostname.yml 最高
组变量 group_vars/groupname.yml
全局变量 group_vars/all.yml
剧本内变量 vars:vars_files: 覆盖默认

事实数据(自动收集):

1
ansible hostname -m setup   # 查看所有事实

常用事实:ansible_os_familyansible_distributionansible_default_ipv4.address

变量引用{{ variable_name }}

5.5 循环与条件

循环(with_items)

1
2
3
4
5
6
7
- name: 创建多个用户
  user:
    name: "{{ item.username }}"
    groups: "{{ item.groups }}"
  with_items:
    - {username: alice, groups: wheel}
    - {username: bob, groups: sudo}

条件(when)

1
2
3
4
5
- name: 仅在FreeBSD上设置主机名
  lineinfile:
    path: /etc/rc.conf
    line: "hostname={{ hostname }}"
  when: ansible_os_family == "FreeBSD"

5.6 剧本(Playbook)—— 绑定

剧本结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
- name: 配置Web服务器
  hosts: webservers           # 目标组
  become: yes                 # 提权(sudo)
  vars:
    nginx_port: 80
  tasks:
    - name: 安装Nginx
      package: name=nginx state=present
    - name: 复制配置
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: restart nginx   # 变更时触发handler
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

执行

1
2
3
ansible-playbook -i inventory playbook.yml --ask-become-pass
ansible-playbook playbook.yml -l hostname        # 限制执行主机
ansible-playbook playbook.yml -t tag_name        # 仅执行特定标签

5.7 角色(Role)—— 操作集

角色目录结构

roles/
  webserver/
    defaults/main.yml     # 最低优先级变量
    vars/main.yml         # 固定变量
    tasks/main.yml        # 主要任务列表
    handlers/main.yml     # 处理程序
    files/                # 静态文件
    templates/            # Jinja2模板
    meta/main.yml         # 依赖关系

使用角色

1
2
3
4
5
6
- name: 部署Web应用
  hosts: webservers
  roles:
    - common
    - {role: nginx, nginx_port: 8080}   # 带参数的角色实例
    - postgresql

安装公共角色(Ansible Galaxy):

1
ansible-galaxy install ANXS.postgresql

5.8 加密配置(ansible-vault)

1
2
3
4
ansible-vault create secrets.yml          # 创建加密文件
ansible-vault edit secrets.yml            # 编辑
ansible-vault decrypt secrets.yml         # 解密
ansible-playbook playbook.yml --ask-vault-pass

5.9 Ansible安全最佳实践(23.5.14节)

实践 说明
专用账户 每个客户端使用同名专用账户(如ansible
分离凭证 SSH私钥口令 ≠ vault口令,单个凭证受损不暴露全部
禁用密码SSH PasswordAuthentication no
ssh-agent 管理私钥访问,会话期间只输入一次口令
避免私钥落地客户端 使用ForwardAgent临时转发,不复制私钥

6. Salt核心知识

6.1 架构与安装

组件 说明
Master 中央配置服务器,TCP端口4505(消息总线)+ 4506(文件服务)
Minion 受管节点,主动连接master拉取配置
密钥管理 minion首次连接需master用salt-key批准

安装(Master + Minion)

1
2
3
# 通用引导脚本(推荐)
curl -L https://bootstrap.saltstack.com -o /tmp/saltboot
sudo sh /tmp/saltboot -P -M   # -P安装Python,-M安装master

配置文件

  • Master:/etc/salt/master
  • Minion:/etc/salt/minion(设置master: salt.example.com

密钥管理

1
2
3
sudo salt-key -l unaccepted   # 查看待批准minion
sudo salt-key -yA             # 批准所有待批准密钥
sudo salt '*' test.ping       # 测试连通性

6.2 核心概念:Pillar(变量) vs State(操作)

概念 位置 求值 用途
Pillar /srv/pillar/ Master端 存储变量、密码、配置数据(每个minion看到不同内容)
State /srv/salt/ Minion端 定义期望状态(操作列表)

Pillar/State根目录配置/etc/salt/master):

1
2
3
4
file_roots:
  base: /srv/salt
pillar_roots:
  base: /srv/pillar

6.3 绑定(top.sls)

State绑定/srv/salt/top.sls):

1
2
3
4
5
6
7
base:
  '*':                    # 所有minion
    - bootstrap
  'G@os:Ubuntu':          # grain匹配
    - ubuntu
  'webserver':            # grain值
    - nginx

Pillar绑定/srv/pillar/top.sls):

1
2
3
4
5
base:
  '*':
    - baseline
  'G@os:FreeBSD':
    - freebsd

6.4 Minion匹配类型(表23.5)

类型 语法 示例
扩展匹配(默认) glob '*.example.com'
正则表达式 E@ E@web-\d+\.example\.com
Grain匹配 G@ G@os:Ubuntu
Pillar匹配 I@ I@role:database
列表 L@ L@host1,host2,host3
复合匹配 compound not G@os_family:RedHat

查看grain/pillar

1
2
salt '*' grains.items      # 查看所有grain
salt '*' pillar.items      # 查看所有pillar值

6.5 State文件(.sls)语法

示例(安装sudo并配置sudoers):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 状态ID必须全局唯一(作为散列键)
install-sudo-package:
  pkg.installed:
    - name: sudo
    - refresh: true

create-sudo-group:
  group.present:
    - name: sudo
    - require:              # 依赖声明
      - install-sudo-package

/etc/sudoers:
  file.managed:
    - source: salt://files/sudoers
    - user: root
    - group: wheel
    - mode: '0600'

依赖关系require(前驱必须成功)、watch(变更时触发重启)

名称简化:状态ID可同时作为操作名:

1
2
3
sudo:
  pkg.installed: []
  group.present: []

6.6 Jinja模板与循环

1
2
3
4
5
6
7
{% for admin in pillar.admins %}
{{ admin.username }}:
  user.present:
    - gid: {{ admin.username }}
    - groups: [wheel, sudo]
    - fullname: {{ admin.fullname }}
{% endfor %}

Salt + Jinja原则:尽可能将逻辑放在pillar数据中,而非Jinja代码中。用pillar替代条件判断(见23.6.5节示例)。

6.7 Highstate(执行配置)

1
2
3
salt '*' state.apply               # 应用highstate(所有绑定状态)
salt 'hostname' state.apply webserver   # 仅运行单个state文件
salt -C 'G@os:RedHat' state.apply   # 复合匹配

6.8 Salt Formulas(操作集)

  • 位于/srv/salt/子目录中的操作集
  • 社区仓库:GitHub salt-formulas组织
  • 与Ansible角色不同:Salt formula不可多次实例化(通过pillar数据迭代模拟)

6.9 环境(Environment)与限定(Pinning)

Salt环境(开发/测试/生产)配置在file_roots中定义,minion通过environment设置限定。

模式 说明
默认(多环境混合) minion可接收多个环境的状态(有弗兰肯服务器风险)
限定(Pinned) minion硬编码到单一环境(更安全,需复制通用配置)

调试命令

1
2
salt 'minion' config.get environment   # 查看minion环境
salt 'minion' state.show_top           # 查看minion将运行哪些状态

7. 最佳实践(23.8节)

实践 说明
版本控制 配置基础库必须置于Git等版本控制之下(CM健全性基本要求)
单一集成仓库 避免分散目录/仓库,统一管理简化日常操作
加密敏感数据 密码/密钥禁止明文进入Git(Ansible用vault,Salt用外部工具)
配置服务器加固 CM服务器拥有root访问权 → 最高安全级别的专用服务器
幂等性检查 确保CM运行时无虚假变更报告(脚本和shell命令是常见问题源)
测试环境隔离 用Vagrant/云沙箱测试,绝不在生产环境测试
细分配置 每个文件职责单一清晰
完全托管状态 禁用手动修改/临时禁用CM(避免状态漂移)
与CM集成数据源 从LDAP/CMDB等权威来源接入数据,避免信息重复
弹性环境优化 新节点引导时间控制在60s内:预先构建含软件包的镜像,CM只做最后配置

8. 本章核心命令速查表

命令 功能 系统
ansible -m setup host 查看主机事实数据 Ansible
ansible-playbook playbook.yml 执行剧本 Ansible
ansible-playbook playbook.yml -l host 限制执行主机 Ansible
ansible-playbook playbook.yml -t tag 仅执行特定标签 Ansible
ansible-galaxy install role 安装公共角色 Ansible
ansible-vault create/edit/file 管理加密文件 Ansible
salt '*' test.ping 测试minion连通性 Salt
salt-key -l unaccepted 查看待批准minion Salt
salt-key -yA 批准所有minion Salt
salt '*' state.apply 应用highstate Salt
salt 'host' grains.items 查看grain Salt
salt 'host' pillar.items 查看pillar Salt
puppet agent -t 手动触发Puppet运行 Puppet
chef-client 手动运行Chef Chef
knife node list 列出Chef节点 Chef

DBA视角补充

  • CM是DBA运维的“工业化升级”:传统DBA用脚本管理数十台数据库服务器 → CM可管理数百台,且配置可版本控制、可审计、可复用。为不同环境(开发/测试/生产)定义差异化的数据库配置。
  • 数据库配置模板化my.cnf/postgresql.conf通过模板(Jinja/ERB)根据主机角色(主库/从库、内存大小)动态生成,避免每台手动调优。
  • Ansible实战价值:因无agent要求,适合快速为现有数据库服务器建立CM(只需SSH+Python)。典型用例:部署pt-query-digest等监控工具、批量修改数据库参数、自动化备份脚本分发。
  • 敏感数据管理:数据库密码、SSL证书私钥应通过CM的加密机制(ansible-vault)存储,绝不以明文放入Git
  • 幂等性核心价值:重复运行CM不会破坏已有数据库(如mysql_user模块检查用户是否存在,不存在才创建),适合CI/CD流水线中的数据库变更管理。
  • 环境隔离:开发、测试、生产数据库的CM配置使用不同环境(变量不同,如连接字符串、缓冲池大小),确保开发环境误操作不影响生产。
  • 迁移现有数据库:将现有“雪花”数据库迁移到CM时,先“捕获”当前配置(如SHOW VARIABLES),再编写CM代码复现,在测试环境验证后逐步推广。