企業自動化運維ansible

自動化運維工具ansible

  • 運維自動化發展歷程及技術應用
  • mark
  • mark

雲計算工程師核心職能

  • mark
  • Linux運維工程師職能劃分
    mark

自動化動維應用場景

  • 文件傳輸
  • 命令執行
    • 應用部署
    • 配置管理
    • 任務流編排

企業實際應用場景分析

1 Dev開發環境

使用者:程序員
功能:程序員開發軟件,測試BUG的環境
管理者:程序員

2 測試環境

使用者:QA測試工程師
功能:測試經過Dev環境測試通過的軟件的功能
管理者:運維
說明:測試環境往往有多套,測試環境滿足測試功能即可,不宜過多
(1)測試人員希望測試環境有多套,公司的產品多產品線併發,即多個版本,意味着多個版本同步測試
(2)通常測試環境有多少套和產品線數量保持一樣

3 發佈環境:代碼發佈機,有些公司爲堡壘機(安全屏障)

使用者:運維
功能:發佈代碼至生產環境
管理者:運維(有經驗)
發佈機:往往需要有2臺(主備)

4 生產環境

使用者:運維,少數情況開放權限給核心開發人員,極少數公司將權限完全開放給開發人員並其維護
功能:對用戶提供公司產品的服務
管理者:只能是運維
生產環境服務器數量:一般比較多,且應用非常重要。往往需要自動工具協助部署配置應用

5 灰度環境(生產環境的一部分)

使用者:運維
功能:在全量發佈代碼前將代碼的功能面向少量精準用戶發佈的環境,可基於主機或用戶執行灰度發佈
案例:共100臺生產服務器,先發布其中的10臺服務器,這10臺服務器就是灰度服務器
管理者:運維
灰度環境:往往該版本功能變更較大,爲保險起見特意先讓一部分用戶優化體驗該功能,待這部分用戶使用沒有重大問題的時候,再全量發佈至所有服務器

程序發佈

  • 預發佈驗證
    • 新版本的代碼先發布到服務器(跟線上環境配置完全相同,只是未接入到調度器)
  • 程序發佈:
    • 不能導致系統故障或造成系統完全不可用
    • 不能影響用戶體驗
  • 灰度發佈:
  • 發佈路徑:
把原來的舊版本保留
/webapp/tuangou-1.1
/webapp/tuangou
/webapp/tuangou-1.2
  • 發佈過程:在調度器上下線一批主機(標記爲maintanance狀態) –> 關閉服務 –> 部署新版本的應用程序 –> 啓動服務 –> 在調度器上啓用這一批服務器
  • 自動化灰度發佈:腳本、發佈平臺

常用自動化運維工具

  • Ansible:python,Agentless,中小型應用環境(不需要在客戶端安裝代理程序,基於ssh來管理,300-500臺服務器)
  • Saltstack:python,一般需部署agent,執行效率更高
  • Puppet:ruby, 功能強大,配置複雜,重型,適合大型環境
  • Fabric:python,agentless
  • Chef: ruby,國內應用少
  • Cfengine
  • func

企業級自動化運維工具應用實戰ansible

  • 公司計劃在年底做一次大型市場促銷活動,全面衝刺下交易額,爲明年的上市做準備。公司要求各業務組對年底大促做準備,運維部要求所有業務容量進行三倍的擴容,並搭建出多套環境可以共開發和測試人員做測試,運維老大爲了在年底有所表現,要求運維部門同學儘快實現,當你接到這個任務時,有沒有更快的解決方案?

Ansible發展史

  • Ansible
    • 創始人,Michael DeHaan( Cobbler 與 Func 的作者)
    • 2012-03-09,發佈0.0.1版,紅帽收購
    • 2015-10-17,Red Hat宣佈收購
  • 同類自動化工具 GitHub關注程度( 2016- - 07- - 10)
  • mark

特性

  • 模塊化:調用特定的模塊,完成特定任務
  • 有Paramiko,PyYAML,Jinja2(模板語言)三個關鍵模塊
  • 支持自定義模塊
  • 基於Python語言實現
  • 部署簡單,基於python和SSH(默認已安裝),agentless
  • 安全,基於OpenSSH
  • 支持playbook編排任務
  • 冪等性:一個任務執行1遍和執行n遍效果一樣,不因重複執行帶來意外情況
  • 無需代理不依賴PKI(無需ssl)
  • 可使用任何編程語言寫模塊
  • YAML格式,編排任務,支持豐富的數據結構
  • 較強大的多層解決方案

ansible架構

-mark
- ansible是基於key的,所以需要將主機間實現key驗證。當然用密碼也可以,只是比較麻煩

Ansible工作原理

  • mark
    1. 直接使用ansible命令來執行一條命令
    2. 當生產環境穩定後可以用ansible編寫playboot腳本來執行
    3. 可以使用公有云或私有云
    4. 可以使用CMDB,配置管理數據庫

Ansible主要組成部分

  • ANSIBLE PLAYBOOKS:任務劇本(任務集),編排定義Ansible任務集的配置文件,由Ansible順序依次執行,通常是JSON格式的YML文件
  • INVENTORY:Ansible管理主機的清單/etc/anaible/hosts
  • MODULES:Ansible執行命令的功能模塊,多數爲內置的核心模塊,也可自定義
  • PLUGINS:模塊功能的補充,如連接類型插件、循環插件、變量插件、過濾插件等,該功能不常用
  • API:供第三方程序調用的應用程序編程接口
  • ANSIBLE:組合INVENTORY、API、MODULES、PLUGINS的綠框,可以理解爲是ansible命令工具,其爲核心執行工具
  • Ansible命令執行來源:
    • USER,普通用戶,即SYSTEM ADMINISTRATOR
    • CMDB(資產管理系統) API 調用
    • PUBLIC/PRIVATE CLOUD API調用
    • USER-> Ansible Playbook -> Ansibile
  • 利用ansible實現管理的方式:
    • Ad-Hoc 即ansible命令,主要用於臨時命令使用場景
    • Ansible-playbook 主要用於長期規劃好的,大型項目的場景,需要有前提的規劃
      -Ansible-playbook(劇本)執行過程:
    • 將已有編排好的任務集寫入Ansible-Playbook
    • 通過ansible-playbook命令分拆任務集至逐條ansible命令,按預定規則逐條執行
  • Ansible主要操作對象:
    • HOSTS主機
    • NETWORKING網絡設備
  • 注意事項
    • 執行ansible的主機一般稱爲主控端,中控,master或堡壘機
    • 主控端Python版本需要2.6或以上
    • 被控端Python版本小於2.4需要安裝python-simplejson
    • 被控端如開啓SELinux需要安裝libselinux-python
    • windows不能做爲主控端

安裝

rpm包安裝: EPEL源

yum install ansible
ansible不是一個服務/etc/hosts是最重要的文件
ansible是一個管理端

編譯安裝

