Saltstack ====== [toc] 简介 ------ 线上所有的统一配置管理工具均有saltstack完成 完成的线上任务: 1. 用于系统的初始化 2. 用于开源软件的配置管理,包括 * nginx * phpfpm * redis * mongodb * memcache * ... 3. 用于管理c++开发的所有组件配置已经更新 * roommaster * chatroom * gateserver * secgateserver * rediswriter * ... ## SaltStack介绍 SaltStack,一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯。 ### 特性 1. 具备配置管理 2. 可以远程执行 3. 基于python实现 4. 部署简单方便 5. 支持API以及自定义模块,通过python可以进行轻松的扩展 6. 主控端与被控端基于证书认证,安全可靠 7. 基于ZeroMQ进行消息传输 ### 基本原理 SaltStack采用C/S模式,server端就是salt的salt-master,client端为salt-minion,minion与master之间通过ZeroMQ消息队列通信 minion上线后先与master端联系,把自己的pub key发过去,这时master端通过salt-key -L命令就会看到minion的key,接受该minion-key后,也就是master与minion已经互信 master可以发送任何指令让minion执行了,salt有很多可执行模块,比如说cmd模块,在安装minion的时候已经自带了,它们通常位于你的python库中,locate salt | grep /usr/ 可以看到salt自带的所有东西。 具体步骤如下 1. Salt stack的Master与Minion之间通过ZeroMq进行消息传递,使用了ZeroMq的发布-订阅模式,连接方式包括tcp,ipc 2. salt命令,将cmd.run ls命令从salt.client.LocalClient.cmd\_cli发布到master,获取一个Jodid,根据jobid获取命令执行结果。 3. master接收到命令后,将要执行的命令发送给客户端minion。 4. minion从消息总线上接收到要处理的命令,交给minion.\_handle\_aes处理 5. minion.\_handle\_aes发起一个本地线程调用cmdmod执行ls命令。线程执行完ls后,调用minion.\_return\_pub方法,将执行结果通过消息总线返回给master 6. master接收到客户端返回的结果,调用master.\_handle\_aes方法,将结果写的文件中 7. salt.client.LocalClient.cmd\_cli通过轮询获取Job执行结果,将结果输出到终端。 ### 安装 saltstack的包已经加入EPEL源,可以直接通过yum安装 1. salt-master 安装 ```bash yum install salt-master ``` 2. salt-minion 安装 ```bash wget -O install_salt.sh https://bootstrap.saltstack.com --no-check-certificate && sh install_salt.sh ``` ### 提供的功能 #### Target 指定执行命令或者模块应用在哪个Minion上 1. globbing匹配 ```bash salt 'Dy-JXQ-101' test.ping ``` 2. RE正则 ```bash salt -E 'Dy-JXQ-9(1-2)$' test.ping ``` 3. grains ```bash salt -G "os:CentOS" test.ping # 查看所有grains的键值 salt 'test' grains.items # 查看所有grains项 salt 'test' grains.ls # 查看某个grains的值 salt 'test' grains.item num_cpus ``` 在top file中匹配grains ```bash 'node_type:webserver': - match: grain - nginx - phpfpm - ``` 4. nodegroups 是对minion分组 ```bash # /etc/salt/master.d/nodegroup.conf nodegroups: test1: 'L@test1, test2 or test3' test2: 'G@os:CentOS or test2' salt -N test1 test.ping ``` #### 批量执行 同Target类似例子 使用命令可以执行各种命令 ```bash salt -E 'Dy-JXQ-10[1-9]$' cmd.run "uptime" ``` #### 多个Master 多个Master,在我们的生产环境中还未正式使用 多Master需要注意的地方: 1. 2个master之间并不会共享minion key,互相独立 2. 不会自动同步file\_roots,需要手动维护,可以使用git 3. 不会自动同步Pillar\_roots,需要手动维护,可以使用git 4. master的配置文件是独立 #### Pillar Pillar在salt中是非常重要的组成部分,利用它可以完成动态的数据调整,可以使用sls文件编写 适用场景 1. 比较敏感的数据,如密码,key等 2. 特殊数据到指定的minion上 3. 动态内容 ##### 查看Minion的pillar信息 ```bash salt '*' pillar.items salt '*' pillar.item salt '*' pillar.get : ``` ##### 编写pillar数据 1. 指定pillar\_roots,默认是/srv/pillar 2. 在top file中使用pillar ```bash '*': - {{ environment }}.epel - {{ environment }}.ntp - {{ environment }}.systembase - {{ environment }}.openssh - {{ environment }}.zabbix_agent - {{ environment }}.douyu_sudo ``` 3. 在state中通过jinja使用pillar数据 ```python {% set zabbix_conf = salt['pillar.get']('zabbix_agent:config_settings', config_map, merge=True) %} ``` #### Grains Grains主要提供一种对服务器静态信息的描述,可以对Grains增加自己对服务器节点的描述 grains的解析使用yaml模块进行解析,所以对齐是必须的,否则会出现不可预料的错误 通常Grains所提供的键值对有以下三种: 1. 针对常用的键值对,比如系统版本号,网卡地址,mac地址,salt有一套原生的grains定义,该定义均由salt官方提供的python脚本提供,这些python脚本均内置到salt中 2. 通过编写minion端的/etc/salt/grains 加入额外的grains定义 ```bash environment: live node_type: - webserver - memcache - room_service - redis - nginx_lua ``` 3. 通过编写master端的/etc/salt/\_grains目录下的python脚本,自定义需要的grains值 ```python def hello(): agrain = {} agrain['hello'] = 'saltstack' return agrain ``` 符合salt自己自定义的要求返回一个字典即可 在三种情况下,会执行_grains目录下的py脚本 * 重启salt-minion * 在master端执行 salt 'test' saltutil.sync_all * master端执行 salt 'test' state.highstate 备注:在room\_services的state模块中,使用了dy\_extends.py脚本对对应的服务器进行了定制化配置 #### State 它的核心是SLS(salt state file),文件默认是YAML格式,并默认使用jinja模板 该State是salt的配置管理核心,所有的配置定义均由state文件通过salt解析完成 ##### 示例文件 选取自ntp中的init.sls ```python # Include :download:`map file ` of OS-specific package names and # file paths. Values can be overridden using Pillar. {% from "ntp/map.jinja" import ntp with context %} {% set service = {True: 'running', False: 'dead'} %} ntp: pkg.installed: - name: {{ ntp.lookup.package }} {% if 'ntp_conf' in ntp.lookup %} ntpd_conf: file.managed: - name: {{ ntp.lookup.ntp_conf }} - source: salt://ntp/files/ntp.conf - template: jinja - context: config: {{ ntp.settings.ntp_conf }} - require: - pkg: ntp {% endif %} {% if salt['service.status']('ntpd') != True %} correct_time: cmd.run: - name: ntpdate 2.asia.pool.ntp.org {% endif %} {% if 'ntpd' in ntp.settings %} ntpd: service.{{ service.get(ntp.settings.ntpd) }}: - name: {{ ntp.lookup.service }} - enable: {{ ntp.settings.ntpd }} - require: - pkg: ntp {% if salt['service.status']('ntpd') != True %} - cmd: correct_time {% endif %} - watch: - file: ntpd_conf {% endif %} ``` 通过适当的配置,配置管理的功能和便利性会远超puppet ##### 关于salt的render\_system salt默认的渲染器是yaml\_jinja,salt处理我们的sls文件时,会先把文件用jinja2处理,然后传给ymal处理器在处理,然后生成的是salt需要的python数据类型。除了yaml\_jinja还有yaml\_mako,yaml\_wempy,py,pydsl yaml\_jinja是默认的,而py是用纯python来写的。 ## 线上saltstack的使用 ### 约定 针对我们的业务需求和基于一定的安全考虑 线上的saltstack使用上会区分为 * 北京机房,一个独立的salt-master * 外网机房,一个独立的salt-master 两个salt-master的代码基本一样,基于room\_service和nginx的配置有些微不同 nginx的模块主要是外网代理vhost的不同 room\_service外网主要使用MsgRepeater的配置 ### 配置目录的组织 salt的state配置采用归一化的编排,而针对不同环境的不同变量配置采用pillar的动态特性进行区分 具体实施上采用以下的目录结构 ```bash ├── pillar │   ├── bj-test │   │   ├── douyu_sudo.sls │   │   ├── epel.sls │   │   ├── init.sls │   │   ├── memcache.sls │   │   ├── mongodb.sls │   │   ├── nginx_lua.sls │   │   ├── nginx.sls │   │   ├── ntp.sls │   │   ├── openssh.sls │   │   ├── phpfpm.sls │   │   ├── redis.sls │   │   ├── room_service.sls │   │   ├── systembase.sls │   │   └── zabbix_agent.sls │   ├── dev │   │   ├── douyu_sudo.sls │   │   ├── epel.sls │   │   ├── init.sls │   │   ├── memcache.sls │   │   ├── mongodb.sls │   │   ├── nginx.sls │   │   ├── ntp.sls │   │   ├── openssh.sls │   │   ├── phpfpm.sls │   │   ├── redis.sls │   │   ├── room_service.sls │   │   ├── systembase.sls │   │   └── zabbix_agent.sls │   ├── live │   │   ├── douyu_sudo.sls │   │   ├── epel.sls │   │   ├── init.sls │   │   ├── memcache.sls │   │   ├── mongodb.sls │   │   ├── nginx_lua.sls │   │   ├── nginx.sls │   │   ├── ntp.sls │   │   ├── openssh.sls │   │   ├── phpfpm.sls │   │   ├── redis.sls │   │   ├── room_service.sls │   │   ├── systembase.sls │   │   └── zabbix_agent.sls │   ├── pressure │   │   ├── douyu_sudo.sls │   │   ├── epel.sls │   │   ├── init.sls │   │   ├── memcache.sls │   │   ├── mongodb.sls │   │   ├── nginx.sls │   │   ├── ntp.sls │   │   ├── openssh.sls │   │   ├── phpfpm.sls │   │   ├── redis.sls │   │   ├── room_service.sls │   │   ├── systembase.sls │   │   └── zabbix_agent.sls │   ├── prod │   │   ├── douyu_sudo.sls │   │   ├── epel.sls │   │   ├── init.sls │   │   ├── memcache.sls │   │   ├── mongodb.sls │   │   ├── nginx.sls │   │   ├── ntp.sls │   │   ├── openssh.sls │   │   ├── phpfpm.sls │   │   ├── redis.sls │   │   ├── room_service.sls │   │   ├── systembase.sls │   │   └── zabbix_agent.sls │   └── top.sls └── salt ├── douyu_sudo ├── epel ├── _grains ├── memcache ├── mongodb ├── mysql ├── nginx ├── nginx_lua ├── ntp ├── openssh ├── phpfpm ├── redis ├── room_service ├── systembase ├── zabbix_agent └── top.sls ``` #### 区分环境 利用pillar的top.sls入口文件,对符合的主机进行环境区分 1. 所有主机都必须在/etc/salt/grains中指定 'environment:prod/live/pressure/dev/bj-test‘ 用于标示主机是否属于生产环境或者测试环境 2. top.sls文件示例 ```python # top.sls {% set environment = salt['grains.get']('environment', '') %} include: - {{ environment }} ``` ```python # init.sls {% set environment = salt['grains.get']('environment', '') %} {{ saltenv if saltenv != None else env }}: '*': - {{ environment }}.epel - {{ environment }}.ntp - {{ environment }}.systembase - {{ environment }}.openssh - {{ environment }}.zabbix_agent - {{ environment }}.douyu_sudo 'node_type:webserver': - match: grain - {{ environment }}.nginx - {{ environment }}.phpfpm 'node_type:nginx': - match: grain - {{ environment }}.nginx 'node_type:nginx_lua': - match: grain - {{ environment }}.nginx_lua 'node_type:phpfpm': - match: grain - {{ environment }}.phpfpm 'node_type:memcache': - match: grain - {{ environment }}.memcache 'node_type:redis': - match: grain - {{ environment }}.redis 'node_type:mongodb': - match: grain - {{ environment }}.mongodb 'node_type:room_service': - match: grain - {{ environment }}.room_service ``` 其中的node_type为自定义grains,用来区分主机需要安装的服务类型 #### 典型的salt模块目录组成 salt的所有使用的模块基本是自有,线上所提供的各种开源模块无法符合自身业务的需求 以nginx目录结构为例 ```nginx nginx ├── files │   ├── conf │   │   ├── mime.types │   │   └── nginx.conf │   ├── initd │   │   └── nginxd │   ├── logrotate │   │   ├── nginxd │   │   └── nginx_logfile_logrotate.py │   ├── monitor │   │   ├── nginx.conf │   │   ├── nginx_monitor.conf │   │   └── nginx_status.sh │   ├── nginx_install.sh │   ├── ssl_conf │   │   ├── server.key │   │   ├── server.pem │   │   ├── ybadmin.crt │   │   └── ybadminv1.key │   ├── tar_package │   │   ├── nginx-1.8.0.tar.gz │   │   ├── Nginx-accesskey-2.0.3.tar.gz │   │   └── ngx_cache_purge-master.zip │   ├── vhost │   │   ├── cooperate │   │   │   ├── backend │   │   │   │   ├── cooperate.backend.036yx.com.conf │   │   │   │   ├── cooperate.backend.2144.com.conf │   │   │   │   └── cooperate.backend.ilongyuan.com.cn.conf │   │   │   └── edge │   │   │   ├── cooperate.proxy.036yx.com.conf │   │   │   ├── cooperate.proxy.2144.com.conf │   │   │   └── cooperate.proxy.ilongyuan.com.cn.conf │   │   └── core │   │   ├── backend │   │   │   ├── adsys.douyutv.com.conf │   │   │   ├── api.douyutv.com.conf │   │   │   ├── file.douyutv.com.conf │   │   │   ├── ssl.douyutv.com.conf │   │   │   ├── static2.douyutv.com.conf │   │   │   ├── staticdn.douyutv.com.conf │   │   │   ├── staticlive.douyutv.com.conf │   │   │   ├── uc.douyutv.com.conf │   │   │   ├── upload.douyutv.com.conf │   │   │   └── www.douyutv.com.conf │   │   └── edge │   │   ├── proxy_adsys.douyutv.com.conf │   │   ├── proxy_api.douyutv.com.conf │   │   ├── proxy_ssl.douyutv.com.conf │   │   ├── proxy_static2.douyutv.com.conf │   │   ├── proxy_staticlive.douyutv.com.conf │   │   ├── proxy_uc.douyutv.com.conf │   │   ├── proxy_www.douyutv.com.conf │   │   └── proxy_ybadmin.douyutv.com.conf │   └── web_rsync │   ├── exclude.txt │   ├── rsync.pwd │   └── webrsync.sh ├── init.sls ├── map.jinja └── states ├── config.sls ├── install.sls ├── logrotate.sls ├── monitor.sls ├── service.sls ├── user.sls └── vhost_conf ├── cooperate_backend_vhost_group.sls ├── cooperate_proxy_vhost_group.sls ├── core_backend_vhost_adsys.sls ├── core_backend_vhost_fileupload.sls ├── core_backend_vhost_group.sls ├── core_backend_vhost_ssl.sls ├── core_backend_vhost_staticdn.sls ├── core_backend_vhost_uc.sls ├── core_proxy_vhost_group.sls ├── core_proxy_vhost_ssl.sls ├── douyu.sls └── yuba_proxy_vhost_ybadmin.sls ``` 1. init.sls 为整个模块的应用入口,用于囊括states目录下面的state定义 2. map.jinja 为整个模块配置的默认变量设置,可以使用pillar覆盖map里面设置的变量,该件也是其他sls定义文件的变量的源 3. files目录存放所有需要引入的文件,包括tar包,各种配置文件 4. states目录存放所有的配置sls文件 ### 使用的模块 现在使用的模块分为 ```bash salt ├── douyu_sudo # 控制服务器的sudo权限 ├── epel # 控制所有CentOS主机的epel源 ├── _grains # 扩展grains ├── memcache # memcache的配置管理 ├── mongodb # mongodb的配置管理,暂时未上线 ├── mysql # mysql的配置管理,暂时未上线 ├── nginx # nginx的配置管理,包括所有在线使用的webserver ├── nginx_lua # nginx_lua环境模块,应php要求新加入的配置管理 ├── ntp # ntp配置管理,控制所有服务器的ntp client同步时间 ├── openssh # 服务器的ssh服务管理 ├── phpfpm # phpfpm进程配置管理,线上使用的配置统一一致,个别phpfpm特殊需求 ├── redis # redis的配置管理,负责控制所有redis主从关系 ├── room_service # c++组件的配置管理,部分功能未启用 ├── systembase # 系统初始化的配置管理,包括安装包,kernel参数优化 ├── zabbix_agent # zabbix_agent的配置管理,监控客户端 └── top.sls # 入口文件 ```