官方文档
https://docs.ansible.com/ansible/latest/reference_appendices/playbooks_keywords.html#playbook-keywords
Playbook 核心组件
一个playbook 中由多个组件组成,其中所用到的常见组件类型如下:
Hosts 执行的远程主机列表
Tasks 任务集,由多个task的元素组成的列表实现,每个task是一个字典,一个完整的代码块功能需最
少元素需包括 name 和 task,一个name只能包括一个task
Variables 内置变量或自定义变量在playbook中调用
Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
hosts 组件
Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.com
one.example.com:two.example.com
172.16.1.50
172.16.1.*
Websrvs:dbsrvs #或者,两个组的并集
Websrvs:&dbsrvs #与,两个组的交集
webservers:!dbsrvs #在websrvs组,但不在dbsrvs组
案例:
- hosts: websrvs:appsrvs
remote_user 组件
remote_user: 可用于Host和task中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs
remote_user: root
tasks:
- name: test connection
ping:
remote_user: wang
sudo: yes #默认sudo为root
sudo_user:long #sudo为long
task列表和action组件
play的主体部分是task list,task list中有一个或多个task,各个task 按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出
task两种格式:
action: module arguments #示例: action: shell wall hello
module: arguments #建议使用 #示例: shell: wall hello
注意:shell和command模块后面跟命令,而非key=value
范例:
[root@ansible ansible]# cat hello.yaml
---
# first yaml file
- hosts: websrvs
remote_user: root
gather_facts: no #不收集系统信息,提高执行效率
tasks:
- name: test network connection
ping:
- name: excute command
command: wall "hello world!"
范例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd
- name: start httpd
service: name=httpd state=started enabled=yes
其它组件说明
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务
还可以通过"tags"给task打标签,可在ansible-playbook命令上使用-t指定进行调用
playbook 命令
格式
ansible-playbook <filename.yml> ... [options]
常见选项
--syntax-check #语法检查,可缩写成--syntax, 相当于bash -n
-C --check #模拟执行,只检测可能会发生的改变,但不真正执行操作,dry run
--list-hosts #列出运行任务的主机
--list-tags #列出tag
--list-tasks #列出task
--limit 主机列表 #只针对主机列表中的特定主机执行
-i INVENTORY #指定主机清单文件,通常一个项对应一个主机清单文件
--start-at-task START_AT_TASK #从指定task开始执行,而非从头开始,START_AT_TASK为任务的
name
-v -vv -vvv #显示过程
范例:
[root@ansible ansible]# cat hello.yml
---
- hosts: websrvs
tasks:
- name: hello
command: echo "hello ansible"
[root@ansible ansible]#ansible-playbook hello.yml
[root@ansible ansible]#ansible-playbook -v hello.yml
范例
[root@ansible ansible]# ansible-playbook file.yml --check #只检测
[root@ansible ansible]# ansible-playbook file.yml
[root@ansible ansible]# ansible-playbook file.yml --limit websrvs
ShellScripts VS Playbook 案例
# SHELL脚本实现
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
systemctl enable --now httpd
# Playbook实现
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: "安装Apache"
yum: name=httpd
- name: "复制配置文件"
copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/
- name: "复制配置文件"
copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/
- name: "启动Apache,并设置开机启动"
service: name=httpd state=started enabled=yes
利用 playbook 创建 mysql 用户
范例:mysql_user.yml
---
- hosts: dbsrvs
remote_user: root
gather_facts: no
tasks:
- {name: create group, group: name=mysql system=yes gid=306}
- name: create user
user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 home=/data/mysql create_home=no
利用 playbook 安装 nginx
范例:install_nginx.yml
---
# install nginx
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: add group nginx
group: name=nginx state=present
- name: add user nginx
user: name=nginx state=present group=nginx
- name: Install nginx
yum: name=nginx state=present
- name: web page
copy: src=files/index.html dest=/usr/share/nginx/html/index.html
- name: start nginx
service: name=nginx state=started enabled=yes
利用 playbook 安装和卸载httpd
范例:install_httpd.yml
---
# install httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd
- name: modify config list port
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^Listen'
line: 'Listen 8080'
- name: modify config data1
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^DocumentRoot "/var/www/html"'
line: 'DocumentRoot "/data/html"'
- name: modify config data2
lineinfile:
path: /etc/httpd/conf/httpd.conf
regexp: '^<Directory "/var/www/html">'
line: '<Directory "/data/html">'
- name: mkdir website dir
file: path=/data/html state=directory
- name: web html
copy: src=/files/index.html dest=/data/html/
- name: start service
service: name=httpd state=started enabled=yes
执行上面的
[root@centos8 /etc/ansible]# ansible-playbook install_httpd.yml
范例:remove_httpd.yml
---
# remove httpd
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: remove httpd package
yum: name=httpd state=absent
- name: remove apache user
user: name=apache state=absent
- name: remove config file
file: name=/etc/httpd state=absent
- name: remove web html
file: name=/data/html/ state=absent
执行上面的
[root@centos8 /etc/ansible]# ansible-playbook remove_httpd.yml
案例:安装Mariadb二进制压缩包
---
# install mariadb
- hosts: dbserver
remote_user: root
gather_facts: no
tasks:
- name: create group
group: name=mysql gid=25 system=yes
- name: create user
user: name=mysql uid=25 system=yes group=mysql shell=/sbin/nologin home=/data/mysql create_home=no
- name: mkdir datadir
file: path=/data/mysql owner=mysql group=mysql state=directory
- name: unarchive package
unarchive: src=files/mariadb-10.2.33-linux-x86_64.tar.gz dest=/usr/local/ owner=root group=root
- name: link
file: src=/usr/local/mariadb-10.2.33-linux-x86_64 path=/usr/local/mysql state=link
- name: install database
shell: chdir=/usr/local/mysql ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
- name: config file
copy: src=files/my.cnf dest=/etc/ backup=yes
- name: service script
shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/myqld
- name: start service
service: name=mysqld state=started enabled=yes
- name: PATH variable
copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh
忽略错误 ignore_errors
如果一个task出错,默认将不会继续执行后续的其它task利用 ignore_errors: yes
可以忽略此task的错误,继续向下执行playbook其它task
[root@ansible ansible]# cat test_ignore.yml
---
- hosts: websrvs
tasks:
- name: error
command: /bin/false
ignore_errors: yes
- name: continue
command: wall continue
Playbook中使用handlers和notify
Handlers本质是task list ,类似于MySQL中的触发器触发的行为,其中的task与前述的task并没有本质上的不同,主要用于当关注的资源发生变化时,才会采取一定的操作。而Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操
作
注意:
如果多个task通知了相同的handlers, 此handlers仅会在所有tasks结束后运行一 次。
只有notify对应的task发生改变了才会通知handlers, 没有改变则不会触发handlers
handlers 是在所有前面的tasks都成功执行才会执行,如果前面任何一个task失败,会导致handler跳
过执行,可以使用force_handlers: yes 强制执行handler
范例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
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
- wall
- name: ensure apache is running
service: name=httpd state=started enabled=yes
handlers:
- name: restart httpd
service: name=httpd state=restarted
- name: wall
command: wall "The config file is changed"
范例:
---
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: add group nginx
group: 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
范例:强制调用handlers
- hosts: websrvs
force_handlers: yes #无论task中的任何一个task失败,仍强制调用handlers
tasks:
- name: config file
copy: src=nginx.conf dest=/etc/nginx/nginx.conf
notify: restart nginx
- name: install package
yum: name=no_exist_package
handlers:
- name: restart nginx
service: name=nginx state=restarted
Playbook中使用tags组件
官方文档:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
在playbook文件中,可以利用tags组件,为特定 task 指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件可以一个task对应多个tag,也可以多个task对应一个tag还有另外3个特殊关键字用于标签, tagged, untagged 和 all,它们分别是仅运行已标记,只有未标记和所有任务。
案例:
---
# tage example
- hosts: websrvs
remote_user: root
gather_facts: no
tasks:
- name: install httpd
yum: name=httpd state=present
- name: install configure file
copy: src=files/httpd.conf dest=/etc/httpd/conf/
tags:
- conf
- file
- name: start httpd service
tags: service
service: name=httpd state=started enabled=yes
范例:列出所有标签
[root@centos8 /etc/ansible]# ansible-playbook --list-tags httpd.yml
playbook: httpd.yml
play #1 (websrvs): websrvs TAGS: []
TASK TAGS: [conf, file, service]
# 选择标签执行
[root@centos8 /etc/ansible]# ansible-playbook -t conf,service httpd.yml
# 选择跳过文件某个定义的标签执行
[root@centos8 /etc/ansible]# ansible-playbook --skip-tags conf httpd.yml
# 跳过未标记标签
[root@centos8 /etc/ansible]# ansible-playbook httpd.yml --skip-tags untagged