yum -y install python-jinja2 PyYAML python-paramiko
python-babel python-crypto
tar xf ansible-1.5.4.tar.gz
cd ansible-1.5.4
python setup.py build
python setup.py install
mkdir /etc/ansible
cp -r examples/* /etc/ansible

Git方式

git clone git://github.com/ansible/ansible.git --
recursive

cd ./ansible
source ./hacking/env-setup

pip安裝: pip是安裝Python包的管理器,類似yum

yum install python-pip python-devel
yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel
pip install --upgrade pip
pip install ansible --upgrade
  • 確認安裝: ansible –version

相關文件

配置文件

/etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性
/etc/ansible/hosts 主機清單被管理端的主機存放,如果將主機不寫入這個文件則無法管理這個主機
/etc/ansible/roles/ 存放角色的目錄
  • 如果要管理的ip沒加入到hosts這文件中則會出現這種錯誤
[root@centos7 yum.repos.d]# ansible 192.168.27.101 -m ping
 [WARNING]: Could not match supplied host pattern, ignoring: all

 [WARNING]: provided hosts list is empty, only localhost is available

 [WARNING]: Could not match supplied host pattern, ignoring: 192.168.27.101

 [WARNING]: No hosts matched, nothing to do
  • 將主機加入到hosts文件中,最簡單的方法是將要管理的主機ip寫進去,推薦,用分類的方式
    -mark
  • 分類的方式
[root@centos7 yum.repos.d]# vim /etc/ansible/hosts 
#   - Blank lines are ignored
#   - Groups of hosts are delimited by [header] elements
#   - You can enter hostnames or ip addresses
#   - A hostname/ip can be a member of multiple groups
192.168.27.[101:103]   也可以寫成這種格式這表示192.168.27.101103直接的ip


# Ex 1: Ungrouped hosts, specify before any group headers.

## green.example.com
## blue.example.com
## 192.168.100.1
## 192.168.100.10

# Ex 2: A collection of hosts belonging to the 'webservers' group

## [webservers]
## alpha.example.org
## beta.example.org
## 192.168.1.100
## 192.168.1.110

# If you have multiple hosts following a pattern you can specify
# them like this:

## www[001:006].example.com

# Ex 3: A collection of database servers in the 'dbservers' group

## [dbservers]
## 
## db01.intranet.mydomain.net
## db02.intranet.mydomain.net
## 10.25.1.56
## 10.25.1.57

# Here's another example of host ranges, this time there are no
# leading 0s:

## db-[99:101]-node.example.com
  • 然後在次用ping命令來檢查主機是否活躍
  • mark
  • 因爲ansible是基於shh的,第一次鏈接需要輸入yes/no,不是很方便,想要去掉這個yes/no需要修改配置文件/etc/ansible/ansible.cfg這個文件
  • mark
  • 把host_key_checking = False這一行註釋去掉
  • 在重新執行就不會提示這樣第一次yes或no
  • mark
  • 但是報錯,也沒有讓我們輸入密碼,ansible默認是基於key驗證的,如果想使用密碼在後面加-k
  • mark
  • 這樣就成功了,當然我們也可以多臺主機,主機ip之間用逗號隔開
  • mark
  • 當然我們只用輸入一遍密碼兩個主機都成功了,說明如果主機密碼不一樣會報錯
  • mark

用分組的方式將被管理主機寫如/etc/ansible/ansible.cfg文件中

  • mark
  • 分組就是將一組主機分成一組,並在中括號裏取一個組名,一個主機可以在多個組裏。還有一個默認組就是all,這個組表示在這個文件中的所有主機
  • mark

創建key驗證

  1. 用ssh-keygen 生成公鑰私鑰對
    • mark
[root@ansible ~]# cd ~
[root@ansible ~]# cd .ssh/
[root@ansible .ssh]# ls
id_rsa  id_rsa.pub  known_hosts
[root@ansible .ssh]# 
  1. 用ssh-copy-id 要連接的ip主機
    • mark
    • 完成key驗證後,就不用加-k選項了
    • mark

由於ansible默認是沒有啓用日誌的,所以我們要在配置文件中啓用配置文件

  • mark
    mark
  • 默認也是沒有啓用的,把註釋去掉啓用,當然也可改成其它路徑
  • 執行以下ansible命令,然後看一下日誌文件
  • mark
  • 這裏面存放着命令的執行結果

程序

/usr/bin/ansible 主程序,臨時命令執行工具
/usr/bin/ansible-doc 查看配置文檔,模塊功能查看工具
/usr/bin/ansible-galaxy 下載/上傳優秀代碼或Roles模塊的官網平臺
/usr/bin/ansible-playbook 定製自動化任務,編排劇本工具
/usr/bin/ansible-pull 遠程執行命令的工具
/usr/bin/ansible-vault 文件加密工具
/usr/bin/ansible-console 基於Console界面與用戶交互的執行工具

主機清單inventory

  • Inventory 主機清單
    • ansible的主要功用在於批量主機操作,爲了便捷地使用其中的部分主機,可以在inventory file中將其分組命名
  • 默認的inventory file爲/etc/ansible/hosts
  • inventory file可以有多個,且也可以通過DynamicInventory來動態生成
  • /etc/ansible/hosts文件格式
  • inventory文件遵循INI文件風格,中括號中的字符爲組名。可以將同一個主機同時歸併到多個不同的組中;此外,當如若目標主機使用了非默認的SSH端口,還可以在主機名稱之後使用冒號加端口號來標明
ntp.magedu.com
[webservers]
www1.magedu.com:2222
www2.magedu.com
[dbservers]
db1.magedu.com
db2.magedu.com
db3.magedu.com
  • 如果主機名稱遵循相似的命名模式,還可以使用列表的方式標識各主機
    示例
[websrvs]
www[01:100].example.com
[dbsrvs]
db-[a:f].example.com

ansible配置文件

Ansible 配置文件/etc/ansible/ansible.cfg (一般保持默認)
[defaults]
#inventory = /etc/ansible/hosts # 主機列表配置文件
#library = /usr/share/my_modules/ # 庫文件存放目錄
#remote_tmp = $HOME/.ansible/tmp #臨時py命令文件存放在遠程主機目錄,就是當我們執行命令是相當於把命令複製到遠程主機中這個目錄下生成一個臨時文件,執行完後刪除
#local_tmp = $HOME/.ansible/tmp # 本機的臨時命令執行目錄
#forks = 5 # 默認併發數,如果有100臺主機就會5臺5臺的執行,分批次的,也可以調100,要求機器性能好
#sudo_user = root # 默認sudo 用戶,需要在被管理主機上做sudo配置
#ask_sudo_pass = True #每次執行ansible命令是否詢問ssh密碼
#ask_pass = True
#remote_port = 22  因爲是基於ssh,ssh默認是22端口,如果ssh端口號改成其它的,這裏也是要改的
#host_key_checking = False # 檢查對應服務器的host_key,建議取消註釋

ansible系列命令

  • Ansible系列命令
ansible ansible-doc ansible-playbook ansible-vault
ansible-console ansible-galaxy ansible-pull
  • ansible-doc: 顯示模塊幫助
    ansible-doc [options] [module...]
    -a 顯示所有模塊的文檔
    -l, --list 列出可用模塊
    -s, --snippet 顯示指定模塊的playbook片段

示例

ansible-doc –l 列出所有模塊
ansible-doc ping 查看指定模塊幫助用法
ansible-doc –s ping 查看指定模塊幫助用法簡要信息
  • mark
  • mark

  • ansible通過ssh實現配置管理、應用部署、任務執行等功能,建議配置ansible端能基於密鑰認證的方式聯繫各被管理節點
  • ansible [-m module_name] [-a args]
--version 顯示版本
-m module 指定模塊,默認爲command模塊
-v 詳細過程 –vv -vvv更詳細
--list-hosts 顯示主機列表,可簡寫—list
-k, --ask-pass 提示連接密碼,默認Key驗證
-K, --ask-become-pass 提示輸入sudo
-C, --check 檢查,並不執行,只是模擬的執行一次,並不會在真正的主機上執行
-T, --timeout=TIMEOUT 執行命令的超時時間,默認10s
-u, --user=REMOTE_USER 執行遠程執行的用戶,指定以哪個用戶執行,如果不指定則默認是root
-b, --become 代替舊版的sudo 切換
  • 顯示主機列表
  • mark
  • 指定用戶
  • mark
  • 也可以用sudo,提前是要把對端主機上配置好sudo文件
    1. 配置sudo文件,這裏我們直接把用戶加入wheel組中,因爲wheel組中在sudo是一個管理員組,擁有root的權限
  • mark
  • 這裏用command模塊是命令模塊,加-a是可以後面跟參數,但是這裏報錯,讓我們輸入sudo的密碼加上大K參數
  • mark
  • 這裏會讓輸入兩邊口令,一個是guo用戶ssh的口令,一個sudo的口令,這樣會很麻煩,我們改一下sudo配置文件設置成不輸入此密碼,在/etc/sudoers
  • mark
  • 這樣就只用輸入一個ssh口令了
    mark

如何將guo用戶也設置成key驗證呢

  1. 用命令ssh-copy-i [email protected]
    -mark
    • 在執行以下就不用輸入密碼了
    • mark
usermod -aG wheel guo

ansible的Host-pattern

  • ansible的Host-pattern
    • 匹配主機的列表
    • All :表示所有Inventory中的所有主機
      • ansible all –m ping
    • *:通配符
      • ansible “*” -m ping 這個”*”號相當於all全部主機
        “`bash
      • mark
      • ansible 192.168.1.* -m ping
      • ansible “*srvs” -m ping
    • 或關係
      • ansible “websrvs:appsrvs” -m ping 表示這兩個都執行可以加多個
      • ansible “192.168.1.10:192.168.1.20” -m ping
      • mark
  • 邏輯與
    • ansible ‘websrvs:&dbsrvs’ –m ping 就是取交集
      • 在websrvs組並且在dbsrvs組中的主機
      • mark
  • 邏輯非
    • ansible ‘websrvs:!dbsrvs’ –m ping
    • 在websrvs組,但不在dbsrvs組中的主機
    • mark
  • 綜合邏輯
    • ansible ‘websrvs:dbsrvs:&appsrvs:!ftpsrvs’ –m ping
  • 正則表達式
    • ansible “websrvs:&dbsrvs” –m ping
    • ansible “~(web|db).*.magedu.com” –m ping
    • mark
    • mark
      • 這裏的波浪符表示是一個正則表達式,點在正則表示任意字符,所有要用反向單引號轉義

ansible命令執行過程

  • ansible命令執行過程可以用-vvv來查看執行過程
  • 可以用-vvv來查看命令執行的詳細過程[root@ansible ~]# ansible ‘~(web|db|ag)ser’ -m command -a “ls /root” -vvv
    1. 加載自己的配置文件 默認/etc/ansible/ansible.cfg
    2. 加載自己對應的模塊文件,如command
    3. 通過ansible將模塊或命令生成對應的臨時py文件,並將該 文件傳輸至遠程服務器的對應執行用戶$HOME/.ansible/tmp/ansible-tmp-數字/XXX.PY文件
    4. 給文件+x執行
    5. 執行並返回結果
    6. 刪除臨時py文件,sleep 0退出
  • 執行狀態:
    • 顏色的定義在ansible的配置文件裏定義的
    • mark
    • 綠色:執行成功並且不需要做改變的操作
    • 黃色:執行成功並且對目標主機做變更
    • 紅色:執行失敗

ansible使用示例

  • 以wang用戶執行ping存活檢測
    • ansible all -m ping -u wang -k
  • 以wang sudo至root執行ping存活檢測
    • ansible all -m ping -u wang –b -k
  • 以wang sudo至mage用戶執行ping存活檢測
    • ansible all -m ping -u wang –b -k –become-user mage
  • 以wang sudo至root用戶執行ls
    • ansible all -m command -u wang –become-user=root -a’ls /root’ -b –k -K

ansible常用模塊

  • ping :探測對方主機是否在開機,這裏的ping模塊並不是用ICMP協議的
    “bash
    將主機設置爲禁止ping
    [root@localhost ~]# cat /proc/sys/net/ipv4/icmp_echo_ignore_all
    0
    [root@localhost ~]# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
    現在在測這個主機
    [root@ansible .ssh]# ansible 192.168.27.101 -m ping
    192.168.27.101 | SUCCESS => {
    “changed”: false,
    “ping”: “pong”
    }
    [root@ansible .ssh]# ping 192.168.27.101
    PING 192.168.27.101 (192.168.27.101) 56(84) bytes of data.
    ^C
    — 192.168.27.101 ping statistics —
    6 packets transmitted, 0 received, 100% packet loss, time 5002ms
    如果把ssh服務停了也是可以執行成功的,只有把網絡服務停了纔會失敗
> Command:在遠程主機執行命令,默認模塊,可忽略-m選項  
-a是後面要執行的參數  
- 參數
    + chdir 運行command命令前先cd到這個目錄
    + creates 如果這個參數對應的文件存在,就不運行command
    + executable 將shell切換爲command執行,這裏的所有命令需要使用絕對路徑
    + removes 如果這個參數對應的文件不存在,就不運行command
```bash  
ansible srvs -m command -a 'service vsftpd start'
ansible srvs -m command -a 'echo magedu |passwd --stdin wang' 不成功
此命令不支持 $VARNAME < > | ; & 等,用shell模塊實現
用chdir進入到某個目錄來執行參數
[root@ansible ~]# ansible 'dbser' -m command -a 'chdir=/app/ ls'
192.168.27.102 | SUCCESS | rc=0 >>
123

192.168.27.128 | SUCCESS | rc=0 >>
1
aaa
access_log
awk.txt
dir
f1.txt
f2
lost+found
passwd
[root@ansible ~]# ansible 'dbser' -m command -a 'chdir=/app/ creates=123 ls'  
192.168.27.102 | SUCCESS | rc=0 >>
skipped, since 123 exists  這裏寫着123這個文件存在就跳過,而另一個主機沒有對應的文件所有執行ls

192.168.27.128 | SUCCESS | rc=0 >>
1
aaa
access_log
awk.txt
dir
f1.txt
f2
lost+found
passwd




<div class="se-preview-section-delimiter"></div>
  • mark
  • 如果文件不存在則不執行
    mark

    Shell:和command相似,用shell執行命令

  • 常用參數
    • chdir 跟command一樣的,運行shell之前cd到某個目錄
    • creates 跟command一樣的,如果某個文件存在則不運行shell
    • remove 跟command一樣的,如果某個文件不存在則不運行shell
ansible srv -m shell -a 'echo magedu |passwd –stdin wang'
調用bash執行命令 類似 cat /tmp/stanley.md | awk -F'|''{print $1,$2}' &> /tmp/example.txt 這些複雜命令,即使使用shell也可能會失敗,解決辦法:寫到腳本時,copy到遠程,執行,再把需要的結果拉回執行命令的機器
查看主機名
[root@ansible ~]# ansible 'dbser' -m shell -a  'echo $HOSTNAME'
192.168.27.102 | SUCCESS | rc=0 >>
102

192.168.27.128 | SUCCESS | rc=0 >>
centos6.magedu.com
體驗shell和command的區別,先cd到某個需要編譯的目錄,執行condifgure然後,編譯,然後安裝。
 ansible -i hosts all -m shell -a "./configure && make && make insatll" chdir=/xxx/yyy/
 shell也支持條件判斷&&||
 [root@ansible ~]# ansible 'dbser' -m shell -a 'grep -q root /etc/passwd && ls /app'
192.168.27.102 | SUCCESS | rc=0 >>
123

192.168.27.128 | SUCCESS | rc=0 >>
1
aaa
access_log
awk.txt
dir
f1.txt
f2
lost+found
passwd

[root@ansible ~]# ansible 'dbser' -m shell -a 'grep -q rootsd /etc/passwd && ls /app'
192.168.27.102 | FAILED | rc=1 >>
non-zero return code   如果沒有則會出現非0錯誤碼

192.168.27.128 | FAILED | rc=1 >>
non-zero return code




<div class="se-preview-section-delimiter"></div>

Script:運行腳本
- 相當於先把腳本傳到遠方節點,然後在執行
- mark

-a "/PATH/TO/SCRIPT_FILE"
snsible websrvs -m script -a f1.sh




<div class="se-preview-section-delimiter"></div>

Copy:從服務器複製文件到客戶端
- 常用參數
+ src
+ 用於定位ansible執行的機器上的文件,需要絕對路徑。如果拷貝的是文件夾,那麼文件夾會整體拷貝,如果結尾是”/”,那麼只有文件夾內的東西被考過去。一切的感覺很像rsync,源地址
+ content
+ 用來替代src,用於將指定文件的內容,拷貝到遠程文件內
+ dest
+ 用於定位遠程節點上的文件,需要絕對路徑。如果src指向的是文件夾,這個參數也必須是指向文件夾,目標文件
+ backup
+ 備份遠程節點上的原始文件,在拷貝之前。如果發生什麼意外,原始文件還能使用。
+ directory_mode
+ 這個參數只能用於拷貝文件夾時候,這個設定後,文件夾內新建的文件會被拷貝。而老舊的不會被拷貝
+ follow
+ 當拷貝的文件夾內有link存在的時候,那麼拷貝過去的也會有link
+ force
+ 默認爲yes,會覆蓋遠程的內容不一樣的文件(可能文件名一樣)。如果是no,就不會拷貝文件,如果遠程有這個文件
+ group
+ 設定一個羣組擁有拷貝到遠程節點的文件權限
+ mode
+ 等同於chmod,參數可以爲“u+rwx or u=rw,g=r,o=r”
+ owner
+ 設定一個用戶擁有拷貝到遠程節點的文件權限
- 把複製selinux配置文件
- mark
- mark
- 看一下備份文件
- mark
- 也可以改權限,所屬組,或所有者
- mark
- mark

也可以把內容複製到指定的文件中
[root@ansible ~]# ansible cen7 -m copy -a 'content="df-h\nhhhhhhhhhhh\nls\n" dest=/app/f1.sh'
[root@ansible ~]# ansible cen7 -a 'cat /app/f1.sh'
192.168.27.102 | SUCCESS | rc=0 >>
df-h
hhhhhhhhhhh
ls

192.168.27.101 | SUCCESS | rc=0 >>
df-h
hhhhhhhhhhh
ls




<div class="se-preview-section-delimiter"></div>
ansible srv -m copy -a "src=/root/f1.sh dest=/tmp/f2.sh owner=wang mode=600 backup=yes"
如目標存在,默認覆蓋,此處指定先備份
ansible srv -m copy -a "content='test content\n' dest=/tmp/f1.txt" 利用內容,直接生成目標文件

Cron:計劃任務

支持時間:minute,hour,day,month,weekday
ansible srv -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.16.0.1 &>/dev/null'
name=Synctime" 創建任務
ansible srv -m cron -a 'state=absent
name=Synctime' 刪除任務
範例1:每五分鐘週六週日執行
[root@ansible ~]# ansible cen7 -m cron -a 'minute=*/5 weekday=0,6 job="/usr/bin/wall cront job" name="test"'
name就是給這個計劃任務起個名字
job表示要執行的命令或操作但是命令要寫絕對路徑
[root@ansible ~]# ansible cen7 -a 'crontab -l'
192.168.27.102 | SUCCESS | rc=0 >>
#Ansible: test
*/5 * * * 0,6 /usr/bin/wall cront job
範例2:禁用範例1的計劃任務
[root@ansible ~]# ansible cen7 -m cron -a 'disabled=true job="/usr/bin/wall cront job" name=test ' 
必須要job
[root@ansible ~]# ansible cen7 -a 'crontab -l'
192.168.27.101 | SUCCESS | rc=0 >>
#Ansible: test
#* * * * * /usr/bin/wall cront job
開啓是disabled=no

