1. 程式人生 > >Ansible詳解(二)

Ansible詳解(二)

latest load 遠程 即使 centos fine oct syn srv

Ansible系列命令

Ansible系列命令有如下:

  • ansible:這個命令是日常工作中使用率非常高的命令之一,主要用於臨時一次性操作;
  • ansible-doc:是Ansible模塊文檔說明,針對每個模塊都有詳細的用法說明和應用案例介紹;
  • ansible-galaxy:可以簡單的理解為Github或PIP的功能,通過ansible-galaxy,我們可以下載安裝優秀個Roles;
  • ansible-playbook:是日常應用中使用頻率最高的命令,其工作機制是,通過讀取預先編寫好的playbook文件實現批量管理;
  • ansible-pull:Ansible的另一種工作模式,pull模式,ansible默認使用push模式;
  • ansible-vault:主要用於配置文件加密;
  • ansible-console:讓用戶可以在ansible-console虛擬出來的終端上像Shell一樣使用Ansible內置的各種命令;

上一篇已經介紹過ansibleansible-doc的基本用法,下面再來介紹一下其他系列命令的用法。

ansible-galaxy

用法:ansible-galaxy [delete|import|info|init|install|list|login|remove|search|setup] [—help] [options] …

https://galaxy.ansible.com/ 上傳或下載優秀的Playbook(roles)

#列出所有已安裝的galaxy
ansible-galaxy list

#安裝galaxy
ansible-galaxy install geerlingguy.redis

#刪除galaxy
ansible-galaxy remove geerlingguy.redis

ansible-valut

用法:ansible-vault [create|decrypt|edit|encrypt|rekey|view] [—help] [options] vaultfile.yml

ansible-vault encrypt hello.yml  # 加密
ansible-vault decrypt hello.yml  # 解密
ansible-vault view hello.yml  # 查看

ansible-console

[email protected] (2)[f:10] $ service name=httpd state=stopped

[email protected] (2)[f:10] $
執行用戶@當前操作的主機組 (當前組的主機數量)[f:並發數]$

設置並發數: forks n  例如: forks 10
切換組: cd groupname  例如: cd mageduweb
列出當前組主機列表: list
列出所有的內置模塊: ?

ansible-playbook

Usage: ansible-playbook playbook.yml

playbook就是一個用yaml語法把多個模塊堆起來的一個文件而已。

1.簡介

yaml是一個可讀性高的用來表達資料序列的格式。YAML參考了其他多種語言,包括:XML、C語言、Python、Perl以及電子郵件格式RFC2822等。Clark Evans在2001年在首次發表了這種語言,另外Ingy d?t Net與Oren Ben-Kiki也是這語言的共同設計者。

2.特點

  • YAML的可讀性好
  • YAML和腳本語言的交互性好
  • YAML使用實現語言的數據類型
  • YAML有一個一致的信息模型
  • YAML易於實現
  • YAML可以基於流來處理
  • YAML表達能力強,擴展性好

YAML的語法和其他高階語言類似,並且可以簡單表達清單、散列表、標量等數據結構。其結構(Structure)通過空格來展示,序列(Sequence)裏的項用”-“來代表,Map裏的鍵值對用”:”分隔。下面是一個示例。

- hosts: 10.1.0.1        #定義主機
      vars:                      #定義變量
           var1: value
           var2: value
      tasks:                    #定義任務
           - name:           #任務名稱。
       #這裏就可以開始用模塊來執行具體的任務了。

      handlers:     #定義觸發通知所作的操作。裏面也是跟tasks一樣,用模塊定義任務。
           - name:

      remote_user:             #遠程主機執行任務時的用戶。一般都是root,一般也不用指定。

    - hosts: web
      vars:
      tasks:
      handlers:
      remote_user:

YAML文件擴展名通常為.yaml,如example.yaml

Playbooks:

技術分享

