Ansible命令大全【下】

#cat blockinfile_ex.yml
---
- name: blockinfile module test
  hosts: test
  tasks:
    - name: copy test.html to dest
      copy:
        src: files/test.html
        dest: /var/www/html/test.html
    - name: add block 
      blockinfile:
        marker: "<!-- {mark} ANSIBLE MANAGED BLOCK -->"
        insertafter: "<body>"
        path: /var/www/html/test.html
        block: |
          <h1>Welcome to {{ ansible_hostname }}</h1>
          <p>Last updated on {{ ansible_date_time.iso8601 }}</p>
執行後結果如下:
[root@app html]# cat test.html 
<html>
  <head>
  </head>
  <body>
<!-- BEGIN ANSIBLE MANAGED BLOCK -->
<h1>Welcome to app</h1>
<p>Last updated on 2019-05-28T15:00:03Z</p>
<!-- END ANSIBLE MANAGED BLOCK -->
  </body>
</html>

2、Jinja2模板管理
介紹:Jinja2是基於python的模板引擎。那麼什麼是模板?
假設說現在我們需要一次性在10臺主機上安裝redis,這個通過playbook現在已經很容易實現。默認情況下,所有的redis安裝完成之後,我們可以統一爲其分發配置文件。這個時候就面臨一個問題,這些redis需要監聽的地址各不相同,我們也不可能爲每一個redis單獨寫一個配置文件。因爲這些配置文件中,絕大部分的配置其實都是相同的。這個時候最好的方式其實就是用一個通用的配置文件來解決所有的問題。將所有需要修改的地方使用變量替換,如下示例中redis.conf.j2文件:
daemonize yes
pidfile /var/run/redis.pid
port 6379
logfile "/var/log/redis/redis.log"
dbfilename dump.rdb
dir /data/redis
maxmemory 1G
bind {{ ansible_eth0.ipv4.address }} 127.0.0.1
timeout 300
loglevel notice
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
maxclients 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
#那麼此時,redis.conf.j2文件就是一個模板文件。{{ ansible_eth0.ipv4.address }}是一個fact變量,用於獲取被控端ip地址以實現替換。

3、在playbook中使用jinja2
現在我們有了一個模板文件,那麼在playbook中如何來使用呢?
playbook使用template模塊來實現模板文件的分發,其用法與copy模塊基本相同,唯一的區別是,copy模塊會將原文件原封不動的複製到被控端,而template會將原文件複製到被控端,並且使用變量的值將文件中的變量替換以生成完整的配置文件。
下面是一個完整的示例:
# cat config_redis.yml 
- name: Configure Redis
  hosts: test
  tasks:
    - name: install redis
      yum:
        name: redis
        state: present
    - name: create data dir
      file:
        path: /data/redis
        state: directory
        recurse: yes
        owner: redis
        group: redis
    - name: copy redis.conf to dest
      template:
        src: templates/redis.conf.j2
        dest: /etc/redis.conf
      notify:
        - restart redis
    - name: start redis
      service:
        name: redis
        state: started
        enabled: yes
  handlers:
    - name: restart redis
      service:
        name: redis
        state: restarted
執行完成之後,我們可以看到被控端/etc/redis.conf配置文件如下:
daemonize yes
pidfile /var/run/redis.pid
port 6379
logfile "/var/log/redis/redis.log"
dbfilename dump.rdb
dir /data/redis
maxmemory 1G
bind 10.1.61.187 127.0.0.1
timeout 300
loglevel notice
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
maxclients 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
關於template模塊的更多參數說明:

backup:如果原目標文件存在,則先備份目標文件
dest:目標文件路徑
force:是否強制覆蓋,默認爲yes
group:目標文件屬組
mode:目標文件的權限
owner:目標文件屬主
src:源模板文件路徑
validate:在複製之前通過命令驗證目標文件,如果驗證通過則複製

