ansible实战应用系列教程5:管理playbook

编写并运行playbook

Ansible Playbooks and Ad Hoc Commands

​ Ad hoc命令可以作为一次性命令对一组目标主机运行单个、简单的任务。然而,Ansible的真正力量在于学习如何使用playbook对一组目标主机以一种容易重复的方式运行多个复杂的任务。
play是一组有序的task,应该针对从inventory中选择的主机运行。playbook是一个文本文件,其中包含一个或多个要按顺序运行的plays列表。
play允许您将一组冗长、复杂的手动管理任务更改为易于重复的例行程序,并具有可预测和成功的结果。在playbook中,你可以将playbook中的task序列保存为人类可读且可立即运行的形式。由于编写task的方式不同,task本身记录了部署应用程序或基础设施所需的步骤。
playbook剧本中可以包含多个play,每个play中包含多个任务task,每个任务对应一个模块module。

Format of an Ansible Playbook

​ 为了帮助您理解ansible playbook的格式,我们将回顾您在前一章中看到的一个临时命令:

[student@workstation ~]$ ansible -m user -a "name=newbie uid=4000 state=present" servera.lab.example.com 

编写为playbook(可多次执行),通常保存在以.yml或者.yaml结尾的文件名中。

---
- name: Configure important user consistently
  hosts: servera.lab.example.com
  tasks:
    - name: newbie exists with UID 4000
      user:
        name: newbie
        uid: 4000
        state: present
[student@workstation ~]$ ansible -a 'id newbie' node1.example.com

playbook是用YAML格式编写的文本文件,通常使用扩展名yml保存。playbook主要使用带有空格字符的缩进来表示其数据的结构。YAML对缩进使用多少空格没有严格的要求,但是有两个基本规则。
 层次结构中相同级别的数据元素(例如相同列表中的项)必须具有相同的缩进。
 作为另一项的子项的项必须比其父项缩进更多。还可以添加空行以增强可读性

缩进只能使用空格字符;不允许使用制表符。
如果您使用Vim文本编辑器,您可以应用一些设置,这可能使编辑您的剧本更容易。例如,在$HOME/.vimrc中添加以下行,当vim检测到您正在编辑一个YAML文件时,它将在按Tab键时执行两个空格的缩进,将自动缩进后续行,并将制表符展开为空格。
/etc/vimrc【全局】或者~/.vimrc【针对某个用户】
autocmd FileType yaml setlocal ai ts=2 sw=2 et
ai = auto indent,自动退格对齐
set tabstop=2(ts=tabstop,即一个tab的宽度被设为2个空格辣么宽)
set shiftwidth=2(sw=shiftwidth,即退格对齐以2个空格为准)
set expandtab(et=expandtab,将tab变成空格)

playbook以一行由三个破折号(—)组成的作为文档标记的开始。它也可能以三个点(…)作为文档结束标记,尽管在实践中这很少用于playbook。

在这些标记之间,playbook被定义为play列表。YAML列表中的项目以一个破折号后跟一个空格开始。例如,YAML列表可能如下所示:

- apple
- orange

play本身是key:value对的集合(一个关联数组或散列/字典)。键在同一play应该有相同的缩进。下面的示例描述了具有三个键的YAML散列/字典。前两个键有简单的值。第三个值是一个包含三个项目的列表。

name: just an example
hosts: webservers
tasks:
	- first
	- second
	- third

最初的示例有三个键:name、hosts和tasks。这些键都有相同的缩进,因为它们属于play。

示例play的第一行以破折号和空格开始(表示play是列表的第一项),然后是第一个键,即name属性。将一个任意字符串作为标签与play关联。name键是可选的,但推荐使用,因为它有助于记录play。当playbook包含多个play时,这一点特别有用。

- name: Configure importantuser consistently

playbook中的第二个键是一个hosts属性,它指定playbook的任务应该在哪些主机上运行。与ansible命令的参数一样,hosts属性接受一个主机模式作为值,例如inventory中托管主机或组的名称。

  hosts: node1.example.com