Fetch:從客戶端取文件至服務器端,copy相反,目錄可先tar

ansible srv -m fetch -a 'src=/root/a.sh dest=/data/scripts'
  • 範例2,將遠程主機的passwd文件複製到本機上
[root@ansible ~]# ansible cen7 -m fetch -a 'src=/etc/passwd dest=/app/'
這裏的src是遠程主機的路徑,dest是本地路徑文件要複製到哪裏
在本機會成一個遠程主機ip名字的一個目錄裏面存放着文件
[root@ansible ~]# tree /app/
/app/
├── 192.168.27.101
│   └── etc
│       └── passwd
└── 192.168.27.102
    └── etc
        └── passwd
  • 範例3.將日誌文件打包壓縮,並複製到本地主機上
[root@ansible ~]# ansible cen7 -m shell -a 'tar Jcf /app/log.tar.xz /var/log/*.log' 
[root@ansible ~]# ansible cen7 -m fetch -a 'src=/app/log.tar.xz dest=/app/' 
  • 有專門的tar模塊可以將打包並複製

File:設置文件屬性和管理文件
- file模塊它包含了文件、文件夾、超級鏈接類的創立、拷貝、移動、刪除操作。
- 常見參數
+ follow
+ 如果原來的文件是link,拷貝後依舊是link
+ force
+ 強制執行,沒說的
+ group
+ 設定所屬組權限
+ mode
+ 等同於chmod,參數可以爲“u+rwx or u=rw,g=r,o=r”
+ owner
+ 設定文件的所有者
+ path
+ 目標路徑,也可以用dest,name代替
+ src
+ 待拷貝文件/文件夾的原始位置。
+ state = ile/link/directory/hard/touch/absent
+ file代表拷貝後是文件;link代表最終是個軟鏈接;directory代表文件夾;hard代表硬鏈接;touch代表生成一個空文件;absent代表刪除

ansible srv -m file -a "path=/root/a.sh owner=wang mode=755"
ansible web -m file -a 'src=/app/testfile dest=/app/testfile-link state=link'
  • 範例1:創建一個空文件
[root@ansible ~]# ansible cen7 -m file -a 'path=/app/testfile state=touch'
192.168.27.101 | SUCCESS => {
    "changed": true, 
    "dest": "/app/testfile", 
    "gid": 0,   組id
    "group": "root",  所屬組
    "mode": "0644",   文件權限
    "owner": "root",  所有者
    "secontext": "unconfined_u:object_r:default_t:s0", 
    "size": 0,  大小
    "state": "file",   
    "uid": 0  
}
  • 範例2:把範例1創建的文件創建一個軟連接
[root@ansible ~]# ansible cen7 -m file -a 'src=/app/testfile path=/app/testlink state=link'
[root@ansible ~]# ansible cen7 -a 'ls -l /app/'   ansible不支持別名命令
lrwxrwxrwx. 1 root root   13 Jan 14 20:18 testlink -> /app/testfile
  • 範例3:創建一個文件夾,推薦用file模塊因爲比較穩定
方法一[root@ansible ~]# ansible cen7 -a 'mkdir /app/mk1'
方法二[root@ansible ~]# ansible cen7 -m file -a 'path=/app/mk2 state=directory'
  • 範例4:刪除文件夾或文件
[root@ansible ~]# ansible cen7 -m file -a 'path=/app/mk1 state=absent'
[root@ansible ~]# ansible cen7 -m file -a 'path=/app/fstab state=absent'
  • 範例5:清空整個文件夾
[root@ansible ~]# ansible cen7 -m shell -a 'rm -rf /app/*'
 ansible cen7 -m file -a 'path=/app state=absent'

Hostname:管理主機名這裏改名是永久改,會把配置文件改掉

ansible node1 -m hostname -a "name=websrv"
ansible 192.168.27.101 -m hostname -a 'name=g101.com' 

Yum:管理包
- 常用參數
+ disable_gpg_check
+ 在安裝包前檢查包,只會影響state參數爲present或者latest的時候
+ name
+ 你需要安裝的包的名字,也能如此使用name=python=2.7安裝python2.7
+ state present/latest/absent
+ 用於描述安裝包最終狀態,present/latest用於安裝包,absent用於remove安裝包
+ update_cache
+ 用於安裝包前執行更新list,只會影響state參數爲present/latest的時候
- 範例1:安裝一個包,做這些一定要yum配置好

[root@ansible ~]# ansible cen7 -m yum -a 'name=tree state=present'
name是要安裝的包名,
如果是安裝的話默認可以不寫state=present,默認是安裝
當然也可以用命令模塊安裝或卸載包
  • 範例2:可以安裝包最新版
[root@ansible ~]# ansible cen7 -m yum -a 'name=dstat state=latest'
  • 範例3:也可以一次性安裝多個包,包之間用逗號隔開
[root@ansible ~]# ansible cen7 -m yum -a 'name=httpd,vsftpd state=present'
ansible srv -m yum -a 'name=httpd state=latest' 安裝
ansible srv -m yum -a 'name=httpd state=absent' 刪除

Service:管理服務
- 常用參數
+ enabled
+ 啓動os後啓動對應service的選項。使用service模塊的時候,enabled和state至少要有一個被定義,設置成開機啓動
+ name
+ 需要進行操作的service名字
+ state stared/stoped/restarted/reloaded
+ service最終操作後的狀態。
- 範例1啓動服務並設置開機啓動

[root@ansible ~]# ansible cen7 -m service -a 'name=httpd state=started enabled=yes'
這相當於先啓動服務,然後在把服務設置成開機啓動
  • ansible service 模塊一條命令只能支持一個服務,name只能寫一個
 ansible srv -m service -a 'name=httpd state=stopped'
 ansible srv -m service -a 'name=httpd state=started'
 ansible srv –m service –a 'name=httpd state=reloaded'
 ansible srv -m service -a 'name=httpd state=restarted'

