管理任务执行
提权
- ansible在进行远程管理时,推荐使用普通用户登录。
- 普通用户在执行管理操作时,需要切换成root账号
[student@warktest inventory-review]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops # ssh登录账号
[privilege_escalation]
become=True # 配置需要提权
become_method=sudo # 提权方法为sudo
become_user=root # 切换成root账号执行命令
become_ask_pass=False # sudo执行命令时,不需交互输入密码
在play中单独设置提权
- 例:
---
- name: Become the user "manager"
hosts: webservers
become: true # 在play上提权
tasks:
- name: Show the user used by this play
debug:
var: ansible_user_id
- name: Do not use privilege escalation
hosts: webservers
become: false # 这个play在执行时,不需要提权
tasks:
- name: Show the user used by this play
debug:
var: ansible_user_id
# 使用ansible.cfg中的配置
- name: Use privilege escalation based on defaults
hosts: webservers
tasks:
- name: Show the user used by this play
debug:
var: ansible_user_id
在task中设置提权
- 例:
---
- name: Play with two tasks, one uses privilege escalation
hosts: all
become: false # play级别不提权
tasks:
- name: This task needs privileges
yum:
name: perl
state: installed
become: true # 该task需要提权
- name: This task does not need privileges
shell: perl -v
register: perlcheck
failed_when: perlcheck.rc != 0
在block上设置提权
- 可以把一组任务放到block中。
- 在block级别设置需要或不需要提权。block中的所有任务都得到了修改。
- name: Deploy web services
hosts: webservers
become: false
tasks:
- block:
- name: Ensure httpd is installed
yum:
name: httpd
state: installed
- name: Start and enable webserver
service:
name: httpd
state: started
enabled: yes
become: true
- name: Test website from itself, do not become
uri:
url: http://{{ ansible_host }}
return_content: yes
register: webpage
failed_when: webpage.status != 200
在role角色中的提权
- 为role中的任务提权有两个方法:
- 在role中直接设置
- 在调用role的playbook中设置(推荐)
- name: Example play with one role
hosts: localhost
roles:
- role: role-name
become: true
通过变量设置提权
- 组变量
webservers:
hosts:
servera.lab.example.com:
serverb.lab.example.com:
vars:
ansible_become: true
- 主机变量
webservers:
hosts:
servera.lab.example.com:
ansible_become: true
serverb.lab.example.com:
- play变量
---
- name: Example play using connection variables
hosts: webservers
vars:
ansible_become: true
tasks:
- name: Play will use privilege escalation even if inventory says no
yum:
name: perl
state: installed
控制任务执行
任务执行顺序
- ansible总是执行roles中的task,然后再执行play中tasks中定义的任务,不管在playbook中的书写顺序是什么样的。
---
- name: Ensure Apache is deployed
hosts: www1.example.com
gather_facts: no
tasks:
- name: Open the firewall
firewalld:
service: http
permanent: yes
state: enabled
roles: # 虽然后书写的,但是比上面的tasks先运行
- role: apache
import或include角色
- 使用
include_role
模块,可以动态引入角色。 - 使用
import_role
模块,可以静态导入角色。 import_role
在playbook执行之前进行导入,导入完成后进行语法检查。include_role
在playbook执行到该角色时,才导入它。include_role
示例:
---
- name: Executing a role as a task
hosts: remote.example.com
tasks:
- name: A normal task
debug:
msg: 'first task'
- name: A task to include role2 here
include_role:
name: role2
- name: Another normal task
debug:
msg: 'second task'
定义pre或post任务
-
pre_tasks
定义在role之前执行的任务 -
post_tasks
定义在tasks这后执行的任务 -
例:
---
- name: Deploying New Application Version
hosts: webservers
pre_tasks:
# Stop monitoring the web server to avoid sending false alarms
# while the service is updating.
- name: Disabling Nagios for this host
nagios:
action: disable_alerts
host: "{{ inventory_hostname }}"
services: http
delegate_to: nagios-srv
roles:
- role: deploy-content
tasks:
- name: Restarting memcached
service:
name: memcached
status: restarted
notify: Notifying the support team
# Confirm that the application is fully operational
# after the update.
- name: Validating the new deployment
uri:
url: "http://{{ inventory_hostname }}/healthz"
return_content: yes
register: result
failed_when: "'OK' not in result.content"
post_tasks:
- name: Enabling Nagios for this host
nagios:
action: enable_alerts
host: "{{ inventory_hostname }}"
services: http
delegate_to: nagios-srv
handlers:
# Send a message to the support team through Slack
# every time the memcached service is restarted.
- name: Notifying the support team
slack:
token: G922VJP25/D923DW937/3Ffe373sfhRE6y52Fg3rvf5GlK
msg: 'Memcached on {{ inventory_hostname }} restarted'
delegate_to: localhost
become: false
-
playbook在执行的时候,有固定的顺序:
pre_tasks
pre_tasks
触发的handlers中的任务- roles
- tasks
- roles或tasks触发的handlers中的任务
post_tasks
post_tasks
触发的handlers中的任务
-
roles和tasks中的任务全部执行完,才会执行它们notify通知的、handlers中的任务。如果希望handlers中的任务立即执行,可以使用meta模块:
---
- name: Updating the application configuration and cache
hosts: app_servers
tasks:
- name: Deploying the configuration file
template:
src: api-server.cfg.j2
dest: /etc/api-server.cfg
notify: Restart api server
- name: Running all notified handlers
meta: flush_handlers # 立即执行handlers中被notify的任务
- name: Asking the API server to rebuild its internal cache
uri:
url: "https://{{ inventory_hostname }}/rest/api/2/cache/"
method: POST
force_basic_auth: yes
user: admin
password: redhat
body_format: json
body:
type: data
delay: 0
status_code: 201
handlers:
- name: Restart api server
service:
name: api-server
state: restarted
enabled: yes
侦听handlers
- 侦听handlers的目的是任务中notify时,handlers中的多个任务被执行。
- 例:
---
- name: Testing the listen directive
hosts: localhost
gather_facts: no
become: no
tasks:
- debug:
msg: Trigerring the handlers
notify: My handlers # 触发执行handlers中的My handlers任务
changed_when: true
handlers:
# Listening to the "My handlers" event
- name: Listening to a notification
debug:
msg: First handler was notified
listen: My handlers # 侦听My handlers,如果它运行,这个任务也运行
# As an example, this handler is also triggered because
# its name matches the notification, but no two handlers
# can have the same name.
- name: My handlers
debug:
msg: Second handler was notified
[student@warktest httpd_alias]$ cat install_httpd_alias.yml
---
- name: Add apache alias
hosts: prod
become: yes
tasks:
- name: check if directory exists
stat:
path: /etc/httpd
register: httpd_dir
- name: create directory if ti doesn't exist
file:
path: /etc/httpd
state: directory
when: not httpd_dir.stat.exists
- name: copy alias file
copy:
src: alias.conf
dest: /etc/httpd/conf.d
notify: install and restart httpd #通告的后面listen的任务
handlers:
- name: check if httpd is installed
command: "rpm -q httpd"
register: httpd_installed
failed_when: false
changed_when: false
listen: install and restart httpd
- name: install httpd
yum:
name: httpd
state: present
when: httpd_installed.rc != 0
listen: install and restart httpd
- name: restart httpd
service:
name: httpd
state: restarted
listen: install and restart httpd
主机执行顺序控制
- 默认情况下,如果playbook的任务需要在很多主机上执行,则按主机清单中的列出顺序执行。
- 通过关键字order,可以改变执行顺序。
---
- name: Testing host order
hosts: web_servers
order: sorted # 按字母顺序排序
tasks:
- name: Creating a test file in /tmp
copy:
content: 'This is a sample file'
dest: /tmp/test.out
order取值:
- inventory:默认值。按主机清单中的书写顺序。
reverse_inventory
:按主机清单中的书写的相反顺序。- sorted:按字母顺序。
- reverse_sorted:按字母,反序。
- shuffle:随机。
运行选择的任务
给资源打标签
-
当使用非常大的、或很复杂的playbook时,有可能只希望运行其中的一部分play或tasks。
-
可以给资源通过tags打标签,将来实现运行一部分资源的功能。
-
在运行playbook时,可以通过
--tags
选项来指定相应的play或tasks。 -
可以为以下资源打标签:
-
标记任务。这是最常见的方式
- name: Install application
hosts: dbservers
vars:
packages:
- postfix
- mariadb-server
tasks:
- name: Ensure that packages are installed
yum:
name: "{{ packages }}"
state: installed
tags:
- install
- 为Play打标签。
- name: Setup web services
hosts: webservers
tags:
- setup
tasks:
- name: Install http daemon
yum:
name: httpd
state: present
- 为
include_tasks
导入的任务设置全局标签
tasks:
- name: Include common web services tasks
include_tasks: common.yml
tags:
- webproxy
- webserver
- 在roles部分为角色打标签。如,为databases角色打两个标签:
roles:
- { role: databases, tags: ['production', 'staging'] }
- 给block的任务打标签。
---
- name: Setup httpd service
tasks:
- name: Notify start of process
debug:
msg: Beginning httpd setup
- block:
- name: Ensure httpd packages are installed
yum:
name:
- httpd
- php
- git
- php-mysqlnd
state: present
- name: Ensure SELinux allows httpd connections to a remote database
seboolean:
name: httpd_can_network_connect_db
state: true
persistent: true
- name: Ensure httpd service is started and enabled
service:
name: httpd
state: started
enabled: true
tags:
- webserver
# 执行具有webserver标签的资源
[user@demo ~]$ ansible-playbook main.yml --tags webserver
# 跳过具有webserver标签的资源
[user@demo ~]$ ansible-playbook main.yml --skip-tags webserver
- 执行任务时,可以指定多个标签
# 执行拥有install或setup标签的资源
[user@demo ~]$ ansible-playbook main.yml --tags install,setup
- 通过
--list-tags
列出playbook中的标签资源。
[student@demo examples]$ ansible-playbook playbook.yml --list-tags
playbook: playbook.yml
play #1 (webservers): Setup web services TAGS: [setup]
TASK TAGS: [setup]
play #2 (webservers): Teardown web services TAGS: [teardown]
TASK TAGS: [teardown]
特殊的标签
- always标签。当为资源打上always标签后,即使执行playbook时,在
--tags
中没有提定它,该资源也会执行。如果需要跳过always标签,可以使用--skip-tags always
。 - never标签。作用与always相反。当为资源打上never标签后,执行playbook时,该资源不会执行。如果需要执行never标签对应的资源,可以使用
--tags never
。 - tagged标签。只要资源打上了标签,就属于tagged。
- untagged标签。没有打过标签的资源,属于untagged。
- all标签。包括所有的任务,不管任务是否打过标签。
优化执行速度
优化playbook
优化架构
- 使用最新的ansible版本。
- 控制节点离被管理节点“近一些”。
禁用facts
- ansible默认会运行一个收集facts变量的任务。
- 如果不需要这些变量,禁用该任务,可以提升速度。
[student@warktest myansible]$ cat mytest.yml
---
- name: test play
hosts: servera
tasks:
- name: display hello
debug:
msg: "Hello World"
[student@warktest myansible]$ time ansible-playbook mytest.yml
... ...
real 0m2.060s
user 0m0.955s
sys 0m0.207s
[student@warktest myansible]$ cat mytest.yml
---
- name: test play
hosts: servera
gather_facts: False # 不收集facts变量
tasks:
- name: display hello
debug:
msg: "Hello World"
[student@warktest myansible]$ time ansible-playbook mytest.ym
... ...
real 0m0.712s
user 0m0.607s
sys 0m0.102s
- 如果在其他任务中需要facts变量,就不能关闭它了。或者是使用其他变量替代。如
ansible_facts['hostname']
或ansible_hostname
用inventory_hostname
替代。
[student@warktest myansible]$ cat mytest.yml
---
- name: test play
hosts: servera
gather_facts: False
tasks:
- name: display hello
debug:
msg: "Hello World from {{ansible_hostname}}"
# 运行playbook报错。因为ansible_hostname是facts变量,收集facts变量已经被禁用了
[student@warktest myansible]$ ansible-playbook mytest.yml
# 可以使用inventory_hostname这个主机清单变量替换
[student@warktest myansible]$ cat mytest.yml
---
- name: test play
hosts: servera
gather_facts: False
tasks:
- name: display hello
debug:
msg: "Hello World from {{inventory_hostname}}"
[student@warktest myansible]$ ansible-playbook mytest.yml
增加并发数
-
ansible在执行任务时,默认每5台主机一组。该组执行完一项任务后,第2组再执行、第3组再执行,依次类推,直到所有主机执行完任务。然后,再进入下一个任务的执行。
-
可以在运行playbook时,通过
-f
选项指定并发数 -
也可以在配置文件中修改:
[user@demo ~]$ cat ansible.cfg
[defaults]
inventory=inventory
remote_user=devops
forks=100
避免使用循环安装软件
- yum模块支持同时安装多个包,不需要使用循环
---
- name: Install the packages on the web servers
hosts: web_servers
become: True
gather_facts: False
tasks:
- name: Ensure the packages are installed
yum:
name:
- httpd
- mod_ssl
- httpd-tools
- mariadb-server
- mariadb
- php
- php-mysqlnd
state: present
# 以上playbook相当于执行了以下命令:
[root@demo ~]# yum install httpd mod_ssl httpd-tools \
> mariadb-server mariadb php php-mysqlnd
- 注意, 不是所有的模块都支持统一设置。比如启动服务,只能使用循环:
- name: Starting the services on the web servers
hosts: web_servers
become: True
gather_facts: False
tasks:
- name: Ensure the services are started
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- httpd
- mariadb
高效上传文件
-
copy模块可以上传文件
-
如果有大量文件,经常上传,使用 synchronize 将会更有效率,它的底层使用的是rsync。
---
- name: Deploy the web content on the web servers
hosts: web_servers
become: True
gather_facts: False
tasks:
- name: Ensure web content is updated
synchronize:
src: web_content/
dest: /var/www/html
使用template模块
-
当一个文件中有很多内容需要修改时,不建议使用lineinfile或者replace模块。
-
建议使用template模块结合jinja2模板,修改文件。
---
- name: Configure the Apache HTTP Server
hosts: web_servers
become: True
gather_facts: False
tasks:
- name: Ensure proper configuration of the Apache HTTP Server
lineinfile:
dest: /etc/httpd/conf/httpd.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
state: present
loop:
- regexp: '^Listen 80$'
line: 'Listen 8181'
- regexp: '^ServerAdmin root@localhost'
line: 'ServerAdmin support@example.com'
- regexp: '^DocumentRoot "/var/www/html"'
line: 'DocumentRoot "/var/www/web"'
- regexp: '^<Directory "/var/www/html">'
line: '<Directory "/var/www/web">'