最后,play中的最后一个键是tasks属性,它的值指定为该play运行的任务列表。这个示例有一个任务,它使用特定的参数运行user模块(以确保user newbie存在并拥有UID4000)。

 tasks:
    - name: newbie exists with UID 4000
      user:
        name: newbie
        uid: 4000
        state: present

tasks属性是play的一部分,它实际上按顺序列出了要在托管主机上运行的任务。列表中的每个任务本身就是键-值对的集合。

在我们的例子中,play中的唯一任务有两个键:

•name是记录任务目的的可选标签。为所有任务命名是一个好主意,以帮助记录自动化过程中每一步的目的。

•user是为此任务运行的模块。它的参数作为键值对的集合传递,键值对是模块的子元素(name、uid和state)。

下面是带有多个任务的任务属性的另一个例子,使用service模块确保在启动时启用多个网络服务:

tasks:
	- name : web server is enabled
      service :
		name : httpd
		enabled: true
	- name: NTP server is enabled
	  service :
		name : chronyd
		enabled: true
	- name : Postfix is enabled
	  service :
		name : postfix
		enabled: true

举例:

---    #代表文件开始,固定格式
- name: Configure importantuser consistently  # - 表示该playbook中的第一个play,
  hosts: node1.example.com
  remote_user:devops
  become:true
  tasks:
    - name: newbie exists with UID 4000   # - 表示该play中的第一个task
      user:
        name: newbie
        uid: 4000
        state: present
… #文件结尾,可省略

运行playbook

ansible-playbook命令用于运行playbooks。该命令在控制节点上执行,将运行的playbook的名称作为参数传递

[student@workstation dep-dynamic]$ ansible-playbook play.yml 

当playbook被执行时,会产生输出来显示play和正在执行的任务。输出还报告执行的每个任务的结果。
下面的示例展示了一个简单剧本的内容,以及运行它的结果。

[student@workstation playbook]$ cat createuser.yaml 

- name: Configure important user consistently
  hosts: node1.example.com
  remote_user: root
  become: true
  tasks:
  - name: newbie exists with UID 4000
    user:
      name: newbie
      uid: 4000
      state: present
   [student@workstation playbook]$ ansible-playbook createuser.yaml 
    PLAY [Configure important user consistently] ******************************
    TASK [Gathering Facts] ****************************************
    ok: [servera.lab.example.com]
    TASK [newbie exists with UID 4000] ************************************
    ok: [servera.lab.example.com]
    PLAY RECAP ********************************************
    servera.lab.example.com    : ok=2    changed=0    unreachable=0    failed=0

一般来说,可执行playbook中的task是幂等的,多次运行playbook是安全的。如果目标托管主机已经处于正确状态,则不应进行任何更改。

[student@workstation playbook]$ ansible-playbook createuser.yaml 
PLAY [configuration user] ******************************************************
TASK [Gathering Facts] *********************************************************
ok: [node1.example.com]
TASK [newbie exists with uid 4000] *****************************************************
ok: [node1.example.com]
PLAY RECAP *************************************************************
node1.example.com    : ok=2    changed=0    unreachable=0    failed=0

这一次,所有任务都以ok状态传递,没有报告任何更改。

选项options

a.语法检查–syntax-check,可以用来验证playbook文件的语法。
在执行剧本之前,最好执行一次验证以确保其内容的语法是正确的。ansible-playbook命令提供了一个–syntax-check选项,可用于验证playbook文件的语法。下面的示例显示了剧本的成功语法验证。

[student@workstation dep-dynamic]$ ansible-playbook play.yml --syntax-check
playbook: play.yml

当语法验证失败时,将报告语法错误。输出还包括剧本中语法问题的大致位置。以下示例显示剧本的语法验证失败,其中剧本的name属性后面缺少空格分隔符。
b.空运行-C
另一个有用的选项是-C选项。这导致Ansible报告如果执行剧本会发生什么变化,但不会对托管主机进行任何实际更改。

[student@workstation dep-dynamic]$ ansible-playbook play.yaml -C