User:管理用戶
- 常用參數
+ home
+ 指定用戶的家目錄
+ groups
+ 用戶的所屬組可以指定多個用逗號分隔
+ uid
+ 指定用戶uid
+ name
+ 要創建的用戶名
+ createhome
+ 是否創建家目錄 yes|no
+ system
+ 是否爲系統用戶
+ remove
+ 當state=absent時,remove=yes則表示連同家目錄一起刪除,等價於userdel -r
+ state
+ 是創建還是刪除,默認是創建
+ shell
+ 指定用戶的shell環境
+ password
+ 指定用戶的密碼
- 範例1:創建一個test1用戶,uid=2000,主組是guo,附屬組是root,bin.指定家目錄爲根下 還有描述

[root@ansible ~]# ansible cen7 -m user -a 'name=test1 comment="test is user" uid=2000 home=/test group=guo groups=root,bin'
192.168.27.101 | SUCCESS => {
    "changed": true, 
    "comment": "test is user", 
    "createhome": true, 
    "group": 1000, 
    "groups": "root,bin", 
    "home": "/test", 
    "name": "test1", 
    "shell": "/bin/bash", 
    "state": "present", 
    "system": false, 
    "uid": 2000
}
  • 範例2:創建一個系統用戶,系統用戶是沒有家目錄的所以要加上createhome=no不創建家目錄,如果不加這個選項則是默認創建家目錄
[root@ansible ~]# ansible cen7 -m user -a 'name=systemuser system=yes createhome=no' 
192.168.27.102 | SUCCESS => {
    "changed": true, 
    "comment": "", 
    "createhome": false, 
    "group": 996, 
    "home": "/home/systemuser",   雖然這裏顯示是創建的,但是事實是沒有創建
    "name": "systemuser", 
    "shell": "/bin/bash", 
    "state": "present", 
    "system": true, 
    "uid": 998
}
  • 範例3:刪除一個普通用戶,包括家目錄以前刪除當state=absent時remove=yes則表示連同家目錄一起刪除,如果只選state=absent則只刪除用戶,而不會刪除家目錄
[root@ansible ~]# ansible cen7 -m user -a 'name=test1 state=absent remove=yes' 
192.168.27.101 | SUCCESS => {
    "changed": true, 
    "force": false, 
    "name": "test1", 
    "remove": true, 
    "state": "absent"
}
ansible srv -m user -a 'name=user1 comment="test user” uid=2048 home=/app/user1 group=root'
ansible srv -m user -a 'name=sysuser1 system=yes home=/app/sysuser1 '
ansible srv -m user -a 'name=user1 state=absent remove=yes'
刪除用戶及家目錄等數據

Group:管理組
+ 和user參數一樣
- 範例1:創建組

[root@ansible ~]# ansible cen7 -m group -a 'name=group1'
  • 範例2:刪除一個組
[root@ansible ~]# ansible cen7 -m group -a 'name=group1 state=absent'
 ansible srv -m group -a "name=testgroup system=yes"
 ansible srv -m group -a "name=testgroup state=absent"

ansible系列命令

  • ansible-galaxy
    • 連接 https://galaxy.ansible.com 下載相應的roles
      • 這個網站是官方的,國外的一些大神做的比較好的playbook,和一些角色,會傳到這裏,可以下載使用或者參考
    • mark
    • 列出所有已安裝的galaxy
      • ansible-galaxy list
    • 安裝galaxy
      • ansible-galaxy install geerlingguy.redis
      • 就將網站上的角色名寫着就可以
        bash
        [root@ansible ~]# ansible-galaxy install geerlingguy.nginx</li>
        <li>downloading role 'nginx', owned by geerlingguy</li>
        <li>downloading role from https://github.com/geerlingguy/ansible-role-nginx/archive/2.5.0.tar.gz</li>
        <li>extracting geerlingguy.nginx to /root/.ansible/roles/geerlingguy.nginx 這裏顯示了下載的位置</li>
        <li>geerlingguy.nginx (2.5.0) was installed successfully
      • 下載完後可以用ansible-galaxy list 查看
      • 進入目錄看一下里面的內容
        bash
        [root@ansible ~]# ls .ansible/roles/geerlingguy.nginx/
        defaults handlers LICENSE meta README.md tasks templates tests vars
      • 這裏都是playbook
      • 最好複製一份並改名,這樣修改如果出現重大失誤可以有參考
    • 刪除galaxy
      • ansible-galaxy remove geerlingguy.redis
  • ansible-pull
    • 推送命令至遠程,效率無限提升,對運維要求較高
  • Ansible-playbook
    • ansible-playbook hello.yml 後綴推薦用.yml它是用yml語言寫的
  • mark
  • 語法,在前面要加—個
[root@ansible ansible]# vim hellow.yml
---
- hosts: cen7
  remote_user: root

  tasks:
    - name: test yml
      command: /usr/bin/wall "hellow word"
  • ansible-playbook 運行腳本 要用-C 檢查一下
  • 語法要求很嚴格
  • 創建一個空文件的一個腳本
[root@ansible ansible]# vim hellow.yml 
---
- hosts: cen7
  remote_user: root

  tasks:
    - name: test yml
      file: name=/app/test12 state=touch
  • Ansible-vault
    • 功能:管理加密解密yml文件
    • ansible-vault [create|decrypt|edit|encrypt|rekey|view]
    • ansible-vault encrypt hello.yml 加密
      bash
      [root@ansible ansible]# ansible-vault encrypt hellow.yml
      New Vault password:
      Confirm New Vault password:
      Encryption successful
    • ansible-vault decrypt hello.yml 解密
    • ansible-vault view hello.yml 查看
    • ansible-vault edit hello.yml 編輯加密文件
    • ansible-vault rekey hello.yml 修改口令
    • ansible-vault create new.yml 創建新文件
  • Ansible-console:2.0+新增,可交互執行命令,支持tab
    • root@test (2)[f:10] @()[f:]
    • 設置併發數: forks n 例如: forks 10
    • 切換組: cd 主機組 例如: cd web
    • 列出當前組主機列表: list
    • 列出所有的內置命令: ?或help
    • 示例:
      bahs
      root@all (2)[f:5]$ list
      root@all (2)[f:5]$ cd appsrvs
      root@appsrvs (2)[f:5]$ list
      root@appsrvs (2)[f:5]$ yum name=httpd state=present
      root@appsrvs (2)[f:5]$ service name=httpd state=started
    • mark
    • mark

playbook

  • playbook是由一個或多個“play”組成的列表
  • play的主要功能在於將事先歸併爲一組的主機裝扮成事先通過ansible中的task定義好的角色。從根本上來講,所謂task無非是調用ansible的一個module。將多個play組織在一個playbook中,即可以讓它們聯同起來按事先編排的機制同唱一臺大戲
  • Playbook採用YAML語言編寫
  • mark

YAML語法簡介

  • List:列表,其所有元素均使用“-”打頭
  • 示例
# A list of tasty fruits
- Apple
- Orange
- Strawberry
- Mango

YAML介紹

  • YAML是一個可讀性高的用來表達資料序列的格式。YAML參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。Clark Evans在2001年在首次發表了這種語言,另外Ingy döt Net與Oren Ben-Kiki也是這語言的共同設計者
  • YAML Ain’t Markup Language,即YAML不是XML。不過,在開發的這種語言時,YAML的意思其實是:”Yet Another Markup Language”(仍是一種標記語言)
    特性
    YAML的可讀性好
    YAML和腳本語言的交互性好
    YAML使用實現語言的數據類型
    YAML有一個一致的信息模型
    YAML易於實現
    YAML可以基於流來處理
    YAML表達能力強,擴展性好
  • 更多的內容及規範參見http://www.yaml.org

YAML語法簡介

  • 在單一檔案中,可用連續三個連字號(—)區分多個檔案。另外,還有選擇性的連續三個點號( … )用來表示檔案結尾
  • 次行開始正常寫Playbook的內容,一般建議寫明該Playbook的功能
  • 使用#號註釋代碼
  • 縮進必須是統一的,不能空格和tab混用
  • 縮進的級別也必須是一致的,同樣的縮進代表同樣的級別,程序判別配置的級別是通過縮進結合換行來實現的
  • YAML文件內容和Linux系統大小寫判斷方式保持一致,是區別大小寫的,k/v的值均需大小寫敏感
  • k/v的值可同行寫也可換行寫。同行使用:分隔
  • v可是個字符串,也可是另一個列表
  • 一個完整的代碼塊功能需最少元素需包括 name: task
  • 一個name只能包括一個task
  • YAML文件擴展名通常爲yml或yaml
  • Dictionary:字典,通常由多個key與value構成
    -範例:
---
# An employee record
name: Example Developer
job: Developer
skill: Elite
也可以將key:value放置於{}中進行表示,用,分隔多個key:value
  • 範例2:
---
# An employee record
{name: Example Developer, job: Developer, skill: Elite}
  • YAML的語法和其他高階語言類似,並且可以簡單表達清單、散列表、標量等數據結構。其結構(Structure)通過空格來展示,序列(Sequence)裏的項用”-“來代表,Map裏的鍵值對用”:”分隔
  • 示列
name: John Smith
age: 41
gender: Male
spouse:
  name: Jane Smith
  age: 37
  gender: Female
children:
- name: Jimmy Smith
  age: 17
  gender: Male
- name: Jenny Smith
  age 13
  gender: Female

Playbook核心元素

  • Hosts 執行的遠程主機列表
  • Tasks 任務集
  • Varniables 內置變量或自定義變量在playbook中調用
  • Templates 模板,可替換模板文件中的變量並實現一些簡單邏輯的文件
  • Handlers 和notity結合使用,由特定條件觸發的操作,滿足條件方纔執行,否則不執行
  • tags 標籤 指定某條任務執行,用於選擇運行playbook中的部分代碼。ansible具有冪等性,因此會自動跳過沒有變化的部分,即便如此,有些代碼爲測試其確實沒有發生變化的時間依然會非常地長。此時,如果確信其沒有變化,就可以通過tags跳過此些代碼片斷
ansible-playbook –t tagsname useradd.yml
  • 範例
  • mark
[root@ansible ansible]# vim test.yml 
---
- hosts: cen7   要執行的主機
  remote_user: root   用哪個用戶執行

  tasks:  任務集
    - name: install package   一條任務要有一個名字
      yum: name=httpd       調用的模塊,和參數
    - name: start service
      service: name=httpd state=started enabled=yes
  • 查看playbook中被執行的主機列表
[root@ansible ansible]# ansible-playbook test.yml --list-host

playbook: test.yml

  play #1 (cen7): cen7  TAGS: []
    pattern: [u'cen7']
    hosts (2):
      192.168.27.101
      192.168.27.102
  • 查看playbook中有哪些任務
ERROR! You must specify a playbook file to run
[root@ansible ansible]# ansible-playbook test.yml --list-tasks  

playbook: test.yml

  play #1 (cen7): cen7  TAGS: []
    tasks:
      install package   TAGS: []
      start service     TAGS: []
  • mark
  • 一個playbook推薦只寫一個play,當然可以寫多個play
  • mark

