Ansible批量部署编译安装nginx
一、ansible介绍:
这次为大家介绍一款批量部署工具ansible,主要有以下几点优点:1、充分利用现有设施。使用 Ansible 无需安装服务端和客户端,只要 SSH 即可。这意味着,任何一台装有 Ansible 的机器都可以成为强大的管理端。我觉得,这种去中心化的思路显得更为灵活。可能有人会担心 SSH 的效率,Ansible 的并行执行及加速模式或许可以打消你的顾虑。2、使用简单,快速上手相当容易。Ansible 上手十分快,用 Ad-Hoc 可以应付简单的管理任务,麻烦点的也可以定义 Playbook 文件来搞定。3、采用人类易读的格式。Ansible 的主机定义文件使用 INI 格式,支持分组,能够指定模式;此外也能动态生成,这对管理云主机应当很有用。而 Playbook 则是 YAML 格式。4、能够使用你熟悉的语言来编写模块。虽然 Ansible 是使用 Python 开发的,但它不会将你限制到某种具体的编程语言,Bash、Python、Perl、Ruby 等等都可以,你擅长什么就用什么。
一言以蔽之,Ansible 背后的简单化哲学深得我心。这也比较符合我选择软件的一贯原则。可能还有人会比较关心目前 Ansible 都有谁在用。毕竟,榜样的力量是无穷。Puppet 不正是因为 Google 在用而吸引了不少眼球么?据我所知,当前使用 Ansible 较为知名的用户包括 Fedora、Rackspace、Evernote 等等。
Ansible企业应用:
二、主要架构功能:
Ansible Core. //核心功能
Modules:
Core Modules //核心功能
Customed Modules //自定义模块
Host Inventory //主机库和主机清单,用来定义要管理的主机
File
CMDB(配置管理数据)
PlayBooks //剧本,定义没个主机扮演的角色
Hosts. //主机
roles. //角色
Connection Plugins. //连接插件,连接至被管控主机,完成并发连接,默认一次管理5台,但是可以修改。
三、安装配置
★安装:
# yum install ansible -y (epel仓库中)
★程序:
ansible
ansible-playbook //唱剧本
ansible-doc //获取帮助文档
★配置文件
/etc/ansible/ansible.cfg //核心配置文件
★主机清单:
/etc/ansible/hosts
★插件目录:
/usr/share/ansible_plugins/
1、设置ansble到各个主机的免密钥通讯:
[root@cml1~]# ssh-keygen
[root@cml1~]# ssh-copy-id 192.168.5.102
2、定义主机组:
[root@cml1~]# cd /etc/ansible/
[root@cml1ansible]# vim hosts
[webserver]
192.168.5.102
192.168.5.104
3、查看主机组内的主机:
[root@cml1ansible]# ansible webserver --list-hosts
hosts (2):
192.168.5.102
192.168.5.104
4、定义角色路径
[root@cml1~]# cat /etc/ansible/nginx.yaml
- hosts: 192.168.5.102
remote_user: root
roles:
-nginx_install ###roles目录下的nginx_install目录
-nginx_config ###roles目录下的nginx_config目录
5、查看目录结构:
[root@cml1 roles]# tree
.
├── nginx_config
│ ├── default
│ ├── files
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ │ └── temp_server.conf
│ └── vars
│ └── main.yml
└── nginx_install
├──default
├──files
│ └── nginx-1.12.0.tar.gz
├──handlers
│ └── main.yml
├──meta
├──tasks
│ └── main.yml
├──templates
│ └── nginx.conf
└── vars
[root@cml1roles]# cd nginx_install/
[root@cml1nginx_install]# ls
default files handlers meta tasks templates vars
6、task定义开始任务:
[root@cml1nginx_install]# cd tasks/ [root@cml1tasks]# cat main.yml - name: copynginx package to remote host copy: src=nginx-1.12.0.tar.gz dest=/tmp/nginx-1.12.0.tar.gz ##拉取nginx解压吧 tags: cppkg - name: tarnginx shell: cd /tmp;tar -xf nginx-1.12.0.tar.gz ##解压nginx包 - name: installpakger yum: name={{ item }} state=latest ##安装依赖包 with_items: - openssl-devel - pcre-devel - gcc - name: installnginx shell: cd /tmp/nginx-1.12.0;./configure--user=nginx --group=nginx --prefix=/usr/local/nginx--with-http_stub_status_module --with-http_ssl_module --with-pcre;make&& make install ####编译安装 - name: copyconf file nginx.conf template: src=nginx.confdest=/usr/local/nginx/conf/nginx.conf ###复制在template目录下的配置文件 tags: ngxconf - name: copyshell copy: src=/opt/create_users.shdest=/tmp/create_users.sh ##拉取创建用户的shell脚本 - name: createuser nginx shell: /bin/bash /tmp/create_users.sh tags: addnginx notify: start nginx service
为什么要写这个脚本?因为加入有些主机创建的用户已存在就会报错
[root@cml1tasks]# cat /opt/create_users.sh #!/bin/bash a=`cat/etc/passwd | grep nginx | wc -l` if [ $a == 0];then useradd nginx fi
6、第二行copy对应file目录:
[root@cml1nginx_install]# cd files/ [root@cml1files]# ls nginx-1.12.0.tar.gz
7、template这一行对应的是template这个目录和主服务端定义的变量:
[root@cml1nginx_install]# cd templates/ [root@cml1templates]# ls nginx.conf [root@cml1templates]# cat nginx.conf user nginx; worker_processes {{ ansible_processor_vcpus }}; #error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info; #pid logs/nginx.pid; events { worker_connections 65535; } http { include 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"'; log_format xiaoluo '$remote_addr -$remote_user [$time_local] ' '"$request" $status$body_bytes_sent ' '"$http_referer" "$http_user_agent" '; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; server { listen {{ ngxport }}; server_name wwwNaNl.com access_log logs/wwwNaNl.com xiaoluo; #location / { # proxy_pass http://192.168.5.101; #} #error_page 404 /404.html; # redirect server error pages to thestatic page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } # proxy the PHP scripts to Apachelistening on 127.0.0.1:80 # #location ~ \.php$ { # proxy_pass http://127.0.0.1; #} # pass the PHP scripts to FastCGIserver listening on 127.0.0.1:9000 # location ~ \.php$ { root /web; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME$document_root$fastcgi_script_name; include fastcgi_params; } # deny access to .htaccess files, ifApache's document root # concurs with nginx's one # #location ~ /\.ht { # deny all; #} } include vhosts/*.conf; }
##需要注意的就是模板变量(客户端自动采集)、和在服务端定义的变量`ngx_port`
8、在vars定义变量:
[root@cml1nginx_install]# cd vars/ [root@cml1vars]# cat main.yml ngxport:"8080"
9、定义触发器:
[root@cml1nginx_install]# cd handlers/ [root@cml1handlers]# cat main.yml - name: startnginx service shell: /usr/loal/nginx/sbin/nginx
10、在nginx_config目录加入我们经常要增加nginx站点,直接写好模板推送到vhos目录:
[root@cml1roles]# cd nginx_config/ [root@cml1nginx_config]# ls default files handlers meta tasks templates vars [root@cml1nginx_config]# cd templates/ [root@cml1templates]# ls temp_server.conf [root@cml1templates]# cat temp_server.conf server { listen 80; server_name {{server_name }}; index index.phpindex.html; root {{root_dir }}; }
###在var定义变量:
[root@cml1templates]# cd ../vars/ [root@cml1vars]# cat main.yml server_name: "www.xiaoluo.com" root_dir:"/web"
11、写配置nginx的tasks步骤:
[root@cml1nginx_config]# cd tasks/ [root@cml1tasks]# ls main.yml [root@cml1tasks]# cat main.yml - name: createvhosts shell: mkdir -p /usr/local/nginx/conf/vhosts/ tags: create_dir - name: copyconf file nginx.conf # 调用templates模块 template: src=temp_server.confdest=/usr/local/nginx/conf/vhosts/{{ server_name }}.conf tags: ngxconf notify: reload nginx service ###定义重启触发器: [root@cml1tasks]# cd ../handlers/ You have newmail in /var/spool/mail/root [root@cml1handlers]# cat main.yml - name: reloadnginx service shell: /usr/local/nginx/sbin/nginx-t;/usr/local/nginx/sbin/nginx -s reload
测试:
[root@cml1ansible]# ansible-playbook -C nginx.yaml PLAY[192.168.5.104] ********************************************************** GATHERING FACTS*************************************************************** ok:[192.168.5.104] TASK:[nginx_install | copy nginx package to remote host] ********************* changed:[192.168.5.104] TASK:[nginx_install | tar nginx] ********************************************* skipping:[192.168.5.104] ok:[192.168.5.104] TASK:[nginx_install | install pakger] **************************************** changed: [192.168.5.104]=> (item=openssl-devel,pcre-devel,gcc) TASK:[nginx_install | install nginx] ***************************************** skipping:[192.168.5.104] ok:[192.168.5.104] TASK:[nginx_install | copy conf file nginx.conf] ***************************** changed:[192.168.5.104] TASK:[nginx_install | copy shell] ******************************************** changed:[192.168.5.104] TASK:[nginx_install | create user nginx] ************************************* skipping:[192.168.5.104] ok: [192.168.5.104] TASK:[nginx_config | create vhosts] ****************************************** skipping:[192.168.5.104] ok:[192.168.5.104] TASK:[nginx_config | copy conf file nginx.conf] ****************************** changed:[192.168.5.104] NOTIFIED:[nginx_config | reload nginx service] ******************************* skipping:[192.168.5.104] ok:[192.168.5.104] PLAY RECAP******************************************************************** 192.168.5.104 : ok=6 changed=5 unreachable=0 failed=0
[root@cml1 ansible]# ansible-playbook nginx.yaml PLAY [192.168.5.104] ********************************************************** GATHERING FACTS *************************************************************** ok: [192.168.5.104] TASK: [nginx_install | copy nginx package to remote host] ********************* ok: [192.168.5.104] TASK: [nginx_install | tar nginx] ********************************************* changed: [192.168.5.104] TASK: [nginx_install | install pakger] **************************************** ok: [192.168.5.104] => (item=openssl-devel,pcre-devel,gcc) TASK: [nginx_install | install nginx] ***************************************** changed: [192.168.5.104] TASK: [nginx_install | copy conf file nginx.conf] ***************************** ok: [192.168.5.104] TASK: [nginx_install | copy shell] ******************************************** ok: [192.168.5.104] TASK: [nginx_install | create user nginx] ************************************* changed: [192.168.5.104] TASK: [nginx_config | create vhosts] ****************************************** changed: [192.168.5.104] TASK: [nginx_config | copy conf file nginx.conf] ****************************** ok: [192.168.5.104] NOTIFIED: [nginx_install | start nginx service] ******************************* changed: [192.168.5.104] PLAY RECAP ******************************************************************** 192.168.5.104 : ok=11 changed=5 unreachable=0 failed=0
[root@cml3 ~]# ifconfig
ens34: flags=4163
inet 192.168.5.104 netmask 255.255.255.0 broadcast 192.168.5.255
[root@cml3 ~]# netstat -ntlp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 29264/nginx: master
tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 29264/nginx: master
四、定义日志文件
下面是介绍如何定义日志:(在ansible1.9.1版本之后有个bug所以定义不了日志文件只能降版本到1.9.1了)
1、ansible倒回去版本:1.9.1
需要安装gcc、python-devel [root@cml1 ~]#yum install python-pip [root@cml1 ~]#pip install ansible==1.9.1
2、callback插件:
[root@cml1tasks]# vim /etc/ansible/ansible.cfg callback_plugins = /usr/share/ansible/plugins/callback bin_ansible_callbacks= True
3、在callback目录下创建日志处理文件:
[root@cml1tasks]# cd /usr/share/ansible/plugins/callback [root@cml1callback]# ls log.py log.pyc [root@cml1callback]# cat log.py import os import time import json TIME_FORMAT="%b%d %Y %H:%M:%S" MSG_FORMAT="%(now)s- %(category)s - %(data)s\n\n" if notos.path.exists("/var/log/ansible/hosts"): os.makedirs("/var/log/ansible/hosts") def log(host,category, data): if type(data) == dict: if 'verbose_override' in data: # avoid logging extraneous datafrom facts data = 'omitted' else: data = data.copy() invocation = data.pop('invocation',None) data = json.dumps(data) if invocation is not None: data = json.dumps(invocation) +" => %s " % data path =os.path.join("/var/log/ansible/hosts", host) now = time.strftime(TIME_FORMAT,time.localtime()) fd =open(path, "a") fd.write(MSG_FORMAT % dict(now=now,category=category, data=data)) fd.close() classCallbackModule(object): """ logs playbook results, per host, in/var/log/ansible/hosts """ def on_any(self, *args, **kwargs): pass def runner_on_failed(self, host, res,ignore_errors=False): log(host, 'FAILED', res) def runner_on_ok(self, host, res): log(host, 'OK', res) def runner_on_skipped(self, host,item=None): log(host, 'SKIPPED', '...') def runner_on_unreachable(self, host, res): log(host, 'UNREACHABLE', res) def runner_on_no_hosts(self): pass def runner_on_async_poll(self, host, res,jid, clock): pass def runner_on_async_ok(self, host, res,jid): pass def runner_on_async_failed(self, host, res,jid): log(host, 'ASYNC_FAILED', res) def playbook_on_start(self): pass def playbook_on_notify(self, host,handler): pass def playbook_on_no_hosts_matched(self): pass def playbook_on_no_hosts_remaining(self): pass def playbook_on_task_start(self, name,is_conditional): pass def playbook_on_vars_prompt(self, varname,private=True, prompt=None, encrypt=None, confirm=False, salt_size=None,salt=None, default=None): pass def playbook_on_setup(self): pass def playbook_on_import_for_host(self, host,imported_file): log(host, 'IMPORTED', imported_file) def playbook_on_not_import_for_host(self,host, missing_file): log(host, 'NOTIMPORTED', missing_file) def playbook_on_play_start(self, name): pass def playbook_on_stats(self, stats): pass