<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>DevOps技术分享 &#187; Saltstack</title>
	<atom:link href="http://www.showerlee.com/archives/tag/saltstack/feed" rel="self" type="application/rss+xml" />
	<link>http://www.showerlee.com</link>
	<description>与你共同学习运维开发</description>
	<lastBuildDate>Mon, 19 Oct 2020 05:51:41 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.6</generator>
		<item>
		<title>[Saltstack] CentOS下批量部署Nginx</title>
		<link>http://www.showerlee.com/archives/1538</link>
		<comments>http://www.showerlee.com/archives/1538#comments</comments>
		<pubDate>Fri, 25 Sep 2015 05:27:56 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[DevTools]]></category>
		<category><![CDATA[Saltstack]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=1538</guid>
		<description><![CDATA[上一篇博文我介绍了如何快速搭建Salt环境, 以及利用相关pillar, state, grains模块进行基 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>上一篇博文我介绍了如何快速搭建Salt环境, 以及利用相关pillar, state, grains模块进行基本的客户端部署操作.<br />
本篇文档我们会详细介绍如何利用Salt来批量部署安装Nginx, 并自动化配置Nginx的相关属性.</p>
<p>
	
</p>
<p>
	Salt环境部署详见:&nbsp;<a href="http://www.showerlee.com/archives/1472" target="_blank">http://www.showerlee.com/archives/1472</a>
</p>
<p>
	
</p>
<p>
	安装环境:
</p>
<p>
	<strong>System:</strong> Centos 6.3
</p>
<p>
	<strong>Salt master:</strong> salt-master.example.com&nbsp;
</p>
<p>
	<strong>Salt minion:</strong> salt-client01.example.com
</p>
<p>
	<strong>Salt minion:</strong><span style="line-height:1.5;">&nbsp;salt-client02.example.com</span><span style="line-height:1.5;"></span>
</p>
<p>
	
</p>
<p>
	<strong><span style="font-size:14px;color:#337FE5;">一. &nbsp;主控端配置</span></strong>
</p>
<p>
	<span style="color:#337FE5;">1. 配置master基本参数</span>
</p>
<p>
	# vi /etc/salt/master<br />
添加:
</p>
<pre class="prettyprint lang-py">nodegroups:
   webgroup1: 'salt-client01.example.com'
   webgroup2: 'salt-client02.example.com'

file_roots:
  base:
    - /srv/salt

pillar_roots:
  base:
    - /srv/pillar</pre>
<p><span style="color:#E53333;">Tip: 这里的nodegroups里的分组会应用到随后的pillar脚本下, 用来区分不同的salt-minion使用相应的pillar参数, 从而定制不同的minion使用不同的配置方案.</span> </p>
<p>
	
</p>
<p>
	重启服务
</p>
<p>
	# /etc/init.d/salt-master restart
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">2. 动态配置客户端系统连接数</span>
</p>
<p>
	使用python脚本编写grains_module, 实现动态配置被控主机连接数(CLI可用"limit -n"查询该值), 以便随后的Nginx配置文件中的worker_rlimit_nofile, worker_connections可动态调用脚本中max_open_file的参数值.
</p>
<p>
	<span style="color:#E53333;">Tip: "ulimit -n" 是用来查询当前linux系统的最大打开文件数, 默认为1024</span>
</p>
<p>
	也可用"ulimit -a"来查看其他相关参数
</p>
<p>
	# ulimit -a
</p>
<pre class="prettyprint lang-bsh">core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7819
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 10240
cpu time               (seconds, -t) unlimited
max user processes              (-u) 1024
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited</pre>
<p>暂时修改当前session的参数值</p>
<p>
	# ulimit -n 2048
</p>
<p>
	
</p>
<p>
	永久修改需修改该参数值
</p>
<p>
	# vi&nbsp;/etc/security/limits.conf
</p>
<p>
	添加:
</p>
<pre class="prettyprint lang-bsh">root soft  nofile 2048
root hard  nofile 2048</pre>
<p>#&nbsp;vi /etc/pam.d/common-session</p>
<p>
	添加:
</p>
<pre class="prettyprint lang-bsh">session required pam_limits.so</pre>
<p>
	重启生效.
</p>
<p>
	
</p>
<p>
	脚本具体配置如下:
</p>
<p>
	# mkdir -p /srv/salt/_grains
</p>
<p>
	# vi&nbsp;<span>/srv/salt/_grains/nginx_config.py</span>
</p>
<p>
	<span> </span>
</p>
<pre class="prettyprint lang-bsh">#!/usr/bin/env python

import os,sys,commands  

# return Nginx config grains value  
def NginxGrains():  
    grains = {}  
    max_open_file=65536   
    try:  
        getulimit=commands.getstatusoutput('source /etc/profile &amp;&amp; ulimit -n')  
    except Exception,e:  
        pass  
    if getulimit[0]==0:  
        max_open_file=int(getulimit[1])  
    grains['max_open_file'] = max_open_file  
    return grains</pre>
<p>
	<span style="color:#E53333;">Tip: 该脚本会同步到远程后执行, 脚本实际就是获取并返回当前主机的最大打开数值, 最终返回值会赋予字典&nbsp;<strong>grains['max_open_file']</strong><strong></strong><br />
</span>
</p>
<p>
	同步grains模块:
</p>
<p>
	# salt '*' saltutil.sync_all
</p>
<p>
	<span style="line-height:1.5;">刷新模块(让minion编译模块)</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' sys.reload_modules</span>
</p>
<p>
	<span style="line-height:1.5;">验证max_open_file key的value</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' grains.item max_open_file&nbsp;</span>
</p>
<p>
	<span style="line-height:1.5;color:#E53333;">Tip: 这里笔者测试更改客户端最大文件打开值时发现了一个问题, 无论客户端如何更改这个值, 在验证key value时终会显示最早的系统初始值1024, 翻阅了大量文档, 发现minion端会将所有服务端的推送保存在(</span><span style="line-height:1.5;color:#E53333;">/var/cache/salt/minion</span><span style="line-height:1.5;color:#E53333;"></span><span style="line-height:1.5;color:#E53333;">), 这里删除这个缓存目录并重启salt-minion, 让其生成新的缓存目录, 从新同步grains模块, 新的vaule就会生效.</span>
</p>
<p>
	# salt '*' cmd.run 'rm -rf /var/cache/salt/minion &amp;&amp; /etc/init.d/salt-minion restart'
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">3. 配置pillar</span>
</p>
<p>
	1). 定义入口sls
</p>
<p>
	# vi /srv/pillar/top.sls
</p>
<pre class="prettyprint lang-bsh">base:
  webgroup1:
   - match: nodegroup
   - nginx.webserver1
  webgroup2:
   - match: nodegroup
   - nginx.webserver2</pre>
<p>
	<span style="color:#E53333;">Tip: 这里定义webgroup1的所有minions会使用pillar/nginx/webserver1.sls脚本,&nbsp;</span><span style="color:#E53333;">webgroup2所有minions使用pillar/nginx/webserver2.sls脚本, <strong>match: nodegroup</strong> 定义<span style="color:#E53333;">webgroup1</span>, webgroup2匹配nodegroup组.<br />
</span>
</p>
<p>
	<span style="color:#E53333;"><br />
</span>
</p>
<p>
	2). 定义webserver1, webserver2 sls
</p>
<p>
	# mkdir /srv/pillar/nginx
</p>
<p>
	# <span>vi<span>&nbsp;/srv/pillar/nginx/webserver1.sls</span></span>
</p>
<pre class="prettyprint lang-bsh">nginx:
    hostname: webserver1
    name: nginx
    root: /www
    source: salt://nginx/nginx.conf
    file: /etc/nginx/nginx.conf
    user: root
    group: root
    mode: 644
    template: jinja
    status: installed</pre>
<p><span>#&nbsp;</span><span>vi&nbsp;/srv/pillar/nginx/webserver2.sls</span> </p>
<pre class="prettyprint lang-bsh">nginx:
    hostname: webserver2
    name: nginx
    root: /data
    source: salt://nginx/nginx.conf
    file: /etc/nginx/nginx.conf
    user: root
    group: root
    mode: 666
    template: jinja
    status: installed</pre>
<p>
	3). 查看配置结果