核心組件:

  • Hosts:執行的遠程主機列表
  • Tasks:任務,由模塊定義的操作的列表;
  • Varniables:內置變量或自定義變量在playbook中調用
  • Templates:模板,即使用了模板語法的文本文件;
  • Handlers:和notify結合使用,為條件觸發操作,滿足條件方才執行,否則不執行;
  • Roles:角色;
* 安裝http腳本實現:

#!/bin/bash
# 安裝Apache
yum install --quiet -y httpd httpd-devel   # command: yum install --quiet -y httpd httpd-devel
# 復制配置文件
cp /path/to/config/httpd.conf /etc/httpd/conf/httpd.conf -f
cp/path/to/httpd-vhosts.conf /etc/httpd/conf/httpd-vhosts.conf -f
# 啟動Apache,並設置開機啟動
service httpd start
chkconfig httpd on



* 安裝httpd ansible-playbook實現

---
- hosts: all
  tasks:
   - name: "安裝Apache"
     command: yum install --quiet -y httpd httpd-devel
   - 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,並設置開機啟動"
     command: service httpd start
     command: chkconfig httpd on

playbook的基礎組件:

Hosts:運行指定任務的目標主機;
remote_user:在遠程主機以哪個用戶身份執行;
    sudo_user:非管理員需要擁有sudo權限;
tasks:任務列表
    模塊,模塊參數:
        格式:
            (1) action: module arguments
            (2) module: arguments

示例:

vim test.yaml,後綴也可以是.yml

技術分享

- hosts: all
  remote_user: root
  tasks:
  - name: install a group
    group: name=mygrp system=true 
  - name: install a user
    user: name=user1 group=mygrp system=true

 - hosts: websrvs      
   remote_user: root
   tasks:
    - name: install httpd package
      yum: name=httpd
    - name: start httpd service 
      service: name=httpd state=started

運行playbook,使用ansible-playbook命令:

檢測語法:

  • ansible-playbook --syntax-check /path/to/playbook.yaml

測試運行,即不真正執行:

  • ansible-playbook -C /path/to/playbook.yaml
  • ansible-playbook –check /path/to/playbook.yaml
    --list-hosts
    --list-tasks
    --list-tags

運行:

  • ansible-playbook /path/to/playbook.yaml
    -t TAGS, --tags=TAGS
    --skip-tags=SKIP_TAGS  跳過指定的標簽
    --start-at-task=START_AT 從哪個任務後執行

tags: 標簽,給指定的任務定義一個調用標識;

- name: NAME
      module: arguments
      tags: TAG_ID

指定某條任務執行:ansible-playbook --tags=user useradd.yml

- hosts: mageduweb
  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: Start Nginx
      service: name=nginx state=started enabled=yes

可以一次調用多個名稱相同的標簽。也可以調用不同的標簽用 “,” 分割。

示例:

我們把httpd的監聽端口改為8080

技術分享

用playbook把這個文件傳到node3,4上

技術分享

指明標簽的檢查

技術分享

技術分享

從標簽位置開始執行

技術分享

跳過標簽

技術分享

handlers 和 notify 結合使用觸發條件,讓playbook在滿足一定觸發條件時才去執行某條task

- name: TASK_NAME
  module: arguments
  notify: HANDLER_NAME
handlers:
- name: HANDLER_NAME
  module: arguments

技術分享

第一次的話都會運行,後邊如果文件內容發生改變就會觸發notify,然後會直接執行handlers的內容(這裏notify後邊的事件就都不會執行了)。估計是md5那種的校驗。刪了個#號竟然也會通知。

---

- hosts: mageduweb
  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/config.txt
      notify:
        - Restart Nginx
        - Check Nginx Process


  handlers:
    - name: Restart Nginx
      service: name=nginx state=restarted enabled=yes
    - name: Check Nginx Process
      shell: ss -tnl | grep 80

playbook 變量使用

變量來源:
(1)ansible setup facts遠程主機的所有變量都可以用
(2)自定義變量
a. 在/etc/ansible/hosts 定義變量,在主機組中的主機單獨定義,優先級高於組中公共變量
b. 在/etc/ansible/hosts 定義變量,針對主機組中的所有主機集中定義變量
c. 通過命令行指定變量,優先級最高

