Ansible之Playbook

Posted 空白的Melody

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Ansible之Playbook相关的知识,希望对你有一定的参考价值。

官方文档

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: magedu
      sudo: yes      #默认sudo为root
      sudo_user:long #sudo为wang

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

以上是关于Ansible之Playbook的主要内容,如果未能解决你的问题,请参考以下文章

[原创]实战之Ansible生成Apache多主机配置

ansible学习笔记7-playbooks之执行一个playbook

Ansible之Playbook

Ansible之Playbook

Ansible之Playbook

ansible自动运维工具之ansible-playbook详解