Saltstack自動化部署nginx
作者:彬彬
前言
爲什麼寫這個題材? 上週去武漢高鐵路上,拜讀宇哥(劉宇)的Puppet實戰,裏面講解的細節,讓我萌生寫此題材的想法;目前saltstack社區並沒有像puppet那樣提供nginx部署模塊,但CSSUG(中國saltstack用戶組)已經有貢獻者分享了openstack、moosefs、zabbix、mysql模塊內容分享了。寫這篇文章目的,是想分享自己寫的生產模塊,同時希望更多人分享自己的模塊,讓saltstack變得容易使用、更好。
日常部署nginx可以概括爲兩類:
1.配置變更,新增虛擬主機、安全設置、日誌切割
2.軟件升級,nginx某版本出現漏洞
前期規劃
軟件安裝
推薦大家在自己環境裏部署個Yum倉庫,方便部署軟件包,好處就不用說了,這塊內容我就略過了。
Nginx部署
虛擬主機文件和主配置分開配置,利用pillar和state來做新增虛擬主機,在state存儲描述信息,而pillar存儲真實數據,通過遞增pillar內容來實現虛擬機主機添加,日後可以把pillar信息外存到數據庫,做個平臺來管理pillar信息。
針對機器設備不一致,CPU核數就不一,這時就可以用saltstack grains的{{grains[‘num_cpus’]}}來配置,
日誌切割利用file states和cron 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不能實現按順序執行,期望日後能完善這塊。不然寫require和order有點不夠理想
File state:同步nginx主配置文件和日誌切割腳本到minion上,其中nginx主配置文件中引用grains實現CPU核數不一問題,利用set變量實現nginx啓動用戶設置,當用grains、set、pillar來實現內容替換,請用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
上述3、4代碼,實現pillar管理虛擬主機,簡單來說,在pillar定義3個字段,標識、虛擬機文件源路徑以及目標路徑。通過在state裏for循環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.創建salt和pillar的top.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.sls和nginx.sls,那麼nginx/init.sls會被忽略,只會把nginx.sls當做nginx。所以這裏注意下
$ vi /srv/pillar/top.sls base: ‘*’: - nginx.vhost
9.最後同步SLS代碼到minion
$ salt ‘*’ state.highstate