4、Jinja2條件語句
在上面的示例中,我們直接取了被控節點的eth0網卡的ip作爲其監聽地址。那麼假如有些機器的網卡是bond0,這種做法就會報錯。這個時候我們就需要在模板文件中定義條件語句如下:

daemonize yes
pidfile /var/run/redis.pid
port 6379
logfile "/var/log/redis/redis.log"
dbfilename dump.rdb
dir /data/redis

maxmemory 1G

{% if ansible_eth0.ipv4.address %}
bind {{ ansible_eth0.ipv4.address }} 127.0.0.1
{% elif ansible_bond0.ipv4.address %}
bind {{ ansible_bond0.ipv4.address }} 127.0.0.1
{% else%}
bind 0.0.0.0
{% endif %}

timeout 300
loglevel notice

databases 16
save 900 1
save 300 10
save 60 10000

rdbcompression yes

maxclients 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec
我們可以更進一步,讓redis主從角色都可以使用該文件:

daemonize yes
pidfile /var/run/redis.pid
port 6379
logfile "/var/log/redis/redis.log"
dbfilename dump.rdb
dir /data/redis

maxmemory 1G

{% if ansible_eth0.ipv4.address %}
bind {{ ansible_eth0.ipv4.address }} 127.0.0.1
{% elif ansible_bond0.ipv4.address %}
bind {{ ansible_bond0.ipv4.address }} 127.0.0.1
{% else%}
bind 0.0.0.0
{% endif %}

{% if redis_slave is defined %}
slaveof {{ masterip }} {{ masterport|default(6379) }}
{% endif %}

{% if masterpass is defined %}
masterauth {{ masterpass }}
{% endif %}

{% if requirepass is defined %}
requirepass {{ requirepass }}
{% endif %}

timeout 300
loglevel notice

databases 16
save 900 1
save 300 10
save 60 10000

rdbcompression yes

maxclients 10000
appendonly yes
appendfilename appendonly.aof
appendfsync everysec

stop-writes-on-bgsave-error no
我們定義一個inventory如下:

[redis]
10.1.61.27 redis_slave=true masterip=10.1.61.187 masterpass=123456
10.1.61.187 requirepass=123456

5、Jinja2循環語句
定義一個inventory示例如下:

[redis]
10.1.61.27 redis_slave=true masterip=10.1.61.187 masterpass=123456
10.1.61.187 requirepass=123456

5、Jinja2循環語句
定義一個inventory示例如下:

[proxy]
10.1.61.195

[webserver]
10.1.61.27
10.1.61.187
現在把proxy主機組中的主機作爲代理服務器,安裝nginx做反向代理,將請求轉發至後面的兩臺webserver,即webserver組的服務器。

現在我們編寫一個playbook如下:

#cat config_nginx.conf
- name: gather facts
  gather_facts: Fasle
  hosts: webserver
  tasks:
    - name: gather facts
      setup:
   
- name: Configure Nginx
  hosts: proxy
  tasks:
    - name: install nginx
      yum:
        name: nginx
        state: present
    - name: copy nginx.conf to dest
      template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify:
        - restart nginx
    - name: start nginx
      service:
        name: nginx
        state: started
        enabled: yes
  handlers:
    - name: restart nginx
      service:
        name: nginx
        state: restarted
模板文件 templates/nginx.conf.j2示例如下:

# cat nginx.conf.j2 
user nginx;
worker_processes {{ ansible_processor_vcpus }};
error_log /var/log/nginx/error.log;
pid /var/run/nginx.pid;
include /usr/share/nginx/modules/*.conf;
events {
    worker_connections 65535;
    use epoll;
}
http {
    map $http_x_forwarded_for $clientRealIP {
        "" $remote_addr;
        ~^(?P<firstAddr>[0-9\.]+),?.*$ $firstAddr;
    }
    log_format  real_ip '{ "datetime": "$time_local", '
                        '"remote_addr": "$remote_addr", '
                        '"source_addr": "$clientRealIP", '
                        '"x_forwarded_for": "$http_x_forwarded_for", '
                        '"request": "$request_uri", '
                        '"status": "$status", '
                        '"request_method": "$request_method", '
                        '"request_length": "$request_length", '
                        '"body_bytes_sent": "$body_bytes_sent", '
                        '"request_time": "$request_time", '
                        '"http_referrer": "$http_referer", '
                        '"user_agent": "$http_user_agent", '
                        '"upstream_addr": "$upstream_addr", '
                        '"upstream_status": "$upstream_status", '
                        '"upstream_http_header": "$upstream_http_host",'
                        '"upstream_response_time": "$upstream_response_time", '
                        '"x-req-id": "$http_x_request_id", '
                        '"servername": "$host"'
                        ' }';
    access_log  /var/log/nginx/access.log  real_ip;
    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;
    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;
    include /etc/nginx/conf.d/*.conf;

    upstream web {
    {% for host in groups['webserver'] %}
        {% if hostvars[host]['ansible_bond0']['ipv4']['address'] is defined %}
        server {{ hostvars[host]['ansible_bond0']['ipv4']['address'] }};
        {% elif hostvars[host]['ansible_eth0']['ipv4']['address'] is defined %}
        server {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }};
        {% endif %}
    {% endfor %}
    }
    server {
        listen       80 default_server;
        server_name  _;
        location / {
            proxy_pass http://web;
        }
    }
}
下面再給一個域名解析服務bind的配置文件 named.conf的jinja2模板示例:

options {

listen-on port 53 {
127.0.0.1;
{% for ip in ansible_all_ipv4_addresses %}
{{ ip }};
{% endfor %}
};

listen-on-v6 port 53 { ::1; };
directory "/var/named";
dump-file "/var/named/data/cache_dump.db";
statistics-file "/var/named/data/named_stats.txt";
memstatistics-file "/var/named/data/named_mem_stats.txt";
};

zone "." IN {
type hint;
file "named.ca";
};

include "/etc/named.rfc1912.zones";
include "/etc/named.root.key";

{# Variables for zone config #}
{% if 'authorativenames' in group_names %}
{% set zone_type = 'master' %}
{% set zone_dir = 'data' %}
{% else %}
{% set zone_type = 'slave' %}
{% set zone_dir = 'slaves' %}
{% endif %}

zone "internal.example.com" IN {
type {{ zone_type }};
file "{{ zone_dir }}/internal.example.com";
{% if 'authorativenames' not in group_names %}
masters { 192.168.2.2; };
{% endif %}
};

6、Jinja2過濾器
(1) default過濾器
簡單示例:
"Host": "{{ db_host | default('lcoalhost') }}"
(2)應用於註冊變量的過濾器
正常情況下,當某個task執行失敗的時候,ansible會中止運行。此時我們可以通過ignore_errors來捕獲異常以讓task繼續往下執行。然後調用debug模塊打印出出錯時的內容,拿來錯誤結果後,主動失敗。
- name: Run myprog
  command: /opt/myprog
  register: result
  ignore_errors: True
- debug: 
    var: result
- debug: 
    msg: "Stop running the playbook if myprog failed"
    failed_when: result|failed
任務返回值過濾器:
failed: 如果註冊變量的值是任務failed則返回True
changed: 如果註冊變量的值是任務changed則返回True
success:如果註冊變量的值是任務succeeded則返回True
skipped:如果註冊變量的值是任務skipped則返回True

(3)應用於文件路徑的過濾器
basename:返回文件路徑中的文件名部分
dirname:返回文件路徑中的目錄部分
expanduser:將文件路徑中的~替換爲用戶目錄
realpath:處理符號鏈接後的文件實際路徑
下面是一個示例:

- name: test basename
  hosts: test
  vars:
    homepage: /usr/share/nginx/html/index.html
  tasks:
    - name: copy homepage
      copy:
        src: files/index.html
        dest: {{ homepage }}
可以通過basename改寫成如下方式:

- name: test basename
  hosts: test
  vars:
    homepage: /usr/share/nginx/html/index.html
  tasks:
    - name: copy homepage
      copy:
        src: files/{{ homepage | basename }}
        dest: {{ homepage }}
(4)自定義過濾器
舉個簡單的例子,現在有一個playbook如下:

- name: test filter
  hosts: test
  vars:
    domains: ["www.example.com","example.com"]
  tasks:
    template:
      src: templates/test.conf.j2
      dest: /tmp/test.conf
templates/test.conf.j2如下:
hosts = [{{ domains | join(',') }}]
執行playbook後,在目標機上的test.conf如下:
hosts = [www.example.com,example.com]
現在如果希望目標機上的test.conf文件返回結果如下:
hosts = ["www.example.com","example.com"]
沒有現成的過濾器來幫我們做這件事情。我們可以自己簡單寫一個surround_by_quote.py內容如下:


# 定義過濾器執行的操作
def surround_by_quote(a_list):
  return ['"%s"' % an_element for an_element in a_list]
class FilterModule(object):
  def filters(self):
    return {'surround_by_quote': surround_by_quote}
我們需要開啓ansible.cfg的配置項:
filter_plugins     = /usr/share/ansible/plugins/filter
將剛剛編寫的代碼文件放入/usr/share/ansible/plugins/filter目錄下,然後修改templates/test.conf.j2如下:
hosts = [{{ domains | join(',') }}]
再次執行playbook,最後返回結果:
hosts = ["www.example.com","example.com"]

十五、Playbook高級用法
1、本地執行
如果希望在控制主機本地運行一個特定的任務,可以使用local_action語句。
假設我們需要配置的遠程主機剛剛啓動,如果我們直接運行playbook,可能會因爲sshd服務尚未開始監聽而導致失敗,我們可以在控制主機上使用如下示例來等待被控端sshd端口監聽:
- name: wait for ssh server to be running
  wait_for
      port: 22 
      host: "{{ inventory_hostname }}" 
      search_regex: OpenSSH
  connection: local

2、任務委託
在有些時候,我們希望運行與選定的主機或主機組相關聯的task,但是這個task又不需要在選定的主機或主機組上執行,而需要在另一臺服務器上執行。
這種特性適用於以下場景:
在告警系統中啓用基於主機的告警
向負載均衡器中添加或移除一臺主機
在dns上添加或修改針對某個主機的解析
在存儲節點上創建一個存儲以用於主機掛載
使用一個外部程序來檢測主機上的服務是否正常
可以使用delegate_to語句來在另一臺主機上運行task:
- name: enable alerts for web servers
  hosts: webservers
  tasks:
    - name: enable alerts
      nagios: action=enable_alerts service=web host="{{ inventory_hostname }}"
      delegate_to: nagios.example.com
如果delegate_to: 127.0.0.1的時候,等價於local_action

3、任務暫停
有些情況下,一些任務的運行需要等待一些狀態的恢復,比如某一臺主機或者應用剛剛重啓,我們需要需要等待它上面的某個端口開啓,此時就需要將正在運行的任務暫停,直到其狀態滿足要求。
Ansible提供了wait_for模塊以實現任務暫停的需求

wait_for模塊常用參數:
connect_timeout:在下一個任務執行之前等待連接的超時時間
delay:等待一個端口或者文件或者連接到指定的狀態時,默認超時時間爲300秒,在這等待的300s的時間裏,wait_for模塊會一直輪詢指定的對象是否到達指定的狀態,delay即爲多長時間輪詢一次狀態。
host:wait_for模塊等待的主機的地址,默認爲127.0.0.1
port:wait_for模塊待待的主機的端口
path:文件路徑,只有當這個文件存在時,下一任務纔開始執行,即等待該文件創建完成
state:等待的狀態,即等待的文件或端口或者連接狀態達到指定的狀態時,下一個任務開始執行。當等的對象爲端口時,狀態有started,stoped,即端口已經監聽或者端口已經關閉;當等待的對象爲文件時,狀態有present或者started,absent,即文件已創建或者刪除;當等待的對象爲一個連接時,狀態有drained,即連接已建立。默認爲started
timeout:wait_for的等待的超時時間,默認爲300秒
示例:

#等待8080端口已正常監聽,纔開始下一個任務,直到超時
- wait_for: 
    port: 8080 
    state: started  
    
#等待8000端口正常監聽,每隔10s檢查一次,直至等待超時
- wait_for: 
    port: 8000 
    delay: 10 
    
#等待8000端口直至有連接建立
- wait_for: 
    host: 0.0.0.0 
    port: 8000 
    delay: 10 
    state: drained
    
#等待8000端口有連接建立,如果連接來自10.2.1.2或者10.2.1.3,則忽略。
- wait_for: 
    host: 0.0.0.0 
    port: 8000 
    state: drained 
    exclude_hosts: 10.2.1.2,10.2.1.3 
    
#等待/tmp/foo文件已創建    
- wait_for: 
    path: /tmp/foo 

#等待/tmp/foo文件已創建,而且該文件中需要包含completed字符串    
- wait_for: 
    path: /tmp/foo 
    search_regex: completed 

#等待/var/lock/file.lock被刪除    
- wait_for: 
    path: /var/lock/file.lock 
    state: absent 
    
#等待指定的進程被銷燬
- wait_for: 
    path: /proc/3466/status 
    state: absent 
    
#等待openssh啓動,10s檢查一次
- wait_for: 
    port: 22 
    host: "{{ ansible_ssh_host | default(inventory_hostname) }}" search_regex: OpenSSH 
    delay: 10 

4、滾動執行
默認情況下,ansible會並行的在所有選定的主機或主機組上執行每一個task,但有的時候,我們會希望能夠逐臺運行。最典型的例子就是對負載均衡器後面的應用服務器進行更新時。通常來講,我們會將應用服務器逐臺從負載均衡器上摘除,更新,然後再添加回去。我們可以在play中使用serial語句來告訴ansible限制並行執行play的主機數量。
下面是一個在amazon EC2的負載均衡器中移除主機,更新軟件包,再添加回負載均衡的配置示例:
- name: upgrade pkgs on servers behind load balancer
  hosts: myhosts
  serial: 1
  tasks:
    - name: get the ec2 instance id and elastic load balancer id
      ec2_facts:

    - name: take the host out of the elastic load balancer id
      local_action: ec2_elb
      args:
        instance_id: "{{ ansible_ec2_instance_id }}"
        state: absent

    - name: upgrade pkgs
      apt: 
          update_cache: yes 
          upgrade: yes

    - name: put the host back n the elastic load balancer
      local_action: ec2_elb
      args:
        instance_id: "{{ ansible_ec2_instance_id }}"
        state: present
        ec2_elbs: "{{ items }}"
      with_items: ec2_elbs
在上述示例中,serial的值爲1,即表示在某一個時間段內,play只在一臺主機上執行。如果爲2,則同時有2臺主機運行play。
一般來講,當task失敗時,ansible會停止執行失敗的那臺主機上的任務,但是繼續對其他 主機執行。在負載均衡的場景中,我們會更希望ansible在所有主機執行失敗之前就讓play停止,否則很可能會面臨所有主機都從負載均衡器上摘除並且都執行失敗導致服務不可用的場景。這個時候,我們可以使用serial語句配合max_fail_percentage語句使用。max_fail_percentage表示當最大失敗主機的比例達到多少時,ansible就讓整個play失敗。示例如下:

- name: upgrade pkgs on fservers behind load balancer
  hosts: myhosts
  serial: 1
  max_fail_percentage: 25
  tasks:
    ......
假如負載均衡後面有4臺主機,並且有一臺主機執行失敗,這時ansible還會繼續運行,要讓Play停止運行,則必須超過25%,所以如果想一臺失敗就停止執行,我們可以將max_fail_percentage的值設爲24。如果我們希望只要有執行失敗,就放棄執行,我們可以將max_fail_percentage的值設爲0。

5、只執行一次
某些時候,我們希望某個task只執行一次,即使它被綁定到了多個主機上。例如在一個負載均衡器後面有多臺應用服務器,我們希望執行一個數據庫遷移,只需要在一個應用服務器上執行操作即可。
可以使用run_once語句來處理:
- name: run the database migrateions
  command: /opt/run_migrateions
  run_once: true
還可以與local_action配合使用,如下:

- name: run the task locally, only once
  command: /opt/my-custom-command
  connection: local
  run_once: true
還可以與delegate_to配合使用,讓這個只執行一次的任務在指定的機器上運行:

- name: run the task locally, only once
  command: /opt/my-custom-command
  run_once: true
  delegate_to: app.a1-61-105.dev.unp

6、設置環境變量
我們在命令行下執行某些命令的時候,這些命令可能會需要依賴環境變量。比如在安裝某些包的時候,可能需要通過代理才能完成完裝。或者某個腳本可能需要調用某個環境變量才能完成運行。
ansible 支持通過environment關鍵字來定義一些環境變量。
在如下場景中可能需要用到環境變量:
運行shell的時候,需要設置path變量
需要加載一些庫,這些庫不在系統的標準庫路徑當中
下面是一個簡單示例:
---
- name: upload a remote file to aws s3
  hosts: test
  tasks:
    - name: install pip
      yum:
        name: python-pip
        state: installed
    
    - name: install the aws tools
      pip:
        name: awscli
        state: present  
    - name upload file to s3
      shell aws s3 put-object --bucket=my-test-bucket --key={{ ansible_hostname }}/fstab --body=/etc/fstab --region=eu-west-1
      environment:
        AWS_ACCESS_KEY_ID: xxxxxx
        AWS_SECRET_ACCESS_KEY: xxxxxx
事實上,environment也可以存儲在變量當中:
- hosts: all
  remote_user: root
  vars:
    proxy_env:
      http_proxy: http://proxy.example.com:8080
      https_proxy: http://proxy.bos.example.com:8080
  tasks:
    - apt: name=cobbler state=installed
      environment: proxy_env
交互式提示
在少數情況下,ansible任務運行的過程中需要用戶輸入一些數據,這些數據要麼比較祕密不方便,或者數據是動態的,不同的用戶有不同的需求,比如輸入用戶自己的賬戶和密碼或者輸入不同的版本號會觸發不同的後續操作等。ansible的vars_prompt關鍵字就是用來處理上述這種與用戶交互的情況的。

 - hosts: all
   remote_user: root
   vars_prompt:
      - name: share_user
        prompt: "what is your network username?"
        private: yes
 
      - name: share_pass
        prompt: "what is your network password"
        private: yes     
    tasks:
      - debug:
          var: share_user
      - debug:
          var: share_pass
vars_prompt常用選項說明:
private: 默認爲yes,表示用戶輸入的值在命令行不可見
default:定義默認值,當用戶未輸入時則使用默認值
confirm:如果設置爲yes,則會要求用戶輸入兩次,適合輸入密碼的情況

十六、Playbook之tags
簡介:
在大型項目當中,通常一個playbook會有非常多的task。而我們每次執行這個playbook時,都會將所有task運行一遍。而事實上,在實際使用過程中,我們可能只是想要執行其中的一部分任務而已,並不想把整個playbook完整跑一遍。這個時候就需要用到tags。
通過tags,我們可以給playbook中的某一些任務打上“標籤”,而在執行playbook的時候,我們可以通過選定標籤的方式指定只執行哪一些任務或者不執行哪一些任務。

1、爲task打tag:
下面是一個安裝httpd的簡單示例:
# cat /etc/ansible/playbook/install_web.yml
- name: configure webservers 
  hosts: all
  remote_user: ansible
  tasks:
    - name: Install httpd
      yum: 
        name: httpd
        state: present
      tags: install_httpd
        
    - name: Cofiguration httpd
      copy: 
        src: /root/httpd.conf 
        dest: /etc/httpd/conf/httpd.conf
      tags: conf_httpd   
      notify:
        - restart httpd
        
    - name: Start httpd
      service: 
        name: httpd 
        state: started 
        enabled: no
      tags: start_httpd
  handlers:
    - name: restart httpd
      service: name=httpd state=restart
在上面的示例中,我們爲兩個task定義了三個tags:install_httpd、conf_httpd以及start_httpd。

2、執行指定tag的task
有了tags之後,我們就可以只運行playbook中指定標籤的task了:

# ansible-playbook --tags="start_httpd" install_web.yml 
PLAY [configure webservers] *******************************************************************************
TASK [Gathering Facts] *****************************************************************************************************
ok: [10.1.61.187]
TASK [Start httpd] **************************************************************************************************************
changed: [10.1.61.187]
PLAY RECAP ********************************************************************************************************
10.1.61.187                : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0  
也可以一次指定多個tag執行:

# ansible-playbook --tags="conf_httpd,start_httpd" install_web.yml     
PLAY [configure webservers] ***********************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************************
ok: [10.1.61.187]
TASK [Cofiguration httpd] *************************************************************************************************************************
ok: [10.1.61.187]
TASK [Start httpd] *******************************************************************************************************************************
ok: [10.1.61.187]
PLAY RECAP ****************************************************************************************************************
10.1.61.187                : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

3、排除指定tag的task
通過下面的方式可以排除指定了tag的task,即除了指定tag的task不執行,其他task都執行:
# ansible-playbook --skip-tags="install_httpd" install_web.yml                           
PLAY [configure webservers] **************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************
ok: [10.1.61.187]
TASK [Cofiguration httpd] ****************************************************************************************************************
ok: [10.1.61.187]
TASK [Start httpd] ***********************************************************************************************************************
ok: [10.1.61.187]
PLAY RECAP *******************************************************************************************************************************
10.1.61.187                : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 
執行效果跟上面一樣。

4、查看playbook中的所有tag
可以通過--list-tags參數列出指定的playbook中所有的tag
# ansible-playbook --list-tags install_web.yml                          
playbook: install_web.yml
  play #1 (all): configure webservers   TAGS: []
      TASK TAGS: [conf_httpd, install_httpd, start_httpd]

5、打tag的幾種方式
(1)爲一個任務指定一個標籤
tags: conf_httpd

(2)爲一個任務指定多個標籤  #可以通過列表的方式爲一個任務指定多個標籤:
tags:
  - install_httpd
  - install_web
tags: ['install_httpd','install_web']
tags: install_httpd,install_web

(3)爲一個play指定一組標籤  #當爲一個play指定一組標籤後,該play下的所有task都會自動繼承該標籤,各task也可以自定義自己的標籤。
- name: configure webservers 
  hosts: all
  remote_user: ansible
  tags: 
    - httpd
  tasks:
    ...

6、ansible內置tag
除了用戶自定義tag,ansible也內置了幾個tag,這些tag都包含特殊含義:
always:一旦某個task被打上了always的tag,則無論是playbook的完整執行,還是指定tag執行,不管你指定的tag是啥,該任務總是會被執行。除非明確指定"--sk
ip-tags=always"選項,纔不會執行該task。
never:該標籤與always正好相反,總是不會執行,除非明確指定"--tags=never"選項。

tagged:在調用時使用
```sh
  # 所有打了tag的任務都會被執行,包含never tag的除外,沒有標籤的不會被執行
  ansible-playbook --tags tagged install_web.yaml
  # 所有打了tag的任務都不會被執行,包括always tag也不會被執行
  ansible-playbook --skip-tags tagged install_web.yaml

untagged:在調用時使用
```sh
# 所有未打tag的任務都會被執行,打了always tag的也會被執行
ansibl-playbook --tags untagged install_web.yaml
# 所有未打tag的任務都不會被執行
ansibl-playbook --skip-tags untagged install_web.yaml
```
all:表示所有任務都會被執行,在默認情況下,不指定任何標籤,則使用的就是該標

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