Saltstack自动化部署nginx


作者:彬彬



前言


为什么写这个题材? 上周去武汉高铁路上,拜读宇哥(刘宇)Puppet实战,里面讲解的细节,让我萌生写此题材的想法;目前saltstack社区并没有像puppet那样提供nginx部署模块,但CSSUG(中国saltstack用户组)已经有贡献者分享了openstackmoosefszabbixmysql模块内容分享了。写这篇文章目的,是想分享自己写的生产模块,同时希望更多人分享自己的模块,让saltstack变得容易使用、更好。

日常部署nginx可以概括为两类:


1.配置变更,新增虚拟主机、安全设置、日志切割


2.软件升级,nginx某版本出现漏洞



前期规划


软件安装


   推荐大家在自己环境里部署个Yum仓库,方便部署软件包,好处就不用说了,这块内容我就略过了。

Nginx部署


  虚拟主机文件和主配置分开配置,利用pillarstate来做新增虚拟主机,在state存储描述信息,而pillar存储真实数据,通过递增pillar内容来实现虚拟机主机添加,日后可以把pillar信息外存到数据库,做个平台来管理pillar信息。


  针对机器设备不一致,CPU核数就不一,这时就可以用saltstack grains{{grains[num_cpus]}}来配置,


  日志切割利用file statescron states实现。  


      安全设置,以非root用户启动,在SLS定义变量,在文件当中以{{  nginx_user }}引用




部署


1. 创建nginx模块目录


$ mkdir -p /srv/salt/nginx/files

 

2. 创建nginx安装代码

$ vi /srv/salt/nginx/install.sls
{% set nginx_user = 'nobody' + ' ' + 'nobody' %}
base:
  pkgrepo.managed:
    - humanname: CentOS-$releasever - Base
    - baseurl: http://agent.domain.com/centos/6.3/x86_64/
    - gpgcheck: 0
    - gpgkey: http://agent.domain.com/centos/6.3/x86_64/RPM-GPG-KEY-CentOS-6
  nginx:
    pkg.installed:
      - name: nginx
      - require:
        - pkgrepo: base
    file.managed:
      - name: /usr/local/nginx/conf/nginx.conf
      - source: salt://nginx/files/nginx.conf
      - template: jinja
      - defaults:
        nginx_user: {{ nginx_user }}
        num_cpus: {{grains['num_cpus']}}
    service.running:
      - name: nginx
      - enable: True
      - watch:
        - pkg: nginx
        - file: nginx
cron_nginx_logrote:
  file.managed:
    - name: /opt/run/logrote.sh
    - source: salt://nginx/files/logrote.sh
  cron.present:
    - name: sh /opt/run/logrote.sh
    - user: root
    - minute: 1
    - hour: 0
    - require:
      - file: cron_nginx_logrote


以上代码实现yum仓库、nginx部署、安全设置、日志切割:

Set命令: nginx启动用户定义为变量,在nginx.conf里引用替换

Pkgrepo sate: 创建一个yum repo,让客户端通过此repo下载nginx软件包


Pkg state:从yum repo下载nginx,但依赖base.repo先执行成功,目前salt不能实现按顺序执行,期望日后能完善这块。不然写requireorder有点不够理想


File state:同步nginx主配置文件和日志切割脚本到minion上,其中nginx主配置文件中引用grains实现CPU核数不一问题,利用set变量实现nginx启动用户设置,当用grainssetpillar来实现内容替换,请用jinja模板,推荐在用jinja时使用defaults定义变量。


Service state: 定义nginx服务状态,开机自动启动,当包和文件发生变化时重启;


Cron state:定义切割脚本计划任务。每天0点采用root进行日志切割,依赖file state。验证使用crontab -u root -l



 

3.创建虚拟主机配置代码


$ vi /srv/salt/nginx/vhost.sls
include:
  - nginx.install
{% if 'vhost' in pillar %}
{% for eachvhost in  pillar['vhost'] %}
{% set vhost_id = 'web-vhost-' + eachvhost.name %}
{{ vhost_id }}:
  file.managed:
    - name: {{ eachvhost['target'] }}
    - source: {{ eachvhost['source'] }}
    - watch_in:
      - service: nginx
{% endfor %}
{% endif %}


 