</p>
<p>
	# salt '*' pillar.data nginx
</p>
<pre class="prettyprint lang-bsh">salt-client02.example.com:
    ----------
    nginx:
        ----------
        file:
            /etc/nginx/nginx.conf
        group:
            root
        hostname:
            webserver2
        mode:
            666
        name:
            nginx
        root:
            /data
        source:
            salt://nginx/nginx.conf
        status:
            installed
        template:
            jinja
        user:
            root
salt-client01.example.com:
    ----------
    nginx:
        ----------
        file:
            /etc/nginx/nginx.conf
        group:
            root
        hostname:
            webserver1
        mode:
            644
        name:
            nginx
        root:
            /www
        source:
            salt://nginx/nginx.conf
        status:
            installed
        template:
            jinja
        user:
            root</pre>
<p>
	<span style="color:#E53333;">Tip: 可以通过字典&nbsp;</span><span style="color:#E53333;"><strong><span style="color:#E53333;">pillar['nginx']['root']</span></strong><span style="color:#E53333;"> 在配置文件中调用</span></span>
</p>
<p>
	<span style="color:#E53333;"><span style="color:#E53333;"><br />
</span></span>
</p>
<p>
	<span style="color:#337FE5;">4. 配置state</span>
</p>
<p>
	<span><span>1). 定义入口sls</span></span>
</p>
<p>
	# vi /srv/salt/top.sls
</p>
<pre class="prettyprint lang-bsh">base:
 '*':
   - env
   - nginx.deploy</pre>
<p>
	
</p>
<p>
	2). 定义env, nginx服务状态管理配置sls
</p>
<p>
	通用系统环境配置
</p>
<p>
	# vi /srv/salt/env.sls
</p>
<pre class="prettyprint lang-bsh">policycoreutils:
    pkg.installed
 
policycoreutils-python:
    pkg.installed

{% if grains['selinux']['enabled'] %}
setselinux:
  selinux.mode:
    - name: 'permissive'
    - require:
      - pkg: policycoreutils
      - pkg: policycoreutils-python

/etc/sysconfig/selinux:
  file.replace:
    - pattern: 'SELINUX=\w+'
    - repl: 'SELINUX=disabled'
{% endif %}

iptables:
  pkg:
    - installed
  iptables.flush:
    - table: 'filter'
    - save: True
  cmd.run:
    - name: 'service iptables save'
    - require:
      - pkg: iptables</pre>
<p>
	<span style="color:#E53333;">Tip: 使用setenforce需要安装2个python依赖包, 通过判断系统默认的SELINUX是否打开, 从而确定是否关闭SELINUX, 如果不作此判断, 系统SELINUX若关闭, 部署时会报错.</span>
</p>
<p>
	<span style="color:#E53333;"><br />
</span>
</p>
<p>
	NGINX配置
</p>
<p>
	# mkdir /srv/salt/nginx
</p>
<p>
	# vi /srv/salt/nginx/deploy.sls
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh">{% if 'nginx' in pillar %}
  {% set item = pillar['nginx'] %}
  {{ item['name'] }}:
    pkg: 
     - {{ item['status'] }}
    file.managed:  
     - source: {{ item['source'] }}  
     - name: {{ item['file'] }}  
     - user: {{ item['user'] }}  
     - group: {{ item['group'] }}  
     - mode: {{ item['mode'] }}  
     - template: {{ item['template'] }}  
  
    service.running:  
     - enable: True  
     - reload: True  
     - watch:  
       - file: {{ item['file'] }}  
       - pkg: {{ item['name'] }}

  {{ item['root'] }}:
    file.directory:
      - user: {{ item['name'] }}
      - group: {{ item['name'] }}
      - mode: 755
      - makedirs: True
      - recurse:
        - user
        - group
        - mode

{% endif %}</pre>
<p>
	
</p>
<p>
	<span><span><span style="color:#E53333;">Tip: "source: {{ item['source'] }}"等价于"source: {{ pillar['nginx']['source'] }}"</span><span style="color:#E53333;">为配置模板文件位置</span><span style="color:#E53333;">&nbsp;</span></span></span>
</p>
<p>
	<span style="color:#E53333;"><span style="color:#E53333;">&nbsp; &nbsp; &nbsp; "-enable: True" 等价于 "chkconfig nginx on"</span></span>
</p>
<p>
	<span style="color:#E53333;">&nbsp; &nbsp; &nbsp; "-reload True" 等价于 "service nginx reload</span><span style="color:#E53333;">", 若不加则默认执行"service nginx restart"</span>
</p>
<p>
	<span style="color:#E53333;">&nbsp; &nbsp; &nbsp; "-wotch -file:" 检查 /etc/nginx/nginx.conf是否发生变化</span><span style="color:#E53333;">&nbsp;</span>
</p>
<p>
	<span style="color:#E53333;">&nbsp; &nbsp; &nbsp; "-watch -pkg" 确保nginx安装成功.</span>
</p>
<p>
	&nbsp; &nbsp; &nbsp; <span style="color:#E53333;">"</span><span style="color:#E53333;">{{ item['root'] }}:&nbsp;</span><span style="color:#E53333;">file.directory:</span><span style="color:#E53333;">" 等价于mkdir /www</span>
</p>
<p>
	<span style="color:#E53333;"><br />
</span>
</p>
<p>
	3). 定义Nginx配置文件（引用jinja模板）
</p>
<p>
	# vi /srv/salt/nginx/nginx.conf
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh"># For more information on configuration, see: 
{% set item = pillar['nginx'] %}

user              nginx;  
worker_processes  {{ grains['num_cpus'] }};  
{% if grains['num_cpus'] == 2 %}  
worker_cpu_affinity 01 10;  
{% elif grains['num_cpus'] == 4 %}  
worker_cpu_affinity 1000 0100 0010 0001;  
{% elif grains['num_cpus'] &gt;= 8 %}  
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;  
{% else %}  
worker_cpu_affinity 1000 0100 0010 0001;  
{% endif %}  
worker_rlimit_nofile {{ grains['max_open_file'] }};  
  
error_log  /var/log/nginx/error.log;  
#error_log  /var/log/nginx/error.log  notice;  
#error_log  /var/log/nginx/error.log  info;  
  
pid        /var/run/nginx.pid;  
  
events {  
    worker_connections  {{ grains['max_open_file'] }};  
}  
  
  
http {  
    include       /etc/nginx/mime.types;  
    default_type  application/octet-stream;  
  
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
                      '$status $body_bytes_sent "$http_referer" '  
                      '"$http_user_agent" "$http_x_forwarded_for"';  
  
    access_log  /var/log/nginx/access.log  main;  
  
    sendfile        on;  
    #tcp_nopush     on;  
  
    #keepalive_timeout  0;  
    keepalive_timeout  65;  
  
    #gzip  on;  
      
    # Load config files from the /etc/nginx/conf.d directory  
    # The default server is in conf.d/default.conf  
    #include /etc/nginx/conf.d/*.conf;  
    server {  
        listen       80 default_server;  
        server_name  _;  
  
        #charset koi8-r;  
  
        #access_log  logs/host.access.log  main;  
  
        location / {  
            root   {{ item['root'] }};  
            index  index.html index.htm;  
        }  
  
        error_page  404              /404.html;  
        location = /404.html {  
            root   /usr/share/nginx/html;  
        }  
  
        # redirect server error pages to the static page /50x.html  
        #  
        error_page   500 502 503 504  /50x.html;  
        location = /50x.html {  
            root   /usr/share/nginx/html;  
        }  
  
    }  
  
} </pre>
<p>
	
