自動化運維工具-ansible

一、什麼是ansible?

ansible是一個部署一羣遠程主機的自動化運維工具,基於Python開發,集合了衆多運維工具(puppet、cfengine、chef、func、fabric)的優勢,它不須要安裝客戶端,經過SSH協議實現遠程節點和管理節點之間的通訊,實現了批量系統配置、批量程序部署、批量運行命令等功能。
ansible是基於模塊工做的,模塊能夠由任何語言開發,它不只支持命令行使用模塊,也支持編寫yaml格式的playbook。html

二、ansible的安裝

兩臺主機,jin-10,jin-11,咱們只須要在jin-10上安裝ansible便可。python

[root@jin-10 ~]# yum install -y ansible

而後把jin-10上的公鑰文件id_rsa.pub複製到jin-11上的/root/.ssh/authorized_keys裏,同時,對本機也進行密鑰認證(把/root/.ssh/id_rsa.pub文件的內容複製到authorized_keys裏)。linux

[root@jin-10 ~]# ssh jin-10
Last login: Tue Sep  3 12:27:50 2019 from jin-11
[root@jin-10 ~]# ssh jin-11
Last login: Tue Sep  3 12:24:22 2019 from jin-10

能夠看到,jin-10用ssh的方式鏈接本機和jin-11都不用密碼和密鑰認證。nginx

而後咱們設置一個主機組,用來告訴Ansible須要管理哪些主機。編輯文件vim /etc/ansible/hosts,內容以下:docker

[testhost]
127.0.0.1
jin-11

其中,testhost爲自定義的主機組名字,而後是兩個主機的IP(或主機名)。shell

三、ansible的使用

ansible模塊Module
bash不管在命令行上執行,仍是bash腳本中,都須要調用cd、ls、copy、yum等命令;module就是ansible的「命令」,module是ansible命令行和腳本中都須要調用的。經常使用的ansible module有yum、copy、template等。
在bash,調用命令時能夠跟不一樣的參數,每一個命令的參數都是該命令自定義的;一樣,ansible中調用module也能夠跟不一樣的參數,每一個module的參數也都是由module自定義的。
在命令行中,-m後面接調用module的名字,-a後面接調用module的參數:apache

[root@jin-10 ~]# ansible all -m copy -a "src=/etc/hosts dest=/tmp/hosts"
jin-11 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", 
    "dest": "/tmp/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 182, 
    "state": "file", 
    "uid": 0
}
127.0.0.1 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "checksum": "843eede91ec66c16e38ddb67dee1bb173ea7fe9c", 
    "dest": "/tmp/hosts", 
    "gid": 0, 
    "group": "root", 
    "mode": "0644", 
    "owner": "root", 
    "path": "/tmp/hosts", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 182, 
    "state": "file", 
    "uid": 0
}

在playbook腳本中,tasks中的每個action都是對module的一次調用。在每一個action中:冒號前面是module的名字,冒號後面是調用module的參數:編程

---
  tasks:
  - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
  - name: write the apache config file
    template: src=templates/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
  - name: ensure apache is running
    service: name=httpd state=started

下面是一些經常使用的module:

調試和測試類的module:json

  • ping - ping一下你的遠程主機,若是能夠經過ansible成功鏈接,那麼返回pong
  • debug - 用於調試的module,只是簡單打印一些消息,有點像linux的echo命令。

文件類的module:vim

  • copy - 從本地拷貝文件到遠程節點
  • template - 從本地拷貝文件到遠程節點,並進行變量的替換
  • file - 設置文件的屬性

linux上經常使用的操做:

  • user - 管理用戶帳戶
  • yum - redhat系linux上的安裝包管理
  • service - 管理服務
  • firewalld - 管理防火牆中的服務和端口

執行Shell命令:

  • shell - 在節點上執行shell命令,支持$HOME和"<", ">", "|", ";" and "&"
  • command - 在遠程節點上面執行命令,不支持$HOME和"<", ">", "|", ";" and "&"

3.1 ansible遠程執行命令

例:ansible testhost -m command -a 'w'
此處的testhost爲主機組名(也能夠直接寫一個ip,針對某一臺機器來執行命令),-m後邊是模塊名字,-a後面是命令