在hosts Inventory(/etc/ansible/hosts)中為每個主機定義專用變量值;
[all]
172.16.47.103 aaa=nginx
172.16.47.104 aaa=httpd

###############################
- hosts: all
  remote_user: root
  tasks:
  - name: install web package
    yum: name={{ aaa }} state=latest
(a) 向不同的主機傳遞不同的變量;

        IP/HOSTNAME variable_name=value
            [web]
            10.1.6.72 qzx=httpd
            10.1.6.73 qzx=nginx

(b) 向組內的所有主機傳遞相同的變量 ;

        [groupname:vars]
        variable_name=value

        [web:qzx]
        qzx=httpd

        [web]
        10.1.6.72
        10.1.6.73

變量調用方式:

{{ variable_name }} 通過{{ }} 調用變量,且變量和{}兩頭之間必須有空格

額外介紹的是:

在playbook中調用變量時,有時”{{ variable_name }}”需要要雙引號引起來方可生效,有時候必須不能用””引起來

d.在playbook中定義,建議使用這個!

vars:
    - var_name: value
    - var_name: value

e.Inventory還可以使用參數

用於定義ansible遠程連接目標主機時使用的屬性,而非傳遞給playbook的變量;
        ansible_ssh_host
        ansible_ssh_port
        ansible_ssh_user
        ansible_ssh_pass
        ansible_sudo_pass
        ...

f.在角色調用時傳遞

roles:
- { role: ROLE_NAME, var: value, ...}

templates模版

文本文件,內部嵌套有模板語言腳本(使用模板語言編寫)

Jinja2 是由python編寫的。 在我們打算使用基於文本的模板語言時,jinja2是很好的解決方案。yeml是寫playbookjinja2是寫配置文件模板的。

功能:
將模板的文件的變量值轉換成對應的本地主機的確定值。例如:ansible端寫一個內建變量{{ ansible_processor_vcpus }},當這個文件被復制到對應主機時會自動生成對應主機 cpu的顆數的結果替換之。

Jinja2語法:

字面量:
    字符串:使用單引號或雙引號; 
    數字:整數、浮點數;
    列表:[item1, item2, ...]
    元組:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布爾型:true/false

算術運算:
    +, -, *, /, //, %, **

比較操作:
    ==, !=, >, <, >=, <=

邏輯運算:and, or, not

執行模板文件中的腳本,並生成結果數據流,需要使用template模塊

template:使用了Jinjia2格式作為文件模版,進行文檔內變量的替換的模塊。相當於copy。

將jinja2的文件模板理解並執行,轉化為各個主機間的對應值

backup       建立個包括timestamp在內的文件備份,以備不時之需.
dest       遠程節點上的絕對路徑,用於放置template文件。
group      設置遠程節點上的的template文件的所屬用戶組
mode       設置遠程節點上的template文件權限。類似Linux中chmod的用法
owner      設置遠程節點上的template文件所屬用戶
src        本地Jinjia2模版的template文件位置。

註意:此模板不能在命令行使用,而只能用於playbook;用法同copy

(1) templates文件必須存放於目錄名為templates下,且命名為 .j2 結尾
(2)yaml/yml playbook文件需和templates目錄平級,目錄結構如下:
    ./
    ├── temnginx.yml
    └── templates
        └── nginx.conf.j2

案例1:

// templates/nginx.conf.j2

{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost }}

}

{% endfor %}


// temnginx.yml
---

- hosts: mageduweb
  remote_user: root
  vars:
    nginx_vhosts:
      - web1
      - web2
      - web3
  #  nginx_vhosts:
  #    - listen: 8080



  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

生成的結果:

server {
   listen web1

}


server {
   listen web2

}

server {
   listen web3

}
案例2:

shell腳本與Jinja語法對比:
-- shell腳本中寫法
for i in {1..10}
do
   con
done


if [ xx ];then
    con
elif
     con
else
    con
fi


-- Jinja寫法:

//  templates/nginx.conf.j2

{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen  }}

}

{% endfor %}

* 生成的結果

server {
   listen 8080

}



* playbook調用文件
//  temnginx.yml

---

- hosts: mageduweb
  remote_user: root
  vars:
    nginx_vhosts:
      - listen: 8080



  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf


* 案例3

// temnginx.yml

---

- hosts: mageduweb
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        server_name: "web1.magedu.com"
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.magedu.com"
        root: "/var/www/nginx/web3/"


  ## 案例1
  #  nginx_vhosts:
  #    - web1
  #    - web2
  #    - web3
  ## 案例2



  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf




// templates/nginx.conf.j2

{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen }}
   server_name {{ vhost.server_name }}
   root  {{ vhost.root }}

}

{% endfor %}



* 生成結果:

server {
   listen 8080
   server_name web1.magedu.com
   root  /var/www/nginx/web1/

}

server {
   listen 8080
   server_name web2.magedu.com
   root  /var/www/nginx/web2/

}


server {
   listen 8080
   server_name web3.magedu.com
   root  /var/www/nginx/web3/

}


* 案例4
// templates/nginx.conf.j2

{% for vhost in  nginx_vhosts %}
server {
   listen {{ vhost.listen }}

   {% if vhost.server_name is defined %}
   server_name {{ vhost.server_name }}
   {% endif %}

   root  {{ vhost.root }}

}

{% endfor %}




// temnginx.yml

---

- hosts: mageduweb
  remote_user: root
  vars:
    nginx_vhosts:
      - web1:
        listen: 8080
        #server_name: "web1.magedu.com"
        root: "/var/www/nginx/web1/"
      - web2:
        listen: 8080
        server_name: "web2.magedu.com"
        root: "/var/www/nginx/web2/"
      - web3:
        listen: 8080
        server_name: "web3.magedu.com"
        root: "/var/www/nginx/web3/"


  ## 案例1
  #  nginx_vhosts:
  #    - web1
  #    - web2
  #    - web3
  ## 案例2



  tasks:
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf


* 執行命令

ansible-playbook temnginx.yml


* 生成的結果

server {
   listen 8080


   root  /var/www/nginx/web1/

}

server {
   listen 8080

      server_name web2.magedu.com

   root  /var/www/nginx/web2/

}

server {
   listen 8080

      server_name web3.magedu.com

   root  /var/www/nginx/web3/

}


### ansible-playbook when條件判斷


---

- hosts: mageduweb
  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"

### ansible-playbook with_items 列表

---

- hosts: mageduweb
  remote_user: root

  tasks:
  - name: create rsyncd file
    copy: src={{ item }} dest=/tmp/{{ item }}
    with_items:
      - a
      - b
      - c
      - d


  - name: yum install httpd
    yum: name={{ item }}  state=present 
    with_items:
      - apr
      - apr-util
      - httpd



* with_itmes 嵌套子變量

---

- hosts: mageduweb
  remote_user: root


  tasks:
  - name: add several users
    user: name={{ item.name }} state=present groups={{ item.groups }}
    with_items:
      - { name: ‘testuser1‘ , groups: ‘wheel‘}
      - { name: ‘testuser2‘ , groups: ‘root‘}

1、普通示例:

這裏/root/nginx.conf內容發生了改變。

  - hosts: ngxsrvs
    remote_user: root
    tasks:
    - name: install nginx package
      yum: name=nginx state=latest
    - name: install conf file
      template: src=/root/nginx.conf.j2 dest=/etc/nginx/nginx.conf
      tags: ngxconf
      notify: reload nginx service
    - name: start nginx service
      service: name=nginx state=started enabled=true
    handlers:
    - name: reload nginx service
      shell: /usr/sbin/nginx -s reload

2、條件測試:

when語句:在tasks中使用,Jinja2的語法格式;

-     hosts: all
    remote_user: root
    tasks:
    - name: install nginx package
      yum: name=nginx state=latest
    - name: start nginx service on CentOS6
      shell: service nginx start
      when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "6"
    - name: start nginx service
      shell: systemctl start nginx.service
      when: ansible_distribution == "CentOS" and ansible_distribution_major_version == "7"

