運(yùn)維核心工作:
操作系統(tǒng)安裝(物理機(jī)、虛擬機(jī))--> 應(yīng)用程序包部署(安裝、配置、服務(wù)啟動)--> 批量操作 --> 業(yè)務(wù)系統(tǒng)程序部署(安裝,運(yùn)行以及發(fā)布)--> 監(jiān)控
系統(tǒng)安裝(OS Provisioning):
(a) bare metal:裸機(jī)上安裝系統(tǒng),pxe預(yù)執(zhí)行環(huán)境:cobbler是二次封裝的pxe;
(b) virtual machine:在虛擬機(jī)上安裝系統(tǒng);Configuration:程序配置
(1) puppet(ruby語言研發(fā)):學(xué)習(xí)入門曲線陡峭;早先問世,穩(wěn)定,重量級;
(2) saltstack(python語言研發(fā)):與puppet相似,要有強(qiáng)大的二次研發(fā)能力才能填坑,重量級;
(3) chef:輕量級,使用簡單,早期問世;
(4) cfengine:
(5) ansible:
注意:puppet和saltstack都是重量級應(yīng)用在上百臺服務(wù)器以上的運(yùn)維環(huán)境,需要長時(shí)間學(xué)習(xí)才能靈活運(yùn)用,如果數(shù)量較少,支出會大于收益;
這就產(chǎn)生了一些較輕量級、簡單入門學(xué)習(xí)的運(yùn)維工具來負(fù)責(zé)較少量的服務(wù)器運(yùn)維;
如chef、cfengine、ansible等;
Command and Control:批量執(zhí)行命令控制
(1) fabric輕量級,python語言研發(fā);可編寫fabric腳本完成強(qiáng)大功能;
(2) func 重量級
(3) ansible預(yù)發(fā)布驗(yàn)證:
新版本的代碼先發(fā)布到服務(wù)器(跟線上環(huán)境配置完全相同,只是未接入到調(diào)度器);程序發(fā)布:
不能影響用戶體驗(yàn);
系統(tǒng)不能停機(jī);
不能導(dǎo)致系統(tǒng)故障或造成系統(tǒng)完全不可用;灰度發(fā)布:
發(fā)布路徑:
/webapp/tuangou-1.1
/web/app/tuangou
/webapp/tuangou-1.2
在調(diào)度器上下線一批主機(jī)(maintanance)--> 關(guān)閉服務(wù) --> 部署新版本的應(yīng)用程序 --> 啟動服務(wù) --> 在調(diào)度器上啟用這一批服務(wù)器;
- 自動化灰度發(fā)布: 腳本、發(fā)布平臺;
輕量級的運(yùn)維工具:Ansible
Ansible的特性
- 模塊化:調(diào)用特定的模塊,完成特定任務(wù)
- 基于Python語言實(shí)現(xiàn),有Paramiko,PyYAML,Jinja2(模板語言)三個(gè)關(guān)鍵模塊;
- 部署簡單:agentless
- 支持自定義模塊
- 支持playbook編排任務(wù)
- 有冪等性:一個(gè)任務(wù)執(zhí)行一遍一執(zhí)行n遍效果不一樣,不因?yàn)橹貜?fù)執(zhí)行帶來意外情況
- 安全,基于OpenSSH
- 無需代理不依賴PKI(無需ssl)
- YAML格式編排任務(wù),支持豐富的數(shù)據(jù)結(jié)構(gòu)
- 較強(qiáng)大的多層解決方案
Ansible的架構(gòu)