[root@jin-10 ~]# ansible testhost -m command -a 'w'
jin-11 | CHANGED | rc=0 >>
 09:07:34 up 21:59,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.154.1    二11   20:39m  0.33s  0.33s -bash
root     pts/1    jin-10           09:07    1.00s  0.28s  0.02s w

127.0.0.1 | CHANGED | rc=0 >>
 09:07:34 up 23:03,  3 users,  load average: 0.27, 0.14, 0.19
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.154.1    二10    6.00s  6.63s  5.48s ssh jin-10
root     pts/1    fe80::d601:fb6f: 二12    6.00s  7.09s  0.00s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/21f0e6a9ae -tt 127.0.0.1 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1567559253.0-170559931011383/AnsiballZ_command.py && sleep 0'
root     pts/4    localhost        09:07    1.00s  0.51s  0.01s w

針對某一臺機器來執行命令:

[root@jin-10 ~]# ansible jin-11 -m command -a 'hostname'
jin-11 | CHANGED | rc=0 >>
jin-11

模塊shell也能夠一樣實現:

[root@jin-10 ~]# ansible testhost -m shell -a 'hostname'
jin-11 | CHANGED | rc=0 >>
jin-11

127.0.0.1 | CHANGED | rc=0 >>
jin-10

3.2 ansible拷貝文件或目錄

ansible拷貝目錄時,若是目標指定的目錄不存在,它會自動建立:

[root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755"
jin-11 | CHANGED => {
    "changed": true, 
    "dest": "/tmp/ansible_test/", 
    "src": "/etc/ansible"
}
[root@jin-11 ~]# ll /tmp/ansible_test
總用量 0
drwxr-xr-x. 3 root root 51 9月   4 09:24 ansible

能夠看到目標目錄被建立且源目錄在目標目錄下面。
操做時,要注意src和dest是文件仍是目錄,拷貝文件時,若是目標目錄已經存在同名目錄,那麼會把該文件放到同名目錄裏面:

[root@jin-11 /tmp]# ll -t
總用量 4
drwxr-xr-x. 2 root   root     6 9月   4 09:32 m_test
[root@jin-10 ~]# ansible jin-11 -m copy -a "src=/etc/passwd dest=/tmp/m_test"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "1db31b171f911344344ceb7cf8621d31be83ec07", 
    "dest": "/tmp/m_test/passwd", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "e1a0ce587167dc3587ee5f1b357dc3c4", 
    "mode": "0644", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 1299, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567560870.7-110358489604181/source", 
    "state": "file", 
    "uid": 0
}
[root@jin-11 /tmp]# ls m_test/
passwd

3.3 ansible遠程執行腳本

在jin-10上編寫一個test_ansible.sh的腳本,內容以下:

#!/bin/bash
echo `date` >/tmp/test_ansible.txt

而後分發到主機組testhost:

[root@jin-10 ~]# ansible testhost -m copy -a "src=/tmp/test_ansible.sh dest=/tmp/test.sh mode=0755"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", 
    "mode": "0755", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 48, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567561704.9-93797175448931/source", 
    "state": "file", 
    "uid": 0
}
127.0.0.1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "checksum": "0dc6471ba363889d83d3bf98c4354d874c86bd19", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "bfee9509a7066ca2e822dbe48b21fbe7", 
    "mode": "0755", 
    "owner": "root", 
    "secontext": "unconfined_u:object_r:admin_home_t:s0", 
    "size": 48, 
    "src": "/root/.ansible/tmp/ansible-tmp-1567561704.82-59120276764010/source", 
    "state": "file", 
    "uid": 0
}

而後批量執行該腳本:

[root@jin-10 ~]# ansible testhost -m shell -a "/tmp/test.sh"
jin-11 | CHANGED | rc=0 >>


127.0.0.1 | CHANGED | rc=0 >>
[root@jin-10 ~]# ls /tmp/test_ansible.txt 
/tmp/test_ansible.txt
[root@jin-10 ~]# cat !$
cat /tmp/test_ansible.txt
2019年 09月 04日 星期三 09:50:23 CST
[root@jin-11 /tmp]# ls /tmp/test_ansible.txt 
/tmp/test_ansible.txt
[root@jin-11 /tmp]# cat !$
cat /tmp/test_ansible.txt
2019年 09月 04日 星期三 09:50:23 CST