3、循環:叠代,需要重復執行的任務;

對叠代項的引用,固定變量名為”item”,使用with_item屬性給定要叠代的元素; 這個是以任務為中心,圍繞每個任務來跑主機,如果中間某個任務中斷,那麽所有主機以後的任務就無法安裝。

元素:

  • 列表
  • 字符串
  • 字典

基於字符串列表給出元素示例:

-   hosts: websrvs
    remote_user: root
    tasks:
    - name: install packages
      yum: name={{ item }} state=latest
      with_items:
      - httpd
      - php
      - php-mysql
      - php-mbstring
      - php-gd

基於字典列表給元素示例:item.name .後邊的表示鍵

- hosts: all
  remote_user: root
  tasks:
  - name: create groups
    group: name={{ item }} state=present
    with_items:
    - groupx1
    - groupx2
    - groupx3
  - name: create users
    user: name={{ item.name }} group={{ item.group }} state=present
    with_items:
    - {name: ‘userx1‘, group: ‘groupx1‘}
    - {name: ‘userx2‘, group: ‘groupx2‘}
    - {name: ‘userx3‘, group: ‘groupx3‘}

角色:roles

以特定的層級目錄結構進行組織的tasks、variables、handlers、templates、files等;相當於函數的調用把各個事件切割成片段來執行。

mkdir ./{nginx,memcached,httpd,mysql}/{file,templates,vars,handlers,meta,default,tasks} -pv

role_name/

    files/:存儲由copy或script等模塊調用的文件; 

    tasks/:此目錄中至少應該有一個名為main.yml的文件,用於定義各task;其它的文件需要由main.yml進行“包含”調用;

    handlers/:此目錄中至少應該有一個名為main.yml的文件,用於定義各handler;其它的文件需要由main.yml進行“包含”調用;

    vars/:此目錄中至少應該有一個名為main.yml的文件,用於定義各variable;其它的文件需要由main.yml進行“包含”調用;

    templates/:存儲由template模塊調用的模板文本;

    meta/:此目錄中至少應該有一個名為main.yml的文件,定義當前角色的特殊設定及其依賴關系;其它的文件需要由main.yml進行“包含”調用;

    default/:此目錄中至少應該有一個名為main.yml的文件,用於設定默認變量;

在playbook中調用角色的方法:

- hosts: HOSTS
  remote_user: USERNAME
  roles:
  - ROLE1
  - ROLE2
  - { role: ROLE3, VARIABLE: VALUE, ...}
  - { role: ROLE4, when: CONDITION }

事例: 基於角色的方式安裝 nginx

1.創建需要的文件

mkdir ./{nginx,memcached,httpd,mysql}/{files,templates,vars,handlers,meta,default,tasks} -pv

2.復制相應的安裝包和模板到對應目錄下

技術分享

3.寫tasks/下的主main.yml

技術分享

- name: copy nginx package
  copy: src=nginx-1.10.0-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.0-1.el7.ngx.x86_64.rpm

- name: install nginx package
  yum: name=/tmp/nginx-1.10.0-1.el7.ngx.x86_64.rpm  state=present

- name: install nginx.conf file
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: ngxconf
  notify: reload nginx service

- name: install default.conf file
  template: src=default.conf.j2 dest=/etc/nginx/conf.d/default.conf
  tags: ngxconf
  notify: reload nginx service

- name: start nginx service
  service: name=nginx enabled=true state=started

4.根據需要修改nginx的配置文件模板。(這裏改的是work進程生成數和監聽的端口)

技術分享

技術分享

5.寫handlers目錄和vars/下的main.yml 文件

技術分享

6.寫需要運行的主yml文件

技術分享

7.測試

技術分享

8.運行

技術分享

技術分享

安裝成功

9.改端口測試,通過傳遞參數方式

技術分享

技術分享

修改成功!!!

Ansible詳解(二)