</p>
<p>
	<span style="color:#E53333;">Tip:</span>
</p>
<ul>
<li>
		<span style="line-height:1.5;color:#E53333;"></span><span style="line-height:1.5;color:#E53333;">worker_processes参数采用grains['num_cpus'] 上报值（与设备CPU核数一致）；</span>
	</li>
<li>
		<span style="line-height:1.5;color:#E53333;">worker_cpu_affinity分配多核CPU根据当前设备核数进行匹配，分别为2\4\8\其它核；</span>
	</li>
<li>
		<span style="line-height:1.5;color:#E53333;">worker_rlimit_nofile参数与grains['max_open_file'] 获取的系统ulimit -n一致；</span>
	</li>
<li>
		<span style="line-height:1.5;color:#E53333;">worker_connections 参数理论上为grains['max_open_file']；</span>
	</li>
<li>
		<span style="line-height:1.5;color:#E53333;">root参数为定制的pillar['nginx']['root']值。</span>
	</li>
</ul>
<p>
4). 执行最终state配置, 将master的所有nginx配置部署到客户端</p>
<p>
	# salt '*' state.highstate
</p>
<p>
	<span style="color:#E53333;">Tip: 可使用</span><span style="color:#E53333;">salt '*' -l debug state.highstate 查看部署过程中是否有错误</span>
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh">salt-client02.example.com:
----------
          ID: policycoreutils
    Function: pkg.installed
      Result: True
     Comment: Package policycoreutils is already installed.
     Started: 14:35:20.183439
    Duration: 1165.132 ms
     Changes:   
----------
          ID: policycoreutils-python
    Function: pkg.installed
      Result: True
     Comment: Package policycoreutils-python is already installed.
     Started: 14:35:21.348902
    Duration: 0.875 ms
     Changes:   
----------
          ID: iptables
    Function: pkg.installed
      Result: True
     Comment: Package iptables is already installed.
     Started: 14:35:21.349904
    Duration: 0.47 ms
     Changes:   
----------
          ID: iptables
    Function: iptables.flush
      Result: True
     Comment: Flush iptables rules in filter table  chain ipv4 family
     Started: 14:35:21.351883
    Duration: 16.006 ms
     Changes:   
              ----------
              locale:
                  iptables
