小阿轩yx-通过state模块定义主机状态
小阿轩yx-通过state模块定义主机状态
前言
- 前面学习了远程执行模块,这些模块的执行类似语段 shell 脚本,每次执行都会触发一次相同的功能,在大量的 minion 上运行远程命令当然是重要的,但是对于 minion 的环境控制,使用状态进行管理更为合适,转台是对 minion 的一种描述和定义,管理人员可以不用关心具体部署的任务是如何完成的,只需要描述 minion 要达到什么状态,底层由 salt 的状态模块来完成功能。
state 模块概述
什么是 state
- State 是 Saltstack 系统中的配置语言,在日常运维中需要编写大量的 state 文件
- 例如:创建用户.安装软件、配置软件、服务运行等。
- 需要编写一些 State SLS 文件,即状态配置文件去描述和实现相应的功能。
- State SLS 主要使用 YAML 语言,也可以支持使用 Python 语言编写。
例如,用 yaml 语言描述了一个安装 apache 的 state 模块。
#ID声明,ID必须唯一
apache-install:
#State 状态声明
pkg.installed:
#选项声明
- names:
#选项列表
- httpd
- httpd-devel
apache-service:
service.running:
- name: httpd
- enable: True
state 模块的作用
- 远程执行是 salt 的核心所在。
- 管理员可以通过执行远程执行模块,达到对 minion 的控制(如 cmd.run "yum install -y httpd" ),
- 对于 minion 的环境控制,你想 minion 达到一个什么样的状态,用 state 模块更为合适。
state 配置文件的各个要素
- state 模块可以使用 SLS(Saltstack)配置文件来定义,SLS 配置文件是使用 yaml 语言描述的,yaml 是一个有很多强大特效型的标记性语言,salt 使用的一个 yaml 的小型子集,用来映射那些非常常用的数据结构,像列表和字典。
- yaml renderer 将 yaml 的数据格式编译成为 python 数据结构给 salt 使用。
- YAML 的语法和其它语言类似,也可以表达散列表、标量等数据结构。
- 结构(structure)通过空格来展示;
- 序列(sequence)里的项用 “_” 来代表;
- Map 里的键值对用 “:” 分隔。
- YAML 文件扩展名通常为:yaml,也可以简写为yml。
只需要记住三个非常简单的规则就可以使用 yaml 编写 SLS 文件了。
缩进
- yaml 使用了一个固定的缩进风格来表示数据层的结构关系,salt 需要每个缩进级别用两个空格。注意不要用制表符(Tab)。
冒号
- Python 的字典是一种简单的键值对,这个数据类型在其他语言用户中又叫做哈希表或关联属组。
- 字典的 keys 在 yaml 中的表现实行是一个冒号结尾的字符串。
- values 的表现形式是冒号后面用一个空格隔开,然后写 values 值。
横杠
- 用一个短横杠加一个空格来表示列表项,多个项使用同样的缩进级别作为同一列表的一部分。
SaltStack 常用模块及应用
- 前面曾经用 “salt "web01" sys.list_modules” 命令获取 minion 端所有可以执行的模块,也可以用“sys.list_functions” 获取某一模块包含的所有函数,用 “sys.doc” 获取某一个函数的具体用法。
- Saltstack 工具提供了非常多的功能模块,以便于对操作系统的基础功能和常用工具进行操作。
pkg 模块
作用
- 包管理
- 包增加
- 包删除
- 包更新
三台主机恢复上一章的快照
进入 salt 目录
[root@master ~]# cd /srv/salt
设置 top.sls 文件
[root@master salt]# vim top.sls
base:
"web*':
- init.apache
创建 init
[root@master salt]# mkdir init
进入 init 目录
[root@master salt]# cd init/
安装单个 httpd 包
[root@master init]# vim apache.sls
httpd:
pkg.installed
执行同步命令
[root@master init]# salt '*' state.highstate
卸载一个包
[root@master init]# vim apache.sls
httpd:
pkg.removed
也可以直接用 salt 命令进行安装或卸载
#在 minion 上安装 httpd
[root@master ~]# salt 'web01' pkg.install "httpd"
#检査 httpd 包的版本
[root@master ~]# salt 'web01' pkg.version "httpd'#卸载 minion 上的 httpd
[root@master ~]# salt 'web01' pkg.remove "httpd'
安装一系列软件包
- 方法1
[root@master init]# vim apache.sls
mypkgs:
pkg.installed:pkgs:
- httpd: '=2.4.6'
- mariadb
- 可以使用<,<=,>=,and >等符号指定要安装的版本。
执行同步命令
[root@master init]# salt '*' state.highstate
卸载一组包
[root@master init]# vim apache.sls
mypkgs:
pkg.removed:
- pkgs:
- httpd: '=2.4.6'
- mariadb
也可以用 salt 命令直接对一组包进行管理
[root@master ~]# salt '*' pkg.install pkgs='["httpd","mariadb"]
或
[root@master ~]# salt '*' pkg.install pkgs='["mariadb", {"httpd":"2.4.6"}]'
[root@master ~]# salt '*' pkg.remove pkgs='["httpd", "mariadb"]'
升级软件包到最新
[root@master init]# cat apache.sls
mypkgs:
pkg.latest:
- pkgs:
- httpd
- mariadb
执行同步命令
[root@master init]# salt '*' state.highstate
通过 rpm 文件安装指定的 rpm 包
上传 rpm 包文件到 base 目录
- /srv/salt
[root@master init]# vim apache.sls
mypkgs:
pkg.installed:
- sources:
- zabbix-agent: salt://zabbix-agent-5.2.1-1.el7.x86 64.rpm
执行同步命令
[root@master init]# salt '*' state.highstate
file 模块
作用
- 管理文件操作
- 同步文件
- 设置文件权限
- 所属用户组
- 删除文件
file 模块的函数
- file.managed:文件管理;
- file.append:向文件中添加内容;
- file.comment:文件注释操作;
- file.copy:把 Minion 本地文件复制到某个目录下;
- file.directory:目录创建;
- file.exists:判断文件是否存在;
- file.absent:删除文件;
- file.symlink:建立 link 链接参数详解;
- file.touch:创建空文件,或者修改文件三个时间;
先删除上一步的所有文件
[root@master salt]# rm -rf *
YUM 安装源配置文件同步
[root@master salt]# vim top.sls
base:
"web*':
- init.myfile
创建所需目录
[root@master salt]# mkdir init
[root@master salt]# mkdir files
拷贝 hosts 文件到制定目录下
[root@master salt]# cp /etc/hosts /srv/salt/files/
切换 init 目录
[root@master salt]# cd init
编辑文件
[root@master init]# vim myfile.sls
myhosts:
file.managed:
- name: /etc/hosts
- source: salt://files/hosts
- mode: 644
- owner: root
- group: root
执行同步命令
[root@master init]# salt '*' state.highstate
创建测试页面
[root@master init]# echo '192.168.10.122 test00' >> /srv/salt/files/hosts
执行同步命令
[root@master init]# salt '*' state.highstate
- 同步后再 minion 端査看/etc/hosts 文件的变化。
同步之前备份文件
[root@master salt]# vim top.sls
base:
"web*':
- init.myfile
切换 init 目录
[root@master salt]# cd /init
添加文件配置
[root@master init]# vim myfile.sls
myhosts:
file.managed:
- name: /etc/hosts
- source: salt://files/hosts
- mode: 644
- owner: root
- group: root
- backup: minion
创建测试页面并执行
[root@master init]# echo '192.168.10.123 test01' >> /srv/salt/files/hosts
[root@master init]# salt '*'state.highstate
[root@master init]# echo '192.168.10.124 test02' >> /srv/salt/files/hosts
[root@master init]# salt '*'state.highstate
同步后再 minion 端查看 /etc/hosts 文件的变化
[root@web01 ~]# ll /var/cache/salt/minion/file_backup/etc
向 Minion 的文件中追加内容
[root@master init]# vim myfile.sls
/etc/hosts:
file.append:
- text:
- '192.168.10.125 test03
- '192.168.10.126 test04
- 直接向 minion 中的文件追加内容
执行
[root@master init]# salt '*' state.highstate
把 minion 端的本地的文件拷贝到 minion 端的其它目录中
[root@master init]# vim myfile.sls
opt/hosts.bak:
file.copy:
- source: /etc/hosts
- makedirs: True
- force: True
- 这两个目录和文件都是 minion 端的
执行同步命令
[root@master init]# salt '*' state.highstate
创建目录并做相应设置
[root@master init]# vim myfile.sls
/opt/aaa/bbb/ddd/fff:
file.directory:
- user: root
- group: root
- dir——mode: 755
- file mode: 644
- makedirs: True
- makedirs: True 如果要创建的是目录树,要启用递归方式创建
执行同步命令
[root@master init]# salt '*' state.highstate
判断文件是否存在
[root@master init]# vim myfile.sls
/opt/hosts.bak:
file.exists
执行同步命令
[root@master init]# salt '*' state.highstate
设置链接
[root@master init]# vim myfile.sls
/opt/hosts-link.bak:
file.symlink:
- target: /opt/hosts.bak
- force: True
- /opt/hosts-link.bak:链接文件
- target:/opt/hosts.bak 源文件(必须存在)
创建一个空文件
[root@master init]# vim myfile.sls
/opt/aaa.log:
file.touch
删除文件
[root@master init]# vim myfile.sls
/opt/aaa.log:
file.absent
cmd 模块
作用
- 在 Minion 上执行命令或者脚本
cmd.run 参数
- name:执行脚本或者命令的名字;
- onlyif:测试命令,如果执行测试命令返回 true,cmd.run 的命令才有可能执行;
- unless:与 onlyif 相反,如果执行后为 false,cmd.run 的命令才有可能执行;
- cwd:执行命令当前目录设置,默认为/root;
- user:执行命令的用户,默认 root;
- group:执行命令的组,默认 root;
- shell:执行命令使用的 Shell;
- env:执行命令的环境设置;
- umask:运行命令时候 umask 设置;
- output loglevel:执行命令日志输出级别,其中特殊的设置是 quiet,不输出日志;
- timeout:执行命令的超时时间,如果超时就发送 Kill-l SIGTERM 命令,如果"kill -lSIGTERM"被忽略了,那么紧接着发送 kill 命令。
cmd.wait 参数
- 与 cmd.run 中的参数相比,只是 wait 中没有 timeout 参数,其他参数意义一样。
cmd.run 和 cmd.wait 的区别
- 有多个判断条件的时,在 cmd.run 中只要有一个条件满足就会执行cmd.run;
- 而在cmd.wait 中则所有的条件都满足才会执行 cmd.wait。
- cmd.run 在每次应用 state 的时候都会被执行;
- 而 cmd.wait 用于在某个 state 变化时才会执行,状态不变化,就不会执行,通常和 watch 一起使用,watch 用来检测状态的变化。
进入 salt 目录
[root@master ~]# cd /srv/salt
删除所有文件
[root@master salt]# rm -rf *
使用 root 用户执行脚本 /opt/aaa.sh
[root@master salt]# vim top.sls
base:
"web*':
- init.cmd
将两个目录创建出来
[root@master salt]# mkdir init
[root@master salt]# mkdir files
切换到 init 目录
[root@master salt]# cd init
创建测试文件
[root@master init]# echo "ls">/srv/salt/files/aaa.sh
编写配置文件
[root@master init]# vim cmd.sls
/opt/aaa.sh:
file.managed:
- source: salt://files/aaa.sh
- mode:744
run aaa.sh:
cmd.run:
- name: /opt/aaa.sh
- cwd: /
- user: root
- cwd:执行命令时的当前工作目录
- mode:744 要设置执行权,否则无法在 minion 端执行此脚本
执行同步命令
[root@master init]# salt '*' state.highstate
判断 httpd 配置文件是否改动
- 如果改动,执行同步,然后测试配置文件是否可用,如果可用,重新加载配置文件
进入 salt 目录
[root@master ~]# cd /srv/salt/
编写配置文件
[root@master salt]# vim top.sls
base:
'web*':
- init.cmd
在 minion 上安装 httpd 并启动
[root@master salt]# salt '*' pkg.install "httpd"
[root@master salt]# salt '*' service.start "httpd"
创建服务所需的配置文件
[root@master salt]# mkdir -p /srv/salt/httpd/conf
安装 httpd
[root@master salt]# yum -y install httpd
- 此处安装 httpd,只是为了得到一个 httpd 的配置文件。
拷贝文件到指定目录下
[root@master salt]# cp /etc/httpd/conf/httpd.conf /srv/salt/httpd/conf
修改配置文件
[root@master salt]# vim /srv/salt/httpd/conf/httpd.conf
#修改端口号为 8080
Listen 8080
切换到 init 目录
[root@master salt]# cd init
编写配置文件
[root@master init]# vim cmd.sls
"/etc/httpd/conf/httpd.conf":
file.managed:
- source: salt://httpd/conf/httpd.conf
httpd:
cmd.wait:
- name: "/usr/sbin/httpd -k graceful"
- watch:
- file: "/etc/httpd/conf/httpd.conf"
执行同步命令
[root@master init]# salt '*' state.highstate
在 minion 端查看改动情况
[root@web01 ~]# netstat -anpt | grep httpd
tcp6 0 0 :::8080 :::* LISTEN 17387/httpd
- 需要注意 "/etc/httpd/conf/httpd.conf" 配置文件这块,最好使用引号,因为有时候可能会含有特殊字符。
- 另外,端口不要有冲突,否则,minion端的服务无法启动
- 执行 httpd -k restart 或者 httpd -k graceful 指令都会重启子进程(主进程未重启)。
- 只不过后者更加强调顺滑、优雅,先是启动了相同数量的子进程替代之前的进程进行服务,之后才去关闭之前的进程。
- -k 是明确执行的对象是正在运行中的 httpd 服务,所以有些教程又把这种带 -k 的启动,叫热启动,重启叫热重启。
user 模块
作用
- 管理系统账户操作。
user.present 用于创建用户
- name:要创建的用户名;
- uid:设置 uid;
- gid:设置默认的组 gid;
- groups:设置用户所属组;
- home:用户的自定义登录目录;
- password:为用户设置密码;
- enforce_password:如果密码已设置且密码哈希值与 “password” 字段中设置的密码不同,则设置为 False 以防止密码被更改。如果未设置 “password”,则忽略此选项,默认为 True;
- shell:设置用户的登录后的 Shell,默认将设置为系统默 Shell;
- uid、gid、home 等选项没有设置是系统默认设置
user.absent 用于删除用户
- name:设置需要删除的用户名;
- purge:是否删除用户家目录;
- force:如果用户当前已登录,则 absent state 会失败。选项为 True 时,就算用户当前处于登录状态也会删除本用户。
删除 salt 目录下所有文件
[root@master salt]# rm -rf *
创建用户并设置密码、shell、home 目录、uid、gid、其它所属组
[root@master salt]# vim top.sls
base:
"web*':
- init.user
创建目录
[root@master salt]# mkdir init
进入目录
[root@master salt]# cd init
编写文件
[root@master init]# vim user.sls
zhangsan:
user.present:
- password: "pwd123"
- shell: /bin/bash
执行
[root@master init]# salt '*' state.highstate
service 模块
作用
- 管理系统服务操作
- 包括 start、stop、reload、restart
service 模块的操作有
- name:服务名称;
- enable:设置自启动 True,默认不设置;
- watch:监控一些条件,如果成立默认执行 restart。
- reload:默认为 False,如果设置为 True 时候,当 watch 条件成立,则会 reload, 不会restart。
删除 salt 目录下所有文件
[root@master salt]# rm -rf *
编写文件
[root@master salt]# vim top.sls
base:
'web*':
- init.service
创建目录
[root@master salt]# mkdir init
进入目录
[root@master salt]# cd init
编写服务启动文件
[root@master init]# vim service.sls
httpd:
service:
- running
- enable: True
- reload: True
执行同步命令
[root@master init]# salt '*' state.highstate
service.running: #服务状态运行
- enable: True #允许开机启动
- reload: True #允许 reload 服务,默认restart
其他
- [root@master init]# salt '*' service.start httpd
- [root@master init]# salt '*' service.stop httpd
- [root@master init]# salt '*' service.restart httpd
- [root@master init]# salt '*' service.status httpd
cron 模块
作用
- 管理 cron 服务操作
cron.present 添加 cron 任务的操作
- name:资源名字;
- user:默认 root,或者指定用户执行;
- minute、hour、daymonth、month、dayweek:参数默认是*;
- cron.absent:删除 cron 任务。
删除 salt 目录下所有文件
[root@master salt]# rm -rf *
添加 cron 任务
[root@master salt]# vim top.sls
base:
'web*':
- init.cron
创建目录
[root@master salt]# mkdir init
进入目录
[root@master salt]# cd init/
编写脚本
[root@master init]# vim cron.sls
/path/to/cron/script:
cron.present:
- user: root
- minute: random
- hour: 2
- daymonth: '*'
- month: '*/2'
- dayweek: 4
- comment: "this script is rsync pic"
- - minion: random 随机时间
执行
[root@master init]# salt '*' state.highstate
删除 cron 任务
[root@master init]# vim cron.sls
/path/to/cron/script:
cron.absent
- cron.absent 后面没有冒号
执行同步命令
[root@master init]# salt '*' state.highstate
host 模块
作用
- 管理/etc/hosts 文件
参数
host.present 添加域名操作方法
- name:域名;
- names:多个域名;
- ip:ip 地址。
host.absent 删除域名。
删除 salt 目录下所有文件
[root@master salt]# rm -rf *
添加 ip 与域名对应
[root@master salt]# vim top.sls
base:
'web*':
- init.hosts
创建目录
[root@master salt]# mkdir init
进入 init 目录
[root@master salt]# cd init/
添加文件
[root@master init]# vim hosts.sls
host1:
host.present:
- ip: 192.168.10.101
- name: master
host2:
host.present:
- ip: 192.168.10.102
- names:
- web01
host3:
host.present:
- ip: 192.168.10.103
- names:
- web02
- mysq102
执行
[root@master init]# salt '*' state.highstate
删除 ip 对应的域名
[root@master init]# vim hosts.sls
host2:
host.absent:
- ip: 192.168.10.102
- names:
- web01
执行同步命令
[root@master init]# salt '*' state.highstate
Jinja 模版
- 对于同一文件,推送到不同主机上时,需要改动的内容不一定相同。
- 比如 web 中我们需要监听对应 minion 端自己的一个网卡 IP、某个端口,就不可以直接配置文件指定 IP,需要涉及到一些变量进行获取后更改操作。
- 现在 Saltstack 使用 Jinja 模板进行文件管理,在 jinja 中使用 grains、pillar 等标识并加上一些变量,就可以实现上述操作,同时可以使得文件管理更灵活,使用 jinja 可以减少人为操作提升工作效率。
什么是 Jinja
- 是 state(即 .sls)文件中默认模版语言
- 基于 pythonstate 文件中使用 “_template: jinjia” 声明 Jinja 模板包含变量和表达式
- 变量用 {{ }} 包围,表达式用 {% %} 包围。
Jinja 模板使用的三个场景
- file 状态使用 template 参数
- 模板文件里边使用变量名称 {{变量 }}。比如 {{ HOST }} {{PORT}}
- 变量列表(变量列表和 default 对齐)
Jinjia 语法
变量和表达式的定义
- 设置变量用 {% 表达式 %},jinja 取变量的方法是使用 {{ 变量 }}。
定义方法
设置变量
- {% set var = 'good' %}
取变量值
- {{ var }}
- {{ grains['id'] }}
判断语句
- {% if grains['os'] == 'CentOS '%}
- apache: httpd
- {% elif grains['os'] == 'Debian' %}
- apache: apache2
- {% endif %}
循环语句
- {% for user in users %}
- {{ user }}
- {{ endfor }}
利用 grains 数据编写 Jinja 模板文件
删除 salt 目录下所有文件
[root@master salt]# rm -rf *
编写 top 文件
[root@master salt]# vim top.sls
base:
'web*':
- init.myfile
创建目录
[root@master salt]# mkdir init
[root@master salt]# mkdir files
编写模板文件
[root@master init]# vim files/myhost.conf
{% if grains['os'] == 'RedHat' %}
host: {{ grains['host'] }}
{% elif grains['os'] == 'centos' %}
host: {{ grains['fqdn'] }}
{% endif %}
切换到 init 目录
[root@master salt]# cd init/
编写同步文件
[root@master init]# vim myfile.sls
myhost:
file.managed:
- name: /opt/myhost.conf
- source: salt://files/myhost.conf
- mode: 644
- owner: root
- group: root
- template: jinja
- - template: jinja
执行同步命令
[root@master init]# salt '*' state.highstate
minion 端查看同步过去的文件
[root@web01 ~]# cat /opt/myhost.conf
host: web01
利用 pillar 数据编写 Jinja 模板 --nginx 安装案例
配置 pillar
- 在主控端上创建入口文件 top.sls,入口文件的作用是定义 pillar 的数据覆盖被控主机的有效域范围。
[root@master ~]# vim /srv/pillar/top.sls
base:
group1:
- match: nodegroup
- web01
group2:
- match: nodegroup
- web02
分别定义不同组主机的 Nginx 的根目录
[root@master ~]# vim /srv/pillar/web01.sls
nginx:
root: /data
[root@master ~]# vim /srv/pillar/web02.sls
nginx:
root: /www
使用命令查看 pillar 配置情况
[root@master ~]# salt'web01' pillar.data
nginx:
----------
root:
/data
[root@master ~]# salt'web02' pillar.data
nginx:
----------
root:
/www
- 执行结果中可以很明显的看出,被控主机的 Nginx 的根目录被配置成功。
定义 state 的入口 top.sls 文件
- 注意和 pillar 的入口文件名字一样
[root@master ~]# vim /srv/salt/top.sls
base:
'*':
- nginx
定义被控主机执行的状态,安装 Nginx 软件、配置、启动
[root@master ~]# vim /srv/salt/nginx.sls
nginx:
pkg:
- installed
file.managed:
- source: salt://nginx/nginx.conf
- name: /etc/nginx/nginx.conf
- user: root
- group: root
- mode: 644
- template: jinja
service.running:
- enable: True
- reload: True
- watch:
- file: /etc/nginx/nginx.conf
- pkg: nginx
- salt://nginx/nginx.conf 为配置模板文件位置;
- enable:True 表示检查服务是否在开机自启动服务队列中,如果不在则加上,等价于chkconfig nginx on 命令;
- reload:True 表示服务支持 reload 操作,不加则会默认执行 restart 操作;
- watch 即用于检测/etc/nginx/nginx.conf 是否发生变化,又用于确保 Nginx 已安装成功。
- Jinja 是一种基于 python 的模板引擎,在 SLS 文件里可以直接使用 jinja 模板来做一些操作,通过 jinja 模板可以为不同服务器定义各自的变量。
创建 nginx 目录
[root@master ~]# mkdir /srv/salt/nginx
创建 nginx 模板文件
[root@master ~]# vim /srv/salt/nginx/nginx.conf
user nginx;
worker_processes {{grains['num_cpus']}};
{% if grains['num_cpus'] ==1 %}
worker_cpu_affinity 10;
{% elif grains['num_cpus'] ==2 %}
worker_cpu_affinity 01 10;
{% elif grains['num_cpus'] == 4 %}
worker_cpu_affinity 0001 0010 0100 1000;
{% elif grains['num_cpus'] == 8 %}
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
{% else %}
worker_cpu_affinity 0001 0010 0100 1000;
{% endif %}
error_log /var/log/nginx_error.log;
pid /var/run/nginx.pid;
events
{
worker_connections 1024;
}
http
{
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 60;
log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"' ;
server{
listen 80 default_server;
server_name _;
location / {
root {{ pillar['nginx']['root'] }};
index index.html index.htm;
}
error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
在主控制端执行刷新 state 配置
[root@master ~]# salt '*' state.highstate
- 通过执行结果,看到了三个 ID,相当于三个任务,第一个安装,第二个配置,第三个启动。
- 而且显示三个都成功了,失败数是零个。
- 如果不放心,也可以看看被控端 Nginx 是否启动。
[root@web01 ~]# ps -ef | grep nginx
査看 web01 节点的 Nginx 主配置文件 nginx.conf
[root@web01 ~]# more /etc/nginx/nginx.conf
- 査看 web02 节点的 Nginx 主配置文件 nginx.conf,上面注释的内容有相应的变化。
- 这样,基本完成了通过 Saltstack 批量部署 Nginx 并配置。
小阿轩yx-通过state模块定义主机状态