- Core Modules:核心模塊
- Custom Modules:自定義模塊
- Connection Plugins:連接插件
- Host Inventory:ansible管理主機(jī)的清單
/etc/ansible/hosts - Plugins:模塊功能的補(bǔ)充,如記錄日志發(fā)送通知等
- Playbooks 核心組件;任務(wù)劇本,編排定義ansible任務(wù)集的配置文件,ansible順序依次執(zhí)行,通常是json格式的yaml文件
Ansible的安裝使用
- ansible是基于epel倉庫,因此安裝之前先要配置epel的yum源倉庫
[root@server1 ~]# yum info ansible
Loaded plugins: fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirror.jdcloud.com
* extras: mirrors.shu.edu.cn
* updates: mirrors.shu.edu.cn
Available Packages
Name : ansible
Arch : noarch
Version : 2.7.7
Release : 1.el7
Size : 11 M
Repo : epel
Summary : SSH-based configuration management, deployment, and task execution system
URL : http://ansible.com
License : GPLv3+
Description : Ansible is a radically simple model-driven configuration management,
: multi-node deployment, and remote task execution system. Ansible works
: over SSH and does not require any software or daemons to be installed
: on remote nodes. Extension modules can be written in any language and
: are transferred to managed machines automatically.
[root@server1 ~]# rpm -ql ansible | less
/etc/ansible/ansible.cfg #ansible主配置文件
/etc/ansible/hosts #主機(jī)清單配置文件
/etc/ansible/roles #角色配置文件
...
ansible的使用方式:
(1) 在命令行中直接給出
(2) 在riles中定義好ansible語法格式:
ansible <host-pattern> [options]ansible的簡單格式:
ansible HOST-PATTERN -m MOD_NAME -a MOD_ARGS -f FORKS -C -u USERNAME -c CONNECTION基于密鑰的方式連接兩臺host主機(jī)node1和node2
[root@server1 ~]# ssh-keygen -t rsa -P "" #生成密鑰
[root@server1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.128
# 使用密鑰連接node1
[root@server1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.129
# 使用密鑰連接node2
[root@server1 ~]# vim /etc/ansible/hosts # 編輯主機(jī)清單文件添加主機(jī)
[websrvs]
192.168.1.128
192.168.1.129
[dbsrvs]
192.168.1.128
[root@server1 ~]# ansible all -m ping -C # 使用ping命令測試兩臺主機(jī)node1,node2;-C:測試模式,干跑;
192.168.1.129 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.128 | SUCCESS => {
"changed": false,
"ping": "pong"
}
- ansible的常用模塊:
- group模塊
[root@server1 ~]# ansible-doc -s group # 查看group模塊的幫助文檔 示例: [root@server1 ~]# ansible all -m group -a "gid=3000 name=mygro state=present system=no" 192.168.1.129 | CHANGED => { "changed": true, "gid": 3000, "name": "mygro", "state": "present", "system": false } 192.168.1.128 | CHANGED => { "changed": true, "gid": 3000, "name": "mygro", "state": "present", "system": false } # 在node1和node2上查看/etc/group文件確認(rèn)操作是否成功 [root@node1 ~]# tail -1 /etc/group mygro:x:3000:- user模塊
- *name= 指定要管理的用戶;
- state= 為present | absent;
- system= 是否創(chuàng)建系統(tǒng)帳號;
- uid= 指定UID;
- shell= 默認(rèn)shell類型;
- group= 基于組;
- groups= 額外(附加)組;
- comment= 注釋信息;
- home= 用戶的家目錄;
- move_home= 移動已存在用戶的家目錄;
- password 添加密碼,應(yīng)該指定是的openssl加密后的密碼;
- remove 當(dāng)state=absent時(shí),刪除用戶時(shí)同時(shí)刪除家目錄;
示例:
[root@server1 ~]# ansible all -m user -a "uid=5000 name=testuser state=present groups=mygro shell=/bin/tcsh"
192.168.1.128 | CHANGED => {
"changed": true,
"comment": "",
"create_home": true,
"group": 5000,
"groups": "mygro",
"home": "/home/testuser",
"name": "testuser",
"shell": "/bin/tcsh",
"state": "present",
"system": false,
"uid": 5000
}
192.168.1.129 | CHANGED => {
"changed": true,
"comment": "",
"create_home": true,
"group": 5000,
"groups": "mygro",
"home": "/home/testuser",
"name": "testuser",
"shell": "/bin/tcsh",
"state": "present",
"system": false,
"uid": 5000
}
# 在node1和node2上查看用戶創(chuàng)建結(jié)果
[root@node1 ~]# tail -1 /etc/passwd
testuser:x:5000:5000::/home/testuser:/bin/tcsh
- copy模塊:
ansible-doc -s copy;用來復(fù)制文件到遠(yuǎn)程主機(jī)
2種用法:
1)src= dest=
2)content= dest=
owner,group,mode可同時(shí)指明文件的屬主、組及權(quán)限;
一般有=號的選項(xiàng)為必有選項(xiàng);
src=為本地文件或目錄;
dest=為遠(yuǎn)程被管理主機(jī)文件或目錄;
content=表示把此處的內(nèi)空直接當(dāng)做源文件;
[root@server1 ~]# ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab.ansible mode=600"
192.168.1.128 | CHANGED => {
"changed": true,
"checksum": "f5dec7037c1be2d9c54110114ffb00b9efb834ba",
"dest": "/tmp/fstab.ansible",
"gid": 0,
"group": "root",
"md5sum": "03ef74ad995b394c5265817e23ee086e",
"mode": "0600",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 541,
"src": "/root/.ansible/tmp/ansible-tmp-1550649775.34-194820899443510/source",
"state": "file",
"uid": 0
}
192.168.1.129 | CHANGED => {
"changed": true,
"checksum": "f5dec7037c1be2d9c54110114ffb00b9efb834ba",
"dest": "/tmp/fstab.ansible",
"gid": 0,
"group": "root",
"md5sum": "03ef74ad995b394c5265817e23ee086e",
"mode": "0600",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 541,
"src": "/root/.ansible/tmp/ansible-tmp-1550649775.36-53381265559986/source",
"state": "file",
"uid": 0
}
# 在node1和node2上查看結(jié)果
[root@node1 ~]# ll -d /tmp/fstab.ansible
-rw-------. 1 root root 541 Feb 20 16:02 /tmp/fstab.ansible
- command模塊:
ansible-doc -s command;在被管理遠(yuǎn)程主機(jī)上執(zhí)行命令;省略模塊時(shí),默認(rèn)為command模塊;- chdir:指定在哪個(gè)目錄下運(yùn)行命令;
- creates:命令運(yùn)行前創(chuàng)建文件;如果文件存在就不執(zhí)行命令;
- removes:命令運(yùn)行后移除文件;如果文件不存在就不執(zhí)行命令;
- executable:指定shell程序來運(yùn)行命令;
示例:
[root@server1 ~]# ansible all -m command -a "ifconfig"
192.168.1.129 | CHANGED | rc=0 >>
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.129 netmask 255.255.255.0 broadcast 192.168.1.255
...
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
...
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
...
192.168.1.128 | CHANGED | rc=0 >>
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.128 netmask 255.255.255.0 broadcast 192.168.1.255
...
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
...
virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
...
注意:command執(zhí)行時(shí)不適用shell解析,是裸執(zhí)行;比如傳遞參數(shù)`-a "echo mageedu | passwd --stdin testuser"`不能傳遞密碼給testuser,需要使用下面的shell模塊
- shell模塊:
ansible-doc -s shell;在被管理遠(yuǎn)程主機(jī)上執(zhí)行命令;但是為調(diào)用shell進(jìn)程,然后把命令在子進(jìn)程中運(yùn)行;在執(zhí)行的命令中可使用管道符;
示例:
[root@server1 ~]# ansible all -m shell -a "echo mageedu | passwd --stdin testuser"
192.168.1.128 | CHANGED | rc=0 >>
Changing password for user testuser.
passwd: all authentication tokens updated successfully.
192.168.1.129 | CHANGED | rc=0 >>
Changing password for user testuser.
passwd: all authentication tokens updated successfully.
- file 模塊:
ansible-doc -s file
用法:- 創(chuàng)建鏈接文件:
path= 指明操作的文件
src= 要鏈接的源文件;
state= link - 修改屬性:
path=
owner=
mode=
group= - 創(chuàng)建目錄:
path=
state= directory
- 創(chuàng)建鏈接文件:
示例:
[root@server1 ~]# ansible all -m file -a "path=/var/tmp/hello.dir state=directory"
192.168.1.128 | CHANGED => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/var/tmp/hello.dir",
"secontext": "unconfined_u:object_r:user_tmp_t:s0",
"size": 6,
"state": "directory",
"uid": 0
}
192.168.1.129 | CHANGED => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/var/tmp/hello.dir",
"secontext": "unconfined_u:object_r:user_tmp_t:s0",
"size": 6,
"state": "directory",
"uid": 0
}
node1:
[root@node1 ~]# ls -d /var/tmp/hello.*
/var/tmp/hello.dir
#設(shè)定文件屬性
[root@server1 ~]# ansible all -m copy -a "src=/etc/fstab dest=/var/tmp/fstab.ansible"
[root@server1 ~]# ansible all -m file -a "src=/var/tmp/fstab.ansible path=/var/tmp/fstab.link state=link"
192.168.1.128 | CHANGED => {
"changed": true,
"dest": "/var/tmp/fstab.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"secontext": "unconfined_u:object_r:user_tmp_t:s0",
"size": 22,
"src": "/var/tmp/fstab.ansible",
"state": "link",
"uid": 0
}
192.168.1.129 | CHANGED => {
"changed": true,
"dest": "/var/tmp/fstab.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"secontext": "unconfined_u:object_r:user_tmp_t:s0",
"size": 22,
"src": "/var/tmp/fstab.ansible",
"state": "link",
"uid": 0
}
node1:
[root@node1 ~]# ll -d /var/tmp/fstab.*
-rw-r--r--. 1 root root 541 Feb 20 16:25 /var/tmp/fstab.ansible
lrwxrwxrwx. 1 root root 22 Feb 20 16:30 /var/tmp/fstab.link -> /var/tmp/fstab.ansible
- cron模塊:定義任務(wù)計(jì)劃
- minute= 幾分鐘,范圍0-59
- day= 一個(gè)月的那一天,范圍1-31,例如:1-5,/2等
- month= 哪個(gè)月,范圍1-12;
- hour= 哪個(gè)小時(shí),范圍0-23;
- weekday= 星期幾,范圍0-6;
- job= 表示 state為present時(shí),要執(zhí)行的命令;
- name= 必須指定計(jì)劃任務(wù)條目;
- state=
present:創(chuàng)建cron計(jì)劃任務(wù);默認(rèn);
absent:刪除cron計(jì)劃任務(wù);
示例:
[root@server1 ~]# ansible all -m cron -a "minute=*/3 job='/usr/sbin/update 192.168.1.254 &> /dev/null' name=text1"
192.168.1.128 | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"text1"
]
}
192.168.1.129 | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"text1"
]
}
node1:
[root@node1 ~]# crontab -l
#Ansible: text1
*/3 * * * * /usr/sbin/update 192.168.1.254 &> /dev/null
[root@server1 ~]# ansible all -m cron -a "name=text1 state=absent" #刪除定時(shí)任務(wù)
192.168.1.129 | CHANGED => {
"changed": true,
"envs": [],
"jobs": []
}
192.168.1.128 | CHANGED => {
"changed": true,
"envs": [],
"jobs": []
}
- yum模塊:安裝程序模塊
[root@server1 ~]# ansible all -m yum -a "name=nginx state=installed"
192.168.1.128 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
...
192.168.1.129 | SUCCESS => {
"changed": true,
"msg": "",
"rc": 0,
"results": [
...
node1:
[root@node1 ~]# rpm -q nginx
nginx-1.12.2-2.el7.x86_64
- service模塊:
- name= 指明管理的服務(wù)
- state=
started 啟動服務(wù);
stopped 停止服務(wù);
restarted重啟服務(wù); - enabled= 開機(jī)自動啟動;1或0
- runlevel= 在指定級別下為開機(jī)自動啟動;默認(rèn)為2345,或345級別;
- arguments 向命令行傳參數(shù);
示例:
[root@server1 ~]# ansible all -m service -a "name=nginx state=started"
192.168.1.128 | CHANGED => {
"changed": true,
"name": "nginx",
"state": "started",
"status": {
...
192.168.1.129 | CHANGED => {
"changed": true,
"name": "nginx",
"state": "started",
"status": {
...
node1:
[root@node1 ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*
...
注意:service有2個(gè)選項(xiàng):
enabled設(shè)定開機(jī)自動啟動
runlevel在哪個(gè)級別設(shè)定開機(jī)自動啟動
- spripts模塊:腳本模塊
示例:
[root@server1 ~]# vim /tmp/text.sh
#!/bin/bash
#
echo "ansible script" > /tmp/ansible.txt
[root@server1 ~]# ansible all -m script -a "/tmp/text.sh"
192.168.1.129 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.1.129 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.1.129 closed."
],
"stdout": "",
"stdout_lines": []
}
192.168.1.128 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.1.128 closed.\r\n",
"stderr_lines": [
"Shared connection to 192.168.1.128 closed."
],
"stdout": "",
"stdout_lines": []
}
- Playbook的核心元素:
- hosts:主機(jī)(關(guān)聯(lián)到的主機(jī));可以是一個(gè)或多個(gè)用冒號分隔的主機(jī)組;可以是一個(gè)主機(jī)組,也可以是一個(gè)主機(jī);這些主機(jī)必須定義在hosts iventory中;
- remoute_user:在遠(yuǎn)程主機(jī)上執(zhí)行任務(wù)的用戶;即以哪個(gè)用戶的身份運(yùn)行此任務(wù),可以全局指定,也可以在tasks中單獨(dú)指定執(zhí)行任務(wù)的用戶;即不同的任務(wù)指明不同的用戶;
- sudo_user:在使用sudo方式時(shí)執(zhí)行任務(wù)時(shí),指明臨時(shí)切換哪個(gè)用戶執(zhí)行;只是在指明以sudo的方式運(yùn)行時(shí)才使用;- tasks:任務(wù)列表;定義任務(wù)的方式主要就是調(diào)用模塊和模塊參數(shù);
- variables:變量(多次引用任務(wù)使用)
- templates:模板(包含了模板語法的文本文件)
- handlers:從處理器(由特定條件觸發(fā)的任務(wù))任務(wù),在特定條件下觸發(fā);在handlers所關(guān)注的資源發(fā)生改變時(shí)才觸發(fā)任務(wù);一般使用notify機(jī)制通知來觸發(fā);
生效方式:接收到其他任務(wù)的通知時(shí)被觸發(fā); - roles:角色
playbook的主要作用:
就是能夠把多個(gè)相關(guān)聯(lián)的任務(wù),通過讀取YAML格式的配置文件一次編完;要把任務(wù)、變量、模板、處理器放在一個(gè)YAML格式文件中進(jìn)行指定,然后任務(wù)就可一次批量執(zhí)行;
例如:
playbook的基礎(chǔ)組件hosts和tasks演示:
[root@server1 ~]# mkdir playbook
[root@server1 ~]# cd playbook/
[root@server1 playbook]# vim first.yaml
- hosts: all
remote_user: root
tasks:
- name: install redis
yum: name=redis state=latest
- name: start redis
service: name=redis state=started
[root@server1 playbook]# ansible-playbook --check first.yaml
PLAY [all] ********************************************************************************************************
TASK [Gathering Facts] #只要收集參數(shù)成功都顯示ok; ********************************************************************************************
ok: [192.168.1.128]
ok: [192.168.1.129]
TASK [install redis] #在playbook中定義的第一個(gè)任務(wù)**********************************************************************************************
changed: [192.168.1.128]
changed: [192.168.1.129]
TASK [start redis] #在playbook中定義的第二個(gè)任務(wù)************************************************************************************************
changed: [192.168.1.129]
changed: [192.168.1.128]
PLAY RECAP #返回的報(bào)告********************************************************************************************************
192.168.1.128 : ok=3 changed=2 unreachable=0 failed=0
192.168.1.129 : ok=3 changed=2 unreachable=0 failed=0
[root@server1 playbook]# ansible-playbook --list-hosts first.yaml
#查看這個(gè)playbook運(yùn)行在哪些主機(jī)
playbook: first.yaml
play #1 (all): all TAGS: []
pattern: [u'all']
hosts (2):
192.168.1.128
192.168.1.129
[root@server1 playbook]# ansible-playbook -C first.yaml #干跑一遍測試
[root@server1 playbook]# ansible-playbook first.yaml #真正執(zhí)行
- 注意:
GATHERING FACTS第一個(gè)任務(wù),是默認(rèn)的,在每一個(gè)目標(biāo)主機(jī)上運(yùn)行之前,需要知道目標(biāo)主機(jī)的狀態(tài),例如主機(jī)名、ip地址等,這些都是內(nèi)建變量,叫主機(jī)的facts變量,是ansible可調(diào)用的變量之一;這個(gè)過程就是收集變量的過程,也可以手動收集; - 如果指明了三個(gè)任務(wù),在三臺主機(jī)上運(yùn)行,執(zhí)行次序是,把第一個(gè)任務(wù)在三臺主機(jī)運(yùn)行,沒問題則在三臺主機(jī)上再運(yùn)行第二個(gè)任務(wù),如果在運(yùn)行其中某一主機(jī)出現(xiàn)故障,后面的任務(wù)會終止;
所以,任務(wù)列表,是自上而下,每個(gè)任務(wù)依次進(jìn)行的;
指明任務(wù)的格式:2種
(1) action:module arguments 較新版本支持
(2) module:arguments 所有版本通用 - shell和command模塊參數(shù)獨(dú)特,后面直接跟命令,而非key=value類的參數(shù)列表;
(1) 某任務(wù)的狀態(tài)在運(yùn)行后為changed時(shí),可通過notify通知給相應(yīng)的handlers處理器;
(2) 任務(wù)可以通過tags打標(biāo)簽,而后可在ansibles-playbook命令上使用-t指定進(jìn)行調(diào)用,可調(diào)用多個(gè)標(biāo)簽; - setup模塊:手動收集指定遠(yuǎn)程主機(jī)的變量
ansible 192.168.1.128 -m setup
示例1:安裝httpd,安裝配置文件,啟動httpd服務(wù)
[root@server1 playbook]# mkdir working
[root@server1 playbook]# cd working/
[root@server1 working]# cp /etc/httpd/conf/httpd.conf ./
[root@server1 working]# vim httpd.conf
Listen 8080
[root@server1 working]# cd ..
[root@server1 playbook]# vim web.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=present
- name: install configure file
copy: src=working/httpd.conf dest=/etc/httpd/conf/
- name: start httpd service
service: name=httpd state=started
- name: excute ss command
shell: ss -tnl | grep 8080
[root@server1 playbook]# ansible-playbook --check web.yaml #測試語法
[root@server1 playbook]# ansible-playbook web.yaml #真正執(zhí)行
注意:在ansible-playbook中執(zhí)行ss -tnl | grep :8080,這種查詢是不顯示,所以,一般不在ansible-playbook里執(zhí)行有關(guān)查詢顯示的命令;
示例2:演示使用handlers,觸發(fā)執(zhí)行;
如果把監(jiān)聽端改為808,再執(zhí)行,則不會生效,因?yàn)?,服?wù)已經(jīng)啟動了,除非重啟服務(wù),這時(shí),就應(yīng)該用到handlers處理器
[root@server1 playbook]# vim web-2.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=present
- name: install configure file
copy: src=working/httpd.conf dest=/etc/httpd/conf/
- name: start httpd service
service: name=httpd state=started
handlers:
- name: restart httpd
service: name=httpd state=restarted
[root@server1 playbook]# vim working/httpd.conf
Listen 808
[root@server1 playbook]# ansible-playbook --check web-2.yaml
[root@server1 playbook]# ansible-playbook web-2.yaml
[root@server1 playbook]# ansible websrvs -m shell -a "ss -tnl | grep 808"
192.168.1.129 | CHANGED | rc=0 >>
LISTEN 0 128 :::808 :::*
192.168.1.128 | CHANGED | rc=0 >>
LISTEN 0 128 :::808 :::*
示例3:
根據(jù)上例,如果僅修改了配置文件,卻還要從第一步,執(zhí)行安裝程序包,這樣是沒必要的,所以,可使用tag,給任務(wù)加標(biāo)簽,不指定標(biāo)簽時(shí),執(zhí)行所有任務(wù),加標(biāo)簽時(shí),只執(zhí)行標(biāo)簽所在的任務(wù);
[root@server1 playbook]# cp web-2.yaml web-3.yaml
[root@server1 playbook]# vim web-3.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd package
yum: name=httpd state=present
tags: insthttpd
- name: install configure file
copy: src=working/httpd.conf dest=/etc/httpd/conf/
tags: instconf
- name: start httpd service
service: name=httpd state=started
tags: starthttpd
handlers:
- name: restart httpd
service: name=httpd state=restarted
[root@server1 playbook]# vim working/httpd.conf
Listen 80
[root@server1 playbook]# ansible-playbook -t insthttpd --check web-3.yaml
[root@server1 playbook]# ansible-playbook -t instconf,insthttpd --check web-3.yaml #調(diào)用多個(gè)標(biāo)簽;
- variables:變量
- 1) facts:任何facts變量都由正在通信的目標(biāo)主機(jī)發(fā)回的信息,ansible自動獲取變量,可直接調(diào)用;在setup模塊中查看變量;
- 2)ansible-playbook命令的命令行中的自定義變量;
-e VARS, --extra-vars=VARS - 3)通過roles傳遞變量;
- 4)Host Inventory
- a)向不同的主機(jī)傳遞不同的變量;
- b)向組中的主機(jī)傳遞相同的變量;
[groupname:vars]
variable=value
-
注意:invertory參數(shù):
用于定義ansible遠(yuǎn)程路徑目標(biāo)主機(jī)時(shí)使用的參數(shù),而非傳遞給playbook的變量;
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansible_sudo_pass
...
通常ansible中的inventory還有專門參數(shù),不叫變量,因?yàn)樗皇莻鬟f給playbook使用的,而是通過ansible連接每個(gè)被管理主機(jī)時(shí)使用的;
示例1:演示ansible-playbook命令行調(diào)用變量
[root@server1 playbook]# vim forth.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install {{ pkname }}
yum: name={{ pkname }} state=present
[root@server1 playbook]# ansible-playbook -e pkname=memcached --check forth.yaml
[root@server1 playbook]# ansible-playbook -e pkname=memcached forth.yaml
- playbook的其它組件:
- 變量:5種
ansible facts可使用setup模塊獲?。皇占h(yuǎn)程主機(jī)變量;
ansible-playbook -e "var=value"自定義變量
host variable:host iventory主機(jī)變量
group variable(主機(jī)組上的變量)
roles - 變量調(diào)用方法:{{ variable }}
- 變量:5種
在playbook中定義變量的方法:
vars:
- var1: value1
- var2: valure2
注意:這種變量有個(gè)缺陷,要想改變變量值時(shí)都要改變配置文件,不過可在調(diào)用時(shí)覆蓋其變量的值;
- templates模塊:基于模板方式生成一個(gè)文件復(fù)制到遠(yuǎn)程主機(jī);
src= 指定本地jinja2的模板文件路徑
dest= 遠(yuǎn)程主機(jī)路徑
owner= 屬主
group= 屬組
mode= 權(quán)限-
模板:templates
就是文本文件,內(nèi)部嵌套有腳本(這個(gè)腳本使用模板編程語言編寫)
python只有在實(shí)現(xiàn)web框架時(shí)進(jìn)行嵌入,將自己基于模板編程語言嵌入到其它文本中的機(jī)制,它的模板編程語言叫jinja2嵌入式的編程語言;類似于playbook,在python中叫resource資源和清單facts;在清單中定義資源時(shí)或定義使用的模板時(shí)會用到rubby的模板編程語言;
jinja2模板編程語言所實(shí)現(xiàn)的功能是,可以在文本文件中,使用一個(gè)所謂的嵌入的標(biāo)記語法,引入一段模板編程語言所編寫的腳本;而這種腳本無法就是支持比較簡單的編程元素,如條件判斷、(迭代)循環(huán)、變量;- jinja2:模板編程語言
字面量:是常見的python對象
字符串:一般使用單引號或雙引號;
數(shù)字:整數(shù),浮點(diǎn)數(shù);
列表:使用[item1,tiem2,..],是可變的數(shù)據(jù)結(jié)構(gòu);
元組:(item1,item2,...),是不可變的數(shù)據(jù)結(jié)構(gòu);
字典:{key1:value1,key2:value2,...},就是鍵值對的組合;
key一般為字符串所以要用引號;
布爾型:true/false- 算術(shù)運(yùn)算:
+,-,,/, //只留商,%只留余數(shù),*
比較操作:
==, !=, >, >=, <, <=
邏輯運(yùn)算:
and,or,not
- 算術(shù)運(yùn)算:
- jinja2:模板編程語言
-
演示模板使用:使用ansible在二臺主機(jī)上,安裝nginx,提供配置文件,但其中的worker_processores的值要與主機(jī)的cpu核心數(shù)相同;此時(shí),就可把配置文件基于模板方式提供,而這個(gè)worker_processores的值,放的是jinja2所支持的變量,直接使用變量的方式放在那個(gè)位置,而本機(jī)的template模塊會自動套用這里面變量的值,給ansible facts所報(bào)告的結(jié)果,并把它生成在這個(gè)文件中,而后復(fù)制到目標(biāo)主機(jī)上去;這就是模板的作用;
示例:
[root@server1 ~]# ansible all -m yum --check -a "name=nginx state=latest" #測試安裝nginx
[root@server1 ~]# ansible all -m yum -a "name=nginx state=latest" #安裝nginx
[root@server1 ~]# mkdir files
[root@server1 ~]# cp /etc/nginx/nginx.conf /root/files/nginx.conf.j2
[root@server1 ~]# cd files
[root@server1 files]# vim nginx.conf.j2
修改:
worker_processes {{ ansible_processor_vcpus }};
[root@server1 files]# vim nginx.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: Install nginx
yum: name=nginx state=present
- name: Install config file
template: src=/root/files/nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: start service
service: name=nginx state=started
handlers:
- name: restart nginx
service: name=nginx state=restarted
[root@server1 files]# ansible-playbook nginx.yaml --check
[root@server1 files]# ansible-playbook nginx.yaml
可使用主機(jī)變量,讓不同主機(jī)監(jiān)聽不同端口:
[root@server1 files]# vim /etc/ansible/hosts
[websrvs]
192.168.1.128 http_port=80 #定義主機(jī)變量
192.168.1.129 http_port=8080
[root@server1 files]# vim nginx.conf.j2
修改:
listen {{ http_port }};
[root@server1 files]# ansible-playbook nginx.yaml --check
[root@server1 files]# ansible-playbook nginx.yaml
條件測試:when示例
]# scp root@192.168.1.105:/etc/nginx/nginx.conf files/nginx.conf.c6.j2 復(fù)制一個(gè)centos6上的nginx配置文件;
]# vim files/nginx.conf.c6.j2
worker_processes {{ ansible_processor_vcpus }};
]# vim nginx.yaml
- hosts: all
remote_user: root
tasks:
- name: install nginx
yum: name=nginx state=present
- name: install conf file to c7
template: src=files/nginx.conf.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
notify: restart nginx
tags: instconf
- name: install conf file to c6
template: src=files/nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
notify: restart nginx
tags: instconf
- name: start nginx service
service: name=nginx state=started
handlers:
- name: restart nginx
service: name=nginx state=restarted
示例:
同時(shí)安裝nginx、memcached、php-fpm等程序包,使用循環(huán)
]# vim iter.yaml
- hosts: all
remote_user: root
tasks:
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
- role 角色
有3組服務(wù)器web、db、ha都用到時(shí)間同步服務(wù),當(dāng)編寫三個(gè)yaml文件分別適用于這3組服務(wù)器時(shí),每個(gè)文件都要寫一遍時(shí)間同步的功能;或另有一種情況,假如第一組服務(wù)器即是web又是db,第二組服務(wù)器只是db,第三組服務(wù)器只是web,此時(shí)要寫yaml文件,如果要寫一個(gè)db的,再寫一行web的,還要寫一個(gè)db和web合并的,如果還要memcached服務(wù)器,而有些在db上,有些在web上,在這種場景中,代碼在不同的主機(jī)角色間靈活組合,而這對于此前固化在yaml中的格式顯然是不適用的;
如果把每一種配置的定義的功能獨(dú)立化,而且誰用到時(shí)誰去調(diào)用即可;這種可獨(dú)立化的配置通常按照功能為基準(zhǔn)進(jìn)行劃分的;如果服務(wù)器安裝了某種功能就扮演成了某種角色;即把db功能的定義一個(gè)角色,web功能的配置定義一個(gè)角色,memcached功能配置定義一個(gè)角色等等;需要什么就事先定義好什么,放在特定目錄下,當(dāng)主機(jī)需要進(jìn)行配置時(shí),寫一個(gè)yaml配置文件,在其里面指明用在哪個(gè)主機(jī)上、使用remote_user基于哪個(gè)運(yùn)行、調(diào)用角色即可;
這就是角色機(jī)制,是自包含的,為了讓服務(wù)器能夠調(diào)用其中的角色實(shí)現(xiàn)某種功能,所需要的一切代碼、文件的集合都放在一個(gè)特定位置,這個(gè)組件就稱為角色;
角色的好處是跟主機(jī)是分離的,誰用誰調(diào)用;
對于playbook而言,角色就是在playbook中所應(yīng)該定義各種組件的集合;但此前是寫在playbook一個(gè)文件中的,而如果要變成角色,要扮演成一個(gè)單獨(dú)的目錄,角色名就是目錄名;
每一個(gè)角色一般按固定格式定義,任何角色都不能引用自己目錄以外的資源,這樣把這個(gè)目錄復(fù)制到任何主機(jī)上都可以用,這就是自包含應(yīng)該指明file子目錄;所有的模板放在templates子目錄下;所有的任務(wù)放在tasks子目錄下,所有的處理器放在handlers子目錄下;所有變量放在vars子目錄下;還有一個(gè)補(bǔ)充meta子目錄;
不是所有目錄必須得有,一般用到哪些目錄,就給出哪些目錄即可;這就是角色的目錄組織形式;
角色(role);/etc/ansible/roles也可在ansible.cfg中定義;
一般為目錄,每一個(gè)角色就是一個(gè)子目錄;
角色集合:
roles/
mysql/
httpd/
nginx/
memcached/每個(gè)角色,以特定的層級目錄結(jié)構(gòu)進(jìn)行組織:
mysql/
files/:存放由copy或script模塊等調(diào)用的文件;
templates/:存放為template模塊查找所需的模板文件目錄;
tasks/:至少應(yīng)該包含一個(gè)名為main.yml的文件;其它文件需要在此文件中通過include進(jìn)行包含;
handlers/:至少應(yīng)該包含一個(gè)名為main.yml的文件;其它文件需要在此文件中通過include進(jìn)行包含;
vars/:至少應(yīng)該包含一個(gè)名為main.yml的文件;其它文件需要在此文件中通過include進(jìn)行包含;
meta/:定義當(dāng)前角色的特殊設(shè)定及其依賴關(guān)系;至少應(yīng)該包含一個(gè)名為main.yml的文件;其它文件需要在此文件中通過include進(jìn)行包含;
default/:設(shè)定默認(rèn)變量時(shí)使用此目錄中的main.yml文件;在playbook調(diào)用角色方法1:
- hosts: websrvs
remote_user: root
roles:
- mysql
- memcached
- nginx
- 在playbook調(diào)用角色方法2:在角色調(diào)用時(shí),傳遞變量給角色
- hosts:
remote_user:
roles:
- { role: nginx, username: nginx }
#鍵role用于指定角色名稱,后續(xù)的k/v用于傳遞變量給角色;
#還可以基于條件測試實(shí)現(xiàn)角色調(diào)用;
roles:
- { role: nginx, when: "ansible_distribution_major_version == '7'" }
Ansible實(shí)現(xiàn)主/備模式主可用