實驗

  • 安裝http服務並把它設置爲開機啓動,並將端口改爲8080端口,開啓服務,寫一個playbook
  • 首先在自己的電腦上裝一個http服務,並且修改好配置文件,然後在將配置文件複製到遠程主機上,啓動服務,這裏的所有主機都是centos7的,不同系統版本的http配置文件不一樣,所以要同一版本
- hosts: cen7
  remote_user: root

  tasks:
    - name: isntall httpd
      yum: name=httpd
    - name: copy config httpd
      copy: src=/app/httpd.conf dest=/etc/httpd/conf/  backup=yes
    - name: start httpd
      service: name=httpd state=started enabled=yes
  • 當我們在想把配置文件改爲80端口,如果在重新執行上面的playbook並不會改過了,因爲上面只是定義了啓動服務,所以我們要用handlers條件出發
---
- hosts: cen7
  remote_user: root

  tasks:
    - name: isntall httpd
      yum: name=httpd
    - name: copy config httpd
      copy: src=/app/httpd.conf dest=/etc/httpd/conf/  backup=yes
      notify: restart httpd   當copy發生改變時會執行notify所指定的名字任務
    - name: start httpd
      service: name=httpd state=started enabled=yes

  handlers:   handlers是一個特殊的tasks也可以寫多個任務
    - name: restart httpd
      service: name=httpd state=restarted 
  • 當第一次執行這個playbook會順序執行,不會觸發handlers,因爲第一次包都沒有裝,但是當第二次執行時開始執行handlers,當copy命令執行結果改變時,會執行對應的handlers的任務
  • mark

playbook基礎組件

  • Hosts
    • playbook中的每一個play的目的都是爲了讓某個或某些主機以某個指定的用戶身份執行任務。hosts用於指定要執行指定任務的主機,須事先定義在主機清單中
    • 可以是如下形式
      bash
      one.example.com
      one.example.com:two.example.com
      192.168.1.50
      192.168.1.*
    • Websrvs:dbsrvs 兩個組的並集
    • Websrvs:&dbsrvs 兩個組的交集
    • webservers:!phoenix 在websrvs組,但不在dbsrvs組
    • 示例: - hosts: websrvs:dbsrvs
  • remote_user: 可用於Host和task中。也可以通過指定其通過sudo的方式在遠程主機上執行任務,其可用於play全局或某任務;此外,甚至可以在sudo時使用sudo_user指定sudo時切換的用戶
- hosts: websrvs
  remote_user: root
  tasks:
   - name: test connection
   ping:
   remote_user: magedu
   sudo: yes 默認sudo爲root
   sudo_user:wang sudo爲wang
  • task列表和action
    • play的主體部分是task list。task list中的各任務按次序逐個在hosts中指定的所有主機上執行,即在所有主機上完成第一個任務後再開始第二個。在運行自下而下某playbook時,如果中途發生錯誤,所有已執行任務都將回滾,因此,在更正playbook後重新執行一次即可
    • task的目的是使用指定的參數執行模塊,而在模塊參數中可以使用變量。模塊執行是冪等的,這意味着多次執行是安全的,因爲其結果均一致
    • 每個task都應該有其name,用於playbook的執行結果輸出,建議其內容儘可能清晰地描述任務執行步驟。如果未提供name,則action的結果將用於輸出
  • tasks:任務列表
  • 格式:
    • (1) action: module arguments
    • (2) module: arguments 建議使用
  • 注意:shell和command模塊後面跟命令,而非key=value
  • 某任務的狀態在運行後爲changed時,可通過“notify”通知給相應的handlers
  • 任務可以通過”tags“打標籤,而後可在ansible-playbook命令上使用-t指定進行調用
  • 示例
tasks:
- name: disable selinux
  command: /sbin/setenforce 0
  • 如果命令或腳本的退出碼不爲零,可以使用如下方式替代
tasks:
- name: run this command and ignore the result
  shell: /usr/bin/somecommand || /bin/true
  • 或者使用ignore_errors來忽略錯誤信息
tasks:
- name: run this command and ignore the result
  shell: /usr/bin/somecommand
  ignore_errors: True

運行playbook

  • 運行playbook的方式
ansible-playbook <filename.yml> ... [options]

常見選項
–check 只檢測可能會發生的改變,但不真正執行操作
–list-hosts 列出運行任務的主機
–limit 主機列表 只針對主機列表中的主機執行
-v 顯示過程 -vv -vvv 更詳細
- 範例

ansible-playbook file.yml --check 只檢測
ansible-playbook file.yml
ansible-playbook file.yml --limit websrvs
  • 範例1,限定特定的主機執行,並不是所以的主機執行
[root@ansible app]# ansible-playbook httpd.yml  --limit 192.168.27.101
只針對101主機執行並不是所有主機

mark

Playbook VS ShellScripts

SHELL腳本

#!/bin/bash
# 安裝Apache
yum install --quiet -y httpd
# 複製配置文件
cp /path/to/config/httpd.conf
/etc/httpd/conf/httpd.conf
cp/path/to/httpd-vhosts.conf
/etc/httpd/conf/httpd-vhosts.conf
# 啓動Apache,並設置開機啓動
service httpd start
chkconfig httpd on

Playbook定義

---
- hosts: all
  tasks:
- name: "安裝Apache"
    command: yum install -q -y httpd
- name: "複製配置文件"
    command: cp /tmp/httpd.conf  /etc/httpd/conf/httpd.conf
    command: cp /tmp/httpd-vhosts.conf /etc/httpd/conf/httpd-vhosts.conf
- name: "啓動Apache,並設置開機啓動"
    service: name=httpd state=started enabled=yes
  • 範例
示例:system.yml
---
-hosts: all
 remote_user: root
 tasks:
   - name: create mysql user
   user: name=mysql system=yes uid=36
   - name: create a group
   group: name=httpd system=yes

示例:httpd.yml

- hosts: websrvs
  remote_user: root
  tasks:
    - name: Install httpd
       yum: name=httpd state=present
    - name: Install configure file
       copy: src=files/httpd.conf dest=/etc/httpd/conf/
     - name: start service
       service: name=httpd state=started enabled=yes

handlers和notify結合使用觸發條件

  • Handlers
    • 是task列表,這些task與前述的task並沒有本質上的不同,用於當關注的資源發生變化時,纔會採取一定的操作
  • notify這個action可用於在每個play的最後被觸發,這樣可以避免多次有改變發生時每次都執行指定的操作,僅在所有的變化發生完成後一次性地執行指定操作。在notify中列出的操作稱爲handler,也即notify中調用handler中定義的操作

Playbook中handlers使用

- hosts: websrvs
  remote_user: root
  tasks:
    - name: Install httpd
    yum: name=httpd state=present
    - name: Install configure file
    copy: src=files/httpd.conf dest=/etc/httpd/conf/
    notify: restart httpd
    - name: ensure apache is running
    service: name=httpd state=started enabled=yes
   handlers:
    - name: restart httpd
    service: name=httpd status=restarted
  • 示例
- hosts: websrvs
  remote_user: root
  tasks:
    - name: add group nginx
    tags: user
    user: name=nginx state=present
    - name: add user nginx
    user: name=nginx state=present group=nginx
    - name: Install Nginx
    yum: name=nginx state=present
    - name: config
    copy: src=/root/config.txt dest=/etc/nginx/nginx.conf
    notify:
        - Restart Nginx
        - Check Nginx Process
  handlers:
    - name: Restart Nginx
    service: name=nginx state=restarted enabled=yes
    - name: Check Nginx process 
    shell: killall -0 nginx > /tmp/nginx.log

Playbook中tags使用,從劇本中挑出tags代表的任務,只執行這個,其它的不執行

  • tage的名字可以相同
示例:httpd.yml
- hosts: websrvs
remote_user: root
tasks:
  - name: Install httpd
  yum: name=httpd state=present
  - name: Install configure file
  copy: src=files/httpd.conf dest=/etc/httpd/conf/
  tags: conf
  - name: start httpd service
  tags: service
  service: name=httpd state=started enabled=yes
[root@ansible app]# ansible-playbook -t conf,service httpd.yml 
  • 可以一次啓動多個tags標籤。加-t或者–tags

Playbook中變量使用

  • 變量名:僅能由字母、數字和下劃線組成,且只能以字母開頭
  • 變量來源:
    • 1 ansible setup facts 遠程主機的所有變量都可直接調用
    • 2 在/etc/ansible/hosts中定義
      • 普通變量:主機組中主機單獨定義,優先級高於公共變量
      • 公共(組)變量:針對主機組中所有主機定義統一變量
    • 3 通過命令行指定變量,優先級最高
      • ansible-playbook –e varname=value
    • 4 在playbook中定義
      bash
      vars:</li>
      <li>var1: value1</li>
      <li>var2: value2
    • 5 在role中定義
  • 用setup模塊可以查看機器的所有的內置變量
 ansible cen7 -m setup 
  • 也可以用filter參數搜索變量,支持通配符
[root@ansible app]# ansible cen7 -m setup -a 'filter=*hostname*'
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "g102"
    }, 
    "changed": false
}
192.168.27.101 | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "g101"
    }, 
    "changed": false
}
[root@ansible app]# ansible cen7 -m setup -a 'filter=*nodename*'
192.168.27.101 | SUCCESS => {
    "ansible_facts": {
        "ansible_nodename": "g101.com"
    }, 
    "changed": false
}
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_nodename": "g102.com"
    }, 
    "changed": false
}
[root@ansible app]# ansible cen7 -m setup -a 'filter=*fqdn*'
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_fqdn": "g102.com"
    }, 
    "changed": false
}
192.168.27.101 | SUCCESS => {
    "ansible_facts": {
        "ansible_fqdn": "g101.com"
    }, 
    "changed": false
}
  • 最好寫全名稱
  • 可以查ip地址
ct, raw, meta
[root@ansible app]# ansible cen7 -m setup -a 'filter=*addr*'
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.27.102"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:fe8b:f0dd"
        ]
    }, 
    "changed": false
}
192.168.27.101 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.27.101"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:fec3:887f"
        ]
    }, 
    "changed": false
}

Playbook中變量使用

  • 變量命名
    • 變量名僅能由字母、數字和下劃線組成,且只能以字母開頭
  • 變量定義:key=value
    • 示例:http_port=80
  • 變量調用方式:
    • 通過{{ variable_name }} 調用變量,且變量名前後必須有空格,有時用“{{ variable_name }}”才生效
ansible-playbook –e 選項指定
ansible-playbook test.yml -e "hosts=www user=mageedu"
  • 範例1:var.yml
- hosts: websrvs
  remote_user: root
  tasks
   - name: install package
     yum: name={{ pkname }} state=present
# ansible-playbook -e pkname=httpd var.yml
  • 範例在playbook中賦值並調用
