此次爲你們介紹一款批量部署工具ansible,主要有如下幾點優勢:1、充分利用現有設施。使用 Ansible 無需安裝服務端和客戶端,只要 SSH 便可。這意味着,任何一臺裝有 Ansible 的機器均可以成爲強大的管理端。我以爲,這種去中心化的思路顯得更爲靈活。可能有人會擔憂 SSH 的效率,Ansible 的並行執行及加速模式或許能夠打消你的顧慮。2、使用簡單,快速上手至關容易。Ansible 上手十分快,用 Ad-Hoc 能夠應付簡單的管理任務,麻煩點的也能夠定義 Playbook 文件來搞定。3、採用人類易讀的格式。Ansible 的主機定義文件使用 INI 格式,支持分組,可以指定模式;此外也能動態生成,這對管理雲主機應當頗有用。而 Playbook 則是 YAML 格式。4、可以使用你熟悉的語言來編寫模塊。雖然 Ansible 是使用 Python 開發的,但它不會將你限制到某種具體的編程語言,Bash、Python、Perl、Ruby 等等均可以,你擅長什麼就用什麼。php
一言以蔽之,Ansible 背後的簡單化哲學深得我心。這也比較符合我選擇軟件的一向原則。可能還有人會比較關心目前 Ansible 都有誰在用。畢竟,榜樣的力量是無窮。Puppet 不正是由於 Google 在用而吸引了很多眼球麼?據我所知,當前使用 Ansible 較爲知名的用戶包括 Fedora、Rackspace、Evernote 等等。html
Ansible企業應用:python
Ansible Core. //核心功能nginx
Modules:web
Core Modules //核心功能shell
Customed Modules //自定義模塊編程
Host Inventory //主機庫和主機清單,用來定義要管理的主機json
Filevim
CMDB(配置管理數據)bash
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/
[root@cml1~]# ssh-keygen
[root@cml1~]# ssh-copy-id 192.168.5.102
[root@cml1~]# cd /etc/ansible/
[root@cml1ansible]# vim hosts
[webserver]
192.168.5.102
192.168.5.104
[root@cml1ansible]# ansible webserver --list-hosts
hosts (2):
192.168.5.102
192.168.5.104
[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目錄
[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
[root@cml1nginx_install]# cd files/ [root@cml1files]# ls nginx-1.12.0.tar.gz
[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`
[root@cml1nginx_install]# cd vars/ [root@cml1vars]# cat main.yml ngxport:"8080"
[root@cml1nginx_install]# cd handlers/ [root@cml1handlers]# cat main.yml - name: startnginx service shell: /usr/loal/nginx/sbin/nginx
[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<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
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了)
須要安裝gcc、python-devel [root@cml1 ~]#yum install python-pip [root@cml1 ~]#pip install ansible==1.9.1
[root@cml1tasks]# vim /etc/ansible/ansible.cfg callback_plugins = /usr/share/ansible/plugins/callback bin_ansible_callbacks= True
[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