安裝ansible
[root@localhost ~]# yum -y install ansible keepalive編輯主機(jī)清單
[root@localhost ~]# vim /etc/ansible/host
[websrvs]
192.168.1.115
192.168.1.116
[hasrvs]
192.168.1.10
192.168.1.11
- 創(chuàng)建固定目錄結(jié)構(gòu)
[root@localhost ~]# mkdir -pv /etc/ansible/roles/{keepalived,nginx}/{files,tasks,templates,handlers,vars,default,meta}
[root@localhost ~]# tree /etc/ansible/roles/
/etc/ansible/roles/
├── keepalived
│ ├── default
│ ├── files
│ ├── handlers
│ ├── meta
│ ├── tasks
│ ├── templates
│ └── vars
└── nginx
├── default
├── files
├── handlers
├── meta
├── tasks
│ └── main.yml
├── templates
│ └── index.html.j2
└── vars
- 基于密鑰連接node1、node2、r1、r2、
[root@localhost ~]# ssh-keygen -t rsa -P ""
[root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.10
[root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.11
[root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.115
[root@localhost ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.116
- 編輯roles
[root@localhost ~]# vim /etc/ansible/roles/keepalived/tasks/main.yml
#編輯如下內(nèi)容
- name: install keepalived
yum: name=keepalived state=latest
when: ansible_os_family == "RedHat"
- name: install conf
template: src=kl.conf.j2 dest=/etc/keepalived/keepalived.conf
tags: conf
notify: restart keepalived
- name: start keepalived
service: name=keepalived state=started enabled=yes
[root@localhost ~]# vim /etc/ansible/roles/keepalived/handlers/main.yml
- name: restart keepalived
service: name=keedpalived state=restarted
- 編輯keepalived配置文件,并定義變量
[root@localhost ~]# vim /etc/ansible/roles/keepalived/templates/kl.conf.j2
! Configuration: command not found
global_defs {
notification_email {
root@localhost
}
notification_email_from keepalived@localhost
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id {{ ansible_fqdn }}
vrrp_mcast_group4 224.1.105.33
}
vrrp_instance VI_1 {
state {{ kl_status }}
interface ens33
virtual_router_id 33
priority {{ kl_priority }}
advert_int 1
authentication {
auth_type PASS
auth_pass XXXX1111
}
virtual_ipaddress {
192.168.1.99 dev ens33 label ens33:0
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
virtual_server 192.168.1.99 80 {
delay_loop 1
lb_algo wrr
lb_kind DR
protocol TCP
sorry_server 127.0.0.1 80
real_server 192.168.1.115 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
nb_get_retry 3
delay_before_retry 2
connect_timeout 3
}
}
real_server 192.168.1.116 80 {
weight 1
HTTP_GET {
url {
path /index.html
status_code 200
}
nb_get_retry 3
delay_before_retry 2
connect_timeout 3
}
}
}
[root@localhost files]# vim /etc/ansible/hosts
[hasrvs]
192.168.1.10 kl_status=MASTER kl_priority=100
192.168.1.11 kl_status=BACKUP kl_priority=96
- 配置nginx的roles
[root@localhost files]# vim /etc/ansible/roles/nginx/tasks/main.yml
- name: Install nginx
yum: name=nginx state=latest
- name: Install conf
template: src=index.html.j2 dest=/usr/share/nginx/html/index.html
notify: reload nginx
- name: start script
script: /root/files/setkl.sh start
notify: reload nginx
- name: start nginx
service: name=nginx state=started
[root@localhost files]# vim /etc/ansible/roles/nginx/templates/index.html.j2
<h1> {{ ansible_fqdn }} </h1>
[root@localhost files]# vim /etc/ansible/roles/nginx/handlers/main.yml
- name: reload nginx
service: name=nginx state=reload
- 編輯keepalived和nginx的playbook
[root@localhost ~]# cd files
[root@localhost files]# vim kl.yml
- hosts: hasrvs
remote_user: root
roles:
- keepalived
[root@localhost files]# vim nginx.yml
- hosts: websrvs
remote_user: root
roles:
- nginx
- 測試并執(zhí)行
[root@localhost files]# ansible-playbook --check kl.yml
[root@localhost files]# ansible-playbook --check kl.yml
[root@localhost files]# ansible-playbook --check nginx.yml
[root@localhost files]# ansible-playbook nginx.yml
- 訪問測試
[root@localhost files]# curl http://192.168.1.99
<h1> rs1.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs2.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs1.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs2.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs1.ilinux.com </h1>
node1:規(guī)則已生成
[root@node1 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.99:80 wrr
-> 192.168.1.115:80 Route 1 0 3
-> 192.168.1.116:80 Route 1 0 2
[root@node1 ~]# ifconfig
ens33: ...
ens33:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.1.99 netmask 255.255.255.255 broadcast 0.0.0.0
ether 00:0c:29:6d:e2:f7 txqueuelen 1000 (Ethernet)
[root@node1 ~]# systemctl stop keepalived.service
node2:
[root@node2 ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.99:80 wrr
-> 192.168.1.115:80 Route 1 0 0
-> 192.168.1.116:80 Route 1 0 0
#使用客戶端訪問:
[root@localhost files]# curl http://192.168.1.99
<h1> rs2.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs1.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs2.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs1.ilinux.com </h1>
[root@localhost files]# curl http://192.168.1.99
<h1> rs2.ilinux.com </h1>