[root@ansible ansible]# vim var2.yml
---
- hosts: cen7
  remote_user: root
  vars:                    //如果要在play中第一變量要用vars
   - username: user123     //變量名:賦值
   - groupname: group123

  tasks:
   - name: create group
     group: name={{ groupname }}   //調用變量
   - name: create uesr
     user: name={{ username }} group={{ groupname }} home=/app/{{ username }}dir  //可以寫變量加其它字段
[root@ansible ansible]# ansible-playbook  var2.yml
[root@ansible ansible]# ansible cen7 -a 'getent passwd user123'
192.168.27.101 | SUCCESS | rc=0 >>
user123:x:1001:1001::/app/user123dir:/bin/bash
  • 範例2:變量
# vim var2.yml
- hosts: websrvs
  remote_user: root
  vars:
   - username: user1
   - groupname: group1

  tasks:
   - name: create group
     group: name={{ groupname }} state=present
   - name: create user
     user: name={{ username }} state=present
# ansible-playbook var2.yml
# ansible-playbook -e "username=user2 groupname=group2” var2.yml
  • 範例3

[root@ansible ansible]# vim var1.yml

  • hosts: cen7
    remote_user: root

    tasks:

    • name: install package
      yum: name={{ pkname }} //定義一個變量名爲pkname

[root@ansible ansible]# ansible-playbook -e pkname=vsftpd var1.yml 用-e 寫要指定定的變量名然後賦值

- 範例4:使用多個變量名
```bash  




<div class="se-preview-section-delimiter"></div>

[root@ansible ansible]# vim var1.yml 
---
- hosts: cen7
  remote_user: root

  tasks:
    - name: install package
      yum: name={{ pkname }}   //第一個變量
    - name: copy file
      copy: src=/app/{{ filename }} dest=/app/   //第二個變量

[root@ansible ansible]# ansible-playbook -e "pkname=dstat filename=httpd.conf" var1.yml
要賦值多個變量要用雙引號引起來,




<div class="se-preview-section-delimiter"></div>
  • 用yum模塊可以一次安裝或卸載多個包
[root@ansible ansible]# ansible cen7 -m yum -a 'name=dstat,httpd state=absent'




<div class="se-preview-section-delimiter"></div>
[root@ansible ansible]# vim var2.yml
---
- hosts: cen7
  remote_user: root
  vars:
   - username: user123
   - groupname: group123

  tasks:
   - name: create group
     group: name={{ groupname }}
   - name: create uesr
     user: name={{ username }} group={{ groupname }} home=/app/{{ username }}dir

也可在palybook中調用setup模塊中的變量,setup模塊是系統內所有的變量可以用filter參數搜索對應的變量名

  • 在setup是有定義主機名的變量,分別是ansible_nodename這個變量是主機名全名,還有一個ansible_hostnam是隻有前面一般,可以根據下面的例子看出很明顯。
[root@ansible ansible]# ansible cen7 -m setup -a 'filter="*nodename*"'
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_nodename": "g102.com"
    }, 
    "changed": false
}
[root@ansible ansible]# ansible cen7 -m setup -a 'filter="*hostname*"'
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_hostname": "g102"
    }, 
    "changed": false
}
  • 在playbook中調用setup系統中的變量
[root@ansible ansible]# vim var3.yml
---
- hosts: cen7
  remote_user: root

  tasks:
    - name: create file
      file: name=/app/{{ ansible_hostname }}.txt  state=touch    //ansible_hostnam 是setup中的變量,我們可以直接調用
[root@ansible ansible]# ansible-playbook var3.yml 

在主機清單hosts中定義變量

mark
- 這裏101主機定義的http_port是85,102直接定義的是86,雖然變量名都是同一個,針對不同的主機可以設置不同的值
- 然後我們可以調用用命令行

[root@ansible ~]# ansible webser -m hostname -a 'name=web{{ http_port  }}'  //修改主機名,會針對不同的主機的變量值不一樣
[root@ansible ~]# ansible webser -a 'hostname'
192.168.27.101 | SUCCESS | rc=0 >>
web85   這是針對某個主機設置不同的值

192.168.27.102 | SUCCESS | rc=0 >>
web86
  • 也可定義多個變量,並在playbook中使用
    mark
[root@ansible ansible]# vim var4.yml
---
- hosts: webser
  remote_user: root

  tasks:
    - name: set hostname
      hostname: name={{ hostname }}-{{ http_port}}
[root@ansible ansible]# ansible webser -a 'hostname'
192.168.27.101 | SUCCESS | rc=0 >>
web1-88

192.168.27.102 | SUCCESS | rc=0 >>
web2-86
  • 如果我們人爲的用-e指定變量值,則會以-e定義的參數爲準,不會調用hosts中的變量
[root@ansible ansible]# ansible-playbook -e "http_port=9090 hostname=abc.com" var4.yml
[root@ansible ansible]# ansible webser -a 'hostname'
192.168.27.101 | SUCCESS | rc=0 >>
abc.com-9090

192.168.27.102 | SUCCESS | rc=0 >>
abc.com-9090

變量

  • 主機變量
    • 可以在inventory中定義主機時爲其添加主機變量以便於在playbook中使用
[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909
  • 組變量
    • 組變量是指賦予給指定組內所有主機上的在playbook中可用的變量
  • 範例
[websrvs]
www1.magedu.com
www2.magedu.com

[websrvs:vars]     這個相當於是在websrvs組中的所有主機公用的,叫做組公共變量
ntp_server=ntp.magedu.com
nfs_server=nfs.magedu.com

mark

[root@ansible ansible]# vim var4.yml
---
- hosts: webser
  remote_user: root

  tasks:
    - name: set hostname
      hostname: name={{ hname }}-{{ http_port}}
[root@ansible ansible]# ansible-playbook  var4.yml 
[root@ansible ansible]# ansible webser -a 'hostname'
192.168.27.102 | SUCCESS | rc=0 >>
ansible-91

192.168.27.101 | SUCCESS | rc=0 >>
ansible-90
  • 普通變量
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
  • 公共變量
[websvrs:vars]
http_port=808
mark=“_”
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
# ansible websvrs –m hostname –a ‘name={{ hname }}{{ mark }}{{http_port }}’
  • 命令行指定變量
ansible websvrs –e http_port=8000 –m hostname –a ‘name={{hname }}{{ mark }}{{ http_port }}’

也可以把變量專門寫到一個文件中,可以讓別的playbook調用此變量

  • 名字必須是.yml後綴的
[root@ansible ~]# vim add.yml
host: 123  在文件中定義變量是這中格式 host是變量名 :後面是值 這是和上面定義變量是用區別的 
filen: 456
[root@ansible ansible]# vim var5.yml
---
- hosts: cen7
  remote_user: root
  vars_files:   一定要寫vars_files 
    - /root/add.yml   這裏是定義變量的文件路徑,然後就可以調用裏面的變量了

  tasks:
   - name: create file
     file: name=/app/{{host}}-{{filen}}.log  state=touch  mode=600 owner=guo  
[root@ansible ansible]# ansible cen7 -a 'ls /app/'
192.168.27.102 | SUCCESS | rc=0 >>
123-456.log

192.168.27.101 | SUCCESS | rc=0 >>
123-456.log
f2
f3

模板templates

  • templates 是一個模塊
    • 模板存放着將來要實現的配置文件的公用設置放在模板裏,必須是特殊格式的,可以根據一些變量來根據主機生成配置文件
  • 文本文件,嵌套有腳本(使用模板編程語言編寫)
  • Jinja2語言,使用字面量,有下面形式
字符串:使用單引號或雙引號
數字:整數,浮點數
列表:[item1, item2, ...]
元組:(item1, item2, ...)
字典:{key1:value1, key2:value2, ...}
布爾型:true/false
  • 算術運算:+, -, , /, //, %, *
  • 比較操作:==, !=, >, >=, <, <=
  • 邏輯運算:and, or, not
  • 流表達式:For If When
  • templates功能:根據模塊文件動態生成對應的配置文件,並複製到遠端主機上
    • templates文件必須存放於templates目錄下,且命名爲 .j2 結尾
    • yaml/yml 文件需和templates目錄平級,目錄結構如下
./
├── temnginx.yml
└── templates
    └── nginx.conf.j2   

範例

  • 利用templates 同步nginx配置文件
    • 準備templates/nginx.conf.j2文件
# vim temnginx.yml
---
- hosts: websrvs
  remote_user: root
  tasks:
   - name: template config to remote hosts
     template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
# ansible-playbook temnginx.yml
首先要在本機上安裝相同的服務,然後把配置文件複製一份到template目錄下改後綴爲j2
1. [root@ansible ansible]# cp /etc/nginx/nginx.conf templates/nginx.conf.j2   首先把要準備一份模板文件,後綴名必須是j2
[root@ansible ansible]# vim temnginx.yml
---
- hosts: cen7
  remote_user: root

  tasks:
   - name: install nginx
     yum: name=nginx
   - name: template
     template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf    //src=這個可以寫絕對路徑,也可以這樣寫,因爲我的template目錄和這playbook文件是在同一目錄,默認play會到template目錄下找。
     tags: instconf
   - name: start service
     service: name=nginx state=started
[root@ansible ansible]# ansible-playbook temnginx.yml  運行這個playbook,安裝服務,並生成模板文件
  1. 修改模板文件
    mark
  2. 查看一下默認是幾個進程號發現是一個進程
    mark
  3. 我們修改一下CPU的數量在看一下結果,只修改一個主機上的CPU個數
    mark
  4. 在setup模塊中有一個變量是顯示CPU個數的變量
[root@ansible ansible]# ansible cen7 -m setup -a 'filter="*cpu*"'
192.168.27.101 | SUCCESS => {
    "ansible_facts": {
        "ansible_processor_vcpus": 1   這個就是顯示CPU變量的
    }, 
    "changed": false
}
192.168.27.102 | SUCCESS => {
    "ansible_facts": {
        "ansible_processor_vcpus": 4
    }, 
    "changed": false
}
  1. 修改模板文件
    mark
    • 這樣就會變成,模板是一樣的,但是到各個主機上回吧ansible_processor_vcpus這個變量會變成CPU個數,機器有是幾個CPU就替換成幾,這樣生成的配置文件也不同。
    • 剛剛上面的playbook已經將服務啓動了,所以我們在修改一下playbook,在template下加一個notify,當template這個任務執行時會觸發指示的任務
[root@ansible ansible]# vim temnginx.yml 
---
- hosts: cen7
  remote_user: root

  tasks:
   - name: install nginx
     yum: name=nginx
   - name: template
     template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
     notify: restart nginx
     tags: instconf
   - name: start service
     service: name=nginx state=started

  handlers:
   - name: restart nginx
     service: name=nginx state=restarted
  • 現在執行一下playbook,執行完後我們可以看一下是不是按CPU數來創建進程的
    mark
  • 確實4顆CPU就是4個進程數,1個CPU就是一個,這就是template模板的強大之處
  • 看一下各自的配置文件
    mark
    mark

  • 還可以做運算
    mark

  • 我們*2把CPUx2,執行一下playbook
    mark

Playbook中template變更替換

  • 修改文件nginx.conf.j2 下面行爲
worker_processes {{ ansible_processor_vcpus }};
# cat temnginx2.yml
---
- hosts: websrvs
remote_user: root
tasks:
  - name: template config to remote hosts
    template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
# ansible-playbook temnginx2.yml

Playbook中template算術運算

  • 算法運算
  • 範例
# vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus*2 }};
worker_processes {{ ansible_processor_vcpus+2 }};

template也支持在主機清單中變量

mark
- 修改模板文件
mark
- 執行playbook
- 查看監聽端口是否改變
mark
- 我們也可以在playbook中定義變量讓模板調用

[root@ansible ansible]# vim temnginx.yml 
---
- hosts: cen7
  remote_user: root
  vars:
    - http_port: 6060    在playbook中定義http_port變量值爲6060

  tasks:
   - name: install nginx
     yum: name=nginx
   - name: template
     template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
     notify: restart nginx
     tags: instconf
   - name: start service
     service: name=nginx state=started

  handlers:
   - name: restart nginx
     service: name=nginx state=restarted
  • 現在有一個問題是,我們在主機清單中也定義了同樣名字的變量,這種情況會以playbook中的變量會生效,如果在命令行中用-e也定義了同樣名字的變量則命令行的優先
    mark

變量參數的優先級

命令行定義變量> playbook中定義的> hosts主機清單中定義的變量> 模板文件中

when

  • 條件測試:如果需要根據變量、facts或此前任務的執行結果來做爲某task執行與否的前提時要用到條件測試,通過when語句實現,在task中使用,jinja2的語法格式
  • when語句
  • 在task後添加when子句即可使用條件測試;when語句支持Jinja2表達式語法
  • 示例
tasks:
  - name: "shutdown RedHat flavored systems"
    command: /sbin/shutdown -h now
    when: ansible_os_family == "RedHat"
  • 示例:when條件判斷
---

- hosts: websrvs
  remote_user: root
  tasks:
    - name: add group nginx
      tags: user
      user: name=nginx state=present
    - name: add user nginx
      user: name=nginx state=present group=nginx
    - name: Install Nginx
      yum: name=nginx state=present
    - name: restart Nginx
      service: name=nginx state=restarted
      when: ansible_distribution_major_version == "6"
  • 示例
tasks:
  - name: install conf file to centos7
    template: src=nginx.conf.c7.j2
    when: ansible_distribution_major_version == "7"
  - name: install conf file to centos6
    template: src=nginx.conf.c6.j2
    when: ansible_distribution_major_version == "6"
  • 範例
  • 當系統版本不同,服務版本也會不同,就httpd服務,7版本和6版本不同,如果在管理主機中有6的機器,也有centos7的機器,我們在用模板文件創建配置文件時就需要判斷一下系統是幾的就用對應的配置模板
  • 首先把centos7 版本和6版本的httpd配置文件複製一份到template文件夾中當模板文件
    mark
  • 現在已經找到了版本號我們在playbook中用when判斷
[root@ansible ansible]# vim when.yml                 
---
- hosts: all
  remote_user: root

  tasks:
   - name: install httpd
     yum: name=httpd

   - name: template
▽    template: src=httpd-6.conf.j2 dest=/etc/httpd/conf/httpd.conf
     when: ansible_distribution_major_version=="6"    當版本==6時會執行,不然就不執行

   - name: template
     template: src=httpd-7.conf.j2 dest=/etc/httpd/conf/httpd.conf
     when: ansible_distribution_major_version=="7"

   - name: start service
     service: name=httpd state=started

mark

迭代:with_items(類似於循環)

  • 迭代:當有需要重複性執行的任務時,可以使用迭代機制
    • 對迭代項的引用,固定變量名爲”item“
    • 要在task中使用with_items給定要迭代的元素列表
    • 列表格式:
      • 字符串
      • 字典
  • 示例,在系統中創建若干用戶
- name: add several users
  user: name={{ item }} state=present groups=wheel   //item是個關鍵字,必須這樣寫
  with_items:
    - testuser1
    - testuser2
  • 上面語句的功能等同於下面的語句
- name: add user testuser1
  user: name=testuser1 state=present groups=wheel
- name: add user testuser2
  user: name=testuser2 state=present groups=wheel
  • 創建多個用戶
[root@ansible ansible]# vim with_items.yml
---
- hosts: cen7
  remote_user: root

  tasks:
   - name: create servel users
     user: name={{ item }} group=root groups=guo   
     with_items:
       - xiaoming
       - xiaowang
       - xiaoguo
````
- 示例:將多個文件進行copy到被控端




<div class="se-preview-section-delimiter"></div>

```bash  
---
- hosts: testsrv
  remote_user: root

  tasks
  - name: Create rsyncd config
    copy: src={{ item }} dest=/etc/{{ item }}
    with_items:
        - rsyncd.secrets
        - rsyncd.conf