模拟实际运行情况。

playbook中编写多个plays

Writing Multiple Plays

playbook是一个包含一个或多个play列表的YAML文件。请记住,单个play是要对从inventory中选择的主机执行的任务的有序列表。因此,如果playbook包含多个play,每个play都可以将它的任务应用到一组独立的主机上。
这在编排可能涉及不同主机上的不同任务的复杂部署时非常有用。可以编写一个playbook,对一组主机运行一个play,完成后对另一组主机运行另一个play。
编写包含多个plays的playbook非常简单。playbook中的每个play都被编写为playbook中的顶级列表项。每个play都是一个列表项,包含通常的play指令。

下面的示例展示了一个包含了两个play的playbook,第一个play对node1.example.com运行,第二个play对node2.example.com运行。

- name: first play
  hosts: node1.example.com
  tasks:
  - name: first task
    yum:
      name: httpd
      state: present
  - name: second task
    service:
      name: httpd
      enabled: true
- name: second play
  hosts: node2.example.com
  tasks:
  - name: first task
    yum:
      name: mariadb-server
      state: present
  - name: second task
    service:
      name: mariadb
      enabled: true

Remote Users and Privilege Escalation in Plays

remote_user和提权privilege escalation设置默认使用ansible.cfg配置,也可以在play中单独设定。与hosts和tasks是指令是同一级别。

playbook提权

playbook中的任务通常通过与托管主机的网络连接来执行。与ad hoc一样,用于任务执行的用户帐户取决于可执行配置文件/etc/ansibl/ansible.cfg中的各种参数。运行任务的用户可以由remote_user参数定义。但是,如果启用了特权升级Privilege Escalation,其他参数(如become_user)也会产生影响。
如果在任务执行的ansible configuration中定义的远程用户不合适,可以在剧本中使用remote_user属性覆盖它。

remote_user: devops
become: true
become_method: sudo
becom_user: root

配置文件提权

还可以使用其他属性从playbook中定义特权升级参数。可以使用become布尔参数来启用或禁用特权升级,而不管它是如何在ansible的配置文件中定义的。通常,可以使用yes或true来启用权限升级,使用no或false来禁用权限升级。
如果启用了特权升级,则可以使用become_method属性来定义在特定play期间要使用的特权升级方法。
此外,启用了特权升级后,become_user属性可以定义用户帐户,用于在特定play的上下文中进行特权升级。

[student@workstation basic-playbook]$ cat ansible.cfg 
[defaults]
inventory=inventory
remote_user=devops

[privilege_escalation]
become=True
become_method=sudo
become_user=root
become_ask_pass=False

示例:

---
- name: /etc/hosts is up to date
  hosts: servera.lab.example.com
  remote_user: devops
  become: yes
 
  tasks:
    - name: update hosts
      lineinfile:
        path: /etc/hosts
        line: '192.168.1.1 server.lab.example.com server'
        state: present

Finding Modules for Tasks

Module Documentation

Ansible提供了大量的模块,为管理员提供了很多工具来完成常见的管理任务。在本课程的早些时候,我们在http://docs.ansible.com上讨论了Ansible文档网站。网站上的模块索引是一个简单的方式浏览与Ansible模块列表。例如,用于user和service管理的模块可以在系统模块下找到,用于数据库管理的模块可以在数据库模块下找到。
对于每个模块,Ansible documentation网站提供了其功能的摘要,以及如何通过模块选项调用每个特定功能的说明。文档还提供了一些有用的示例,向您展示如何使用每个模块以及如何在任务中设置它们的参数。
您已经使用了ansible-doc命令来查找本地系统上安装的模块的信息。作为回顾,要查看控制节点上可用模块的列表,请运行ansible-doc -l命令。这将显示模块名称的列表及其函数的概要。

[student@workstation basic-playbook]$ ansible-doc -l

可以通过将模块名称传递给ansible-doc来显示有关特定模块的详细文档。与Ansible documentation网站一样,该命令提供了模块功能的概要、各种选项的详细信息和示例。下面的示例显示了为yum模块显示的文档。