4.创建pillar文件


$ vi /srv/pillar/nginx/vhost.sls
vhost:
  - name: web
    source: salt://nginx/files/web.domain.com.conf
    target: /usr/local/nginx/conf/vhost/web.domain.com.conf
  - name: call
    source: salt://nginx/files/call.domain.com.conf
    target: /usr/local/nginx/conf/vhost/call.domain.com.conf

     

上述34代码,实现pillar管理虚拟主机,简单来说,在pillar定义3个字段,标识、虚拟机文件源路径以及目标路径。通过在statefor循环pillar里的信息,实现虚拟机管理。



 

5.nginx主配置文件代码如下


$ vi /srv/salt/nginx/files/nginx.conf
user  {{ nginx_user }};
worker_processes {{grains['num_cpus']}};     //grains引用
error_log  /opt/log/nginx/nginx_error.log  crit;
pid        /opt/run/nginx.pid;
#Specifies the value for maximum file descriptors that can be opened by this process.
worker_rlimit_nofile 65535;
events
     {
              use epoll;
              worker_connections 65535;
      }
http
     {
              include       mime.types;
              default_type  application/octet-stream;
              charset  utf-8;
              server_names_hash_bucket_size 128;
              client_header_buffer_size 32k;
              large_client_header_buffers 4 32k;
              client_max_body_size 300m;
              sendfile on;
              tcp_nopush     on;
              keepalive_timeout 60;
              tcp_nodelay on;
              server_tokens off;
              client_body_buffer_size  512k;
              gzip on;
              gzip_min_length  1k;
              gzip_buffers     4 16k;
              gzip_http_version 1.1;
              gzip_comp_level 2;
              gzip_types      text/plain application/x-javascript text/css application/xml;
              gzip_vary on;
         log_format  wwwlogs  '$remote_addr - $remote_user           [$time_local] "$request" '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for' ;
              #limit_zone  crawler  $binary_remote_addr  10m;
              include vhost/*.conf;
       }


 

6.创建虚拟主机配置,虚拟主机目录在软件包中已经被定义了,所以创建就省去了。


$ vi /srv/salt/nginx/files/web.domain.com.conf
      server
      {
          listen  80;
          server_name     web.domain.com;
          index index.php;
          root    /opt/www/web;
          location ~ \.php$
          {
          fastcgi_pass   unix:/var/run/php-fpm.sock;
          fastcgi_index  index.php;
          fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
           include        fastcgi.conf;
           }
          access_log  /opt/log/nginx/access.log wwwlogs;
      }


7.创建日志切割脚本,脚本来自puppet实战,生产环境是使用logrotate切割


$ vi /srv/salt/nginx/files/logrote.sh
 #!/bin/bash
 logpath=/opt/log/nginx/
 pidfile=/opt/run/nginx.pid
 ACCESS_LOG="${logpath}$(date -d "yesterday" + "%Y")/$(date -d "yesterday" + "%m")/$(date -d "yesterday" + "%Y%m%d").log"
 mkdir -p ${logpath}$(date -d "yesterday" + "%Y")/$(date -d "yesterday" + "%m")/
 mv ${logs_path}access.log $ACCESS_LOG
 kill -USR1 `cat $pidfile`
 /bin/gzip -9 $ACCESS_LOG
 find ${logs_path} -name "*.log.gz" -mtime +7 | xargs rm -f


8.创建saltpillartop.sls入口文件和nginx.init


$ vi /srv/salt/nginx/init.sls
include:
  - nginx.install
  - nginx.vhost

 引用路径是以/srv/salt为开始。为了top.sls书写简单,一般每个模块下都写个init.sls, 然后用include包含要执行的sls

 

$ vi /srv/salt/top.sls
base:                    //指定环境
  '*':                    //minion指定,这里是所有
    - nginx               //应用nginx.init


 在SLS命名里,一个子目录里存在init.sls文件,那么nginx/init.sls可以简写为nginx,但是如果同时存在nginx/init.slsnginx.sls,那么nginx/init.sls会被忽略,只会把nginx.sls当做nginx。所以这里注意下


  $ vi /srv/pillar/top.sls
base:
‘*’:
    - nginx.vhost


 

9.最后同步SLS代码到minion


$ salt ‘*’ state.highstate