- hosts: websrvs
  remote_user: root
  tasks:
    - name: copy file
      copy: src={{ item }} dest=/tmp/{{ item }}
      with_items:
        - file1
        - file2
        - file3

    - name: yum install httpd
      yum: name={{ item }} state=present
      with_items:
        - apr
        - apr-util
        - httpd
- hosts:websrvs
  remote_user: root
  tasks
    - name: install some packages
      yum: name={{ item }} state=present
      with_items:
        - nginx
        - memcached
        - php-fpm

示例:迭代嵌套子變量

  • 當有多個變量時可以用子變量
- hosts:websrvs
  remote_user: root
  tasks:
    - name: add some groups
      group: name={{ item }} state=present
      with_items:
        - group1
        - group2
        - group3
    - name: add some users
      user: name={{ item.name }} group={{ item.group }} state=present
      with_items:
        - { name: 'user1', group: 'group1' }
        - { name: 'user2', group: 'group2' }
        - { name: 'user3', group: 'group3' }
  • 範例2
[root@ansible ~]# vim qiantaoitem.yml                 
---
- hosts: cen7
  remote_user: root

  tasks:
   - name: create group
     group: name={{ item }}
     with_items:
      - igroup1
      - igroup2
      - igroup3

   - name: create user
     user: name={{item.username }} group={{item.groupname}}
     with_items:
      - {username: 't1', groupname: 'igroup1' }   一行有兩個變量,用逗號隔開冒號後面有空格
      - {username: 't2', groupname: 'igroup2' }
      - {username: 't3', groupname: 'igroup3' }

Playbook中template for if

  • for語句
  • 格式
{%for 變量 in 列表%}
    循環體   
{%endfor}
這種是用於template模板中,在playbook中定義列表
  • 範例
[root@ansible ansible]# vim for.yml
---
- hosts: cen7
  remote_user: root
  vars:        
▽   ports:        //這裏定義列表名,裏面有幾個值for就循環幾遍
      - 81
      - 82
      - 83

  tasks:
    - name: test for1
      template: src=for1.conf.j2 dest=/app/for1.conf


[root@ansible ansible]# vim templates/for1.conf.j2   在模板文件裏寫for循環
{%for port in ports %}     port類似shell,for循環中的i可以隨便寫,ports必須寫列表名
server {                         這裏是循環體
        listen {{port}};         這裏調用{{port}}這裏的值就是列表裏的值
}
{%endfor%}     結束循環體

運行playbook文件
[root@ansible-90 ~]# cat /app/for1.conf 
server {
        listen 81;
}
server {
        listen 82;
}
server {
        listen 83;
}
  • 第二種for寫法
[root@ansible ansible]# vim for2.yml
---
- hosts: cen7
  remote_user: root
  vars:
    ports:  這是列表名
       - http_port: 81      寫成這樣相當於子變量
       - http_port: 82
       - http_port: 83

  tasks:
▽  - name: template file
     template: src=for2.conf.j2 dest=/app/for2.conf
模板文件
[root@ansible ansible]# vim templates/for2.conf.j2
{%for port in ports %}
server {
        listen {{port.http_port}};   這種類似於item的寫法port相當於http_port,然後把http_port的變量名替換成值
}
{%endfor%} 
---------------------------------------------------------------------------------------
[root@ansible-90 ~]# cat /app/for2.conf 
server {
        listen 81;
}
server {
        listen 82;
}
server {
        listen 83;
}

重點第三種for寫法

[root@ansible ansible]# vim for3.yml                 
---
- hosts: cen7
  remote_user: root
  vars:
    hhh:   一個列表中可以有對個元素
      - web1:
        port: 88
        name: web1.server
        root: /app/web1.server
      - web2:
        port: 89
        name: web2.server
        root: /app/web2.server
      - web3:
        port: 90
        name: web3.server
        root: /app/web3.server

  tasks:
    - name: test for3
      template: src=for3.conf.j2  dest=/app/for3.con
模板文件
{%for i in hhh%}    
server {
        listen {{i.prot}}
        servername {{i.name}}
        rootdir {{i.root}}
}
{%endfor%}
生成結果
[root@ansible-90 ~]# cat /app/for3.conf 
server {
        listen 88
        servername web1.server
        rootdir /app/web1.server 
}
server {
        listen 89
        servername web2.server
        rootdir /app/web2.server 
}
server {
        listen 90
        servername web3.server
        rootdir /app/web3.server 
}
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen | default('80 default_server') }};

{% if vhost.server_name is defined %}   //這表示如果vhost.server_name被定義了有值了則就用這裏定義的值,如果沒有定義就不用
server_name {{ vhost.server_name }};
{% endif %}

{% if vhost.root is defined %}
root {{ vhost.root }};
{% endif %}

-範例

[root@ansible ansible]# vim for4-if.yml 
---
- hosts: cen7
  remote_user: root
  vars:
    hhh:
      - web1:
▽       port: 88
        #name: web1.server   我們把web1中name註釋
        root: /app/web1.server
      - web2:
        port: 89
        name: web2.server
        root: /app/web2.server
      - web3:
        port: 90
        #name: web3.server  web#中name註釋   這樣用if時就不會定義這個name
        root: /app/web3.server

  tasks:
    - name: test for3
      template: src=for4-if.conf.j2  dest=/app/for4-if.conf
模板文件
[root@ansible ansible]# vim templates/for4-if.conf.j2
{%for i in hhh %}
service {
        listen {{i.port}}
{%if i.name is defined %}            一點要頂頭寫這些,當i.name被定義就調用,如果沒有被定義則不調用
        servername {{i.name}}
{%endif%}                            if這種格式一點要頂頭寫
        rootdir {{i.root}}
}
{%endfor%}
結果
[root@ansible-90 ~]# cat /app/for4-if.conf 
service {
        listen 88
        rootdir /app/web1.server
}
service {
        listen 89
        servername web2.server     這裏只有web2的name有名字
        rootdir /app/web2.server
}
service {
        listen 90
        rootdir /app/web3.server
}
  • 示列1