[student@workstation ~]$ ansible-doc yum
> YUM    (/usr/lib/python2.7/site-packages/ansible/modules/packaging/os/yum.py)

  Installs, upgrade, removes, and lists packages and groups with the `yum' package manager.

Options (= is mandatory):

- conf_file
        The remote yum configuration file to use for the transaction.
        [Default: None]
- disable_gpg_check
        Whether to disable the GPG checking of signatures of packages being installed. Has an effect only if state is `present' or `latest'.
        (Choices: yes, no)[Default: no]
- disablerepo
        `Repoid' of repositories to disable for the install/update operation. These repos will not persist beyond the transaction. When specifying
        multiple repos, separate them with a ",".
        [Default: None]
- enablerepo
        `Repoid' of repositories to enable for the install/update operation. These repos will not persist beyond the transaction. When specifying
        multiple repos, separate them with a ",".
        [Default: None]
- exclude
        Package name(s) to exclude when state=present, or latest
        [Default: None]
- installroot
        Specifies an alternative installroot, relative to which all packages will be installed.
  • 模块的维护

    Ansibie配备了大量可以用于许多任务的模块。上游社区非常活跃,这些模块可能处于不同的开发阶段。该模块的ansible-doc文档预计将指定在Ansibie上游社区中谁为该模块提供维护,以及该模块的开发状况。该模块的ansible-doc输出末尾的METADATA部分指出了这一点。
    status字段记录模块的开发状态:
    stableinterface:模块参数稳定,尽量不删除参数,不改变参数含义。
    preview:模块处于技术预览状态,可能不稳定,它的参数可能会改变,或者它可能需要库或web服务,而这些库或web服务本身也会发生不兼容的变化。
    deprecated:该模块已弃用,在未来的某个版本中将不再可用。
    removed:模块已经从版本中删除,但是存在一个存根用于文档目的,以帮助以前的用户迁移到新的模块。
    stableinterface状态只表明模块的接口是稳定的,它并不评价模块的代码质量。
    在上游Ansibie社区维护该模块的supported_by字段记录。可能的值是:
    CORE:由“CORE”Ansibie开发者上游维护,并始终包含在Ansibie中。
    curated:由社区合作伙伴或公司提交和维护的模块。这些模块的维护者必须注意报告的问题或对模块提出的pull请求。在社区维护人员批准变更后,上游“核心”开发人员会审查对管理模块的建议变更。核心提交者还确保这些模块由于Ansibie引擎的变化而产生的任何问题都得到了纠正。这些模块目前包含在Ansibie中,但将来可能会单独打包。
    community:核心上游开发者或合作伙伴/公司不支持的模块,但完全由一般的开源社区维护。这个类别中的模块仍然是完全可用的,但是问题的响应率完全取决于社区。这些模块目前也包含在Ansible中,但可能会在将来的某个时候单独打包。
    有时候,你想做的事情模块并不存在。作为最终用户,您还可以编写自己的私有模块,或者从第三方获取模块。Ansible在ANSIBLE_LIBRARY环境变量指定的位置搜索定制模块,如果没有指定,在当前Ansible配置文件中的库指令中搜索定制模块。Ansible也搜索定制模块。/library目录相对于当前运行的剧本。
    library = /usr/share/my_modules

    实战:

在taijitao-server上已经为Ansible项目创建了工作目录“/home/student/playbook”。目录中已经编写了ansible.cfg配置文件和一个inventory清单文件。托管主机server.example.com已经在这个inventory文件中定义。
在这个路径中,创建一个名为internet.yml的剧本,其中将包含两个plays。第一次play需要特权升级,并且必须按照指定的顺序执行以下任务:

  1. 使用yum模块确保安装了最新版本的软件包:firewall、httpd。

  2. 确保防火墙服务已启用并启动。

  3. 确保防火墙配置为允许连接到httpd服务使用的端口。

  4. 确保httpd服务已启用并启动。

  5. 确保托管主机的/var/www/html/index.html文件包含“Welcome to the ansible test !”。

    第二种方法不需要特权升级,应该使用uri模块运行一个任务来确认URL http://server.example.com返回的HTTP状态码为200。

    操作步骤如下:

    1. 切换到工作目录,/ home/student/playbook。
    [ student@taijitao-server ~] cd /home/student/playbook
    
    1. 创建一个新的剧本,/home/student/playbook/intranet.yml,并添加开始第一个play所需的内容。它应该以托管主机taijitao-server.example.com为目标,并启用特权升级。

    2.1. 创建并打开一个新的playbook,/home/student/playbook/intranet.yml,并在文件的开头添加一行由三个破折号组成的行,以指示YAML文件的开始。

    ---
    

    2.2. 将以下行添加到/home/student/imp -playbook/intranet.yml文件表示play的开始,其名称为Enable intranet services。

    - name: Enable intranet services
    

    2.3. 在/home/student/imp-playbook/intranet.yml文件中添加以下一行,以指示该plays应用于servera托管主机。确保用两个空格缩进一行(与上面的name指令对齐),以表明它是第一个剧本的一部分。

      hosts: servera.lab.example.com
    

    2.4. 将以下行添加到/home/student/playbook/intranet.yml文件来启用权限升级。确保用两个空格缩进一行(与上面的指示对齐),以表明它是第一个剧本的一部分。

      become: yes
    
    1. 在/home/student/playbook/intranet.yml文件中添加以下一行,定义任务列表的开头,将该行缩进两个空格(与上面的指令对齐),以表明它是第一个play的一部分。
      tasks:
    
    1. 作为第一个play中的第一个任务,定义一个任务,以确保httpd和firewalld包是最新的。

    4.1. 在第一个play中的tasks指令下,将以下行添加到/home/student/playbook/intranet.yml文件。这将创建确保安装最新版本httpd和firewalld包的任务。
    一定要用四个空格、一个破折号和一个空格缩进任务的第一行。这表明该任务是第一次play tasks列表中的一个项目。
    第一行提供了任务的描述性名称。第二行用六个空格缩进并调用yum模块。下一行缩进了8个空格,是一个name指令。它告诉yum模块应该确保哪些包是最新的。yum模块的name指令(与任务的名称不同)可以接受一个包列表,在接下来的两行中缩进10个空格。在列表之后,八个空格的缩进状态指令告诉yum模块应该安装软件包的最新版本。

        - name: latest version of httpd and firewalld installed
          yum:
            name:
              - httpd
              - firewalld
            state: latest
    
    1. 在play中定义另外两个任务,以确保firewalld正在运行,并将在引导时启动,并允许连接到http服务。

    5.1. 在“/home/student/playbook/intranet.yml”文件中添加如下代码行,创建防火墙服务启用并运行的任务。请确保用四个空格、一个破折号和一个空格缩进该行。这表明该tasks包含在palys中,并且它是tasks列表中的一个项目。
    第一个条目为任务提供了一个描述性名称。第二个条目用8个空格缩进并调用服务模块。其余条目缩进十个空格,并传递必要的参数,以确保启用并启动防火墙服务。

        - name: firewalld enabled and running
          service:
            name: firewalld
            state: started
            enabled: true
    


    5.2. 在/home/student/playbook/intranet.yml文件中添加以下代码行,以创建任务,确保防火墙向远程系统打开HTTP服务。请确保用四个空格、一个破折号和一个空格缩进该行。这表明该任务包含在播放中,并且它是任务列表中的一个项目。
    第一个条目为任务提供了一个描述性名称。第二个条目用六个空格缩进并调用防火墙模块。其余条目用8个空格缩进,并传递必要的参数,以确保永久允许对HTTP服务的访问。

        - name: firewalld permits httpd service
          firewalld:
            service: http
            permanent: true
            state: enabled
            immediate: true
    
    1. 向第一个play的列表中添加另一个任务,以确保httpd服务正在运行并将在引导时启动。

    6.1. 在/home/student/playbook/intranet.yml文件中添加以下代码行,创建任务以确保httpd服务已启用并正在运行。请确保用四个空格、一个破折号和一个空格缩进该行。这表明该任务包含在播放中,并且它是任务列表中的一个项目。
    第一个条目为任务提供了一个描述性名称。第二个条目用六个空格缩进并调用服务模块。其余条目用8个空格缩进并传递必要的参数,以确保httpd服务已启用并正在运行。

        - name: httpd enabled and running
          service:
            name: httpd
            state: started
            enabled: true
    
    1. 在第一个play列表中添加最后一个任务,确保正确的内容在/var/www/html/index.html中。

    7.1. 在/home/student/playbook/intranet.yml文件中添加以下行,以创建确认/var/www/html/index.html文件填充了正确内容的任务。请确保用四个空格、一个破折号和一个空格缩进该行。这表明该任务包含在播放中,并且它是任务列表中的一个项目。
    第一个条目为任务提供了一个描述性名称。第二个条目用六个空格缩进并调用copy模块。其余条目用8个空格缩进,并传递必要的参数,以确保web页面中有正确的内容。

        - name: test html page is installed
          copy:
            content: "welcome to the ansible test !\n"
            dest: /var/www/html/index.html
    
    1. 在/home/student/playbook/intranet.yml中定义针对localhost的第二个play,该play将测试intranet web服务器。它不需要特权升级。

    8.1. 在/home/student/playbook/intranet.yml文件中添加以下一行,表示第二次play的开始。

    - name: test intranet web server
    

    8.2. 在/home/student/playbook/intranet.yml文件中添加以下一行,以指示play应用于localhost管理的主机。请确保用两个空格缩进该行,以表明它包含在第二个play中。

      hosts: localhost  
    

    8.3. 在“/ home/student/playbook/intranet.yml”文件中添加如下代码,禁用权限升级。确保将成为指令的缩进与它上面的hosts指令对齐。

      become: no
    
    1. 在/home/student/playbook/intranet.yml文件中添加以下一行,以定义任务列表的开头。请确保用两个空格缩进该行,以表明它包含在第二个play中。
      tasks:
    
    1. 在第二个play中添加一个任务,该任务使用uri模块联系http://server.lab.example.com,如果HTTP状态代码为200则成功返回。

    10.1. 在/home/student/playbook /intranet.yml文件中添加以下行,以创建从控制节点验证web服务的任务。请确保用四个空格、一个破折号和一个空格缩进第一行。这表明该任务是第二个剧本任务列表中的一个项目。
    第一行提供了任务的描述性名称。第二行用六个空格缩进并调用uri模块。其余行缩进八个空格,并传递必要的参数以执行从控制节点到托管主机的web内容查询,并验证接收到的状态代码。

        - name: connect to intranet web server
          uri:
            url: http://server.example.com
            status_code: 200
    
    1. 看看最终的/ home / student /playbook /intranet.yml
---
- name: enable intranet services
  hosts: server.example.com
  become: yes
  tasks:
    - name: latest version of httpd and firewalld installed
      yum:
        name:
          - httpd
          - firewalld
        state: latest
    - name: firewalld enabled and running
      service:
        name: firewalld
        state: started
        enabled: true
    - name: firewalld permits httpd service
      firewalld:
        service: http
        permanent: true
        state: enabled
        immediate: true
    - name: httpd enabled and running
      service:
        name: httpd
        state: started
        enabled: true
    - name: test html page is installed
      copy:
        content: "Welcome to the ansible test!\n"
        dest: /var/www/html/index.html
- name: test intranet web server
  hosts: localhost
  become: no
  tasks:
    - name: connect to intranet web server
      uri:
        url: http://server.example.com
        status_code: 200
  1. 通过使用–syntax-check选项执行ansible-playbook命令来验证intranet.yml剧本的语法。

[student@taijitao-server playbook]$ ansible-playbook --syntax-check intranet.yml

playbook: intranet.yml

  1. 执行playbook。以确保所有任务成功完成。

[student@taijitao-server playbook]$ ansible-playbook intranet.yml

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太极淘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值