3.4 ansible管理任務計劃

使用cron模塊能夠建立計劃任務:

[root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' job='/bin/touch /tmp/test_cron' weekday=6"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}
[root@jin-11 /tmp]# crontab -l
#Ansible: test cron
* * * * 6 /bin/touch /tmp/test_cron

使用cron模塊刪除計劃任務:

[root@jin-10 ~]# ansible jin-11 -m cron -a "name='test cron' state=absent"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "envs": [], 
    "jobs": []
}
[root@jin-11 /tmp]# crontab -l

能夠看到,以前建立的計劃任務已經被刪除了。

3.5 ansible安裝包和管理服務

ansible的yum模塊能夠安裝包和管理服務(能夠進行安裝包的安裝、卸載和遠程啓動等)。 咱們在jin-11上安裝httpd爲例:

[root@jin-11 ~]# rpm -qa httpd
[root@jin-11 ~]#

能夠看到,jin-11是沒有安裝httpd的。
在jin-10上執行以下命令:

[root@jin-10 ~]# ansible jin-11 -m yum -a "name=httpd state=installed"
jin-11 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": true, 
    "changes": {
        "installed": [
            "httpd"
        ]
    }, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.tuna.tsinghua.edu.cn\n * epel: hkg.mirror.rackspace.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.tuna.tsinghua.edu.cn\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-89.el7.centos.1 for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-89.el7.centos.1.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-3.el7_4.1 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-89.el7.centos.1 will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package           Arch         Version                     Repository     Size\n================================================================================\nInstalling:\n httpd             x86_64       2.4.6-89.el7.centos.1       updates       2.7 M\nInstalling for dependencies:\n apr               x86_64       1.4.8-3.el7_4.1             base          103 k\n apr-util          x86_64       1.5.2-6.el7                 base           92 k\n httpd-tools       x86_64       2.4.6-89.el7.centos.1       updates        91 k\n mailcap           noarch       2.1.41-2.el7                base           31 k\n\nTransaction Summary\n================================================================================\nInstall  1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal                                              260 kB/s | 3.0 MB  00:11     \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n  Installing : apr-1.4.8-3.el7_4.1.x86_64                                   1/5 \n  Installing : apr-util-1.5.2-6.el7.x86_64                                  2/5 \n  Installing : httpd-tools-2.4.6-89.el7.centos.1.x86_64                     3/5 \n  Installing : mailcap-2.1.41-2.el7.noarch                                  4/5 \n  Installing : httpd-2.4.6-89.el7.centos.1.x86_64                           5/5 \n  Verifying  : httpd-2.4.6-89.el7.centos.1.x86_64                           1/5 \n  Verifying  : mailcap-2.1.41-2.el7.noarch                                  2/5 \n  Verifying  : httpd-tools-2.4.6-89.el7.centos.1.x86_64                     3/5 \n  Verifying  : apr-util-1.5.2-6.el7.x86_64                                  4/5 \n  Verifying  : apr-1.4.8-3.el7_4.1.x86_64                                   5/5 \n\nInstalled:\n  httpd.x86_64 0:2.4.6-89.el7.centos.1                                          \n\nDependency Installed:\n  apr.x86_64 0:1.4.8-3.el7_4.1                  apr-util.x86_64 0:1.5.2-6.el7   \n  httpd-tools.x86_64 0:2.4.6-89.el7.centos.1    mailcap.noarch 0:2.1.41-2.el7   \n\nComplete!\n"
    ]
}

再在jin-11上查看,已經安裝了httpd包,而且沒有啓動:

[root@jin-11 ~]# rpm -qa httpd
httpd-2.4.6-89.el7.centos.1.x86_64
[root@jin-11 ~]# ps aux |grep httpd
root       4256  0.0  0.1 112724   996 pts/0    S+   11:29   0:00 grep --color=auto httpd

咱們再遠程啓動httpd:

[root@jin-10 ~]# ansible jin-11 -m service -a "name=httpd state=started enabled=no"

再查看jin-11是否成功啓動httpd服務:

[root@jin-11 ~]# ps aux |grep httpd
root       4355 19.0  0.5 230408  5184 ?        Ss   11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4356  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4357  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4358  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4360  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
apache     4361  0.0  0.3 230408  3004 ?        S    11:31   0:00 /usr/sbin/httpd -DFOREGROUND
root       4370  0.0  0.1 112724   996 pts/0    R+   11:31   0:00 grep --color=auto httpd

能夠看到,httpd服務已經成功啓動。

四、ansible playbook

playbook是指一個可被ansible執行的yml文件,最基本的playbook腳本分爲三個部分:
一、在什麼機器上以什麼身份執行:

  • hosts:爲主機的IP,或者主機組名,或者關鍵字all。
  • users:在遠程以哪一個用戶身份執行。
  • ...

二、執行的任務有哪些:

  • tasks
    • tasks是從上到下順序執行,若是中間發生錯誤,那麼整個playbook會停止。咱們能夠改修文件後,再從新執行。
    • 每個task都是對module的一次調用,只是使用不一樣的參數和變量而已。
    • 每個task最好有name屬性(可選),這個是供人讀的,沒有實際的操做。而後會在命令行裏面輸出,提示用戶執行狀況。
    • task中每一個action會調用一個module,在module中會去檢查當前系統狀態是否須要從新執行。
      • 若是本次執行了,那麼action會獲得返回值changed。
      • 若是不須要執行,那麼action獲得返回值ok。

三、善後的任務有哪些:

  • handlers
    • handler也是對module的一次調用,與tasks不一樣,tasks會默認的按定義順序執行每個task,handlers則不會,它須要在tasks中被調用,纔有可能被執行。
    • handler能夠理解爲playbook的event,在ansible中,只在task的執行狀態爲changed的時候,纔會執行該task調用的handler,這也是handler與普通的event機制不一樣的地方。
    • 若是有多個task notify同一個handler,那麼只執行一次。
    • handler的使用場景:例如執行task以後,服務器狀態發生變化以後要執行的一些操做,好比咱們修改了配置文件後,須要重啓一下服務,這時候就能夠用handler模塊。

下面咱們來編寫一個簡單的playbook,vim /etc/ansible/test.yml:

---
- hosts: jin-11
  remote_user: root
  tasks:
   - name: test_playbook
     shell: touch /tmp/test_playbook.txt

而後執行:

[root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/test.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [test_playbook] *****************************************************************
 [WARNING]: Consider using the file module with state=touch rather than running
'touch'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
[root@jin-11 ~]# ll -t /tmp/
總用量 16
-rw-r--r--. 1 root   root      0 9月   4 14:49 test_playbook.txt

能夠看到,在jin-11的/tmp/下生成了文件test_playbook.txt。

4.1 playbook的變量

  • 自定義變量

在playbook中,經過vars關鍵字自定義變量,使用時用{{ }}引用以來便可。
咱們以建立用戶爲例,編輯vim /etc/ansible/create_user.yml,內容以下:

---
- name: create_user
  hosts: jin-11
  user: root
  gather_facts: false
  vars:
   - user: "test"
  tasks:
   - name: create user
     user: name="{{ user }}"

而後執行:

[root@jin-10 /etc/ansible]# ansible-playbook /etc/ansible/create_user.yml 

PLAY [create_user] *******************************************************************

TASK [create user] *******************************************************************
changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11上查看:

[root@jin-11 ~]# id test
uid=1002(test) gid=1002(test) 組=1002(test)
  • 主機的系統變量(facts)

ansible會經過module setup來收集主機的系統信息,這些收集到的系統信息叫作facts,這些facts信息能夠直接以變量的形式使用。

[root@jin-10 ~]# ansible all -m setup -u root
jin-11 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.154.11"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::c9a8:961e:9b39:d180"
        ], 
        "ansible_apparmor": {
            "status": "disabled"
        }, 
        "ansible_architecture": "x86_64",
		...
  • 文件模板中使用的變量

在playbook中定義的變量,能夠直接在template中使用,facts變量也能夠直接在template中使用,包含在inventory裏面定義的host和group變量。只要是在playbook中能夠訪問的變量,均可以在template文件中使用。

  • 把運行結果當作變量使用-註冊變量