// temnginx.yml
---
- hosts: testweb
  remote_user: root
  vars:
    nginx_vhosts:
        - listen: 8080
//templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost.listen }}
}
{% endfor %}

生成的結果
server {
listen 8080
}
  • 示例2

// temnginx.yml

  • hosts: mageduweb
    remote_user: root
    vars:
    nginx_vhosts:
    • web1
    • web2
    • web3
      tasks:
    • name: template config
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
```bash 
 // templates/nginx.conf.j2
{% for vhost in nginx_vhosts %}
server {
listen {{ vhost }}
}
{% endfor %}



生成的結果:
server {
listen web1
}
server {
listen web2
}
server {
listen web3
}

mark
mark

roles

  • roles
    • ansilbe自1.2版本引入的新特性,用於層次性、結構化地組織playbook。roles能夠根據層次型結構自動裝載變量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。簡單來講,roles就是通過分別將變量、文件、任務、模板及處理器放置於單獨的目錄中,並可以便捷地include它們的一種機制。角色一般用於基於主機構建服務的場景中,但也可以是用於構建守護進程等場景中
  • 複雜場景:建議使用roles,代碼複用度高
    • 變更指定主機或主機組
    • 如命名不規範維護和傳承成本大
    • 某些功能需多個Playbook,通過Includes即可實現
  • 角色(roles):角色集合
roles/    這個文件夾名比較小是roles是固定的
  mysql/
  httpd/
  nginx/
  memcached/

Ansible Roles目錄編排

mark
- git是一個角色
+ 下面有一個tasks目錄,裏面放着所有的任務 這人文件必須要有
+ 而tasks文件夾裏必要要有個文件是main.yml這個playbook。當我們調用git這個服務角色時,它會自動去找tasks下的main.yml這是整個任務的入口,相當於主聯繫人。這個文件必須存在
+ file則是放着要用的文件
+ vars放着所有的變量
- 當roles寫好後要有人調用,則userconf.yml就相當於調用這些服務

roles目錄結構

  • 每個角色,以特定的層級目錄結構進行組織
  • roles目錄結構
playbook.yml   這是調用的劇本是和roles是在同一目錄是平級的
roles/
 project/
  tasks/
  files/
  vars/ 不常用
  default/ 不常用
  templates/
  handlers/
  meta/ 不常用
- roles這個文件夾在哪裏創建都可以,但是官方有一個推薦位置/etc/ansible/目錄下有一個roles
- 而roles目錄創建完裏面的目錄可以根據需求來創建,但是tasks必須要有
    -

Roles各目錄作用

  • /roles/project/ :項目名稱,有以下子目錄
    • files/ :存放由copy或script模塊等調用的文件
    • templates/:template模塊查找所需要模板文件的目錄
    • tasks/:定義task,role的基本元素,至少應該包含一個名爲main.yml的文件;其它的文件需要在此文件中通過include進行包含
    • handlers/:至少應該包含一個名爲main.yml的文件;其它的文件需要在此文件中通過include進行包含
    • vars/:定義變量,至少應該包含一個名爲main.yml的文件;其它的文件需要在此文件中通過include進行包含
    • meta/:定義當前角色的特殊設定及其依賴關係,至少應該包含一個名爲main.yml的文件,其它文件需在此文件中通過include進行包含
    • default/:設定默認變量時使用此目錄中的main.yml文件

創建role

  • 創建role的步驟
    1. 創建以roles命名的目錄
    2. 在roles目錄中分別創建以各角色名稱命名的目錄,如webservers等
    3. 在每個角色命名的目錄中分別創建files、handlers、meta、tasks、templates和vars目錄;用不到的目錄可以創建爲空目錄,也可以不創建
    4. 在playbook文件中,調用各角色

針對大型項目使用Roles進行編排

mark
- 範例

site.yml
webservers.yml
dbservers.yml
roles/
    common/
        files/
        templates/
        tasks/
        handlers/
        vars/
        meta/
    webservers/
        files/
        templates/
        tasks/
        handlers/
        vars/
        meta/

playbook調用角色

  • 調用角色方法1
- hosts: websrvs
  remote_user: root
  roles:
    - mysql   這是調用roles,就是roles目錄中所創建的
    - memcached
    - nginx
  • 調用角色方法2
傳遞變量給角色
- hosts:
  remote_user:
  roles:
    - mysql
    - { role: nginx, username: nginx }
    鍵role用於指定角色名稱
    後續的k/v用於傳遞變量給角色
  • 調用角色方法3:還可基於條件測試實現角色調用
roles:
- { role: nginx, username: nginx, when:ansible_distribution_major_version== '7' }

完整的roles架構完整的roles架構

mark

roles playbook tags使用

  • roles playbook tags使用
# ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml
// nginx-role.yml
---
- hosts: testweb
  remote_user: root
  roles:
    - { role: nginx ,tags: [ 'nginx', 'web' ] ,when:ansible_distribution_major_version == "6“ }
    - { role: httpd ,tags: [ 'httpd', 'web' ] }
    - { role: mysql ,tags: [ 'mysql', 'db' ] }
    - { role: marridb ,tags: [ 'mysql', 'db' ] }
    - { role: php }

創建一個簡單的roles

  1. 首先創建一個roles目錄
  2. 在roles目錄中創建服務目錄,這裏創建一個NGINX服務的安裝和啓動,和複製文件的roles
    mark
  3. 那就那nginx服務來示列,進去入到nginx目錄中,根據自己的需求創建目錄,tasks目錄必須創建這裏存放playbook,其它如files目錄如果不涉及文件的傳輸可以不創建
    mark
  4. 進入tasks目錄創建添加組,添加用戶,安裝服務,複製模本,啓動服務
[root@ansible tasks]# ls
groupadd.yml  install.yml   start.yml  useradd.yml 
  1. 當然這裏寫的playbook和我們之前寫的單個playbook是有區別的,這裏更簡單了 ,不用寫hosts和remote_user和tasks ,只用寫對應的任務

[root@ansible tasks]# cat groupadd.yml 
- name: add group
  group: name=nginx

[root@ansible tasks]# cat useradd.yml 
- name: create user
  user: name=nginx group=nginx  system=yes shell=/sbin/nologin
[root@ansible tasks]# cat install.yml 
- name: install package
  yum: name=nginx

[root@ansible tasks]# cat start.yml 
- name: start service
  service: name=nginx state=started enabled=yes
  1. 當然我們知道每個目錄中都有一個main.yml這個文件,這個文件相當於這些任務的總入口,當我們從外面調用這些模塊化的服務時,它會自動到tasks目錄中找main.yml,所有我們在創建一個main.yml
    mark
    1. 編寫main.yml文件,這裏是有先後順序的一定要注意,自上而下的執行。用- import_tasks: playbookname
[root@ansible tasks]# cat main.yml 
- import_tasks: groupadd.yml
- import_tasks: useradd.yml
- import_tasks: install.yml
- import_tasks: start.yml
  1. 這樣就創建好了,現在回到和roles同級的目錄,創建一個調用這個角色符playbook,一定要和roles這目錄在同級目錄中
[root@ansible ansible]# ls
1  nginx-roles.yml  roles這個是目錄
  1. nginx-roles.yml的編寫
[root@ansible ansible]# cat nginx-roles.yml 
- hosts: cen7
  remote_user: root

  roles:
    - role: nginx   這是調用角色
  1. 這樣就是一個簡單roles
    • 當然如果有多個角色也可以調用
[root@ansible ansible]# cat nginx-roles.yml 
- hosts: cen7
  remote_user: root

  roles:
    - role: nginx   這是調用角色
    - role: filecopy  也可以調用複製文件的角色
  • 當也可以單獨調用某一個角色中在tasks目錄下某個劇本,比如在filecopy角色中調用安裝nginx服務當然,首先我們把剛剛安裝的nginx服務卸載了。
    • 首先要filecopy目錄下中的tasks目錄中的main.yml劇本中添加一行
- name: file copy
  copy: src=fstab dest=/app/

- name: file create
  file: name=/app/testfile state=touch mode=600

- import_tasks: roles/nginx/tasks/install.yml      //這是調用另一個角色中的一個劇本 ,一般不推薦這樣使用               

角色中加標籤tags

  • 在創建一個角色用於安裝和創建httpd服務的
[root@ansible roles]# ls
filecopy  httpd  memcached  nginx
  • 這裏有4個服務角色,在roles的父目錄中寫一個調用角色的腳本叫tags-roles.yml
  • 用大括號引起來
[root@ansible ansible]# vim tags-roles.yml
---
- hosts: cen7
  remote_user: root

  roles:
    - { role: nginx, tags: ['nginx','web' ] }  一個服務可以有多個標籤,也可以和其它標籤名相同tags:後一定要有空格,標籤用單引號,多個標籤用中括號分隔
    - { role: httpd, tags: ['httpd','web' ] }
    - { role: filecopy, tags: 'copyfile' }
  • 然後就可以根據標籤來執行,調用時和任務標籤語法一樣。

創建一個大型的角色示列

  1. 創建roles目錄和目錄裏的nginx角色
  2. 在nginx中創建要用的目錄
mkdir {tasks,templates,handlers,vars}
  1. 想tasks目錄中創建main.yml劇本
[root@ansible ~]# cat /root/ansible/roles/nginx/tasks/main.yml 
- name: install package    安裝nginx包
  yum: name=nginx

- name: template
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: 123  這裏也可以定義標籤
  notify: restart service   當template任務發生變化時則執行restart service

- name: start service
  service: name=nginx state=started
  1. 在handlers目錄中創建main.yml並編輯
[root@ansible ~]# cat /root/ansible/roles/nginx/handlers/main.yml 
- name: restart service    這個名字必須和notify所表示的名字一樣,當template任務發生變化時執行這裏的任務
  service: name=nginx state=restarted
  1. 複製一份nginx文件到template當模板文件
cp /etc/nginx/nginx.conf templates/nginx.conf.j2
  1. 修改模板文件
    mark
    • 這樣就會不同主機會生成不同的配置文件
  2. 在vars目錄中創建一個main.yml文件來設置自定義變量
[root@ansible ~]# cat /root/ansible/roles/nginx/vars/main.yml 
lport: 8080
  1. 在模板文件中調用這個配置文件
    mark
  2. 在roles同級目錄中寫調用角色的playbook文件
[root@ansible ~]# cat ansible/testnginx.yml 
- hosts: all
  remote_user: root

  roles:
    - { role: nginx, when: ansible_distribution_major_version=='7' }  判斷如果系統版本號爲7就執行這個角色
      lport: 9090   在這裏也定義了變量,這裏的變量優先級比vars目錄中的變量優先級高這裏會生效
    - role: filecopy  還可以調用多個角色
      when: ansible_nodename=='ansible-90'  也是判斷,當主機名爲ansible-90就執行這個角色
  1. 用-C檢查然後執行

推薦資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章