----------
          ID: iptables
    Function: cmd.run
        Name: service iptables save
      Result: True
     Comment: Command "service iptables save" run
     Started: 14:35:21.371349
    Duration: 50.934 ms
     Changes:   
              ----------
              pid:
                  3352
              retcode:
                  0
              stderr:
              stdout:
                  iptables: Saving firewall rules to /etc/sysconfig/iptables: ?[60G[?[0;32m  OK  ?[0;39m]
----------
          ID: nginx
    Function: pkg.installed
      Result: True
     Comment: The following packages were installed/updated: nginx
     Started: 14:35:21.422715
    Duration: 19128.275 ms
     Changes:   
              ----------
              nginx:
                  ----------
                  new:
                      1.0.15-12.el6
                  old:
----------
          ID: nginx
    Function: file.managed
        Name: /etc/nginx/nginx.conf
      Result: True
     Comment: File /etc/nginx/nginx.conf updated
     Started: 14:35:40.560042
    Duration: 40.855 ms
     Changes:   
              ----------
              diff:
                  ---  
                  +++  
                  @@ -1,42 +1,70 @@
                  -# For more information on configuration, see:
                  -#   * Official English Documentation: <a href="http://nginx.org/en/docs/" rel="nofollow">http://nginx.org/en/docs/</a>
                  -#   * Official Russian Documentation: <a href="http://nginx.org/ru/docs/" rel="nofollow">http://nginx.org/ru/docs/</a>
                  -
                  -user              nginx;
                  -worker_processes  1;
                  -
                  -error_log  /var/log/nginx/error.log;
                  -#error_log  /var/log/nginx/error.log  notice;
                  -#error_log  /var/log/nginx/error.log  info;
                  -
                  -pid        /var/run/nginx.pid;
                  +# For more information on configuration, see: 
                   
                   
                  -events {
                  -    worker_connections  1024;
                  -}
                  -
                  -
                  -http {
                  -    include       /etc/nginx/mime.types;
                  -    default_type  application/octet-stream;
                  -
                  -    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  -                      '$status $body_bytes_sent "$http_referer" '
                  -                      '"$http_user_agent" "$http_x_forwarded_for"';
                  -
                  -    access_log  /var/log/nginx/access.log  main;
                  -
                  -    sendfile        on;
                  -    #tcp_nopush     on;
                  -
                  -    #keepalive_timeout  0;
                  -    keepalive_timeout  65;
                  -
                  -    #gzip  on;
                  -    
                  -    # Load config files from the /etc/nginx/conf.d directory
                  -    # The default server is in conf.d/default.conf
                  -    include /etc/nginx/conf.d/*.conf;
                  -
                  -}
                  +user              nginx;  
                  +worker_processes  1;  
                  +  
                  +worker_cpu_affinity 1000 0100 0010 0001;  
                  +  
                  +worker_rlimit_nofile 1024;  
                  +  
                  +error_log  /var/log/nginx/error.log;  
                  +#error_log  /var/log/nginx/error.log  notice;  
                  +#error_log  /var/log/nginx/error.log  info;  
                  +  
                  +pid        /var/run/nginx.pid;  
                  +  
                  +events {  
                  +    worker_connections  1024;  
                  +}  
                  +  
                  +  
                  +http {  
                  +    include       /etc/nginx/mime.types;  
                  +    default_type  application/octet-stream;  
                  +  
                  +    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
                  +                      '$status $body_bytes_sent "$http_referer" '  
                  +                      '"$http_user_agent" "$http_x_forwarded_for"';  
                  +  
                  +    access_log  /var/log/nginx/access.log  main;  
                  +  
                  +    sendfile        on;  
                  +    #tcp_nopush     on;  
                  +  
                  +    #keepalive_timeout  0;  
                  +    keepalive_timeout  65;  
                  +  
                  +    #gzip  on;  
                  +      
                  +    # Load config files from the /etc/nginx/conf.d directory  
                  +    # The default server is in conf.d/default.conf  
                  +    #include /etc/nginx/conf.d/*.conf;  
                  +    server {  
                  +        listen       80 default_server;  
                  +        server_name  _;  
                  +  
                  +        #charset koi8-r;  
                  +  
                  +        #access_log  logs/host.access.log  main;  
                  +  
                  +        location / {  
                  +            root   /data;  
                  +            index  index.html index.htm;  
                  +        }  
                  +  
                  +        error_page  404              /404.html;  
                  +        location = /404.html {  
                  +            root   /usr/share/nginx/html;  
                  +        }  
                  +  
                  +        # redirect server error pages to the static page /50x.html  
                  +        #  
                  +        error_page   500 502 503 504  /50x.html;  
                  +        location = /50x.html {  
                  +            root   /usr/share/nginx/html;  
                  +        }  
                  +  
                  +    }  
                  +  
                  +} 
              mode:
                  0666
----------
          ID: nginx
    Function: service.running
      Result: True
     Comment: Service nginx has been enabled, and is running
     Started: 14:35:40.608381
    Duration: 320.864 ms
     Changes:   
              ----------
              nginx:
                  True
----------
          ID: /data
    Function: file.directory
      Result: True
     Comment: Directory /data is in the correct state
     Started: 14:35:40.929607
    Duration: 2.265 ms
     Changes:   

Summary
------------
Succeeded: 9 (changed=5)
Failed:    0
------------
Total states run:     9
salt-client01.example.com:
----------
          ID: policycoreutils
    Function: pkg.installed
      Result: True
     Comment: Package policycoreutils is already installed.
     Started: 18:14:48.158376
    Duration: 1211.452 ms
     Changes:   
----------
          ID: policycoreutils-python
    Function: pkg.installed
      Result: True
     Comment: Package policycoreutils-python is already installed.
     Started: 18:14:49.370171
    Duration: 0.787 ms
     Changes:   
----------
          ID: setselinux
    Function: selinux.mode
        Name: permissive
      Result: True
     Comment: SELinux is already in Permissive mode
     Started: 18:14:49.372833
    Duration: 0.652 ms
     Changes:   
----------
          ID: /etc/sysconfig/selinux
    Function: file.replace
      Result: True
     Comment: No changes needed to be made
     Started: 18:14:49.377284
    Duration: 2.507 ms
     Changes:   
----------
          ID: iptables
    Function: pkg.installed
      Result: True
     Comment: Package iptables is already installed.
     Started: 18:14:49.379941
    Duration: 0.597 ms
     Changes:   
----------
          ID: iptables
    Function: iptables.flush
      Result: True
     Comment: Flush iptables rules in filter table  chain ipv4 family
     Started: 18:14:49.381900
    Duration: 21.393 ms
     Changes:   
              ----------
              locale:
                  iptables
----------
          ID: iptables
    Function: cmd.run
        Name: service iptables save
      Result: True
     Comment: Command "service iptables save" run
     Started: 18:14:49.406906
    Duration: 342.078 ms
     Changes:   
              ----------
              pid:
                  3124
              retcode:
                  0
              stderr:
              stdout:
                  iptables: Saving firewall rules to /etc/sysconfig/iptables: ?[60G[?[0;32m  OK  ?[0;39m]
----------
          ID: nginx
    Function: pkg.installed
      Result: True
     Comment: The following packages were installed/updated: nginx
     Started: 18:14:49.749415
    Duration: 23737.719 ms
     Changes:   
              ----------
              nginx:
                  ----------
                  new:
                      1.0.15-12.el6
                  old:
----------
          ID: nginx
    Function: file.managed
        Name: /etc/nginx/nginx.conf
      Result: True
     Comment: File /etc/nginx/nginx.conf updated
     Started: 18:15:13.490651
    Duration: 52.469 ms
     Changes:   
              ----------
              diff:
                  ---  
                  +++  
                  @@ -1,42 +1,70 @@
                  -# For more information on configuration, see:
                  -#   * Official English Documentation: <a href="http://nginx.org/en/docs/" rel="nofollow">http://nginx.org/en/docs/</a>
                  -#   * Official Russian Documentation: <a href="http://nginx.org/ru/docs/" rel="nofollow">http://nginx.org/ru/docs/</a>
                  -
                  -user              nginx;
                  -worker_processes  1;
                  -
                  -error_log  /var/log/nginx/error.log;
                  -#error_log  /var/log/nginx/error.log  notice;
                  -#error_log  /var/log/nginx/error.log  info;
                  -
                  -pid        /var/run/nginx.pid;
                  +# For more information on configuration, see: 
                   
                   
                  -events {
                  -    worker_connections  1024;
                  -}
                  -
                  -
                  -http {
                  -    include       /etc/nginx/mime.types;
                  -    default_type  application/octet-stream;
                  -
                  -    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                  -                      '$status $body_bytes_sent "$http_referer" '
                  -                      '"$http_user_agent" "$http_x_forwarded_for"';
                  -
                  -    access_log  /var/log/nginx/access.log  main;
                  -
                  -    sendfile        on;
                  -    #tcp_nopush     on;
                  -
                  -    #keepalive_timeout  0;
                  -    keepalive_timeout  65;
                  -
                  -    #gzip  on;
                  -    
                  -    # Load config files from the /etc/nginx/conf.d directory
                  -    # The default server is in conf.d/default.conf
                  -    include /etc/nginx/conf.d/*.conf;
                  -
                  -}
                  +user              nginx;  
                  +worker_processes  1;  
                  +  
                  +worker_cpu_affinity 1000 0100 0010 0001;  
                  +  
                  +worker_rlimit_nofile 1024;  
                  +  
                  +error_log  /var/log/nginx/error.log;  
                  +#error_log  /var/log/nginx/error.log  notice;  
                  +#error_log  /var/log/nginx/error.log  info;  
                  +  
                  +pid        /var/run/nginx.pid;  
                  +  
                  +events {  
                  +    worker_connections  1024;  
                  +}  
                  +  
                  +  
                  +http {  
                  +    include       /etc/nginx/mime.types;  
                  +    default_type  application/octet-stream;  
                  +  
                  +    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  
                  +                      '$status $body_bytes_sent "$http_referer" '  
                  +                      '"$http_user_agent" "$http_x_forwarded_for"';  
                  +  
                  +    access_log  /var/log/nginx/access.log  main;  
                  +  
                  +    sendfile        on;  
                  +    #tcp_nopush     on;  
                  +  
                  +    #keepalive_timeout  0;  
                  +    keepalive_timeout  65;  
                  +  
                  +    #gzip  on;  
                  +      
                  +    # Load config files from the /etc/nginx/conf.d directory  
                  +    # The default server is in conf.d/default.conf  
                  +    #include /etc/nginx/conf.d/*.conf;  
                  +    server {  
                  +        listen       80 default_server;  
                  +        server_name  _;  
                  +  
                  +        #charset koi8-r;  
                  +  
                  +        #access_log  logs/host.access.log  main;  
                  +  
                  +        location / {  
                  +            root   /www;  
                  +            index  index.html index.htm;  
                  +        }  
                  +  
                  +        error_page  404              /404.html;  
                  +        location = /404.html {  
                  +            root   /usr/share/nginx/html;  
                  +        }  
                  +  
                  +        # redirect server error pages to the static page /50x.html  
                  +        #  
                  +        error_page   500 502 503 504  /50x.html;  
                  +        location = /50x.html {  
                  +            root   /usr/share/nginx/html;  
                  +        }  
                  +  
                  +    }  
                  +  
                  +} 
----------
          ID: nginx
    Function: service.running
      Result: True
     Comment: Service nginx has been enabled, and is running
     Started: 18:15:13.550329
    Duration: 424.431 ms
     Changes:   
              ----------
              nginx:
                  True
----------
          ID: /www
    Function: file.directory
      Result: True
     Comment: Directory /www is in the correct state
     Started: 18:15:13.975177
    Duration: 2.586 ms
     Changes:   

Summary
-------------
Succeeded: 11 (changed=5)
Failed:     0
-------------
Total states run:     11</pre>
<p>
	
</p>
<p>
	<span style="color:#E53333;">Tip: 笔者为了验证效果, 事先手动关闭了client02的SELINUX配置, 这里可以看到client02跳过SELINUX配置项, client01则正常执行.</span>
</p>
<p>
	
</p>
<p>
	这样我们就可以从返回信息查看Nginx的配置文件参数是否正确调用, 以及最终是否部署成功.
</p>
<p>
	
</p>
<p>
	最终/srv目录下的树状结构
</p>
<p>
	# cd /srv &amp;&amp; tree .
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh">.
|-- pillar
|   |-- nginx
|   |   |-- webserver1.sls
|   |   `-- webserver2.sls
|   `-- top.sls
`-- salt
    |-- env.sls
    |-- _grains
    |   `-- nginx_config.py
    |-- nginx
    |   |-- deploy.sls
    |   `-- nginx.conf
    |-- nginx.sls.bak
    `-- top.sls

5 directories, 9 files</pre>
<p>
	
</p>
<p>
	
</p>
<p>
	至此, 一个模拟生产环境的WEB服务配置集中管理部署平台已经搭建并测试完成, 大家可以拓展思路, 利用该平台扩展到其他应用业务当中.
</p>
<p>
	</p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/1538">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="[Saltstack] CentOS下批量部署Nginx" href="http://www.showerlee.com/archives/1538">http://www.showerlee.com/archives/1538</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/1538/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CentOS6.3下Saltstack安装部署</title>
		<link>http://www.showerlee.com/archives/1472</link>
		<comments>http://www.showerlee.com/archives/1472#comments</comments>
		<pubDate>Thu, 24 Sep 2015 05:30:13 +0000</pubDate>
		<dc:creator>showerlee</dc:creator>
				<category><![CDATA[DevTools]]></category>
		<category><![CDATA[Saltstack]]></category>

		<guid isPermaLink="false">http://www.showerlee.com/?p=1472</guid>
		<description><![CDATA[&#160;&#160; &#160;Saltstack是一个具备puppet与func功能为一身的集中化管理 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	<a href="http://www.showerlee.com/wp-content/uploads/2015/09/SaltStack-logo-black-on-white-copy1.jpg"><img onerror="javascript:this.src='http://www.showerlee.com/wp-content/themes/BYMT/images/images_error.jpg'" src="http://www.showerlee.com/wp-content/uploads/2015/09/SaltStack-logo-black-on-white-copy1.jpg" alt="SaltStack logo - black on white copy" width="320" height="201" class="alignnone size-large wp-image-1525" /></a>
</p>
<p>
	&nbsp;&nbsp; &nbsp;<a href="http://www.showerlee.com/archives/tag/saltstack" title="查看Saltstack中的全部文章" class="tag_link">Saltstack</a>是一个具备puppet与func功能为一身的集中化管理平台，它基于python实现，功能十分强大，各模块融合度及复用性极高，官方极力推荐作为云计算平台的基础架构。可以轻松维护成千上万台服务器. 相对于同类型的其他平台, 例如Ruby下的Chef, 以及大家比较熟知的puppet, Salt的优势在于他的配置更加简单, 运行效率更高, 自带的模块更加丰富, 以及API是全python语法对于我们搞运维的同学来说相对比较易读, 所以笔者认为是一个大家值得去学习的自动化部署平台.
</p>
<p>
	
</p>
<p>
	本文将帮助大家如何快速部署一个Salt平台.
</p>
<p>
	
</p>
<p>
	大家如果想了解更多地相关知识, 可以去访问salt的官方文档 (<span>中文版需VPN</span>)
</p>
<p><a href="https://docs.saltstack.com/en/latest/topics/index.html" rel="nofollow">https://docs.saltstack.com/en/latest/topics/index.html</a></p>
<p><a href="http://docs.saltstack.cn/zh_CN/latest/" rel="nofollow">http://docs.saltstack.cn/zh_CN/latest/</a></p>
<p>
	<br />
安装环境:
</p>
<p>
	<strong>System:</strong> Centos 6.3
</p>
<p>
	<strong>Salt master:</strong> salt-master.example.com&nbsp;
</p>
<p>
	<strong>Salt minion:</strong> salt-client01.example.com
</p>
<p>
	
</p>
<p>
	
</p>
<p>
	<br />
<strong><span style="font-size:14px;color:#337FE5;">一. 环境部署及安装</span></strong>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">1. 关闭iptables和SELINUX</span>
</p>
<p>
	# service iptables stop
</p>
<p>
	# setenforce 0
</p>
<p>
	# vi /etc/sysconfig/selinux
</p>
<pre class="prettyprint lang-bsh">...
SELINUX=disabled
...</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">2. 安装第三方yum源</span>
</p>
<p>
	# rpm -Uvh <a href="http://ftp.linux.ncsu.edu/pub/epel/6/i386/epel-release-6-8.noarch.rpm" rel="nofollow">http://ftp.linux.ncsu.edu/pub/epel/6/i386/epel-release-6-8.noarch.rpm</a>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">3.&nbsp;</span><span style="line-height:1.5;color:#337FE5;">更新系统证书模块和python到最新版本</span>
</p>
<p>
	<span style="line-height:1.5;"># yum upgrade ca-certificates --disablerepo=epel -y</span>
</p>
<p>
	<span style="line-height:1.5;"># yum update python -y</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">4. 在服务器端(</span><span style="color:#337FE5;">Salt master</span><span style="color:#337FE5;">)安装Salt-master</span>
</p>
<p>
	# yum install salt-master -y<br />
<span style="line-height:1.5;">&nbsp;&nbsp;</span>
</p>
<p>
	<span style="color:#337FE5;">5. 在客户端</span><span style="color:#337FE5;">(</span><span style="color:#337FE5;">Salt minion</span><span style="color:#337FE5;">)</span><span style="color:#337FE5;">安装Salt-minion</span>
</p>
<p>
	# yum install salt-minion -y
</p>
<p>
	
</p>
<p>
	
</p>
<p>
	<span style="font-size:14px;color:#337FE5;"><strong>二. 初始配置</strong></span>
</p>
<p>
	
</p>
<p>
	<span style="color:#E53333;">[Salt minion side]</span>
</p>
<p>
	<span style="color:#337FE5;">1.&nbsp;</span><span style="line-height:1.5;color:#337FE5;">在客户端添加服务端地址从而提交申请</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /etc/salt/minion</span>
</p>
<pre class="prettyprint lang-bsh">... 
# Set the location of the salt master server, if the master server cannot be 
# resolved, then the minion will fail to start. 
master: salt-master.example.com
... </pre>
<p>
	<span style="line-height:1.5;"># /etc/init.d/salt-minion restart</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#E53333;">[Salt master side]</span>
</p>
<p>
	<span style="color:#337FE5;">2. 检查客户端申请</span>
</p>
<p>
	# salt-key list
</p>
<pre class="prettyprint lang-js">Accepted Keys:
Denied Keys:
Unaccepted Keys:
salt-client01.example.com
Rejected Keys:</pre>
<p>
	<span style="color:#337FE5;">3. 获准申请</span>
</p>
<p>
	# salt-key -a salt-client01.example.com
</p>
<pre class="prettyprint lang-bsh">The following keys are going to be accepted:
Unaccepted Keys:
salt-client01.example.com
Proceed? [n/Y] y
Key for minion salt-client01.example.com accepted.</pre>
<p>
	这里服务端与客户端的连接配置基本完成.
</p>
<p>
	
</p>
<p>
	
</p>
<p>
	<strong><span style="font-size:14px;color:#337FE5;">三. 模块介绍</span></strong>
</p>
<p>
	<span style="line-height:1.5;">这里我们可以通过此命令列出Salt常用的模块, 接下来我将介绍一些常用模块的使用方法</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' sys.list_modules</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    - acl
    - aliases
    - alternatives
    - archive
    - artifactory
    - at
    - blockdev
    - bridge
    - btrfs
    - buildout
    - cloud
    - cmd

    …</pre>
<p>
	<span style="color:#337FE5;">1. cmd module</span>
</p>
<p>
	<span style="color:#000000;">1). 执行远程客户端CLI</span>
</p>
<p>
	# salt '*' cmd.run 'hostname'
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
  salt-client01.example.com</pre>
<p>
	2).&nbsp;<span style="line-height:1.5;">将脚本推送到客户端</span><span style="line-height:1.5;">(目录位置: /var/cache/salt/minion/files/base/test.sh)&nbsp;</span><span style="line-height:1.5;">并远程去执行该脚本</span>
</p>
<p>
	<span style="line-height:1.5;"># cd /src/salt</span>
</p>
<p>
	<span style="line-height:1.5;"># echo 'hostname' &gt; test.sh</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' cmd.script salt://test.sh</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    pid:
        3028
    retcode:
        0
    stderr:
    stdout:
        salt-client01.example.com</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">2. cp module</span>
</p>
<p>
	1). GET_FILE方法
</p>
<p>
	<span style="line-height:1.5;color:#E53333;">Tip: Salt默认的文件根文件目录为</span><span style="line-height:1.5;color:#E53333;">/src/salt</span><span style="line-height:1.5;color:#E53333;">, 所以我们可以将我们需要推送的文件放到此目录, 从而可以使用salt自带的协议去传送.</span>
</p>
<p>
	<span style="line-height:1.5;">这里cp.get_file方法</span><span style="line-height:1.5;">是将具体master端的文件推送到客户端具体目录</span>
</p>
<p>
	<span style="line-height:1.5;">[Salt master side]</span>
</p>
<p>
	<span style="line-height:1.5;"># mkdir -p /srv/salt &amp;&amp; cd /srv/salt</span>
</p>
<p>
	<span style="line-height:1.5;"># echo "test" &gt; test.txt</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' cp.get_file salt://test.txt /root/test.txt makedirs=True</span>
</p>
<p>
	<span style="line-height:1.5;"> </span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    /root/test.txt</pre>
<p>
	若传送的文件很大, 而服务器的硬件资源又很充裕, 我们可以通过他的压缩=&gt;传输=&gt;解压的方法提高我们的文件传输速率(这里1到9表示压缩文件的比率)
</p>
<p>
	# salt '*' cp.get_file salt://test.txt /root/test.txt gzip=5
</p>
<p>
	
</p>
<p>
	2). GET_DIR方法
</p>
<p>
	这里cp.get_dir <span>方法</span><span style="line-height:1.5;">是将具体master端的目录及子目录文件推送到客户端</span>
</p>
<p>
	# mkdir -p /srv/salt/test_folder &amp;&amp; cd /srv/salt/test_folder
</p>
<p>
	# touch test_file0{1,2,3}
</p>
<p>
	# salt '*' cp.get_dir salt://test_folder /root
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    - /root/test_folder/test_file01
    - /root/test_folder/test_file02
    - /root/test_folder/test_file03</pre>
<p>
	压缩传送
</p>
<p>
	# salt '*' cp.get_dir salt://test_folder /root gzip=5 template=jinja
</p>
<p>
	<span><br />
</span>
</p>
<p>
	<span>3). GET_URL方法</span>
</p>
<p>
	下载具体的URL文件到客户端
</p>
<p>
	# salt '*' cp.get_url <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a> ~/index.html
</p>
<pre class="prettyprint lang-js">salt-client01.example.com:
    /root/index.html</pre>
<p>
	<span style="color:#337FE5;">3. cron module</span>
</p>
<p>
	1). 查看客户端计划任务列表
</p>
<p>
	# salt '*' cron.raw_cron root
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    * * * * 0 /bin/sh ~/test.sh</pre>
<p>
	
</p>
<p>
	2). 添加一个计划任务
</p>
<p>
	# salt '*' cron.set_job root '*' '*' '*' '*' 1 /usr/local/weekly
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
   new</pre>
<p>
	# salt '*' cron.raw_cron root
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    * * * * 0 /bin/sh ~/test.sh
    # Lines below here are managed by Salt, do not edit
    * * * * 1 /usr/local/weekly</pre>
<p>
	3). 删除一个计划任务
</p>
<p>
	# salt '*' cron.rm_job root &nbsp;/usr/local/weekly
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    removed</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">4. dnsutil module</span>
</p>
<p>
	1). 添加一个HOST记录
</p>
<p>
	# salt '*' dnsutil.hosts_append /etc/hosts 127.0.0.1 salt-client01
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    The following line was added to /etc/hosts:
    127.0.0.1 salt-client01</pre>
<p>
	<span><br />
</span>
</p>
<p>
	<span>2). 删除一个HOST记录</span>
</p>
<p>
	# salt '*' dnsutil.hosts_remove /etc/hosts salt-client01
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    None</pre>
<p></p>
<p>
	<span style="color:#337FE5;">5. file module</span>
</p>
<p>
	1). <span style="line-height:1.5;">获取客户端文件md5值</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.get_sum /etc/passwd md5</span>
</p>
<p>
	<span style="line-height:1.5;"> </span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    17d14d55b712bd36a735b66dd708c177</pre>
<p>
	<span style="line-height:1.5;"></span>
</p>
<p>
	
</p>
<p>
	2). 检查该文件是否匹配给定的md5值, 匹配则返回Ture
</p>
<p>
	# salt '*' file.check_hash /etc/passwd md5:17d14d55b712bd36a735b66dd708c177
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    True</pre>
<p>
	<span style="line-height:1.5;"></span>
</p>
<p>
	
</p>
<p>
	3). 更新客户端文件属主及属组&nbsp;
</p>
<p>
	# salt '*' file.chown ~/test.txt nobody nobody
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
   None</pre>
<p>
	
</p>
<p>
	4). 调用客户端cp命令
</p>
<p>
	# salt '*' file.copy ~/test.txt ~/test1.txt
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
   True</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">5). 查看客户端文件是否存在</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.directory_exists /etc</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    True</pre>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;">6). 获取客户端文件的详细属性</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.stats /etc/passwd</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    atime:
        1442470687.07
    ctime:
        1396603826.1
    gid:
        0
    group:
        root
    inode:
        277879
    mode:
        0644
    mtime:
        1396603826.1
    size:
        1560
    target:
        /etc/passwd
    type:
        file
    uid:
        0
    user:
        root</pre>
<p>
	
</p>
<p>
	7). 获取客户端文件权限
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.get_mode /etc/passwd</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    0644</pre>
<p>
	
</p>
<p>
	8). 更改客户端文件权限
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.set_mode ~/test.txt 0777</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    0777</pre>
<p>
	
</p>
<p>
	9). 创建客户端目录
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.mkdir ~/test_dir</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    None</pre>
<p>
	
</p>
<p>
	10). 替换客户端文件内容字符串.
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.sed /etc/httpd/conf/httpd.conf 'LogLevel warn' 'LogLevel info'</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    pid:
        3666
    retcode:
        0
    stderr:
    stdout:</pre>
<p>
	
</p>
<p>
	11). 添加客户端文件字符串
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.append ~/test.conf "maxclient 100"</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    Wrote 1 lines to "/root/test.conf"</pre>
<p>
	
</p>
<p>
	12). 删除客户端文件
</p>
<p>
	<span style="line-height:1.5;"># salt '*' file.remove ~/test1.txt</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    True</pre>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">6. network module</span>
</p>
<p>
	<span style="line-height:1.5;">1). 调用dig, ping, traceroute命令并返回结果.</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' network.dig <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a></span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' network.ping <a href="http://www.showerlee.com&nbsp" rel="nofollow">http://www.showerlee.com&nbsp</a>;</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' network.traceroute <a href="http://www.showerlee.com" rel="nofollow">http://www.showerlee.com</a></span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">7. pkg package module</span>
</p>
<p>
	<span style="line-height:1.5;">这里本例使用的是CentOS系统, 则这里调用的是yum包管理安装, 若为Ubuntu Salt会调用apt-get.</span>
</p>
<p>
	<span style="line-height:1.5;">1). 安装PHP到客户端</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' pkg.install php</span>
</p>
<p>
	<span style="line-height:1.5;">2). 删除客户端PHP</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' pkg.remove php</span>
</p>
<p>
	<span style="line-height:1.5;">3). 更新客户端所有yum包</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' pkg.upgrade</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">8. service module</span>
</p>
<p>
	1). 开启或关闭httpd服务系统启动(可以理解调用chkconfig命令)
</p>
<p>
	# salt '*' service.enable httpd
</p>
<p>
	# salt '*' service.disable httpd
</p>
<p>
	2).&nbsp;<span style="line-height:1.5;">调用service命令</span><span style="line-height:1.5;">(reload, restart, start, stop, status)</span><span style="line-height:1.5;">执行相关服务操作</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' service.reload httpd</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' service.restart httpd</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' service.start httpd</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' service.stop httpd</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' service.status httpd</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">9. Grains module</span>
</p>
<p>
	<span style="color:#000000;">Grains翻译过来的意思其实就是谷粒, 引用到<a href="http://www.showerlee.com/archives/tag/saltstack" title="查看Saltstack中的全部文章" class="tag_link">Saltstack</a>其实通俗来讲就是它会将检测到的的系统硬件信息(系统名, 内核参数, 网卡配置等)存储到自己的RAM下, 方便Salt其他模块去调用.</span>
</p>
<p>
	<span style="color:#000000;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;">1). 返回匹配给定内核版本的主机</span>
</p>
<p>
	<span style="line-height:1.5;"># salt -G 'kernelrelease:2.6.32-279.el6.x86_64' cmd.run 'uname -a'</span>
</p>
<p>
	
</p>
<p>
	2). 获取所有客户端grain模块相关信息
</p>
<p>
	# salt '*' grains.ls
</p>
<p>
	
</p>
<p>
	3). 获取客户端系统名
</p>
<p>
	# salt '*' grains.item os
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    os:
        CentOS</pre>
<p>
	
</p>
<p>
	4). 获取客户端系统相关信息
</p>
<p>
	<span style="line-height:1.5;"># salt '*' grains.items</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    SSDs:
    biosreleasedate:
        12/01/2006
    biosversion:
        VirtualBox
    cpu_flags:
        - fpu
        - vme
        - de
        - pse
        - tsc
        - msr
        - pae
        - mce
        - cx8
        - apic
        - mtrr
        - pge
        - mca
        - cmov
        - pat
        - pse36
        - clflush
        - mmx
        - fxsr
        - sse
        - sse2
        - syscall
        - nx
        - rdtscp
        - lm
        - constant_tsc
        - up
        - rep_good
        - pni
        - monitor
        - ssse3
        - lahf_lm
    cpu_model:
        Intel(R) Core(TM) i7-4750HQ CPU @ 2.00GHz
    cpuarch:
        x86_64
    domain:
        example.com
    fqdn:
        salt-client01.example.com
    fqdn_ip4:
        - 10.110.16.251
    fqdn_ip6:
    gpus:
        |_
          ----------
          model:
              VirtualBox Graphics Adapter
          vendor:
              unknown
    host:
        salt-client01
    hwaddr_interfaces:
        ----------
        eth0:
            08:00:27:cd:54:79
        lo:
            00:00:00:00:00:00
    id:
        salt-client01.example.com
    init:
        upstart
    ip4_interfaces:
        ----------
        eth0:
            - 10.110.16.251
        lo:
            - 127.0.0.1
    ip6_interfaces:
        ----------
        eth0:
            - fe80::a00:27ff:fecd:5479
        lo:
            - ::1
    ip_interfaces:
        ----------
        eth0:
            - 10.110.16.251
            - fe80::a00:27ff:fecd:5479
        lo:
            - 127.0.0.1
            - ::1
    ipv4:
        - 10.110.16.251
        - 127.0.0.1
    ipv6:
        - ::1
        - fe80::a00:27ff:fecd:5479
    kernel:
        Linux
    kernelrelease:
        2.6.32-279.el6.x86_64
    locale_info:
        ----------
        defaultencoding:
            unknown
        defaultlanguage:
            unknown
        detectedencoding:
            ANSI_X3.4-1968
    localhost:
        salt-client01.example.com
    lsb_distrib_codename:
        Final
    lsb_distrib_id:
        CentOS
    lsb_distrib_release:
        6.3
    machine_id:
        1307a6546720f165db6c202900000006
    manufacturer:
        innotek GmbH
    master:
        salt-master.example.com
    mdadm:
    mem_total:
        996
    nodename:
        salt-client01.example.com
    num_cpus:
        1
    num_gpus:
        1
    os:
        CentOS
    os_family:
        RedHat
    osarch:
        x86_64
    oscodename:
        Final
    osfinger:
        CentOS-6
    osfullname:
        CentOS
    osmajorrelease:
        6
    osrelease:
        6.3
    osrelease_info:
        - 6
        - 3
    path:
        /sbin:/usr/sbin:/bin:/usr/bin
    productname:
        VirtualBox
    ps:
        ps -efH
    pythonexecutable:
        /usr/bin/python2.6
    pythonpath:
        - /usr/bin
        - /usr/lib64/python26.zip
        - /usr/lib64/python2.6
        - /usr/lib64/python2.6/plat-linux2
        - /usr/lib64/python2.6/lib-tk
        - /usr/lib64/python2.6/lib-old
        - /usr/lib64/python2.6/lib-dynload
        - /usr/lib64/python2.6/site-packages
        - /usr/lib64/python2.6/site-packages/gtk-2.0
        - /usr/lib/python2.6/site-packages
    pythonversion:
        - 2
        - 6
        - 6
        - final
        - 0
    saltpath:
        /usr/lib/python2.6/site-packages/salt
    saltversion:
        2015.5.5
    saltversioninfo:
        - 2015
        - 5
        - 5
        - 0
    selinux:
        ----------
        enabled:
            False
        enforced:
            Disabled
    serialnumber:
        0
    server_id:
        1640489673
    shell:
        /bin/bash
    virtual:
        VirtualBox
    zmqversion:
        3.2.5</pre>
<p>
	5). Python API
</p>
<p>
	我们也可以在minion端使用python api来查看系统默认或自定义的grains值, 这个方法方便我们在minions端去confirm该值.
</p>
<p>
	<span style="color:#E53333;">[Salt minion side]</span>
</p>
<p>
	# yum install ipython -y
</p>
<p>
	# ipython
</p>
<p>
	
</p>
<pre class="prettyprint lang-bsh">In [1]: import salt.config

In [2]: import salt.loader

In [3]: __opts__ = salt.config.minion_config('/etc/salt/minion')

In [4]: __grains__ = salt.loader.grains(__opts__)

In [5]: print __grains__['id']
salt-client01.example.com

In [6]: print __grains__['selinux']
{'enforced': 'Permissive', 'enabled': True}

In [7]: print __grains__['selinux']['enforced']
Permissive</pre>
<p>
	
</p>
<p>
	
</p>
<p>
	<span style="font-size:14px;color:#337FE5;"><strong>四. pillar介绍</strong></span>
</p>
<p>
	<span style="line-height:1.5;">Pillar是<a href="http://www.showerlee.com/archives/tag/saltstack" title="查看Saltstack中的全部文章" class="tag_link">Saltstack</a>最重要的组件之一, 其作用是定义与被控主机端相关的任何配置, 使其可以随时被模板, state, API等调用, 他的规范采用YAML形式, 简单来说可以理解为他是一个字典形式的参数列表, 大家随后写的部署脚本等都可以从这里调用数据, 而不需要在具体的脚本里将数据写死, 提高脚本的复用性.</span>
</p>
<p>
	
</p>
<p>
	<span style="color:#337FE5;">1. 获取当前pillar配置信息</span>
</p>
<p>
	# vi /etc/salt/master
</p>
<p>
	<span style="line-height:1.5;">替换pillar_opts 参数为True.</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' pillar.data</span>
</p>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;color:#337FE5;">2. SLS文件定义</span>
</p>
<p>
	<span style="line-height:1.5;">pillar定义的配置参数会保存在sls文件中, 格式需符合YAML规范, 我们常规会配置一个top.sls的入口文件, 用来定义pillar数据的覆盖被控主机的有效范围.</span>
</p>
<p>
	<span style="line-height:1.5;">a. 首先在master主配置文件中定义pillar主目录</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /etc/salt/master</span>
</p>
<p>
	<span style="line-height:1.5;">添加:</span>
</p>
<pre class="prettyprint lang-bsh">pillar_roots:
  base:
    - /srv/pillar</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">b. 定义入口文件top.sls</span>
</p>
<p>
	<span style="line-height:1.5;color:#E53333;">Tip: base代表master主配置文件pillar_roots下定义的对象 (官方推荐定义为具体部署的测试环境,例如dev, stage, prod)</span>
</p>
<p>
	<span style="line-height:1.5;color:#E53333;">&nbsp; &nbsp; &nbsp; &nbsp;"*" 代表任意主机&nbsp;</span>
</p>
<p>
	<span style="line-height:1.5;color:#E53333;">&nbsp; &nbsp; &nbsp; &nbsp;- apache代表该同级目录下的一个apache.sls文件</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /srv/sillar/top.sls</span>
</p>
<pre class="prettyprint lang-bsh">base:
 '*':
   - apache</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">c. 定义具体的apache参数文件</span>
</p>
<p>
	<span># vi /srv/sillar/apache.sls</span>
</p>
<pre class="prettyprint lang-bsh">appname: website
flow:
  maxconn: 30000
  maxmem: 6G</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">d. 校验以上定义好的pillar</span>
</p>
<p>
	<span style="line-height:1.5;">通过查看"</span><span style="line-height:1.5;">salt-client01.example.com</span><span style="line-height:1.5;">"主机的pillar数据,我们可以看到apache数据项, 原因是我们定义top.sls时使用了"*"涵盖了所有主机</span>
</p>
<p>
	<span style="line-height:1.5;">如果返回结果为空我们尝试刷新被控主机数据后查看最终配置结果.</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' saltutil.refresh_pillar</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' pillar.data appname flow</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    appname:
          website
    flow:
           ----------
           maxconn:
                   30000
           maxem:
                   6G</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">这里返回的是我们定义好的appname和flow参数对应的值.</span>
</p>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;">e.pillar的使用</span>
</p>
<p>
	<span style="line-height:1.5;">完成pilar配置后, 我们可以在state, 模板文件中引用配置好的参数字典</span>
</p>
<p>
	<span style="line-height:1.5;">例如:</span>
</p>
<p>
	<span style="line-height:1.5;">一维字典: {{ pillar['appname'] }}&nbsp;</span>
</p>
<p>
	<span style="line-height:1.5;">二维字典: {{ pillar['flow']['maxconn']&nbsp;}}</span>
</p>
<p>
	<span style="line-height:1.5;">我们也可以根据配置项过滤出匹配该参数的主机, 使用任意方法来让其返回相应的系统信息.</span>
</p>
<p>
	<span style="line-height:1.5;">这里通过 -I 参数过滤出该主机并查看该主机的连通状态.</span>
</p>
<p>
	<span style="line-height:1.5;"># salt -I 'appname:website' test.ping</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
       True</pre>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;font-size:14px;color:#337FE5;"><strong>五. state介绍</strong></span>
</p>
<p>
	<span style="line-height:1.5;">state是saltstack最核心的功能, 它通过预先定制好的sls(salt state file)文件, 类似于chef的cookbook对被控主机进行状态管理, 支持常见的pkg, file, network, service, user模块调用, 更多模块可以参考官方文档: <a href="http://docs.saltstack.com/ref/states/all/index.html" rel="nofollow">http://docs.saltstack.com/ref/states/all/index.html</a></span>
</p>
<p>
	<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;color:#337FE5;">1. state定义</span>
</p>
<p>
	<span style="line-height:1.5;">state的定义是通过sls文件进行描述的, 支持YAML语法, 定义规则如下</span>
</p>
<pre class="prettyprint lang-html">$ID:
     $State:
          - $state: state</pre>
<p>
	<span style="line-height:1.5;">$ID 表示具体操作的对象, $State表示具体操作的使用的模块, - $state state表示对具体具体模块方法的调用.</span>
</p>
<p>
	例如:
</p>
<pre class="prettyprint lang-bsh">apache: # state名称
    pkg:  # 使用pkg状态对象
      - installed # 执行installed方法
   service: # 使用service管理系统守护进程
       - running # 执行查看running方法查看是否服务正常安装,未安装则需安装并运行
       - require: # 确保apache只有在安装后, 才会启动.
       - pkg: apache </pre>
<p>
	上述代码检查apache软件包是否安装, 如未安装将通过yum或者api进行安装, 并最终检查apache服务是否处于运行状态.
</p>
<p>
	
</p>
<p>
	
</p>
<p>
	<strong><span style="font-size:14px;color:#337FE5;">六. pillar和state的集成配置实现将apache部署到客户端</span></strong><br />
<span style="line-height:1.5;"><br />
</span>
</p>
<p>
	<span style="line-height:1.5;color:#337FE5;">1. 配置pillar</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /srv/pillar/top.sls</span>
</p>
<pre class="prettyprint lang-bsh">base:
 '*':
   - apache</pre>
<p>
	
</p>
<p>
	b. 通过检查客户端系统, 判断具体的apache服务名
</p>
<p>
	<span style="line-height:1.5;"># mkdir -p /srv/pillar/apache</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /srv/pillar/apache/init.sls</span>
</p>
<pre class="prettyprint lang-bsh">pkgs:
{% if grains['os_family'] == 'Debian' %}
  apache: apache2
  {% elif grains['os_family'] == 'Redhat' %}
  apache: httpd
  {% elif grains['os'] == 'CentOS' %}
  apache: httpd
{% endif %}</pre>
<p>
	
</p>
<p>
	c. 测试pillar数据返回结果
</p>
<p>
	# salt '*' pillar.data pkgs
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
    ----------
    pkgs:
        ----------
        apache:
            httpd</pre>
<p>
	结果返回CentOS下apache服务名httpd, 说明配置已生效.
</p>
<p>
	
</p>
<p>
	d. 配置 state
</p>
<p>
	<span style="line-height:1.5;"># vi /srv/salt/top.sls</span>
</p>
<pre class="prettyprint lang-bsh">base:
 '*':
   - apache</pre>
<p>
	<span style="line-height:1.5;"># mkdir /srv/salt/apache</span>
</p>
<p>
	<span style="line-height:1.5;"># vi /srv/salt/apache/init.sls</span>
</p>
<p>
	<span style="line-height:1.5;">这里可以看到通过python字典来调用pillar已配置参数.</span>
</p>
<pre class="prettyprint lang-bsh">pkg:
  - installed
  - name: {{ pillar['pkgs']['apache']}}
service.running:
  - name: {{ pillar['pkgs']['apache']}}
  - require:
    - pkg: {{ pillar['pkgs']['apache']}}</pre>
<p>
	
</p>
<p>
	e. 执行state
</p>
<p>
	<span style="line-height:1.5;">这里将执行最终的配置, 从而将apache远程部署到客户端.</span>
</p>
<p>
	<span style="line-height:1.5;"># salt '*' state.highstate</span>
</p>
<pre class="prettyprint lang-bsh">salt-client01.example.com:
----------
          ID: apache
    Function: pkg.installed
        Name: httpd
      Result: True
     Comment: The following packages were installed/updated: httpd
     Started: 04:35:34.311058
    Duration: 58831.849 ms
     Changes:   
              ----------
              httpd:
                  ----------
                  new:
                      2.2.15-47.el6.centos
                  old:
----------
          ID: apache
    Function: service.running
        Name: httpd
      Result: True
     Comment: Started Service httpd
     Started: 04:36:33.148020
    Duration: 192.294 ms
     Changes:   
              ----------
              httpd:
                  True

Summary
------------
Succeeded: 2 (changed=2)
Failed:    0
------------
Total states run:     2</pre>
<p>
	
</p>
<p>
	<span style="line-height:1.5;">部署完毕...</span>
</p>
<p>
	
</p>
<p>
	更多详细部署推荐:&nbsp;<a href="http://www.showerlee.com/archives/1538" target="_blank">http://www.showerlee.com/archives/1538</a>
</p>
<p>
	</p>
<div>声明: 本文采用 <a rel="external" href="http://creativecommons.org/licenses/by-nc-sa/3.0/deed.zh" title="署名-非商业性使用-相同方式共享 3.0 Unported">CC BY-NC-SA 3.0</a> 协议进行授权</div><div>转载请注明来源：<a rel="external" title="DevOps技术分享" href="http://www.showerlee.com/archives/1472">DevOps技术分享</a></div><div>本文链接地址：<a rel="external" title="CentOS6.3下Saltstack安装部署" href="http://www.showerlee.com/archives/1472">http://www.showerlee.com/archives/1472</a></div>]]></content:encoded>
			<wfw:commentRss>http://www.showerlee.com/archives/1472/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
