Index ¦ Archives ¦ Categories ¦ Tags

SaltStack 学习笔记(1)

基本概念

  • Salt Master
  • Salt Minion
  • targeting
  • nodegroup
  • grains
  • pillar

配置管理


  • master配置文件: /etc/salt/master :

    example 注意file_root设定(default: /srv/salt/): ##### Master file_roots configuration: file_roots:

            base:
                - /srv/salt/base
            dev:
                - /srv/salt/dev
            qa:
                - /srv/salt/qa
            prod:
                - /srv/salt/prod
    
    • minion配置文件: /etc/salt/minion:

      example

  • 根目录(/srv/salt)

  • top.sls:

    • master通过配置中file_root的路径去找相应文件夹的top.sls来加载state
    • SaltStack通过top.sls加载所有state配置

      • 例如, 对应上文master的file_root配置, top.sls为:
        base:
            '*':
                - global
        dev:
            'webserver*dev*':
                - webserver
            'db*dev*':
                - db
        qa:
            'webserver*qa*':
                - webserver
            'db*qa*':
                - db
        prod:
            'webserver*prod*':
                - webserver
            'db*prod*':
                - db
        
    • top被编译执行的顺序:

      • /srv/salt/base/top.sls和/srv/salt/dev/top.sls中都有关于dev的配置,那么/srv/salt/dev/top.sls中的将被忽略.

      • /srv/salt/dev/top.sls和/srv/salt/qa/top.sls中都有关于qa的配置, 后者会被执行, 因为系统会匹配环境名和qa配置.

      • 如果以上匹配没找到,则按alphabetical order进行匹配.

  • 测试并得到错误输出

    # salt-call state.highstate -l debug
    
  • 最后(完成state创建或者修改), 将master加载的states发到各minion去执行:

    # salt '*' state.highstate -v
    

  • state配置

    • 基本配置:

      apache:                 # ID declaration
          pkg:                # state declaration
              - installed     # function declaration
      
    • 使用子目录: top.sls中webserver.dev用来表示子目录webserver/dev.sls

    • init.sls 在一个子目录里面表示引导文件,也就表示子目录本身, 所以"webserver/init.sls'' 就是表示''webserver''.

      • 例如,在上面apache配置中,为了区分不同系统所提供不同的apache版本:

      apache/init.sls

          apache:
              pkg.installed:
              {% if grains['os'] == 'RedHat'%}
                  - name: httpd
              {% endif %}
              service.running:
              {% if grains['os'] == 'RedHat'%}
                  - name: httpd
              {% endif %}
                  - watch:
                  - pkg: apache
                  - file: /etc/httpd/conf/httpd.conf
                  - user: apache
                  # add file
          /var/www/index.html:        # ID declaration
              file:                   # state declaration
                  - managed           # function
                  - source: salt://webserver/index.html  # function arg
                  - require:              # requisite declaration
                      - pkg: apache           # requisite reference
      * 如果同时存在webserver.slswebserver.init.sls,后者被忽略
      * requirewatch:
      
      • service(state declaration)支持 watch.
      • 例如, 如apache配置文件发生变化时,apache重启:

        /etc/httpd/extra/httpd-vhosts.conf:
            file:
                - managed
                - source: salt://webserver/httpd-vhosts.conf
        apache:
            pkg:
                - installed
            service:
                - running
                - watch:
                    - file: /etc/httpd/extra/httpd-vhosts.conf
                - require:
                    - pkg: apache
        * templating模板
            * 支持Jinja2
            * Grains 模板:
        
        • derive information about the underlying system
        • grains are bits of information loaded when the salt minion starts
      • grains are static

      • 列出grains:

        salt '*' grains.ls
        salt '*' grains.items
        
      • grains 也可以在minions里设置:

        grains:
            roles:
                - webserver
                - memcache
            deployment: datacenter4
            cabinet: 13
            cab_u: 14-15
        
        • 或者在minion的/etc/salt/grains设置
      • 在top(pillar中的top.sls)中匹配grains:

        'node_type:web':
            - match: grain
            - webserver
        'node_type:postgres':
            - match: grain
            - database
        

        或者用Jinja:

            {% set node_type = salt['grains.get']('node_type', '') %}
            {% if node_type %}
                'node_type:{{ self }}':
                        - match: grain
                        - {{ self }}
            {% endif %}
            * 在模板中使用模块(**未完成**)
            * extend declaration:
        

        apache/apache.sls

            apache:
                pkg.installed
        

        apache/mywebsite.sls:

            include:
                - apache.apache
        
            extend:
                apache:
                    service:
                        - running
                        - watch:
                            - file: /etc/httpd/extra/httpd-vhosts.conf
        
            /etc/httpd/extra/httpd-vhosts.conf:
                file.managed:
                     - source: salt://apache/httpd-vhosts.conf
            * inlcude declaration:
        

        python/python-libs.sls:

            python-dateutil:
                pkg.installed
        

        python/django.sls:

            include:
                - python.python-libs
        
            django:
                pkg.installed:
                    - require:
                        - pkg: python-dateutil
            * name declaration:
        

        apache/mywebsite.sls:

            include:
                - apache.apache
        
            extend:
                apache:
                    service:
                        - running
                        - watch:
                            - file: mywebsite
        
            mywebsite:
                file.managed:
                    - name: /etc/httpd/extra/httpd-vhosts.conf
                    - source: salt://apache/httpd-vhosts.conf
        

        我的理解为: 给复杂的"/etc/httpd/extra/httpd-vhosts.conf"起了个别名"mywebsite"作为id. * names declaration: 用一个例子可以解释出names declaration的作用和用法:

                {% for usr in ['moe','larry','curly'] %}
                {{ usr }}:
                    user.present
                {% endfor %}
        
        render后内容如下:
        
                moe:
                    user.present
                larry:
                    user.present
                curly:
                    user.present
        
        names declaration:
        
            stooges:
                user.present:
                    - names:
                        - moe
                        - larry
                        - curly
        