把task的執行結果也能夠做爲一個變量值。這個時候就須要用到「註冊變量」,將執行結果註冊到一個變量中,待後面的action使用,註冊變量常常和debug module一塊兒使用,這樣能夠獲得更多action的輸出信息,幫助用戶調試。

---

- hosts: all

  tasks:

     - shell: ls
       register: result
       ignore_errors: True

     - shell: echo "{{ result.stdout }}"
       when: result.rc == 5

     - debug: msg="{{ result.stdout }}"
  • 用命令行傳遞參數

爲了使Playbook更靈活、通用性更強,容許用戶在執行的時候傳入變量的值,這個時候就須要用到「額外變量」。

在playbook中定義的變量,須要從命令行傳遞變量值。
下面是在命令行裏面傳值得的方法:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "hosts=jin-11 user=root"

能夠用json格式傳遞參數:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "{ 'hosts': 'jin-11', 'user': 'root' }"

還能夠把參數放在文件裏面:

[root@jin-10 ~]# ansible-playbook for_var_test.yml --extra-vars "@vars.json"

4.2 playbook中的條件判斷

when: 相似於編程語言中的if語句
編輯文件vim /etc/ansible/when.yml,內容以下:

---
- hosts: testhost
  user: root
  gather_facts: True
  tasks:
   - name: use when
     shell: touch /tmp/when.txt
     when: ansible_ens32.ipv4.address == "192.168.154.11"

執行:

[root@jin-10 ~]# ansible-playbook /etc/ansible/when.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [use when] **********************************************************************
skipping: [127.0.0.1]
 [WARNING]: Consider using the file module with state=touch rather than running
'touch'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

查看結果:

[root@jin-10 ~]# ll -t /tmp/
總用量 12
-rw-r--r--. 1 root root 43 9月   4 09:50 test_ansible.txt
-rwxr-xr-x. 1 root root 48 9月   4 09:48 test.sh
[root@jin-11 ~]# ll -t /tmp/
總用量 16
-rw-r--r--. 1 root   root      0 9月   5 09:33 when.txt
-rw-r--r--. 1 root   root      0 9月   4 14:49 test_playbook.txt

能夠看到jin-10沒有生成when.txt文件,而jin-11則生成了。

4.3 playbook循環

loop: 相似於編程語言中的while語句,在playbook腳本中通常寫做with_...
編輯文件vim /etc/ansible/while.yml,內容以下:

---
- hosts: testhost
  user: root
  tasks:
   - name: change mode for files
     file: path=/tmp/{{ item }} state=touch mode=600
     with_items:
      - while1.txt
      - while2.txt
      - while3.txt

執行:

[root@jin-10 ~]# ansible-playbook /etc/ansible/while.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [change mode for files] *********************************************************
changed: [jin-11] => (item=while1.txt)
changed: [127.0.0.1] => (item=while1.txt)
changed: [jin-11] => (item=while2.txt)
changed: [jin-11] => (item=while3.txt)
changed: [127.0.0.1] => (item=while2.txt)
changed: [127.0.0.1] => (item=while3.txt)

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

查看結果:

[root@jin-10 ~]# ll -t /tmp/
總用量 12
-rw-------. 1 root root  0 9月   5 09:45 while3.txt
-rw-------. 1 root root  0 9月   5 09:45 while2.txt
-rw-------. 1 root root  0 9月   5 09:45 while1.txt
-rw-r--r--. 1 root root 43 9月   4 09:50 test_ansible.txt

[root@jin-11 ~]# ll -t /tmp/
總用量 16
-rw-------. 1 root   root      0 9月   5 09:45 while3.txt
-rw-------. 1 root   root      0 9月   5 09:45 while2.txt
-rw-------. 1 root   root      0 9月   5 09:45 while1.txt
-rw-r--r--. 1 root   root      0 9月   5 09:33 when.txt

4.4 用playbook安裝nginx

思路:先在一臺機器上編譯安裝好nginx、打包,而後再用ansible去下發。
- 建立相關的目錄
進入ansible配置文件目錄, 建立一個nginx_install的目錄,方便管理,最終目錄以下:

[root@jin-10 /var/lib/docker]# cd /etc/ansible/
[root@jin-10 /etc/ansible]# mkdir nginx_install
[root@jin-10 /etc/ansible]# cd !$
cd nginx_install
[root@jin-10 /etc/ansible/nginx_install]# mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@jin-10 /etc/ansible/nginx_install]# tree
.
└── roles
    ├── common
    │   ├── files
    │   ├── handlers
    │   ├── meta
    │   ├── tasks
    │   ├── templates
    │   └── vars
    └── install
        ├── files
        ├── handlers
        ├── meta
        ├── tasks
        ├── templates
        └── vars

說明:roles目錄下有兩個角色,common爲一些準備操做,install爲安裝nginx的操做。
每一個角色下面又有幾個目錄,handlers下面是當發生改變時要執行的操做,一般用在配置文件發生改變,重啓服務。files爲安裝時用到的一些文件,meta爲說明信息,說明角色依賴等信息,tasks裏面是核心的配置文件,templates一般存一些配置文件,啓動腳本等模板文件,vars下爲定義的變量。

  • 準備相關的文件
    以前已經在jin-10上編譯安裝了nginx,相關目錄文件以下:
  1. nginx的目錄:
[root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/
client_body_temp  fastcgi_temp  logs        sbin       uwsgi_temp
conf              html          proxy_temp  scgi_temp
  1. nginx的啓動腳本:
[root@jin-10 /etc/ansible/nginx_install]# ls /etc/init.d/nginx 
/etc/init.d/nginx
  1. nginx的配置文件:
[root@jin-10 /etc/ansible/nginx_install]# ls /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/conf/nginx.conf

把nginx的目錄打包,並複製文件到以前建立的目錄中:

[root@jin-10 /usr/local]# tar czf nginx.tar.gz --exclude "nginx.conf" --exclude "vhost" nginx/
[root@jin-10 /usr/local]# mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/
[root@jin-10 /usr/local]# cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/
[root@jin-10 /usr/local]# cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/

定義common的tasks,安裝nginx須要的一些依賴包:
進入/etc/ansible/nginx_install/roles/目錄,並編寫/etc/ansible/nginx_install/roles/common/tasks/main.yml文件,內容以下:

[root@jin-10 /etc/ansible/nginx_install/roles]# vim /etc/ansible/nginx_install/roles/common/tasks/main.yml

- name: Install initializtion require software
  yum: name={{ item }} state=installed
  with_items:
   - zlib-devel
   - pcre-devel

再編寫一個定義變量的文件vim /etc/ansible/nginx_install/roles/install/vars/main.yml,內容以下:

nginx_user: www
nginx_port: 80
nginx_basedir: /usr/local/nginx

而後再建立一個配置文件vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml ,用於拷貝文件到目標機器:

- name: Copy nginx software
  copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
- name: Uncompression nginx software
  shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
- name: Copy nginx start script
 template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
- name: Copy nginx config
 template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=06
44

再建立一個文件vim /etc/ansible/nginx_install/roles/install/tasks/install.yml ,用於創建用戶,啓動服務,刪除壓縮包:

- name: Create nginx user
  user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin
- name: Start nginx service
  shell: /etc/init.d/nginx start
- name: Add boot start nginx service
  shell: chkconfig --level 345 nginx on
- name: Delete nginx compression files
  shell: rm -rf /tmp/nginx.tar.gz

再建立一個調用copy和install的文件 /etc/ansible/nginx_install/roles/install/tasks/main.yml,內容以下:

- include: copy.yml
- include: install.yml

最後,咱們再定義一個入口配置文件/etc/ansible/nginx_install/install.yml,內容以下:

---
- hosts: jin-11
  remote_user: root
  gather_facts: True
  roles:
   - common
   - install

最終目錄文件以下:

[root@jin-10 /etc/ansible/nginx_install]# tree
.
├── install.yml
└── roles
    ├── common
    │   ├── files
    │   ├── handlers
    │   ├── meta
    │   ├── tasks
    │   │   └── main.yml
    │   ├── templates
    │   └── vars
    └── install
        ├── files
        │   └── nginx.tar.gz
        ├── handlers
        ├── meta
        ├── tasks
        │   ├── copy.yml
        │   ├── install.yml
        │   └── main.yml
        ├── templates
        │   ├── nginx
        │   └── nginx.conf
        └── vars
            └── main.yml
  • 執行腳本:
[root@jin-11 ~]# yum remove nginx
已加載插件:fastestmirror
參數 nginx 沒有匹配
不刪除任何軟件包

若是目標機器上已安裝了nginx,先用命令yum remove nginx刪除已安裝的nginx。
而後執行playbook腳本:

[root@jin-10 /etc/ansible/nginx_install]# ansible-playbook /etc/ansible/nginx_install/install.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [common : Install initializtion require software] *******************************
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions
 is deprecated. Instead of using a loop to supply multiple items and specifying 
`name: "{{ item }}"`, please use `name: ['zlib-devel', 'pcre-devel']` and remove the 
loop. This feature will be removed in version 2.11. Deprecation warnings can be 
disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [jin-11] => (item=[u'zlib-devel', u'pcre-devel'])

TASK [install : Copy nginx software] *************************************************
changed: [jin-11]

TASK [install : Uncompression nginx software] ****************************************
 [WARNING]: Consider using the unarchive module rather than running 'tar'.  If you
need to use command because unarchive is insufficient you can add 'warn: false' to
this command task or set 'command_warnings=False' in ansible.cfg to get rid of this
message.

changed: [jin-11]

TASK [install : Copy nginx start script] *********************************************
ok: [jin-11]

TASK [install : Copy nginx config] ***************************************************
ok: [jin-11]

TASK [install : Create nginx user] ***************************************************
changed: [jin-11]

TASK [install : Start nginx service] *************************************************
changed: [jin-11]

TASK [install : Add boot start nginx service] ****************************************
changed: [jin-11]

TASK [install : Delete nginx compression files] **************************************
 [WARNING]: Consider using the file module with state=absent rather than running
'rm'.  If you need to use command because file is insufficient you can add 'warn:
false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid
of this message.

changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=10   changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11主機上查看是否有nginx的進程:

[root@jin-11 ~]# ps aux|grep nginx
root       4040  0.0  0.0  20540   628 ?        Ss   08:32   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody     4042  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
nobody     4043  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
root       4192  0.0  0.1 112724   996 pts/0    S+   09:45   0:00 grep --color=auto nginx

4.5 playbook管理配置文件

安裝軟件通常是在初始化環境的時候,而在生產環境中,咱們大多數是要管理配置文件。
下面咱們來寫一個管理nginx配置文件的playbook。
首先先建立所須要的目錄:

[root@jin-10 ~]# mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}

最終目錄以下:

[root@jin-10 ~]# tree /etc/ansible/nginx_config/
/etc/ansible/nginx_config/
└── roles
    ├── new
    │   ├── files
    │   ├── handlers
    │   ├── tasks
    │   └── vars
    └── old
        ├── files
        ├── handlers
        ├── tasks
        └── vars

其中,new目錄更新時用到,old回滾時用到,files下面爲nginx.conf,handlers爲重啓nginx服務的命令。
關於回滾,須要在執行playbook以前先備份舊的配置,因此對於舊的配置文件的管理必定要謹慎,千萬不要隨便去修改線上機器的配置,並且要保證new/files下面的配置和線上的配置保持一致。
拷貝nginx.conf文件到/etc/ansible/nginx_config/roles/new/files/目錄下:

[root@jin-10 /usr/local/nginx/conf]# cp -r nginx.conf /etc/ansible/nginx_config/roles/new/files/

編輯一個定義變量的文件vim /etc/ansible/nginx_config/roles/new/vars/main.yml,內容以下:

nginx_basedir: /usr/local/nginx

再編寫一個從新加載nginx服務的文件vim /etc/ansible/nginx_config/roles/new/handlers/main.yml,內容以下:

- name: restart nginx
  shell: /etc/init.d/nginx reload

再編寫一個核心任務的文件vim /etc/ansible/nginx_config/roles/new/tasks/main.yml ,內容以下:

- name: copy conf file
  copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=r
oot group=root mode=0644
  with_items:
   - { src: nginx.conf, dest: conf/nginx.conf }
  notify: restart nginx

最後,咱們定義一個總入口配置文件vim /etc/ansible/nginx_config/update.yml,內容以下:

---
- hosts: testhost
  user: root
  roles:
  - new

執行update.yml

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

能夠看到,nginx服務已經從新加載了:

[root@jin-11 ~]# ps aux|grep nginx
root       4040  0.0  0.0  20540   628 ?        Ss   08:32   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody     4042  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
nobody     4043  0.0  0.3  22984  3192 ?        S    08:32   0:00 nginx: worker process
root       4570  0.0  0.1 112724   996 pts/0    S+   10:43   0:00 grep --color=auto nginx
[root@jin-11 ~]# date
2019年 09月 09日 星期一 10:44:12 CST

咱們編輯nginx.conf,加上一行註釋內容:# test for the rollback,而後再執行update.yml腳本:

[root@jin-10 ~]# cat /etc/ansible/nginx_config/roles/new/files/nginx.conf|grep test
# test for the rollback
[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
ok: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
ok: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

在jin-11上查看nginx.conf是否備份成功:

[root@jin-11 ~]# cat /usr/local/nginx/conf/nginx.conf|grep test
# test for the rollback

以上的操做是針對於更新、修改配置文件的,下面來介紹一下回滾操做:
回滾操做就是把舊的配置覆蓋,而後從新加載nginx服務, 每次改動nginx配置文件以前先備份到old裏,對應目錄爲/etc/ansible/nginx_config/roles/old/files。
拷貝new目錄裏的文件到old目錄裏,至關於把當前nginx配置文件備份到old裏,如需回滾就將備份還原。

[root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/
sending incremental file list
files/
files/nginx.conf
handlers/
handlers/main.yml
tasks/
tasks/main.yml
vars/
vars/main.yml

sent 2,535 bytes  received 108 bytes  5,286.00 bytes/sec
total size is 2,080  speedup is 0.79

編寫一個一個總入口配置文件vim /etc/ansible/nginx_config/rollback.yml,內容以下:

---
- hosts: jin-11
  user: root
  roles:
  - old

下面咱們來進行一個簡單的回滾操做:
一、先將配置文件同步到old目錄下:

[root@jin-10 ~]# rsync -av /etc/ansible/nginx_config/roles/new/files/nginx.conf /etc/ansible/nginx_config/roles/old/files/nginx.conf 
sending incremental file list

sent 49 bytes  received 12 bytes  122.00 bytes/sec
total size is 1,772  speedup is 29.05

二、修改配置文件/etc/ansible/nginx_config/roles/new/files/nginx.conf,文件末尾增長一行註釋內容:

#test the ansible playbook rollback

三、執行update.yml文件向客戶端更新文件:

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/update.yml 

PLAY [testhost] **********************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]
ok: [127.0.0.1]

TASK [new : copy conf file] **********************************************************
changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
changed: [127.0.0.1] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

RUNNING HANDLER [new : restart nginx] ************************************************
changed: [jin-11]
changed: [127.0.0.1]

PLAY RECAP ***************************************************************************
127.0.0.1                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
jin-11                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

四、在jin-11上查看,文件是否同步:

[root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf
#test the ansible playbook rollback

五、能夠看到,同步成功,而後咱們執行rollback.yml文件進行回滾操做:

[root@jin-10 ~]# ansible-playbook /etc/ansible/nginx_config/rollback.yml 

PLAY [jin-11] ************************************************************************

TASK [Gathering Facts] ***************************************************************
ok: [jin-11]

TASK [old : copy conf file] **********************************************************
changed: [jin-11] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})

RUNNING HANDLER [old : restart nginx] ************************************************
changed: [jin-11]

PLAY RECAP ***************************************************************************
jin-11                     : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

六、在jin-11上查看是否已恢復:

[root@jin-11 ~]# tail -n1 /usr/local/nginx/conf/nginx.conf
}
[root@jin-11 ~]#

能夠看到,以前文件末尾增長的那一行沒有了。 因此,所謂的回滾就是在操做改動前,先把文件備份一份,若是出現誤操做,就將以前備份的文件還原回去,這樣就起到了一個回滾的效果。

相關文章
相關標籤/搜索