配置pillar

pillar是配置在master上,用于更为安全的发布数据(高敏感数据)到指定相关的minions. 我的理解是,实际上就是定义了一堆可以用在states的jinja模板里的静态变量.

  1. 在master的配置文件中设定pillar_roots,并创建pillar文件夹: # mkdir /srv/pillar
  2. 创建top.sls
  3. 创建pillar的.sls文件
  4. pillar is just a Python dict, so Python dict methods such as get and items can be used.

pillar的使用

    # /srv/pillar/top.sls
    base:
        '*':
            - users

    # /srv/pillar/users/init.sls
    users-data:
        thatch: 1000
        shouse: 1001
        utahdave: 1002
        redbeard: 1003

    # /srv/salt/users/init.sls
    #注意, 这里要使用users-data作为字典名因为在/srv/pillar/users/init.sls是这么定义的
    {% for user, uid in pillar.get('users-data', {}).items() %}
    {{user}}:
        user.present:
            - uid: {{uid}}
    {% endfor %}

notes:

  • 配置中source: salt://webserver/index.htmlsalt://指代 "file_root", 如"/srv/salt/" 好像有点不对"salt://"指向top.sls所在directory应该......
  • prereq: prereq目前还没搞明白, 不过看例子, 部署新代码的时候用的到.

    graceful-down:
        cmd.run:
            - name: service apache graceful
            - prereq:
            - file: site-code
    
        site-code:
            file.recurse:
                - name: /opt/site_code
                - source: salt://site/code
    
    • 但是, 部署代码并重启服务(如nginx restart/reload), 这种情况用watch:

          ntpd:
              service.running:
                  - watch:
                      - file: /etc/ntp.conf
              file.managed:
                  - name: /etc/ntp.conf
                  - source: salt://ntp/files/ntp.conf
      
    • 官方文档给出关于watch的note是:

If a state should only execute when another state has changes, and otherwise do nothing, the new onchanges requisite should be used instead of watch. watch is designed to add additional behavior when there are changes, but otherwise execute normally.

If the mod_watch function exists in the watching state module, it will be called in addition to the normal watching state. The return data from the mod_watch function is what will be returned to the master in this case; the return data from the main watching function is discarded.

Not all state modules contain mod_watch. If mod_watch is absent from the watching state module, the watch requisite behaves exactly like a require requisite.

  • top.sls 中的targeting匹配用在highstate的时候,state.sls中没有用.

未完待续.....

© Tian Li. Built using Pelican. Theme by Giulio Fidente on github. .