04.playbook应用和roles自动化批量安装示例

playbook是ansible实现批量自动化最重要的手段。在其中可以使用变量、引用、循环等功能,相比ad-hoc而言,其功能要强大的多。

1.1 yaml简单示例

ansible的playbook采用yaml语法。以下是一个yaml格式的文件:

---
# Members in Bob‘s family
    name: Bob
    age: 30
    gender: Male
    wife:
        name: Alice
        age: 27
        gender: Female
    children:
      - name: Jim
        age: 6
        gender: Male
      - name: Lucy
        age: 3
        gender: Female?

1.2 ansible-playbook命令说明及playbook书写简单示例

以下是一个简单的playbook示例。该示例执行两个任务,第一个任务是执行一个/bin/date命令,第二个任务是复制/etc/fstab文件到目标主机上的/tmp下,它们分别使用了ansible的command模块和copy模块。

cat /tmp/test.yaml
---
    - hosts: centos7
      tasks:
        - name: execute date cmd
          command: /bin/date
        - name: copy fstab to /tmp
          copy: src=/etc/fstab dest=/tmp

书写好playbook后,使用ansible-playbook命令来执行。ansible-playbook命令的选项和ansible命令选项绝大部分都相同。但也有其特有的选项。以下是截取出来的帮助信息。

书写好playbook后,使用ansible-playbook命令来执行。ansible-playbook命令的选项和ansible命令选项绝大部分都相同。但也有其特有的选项。以下是截取出来的帮助信息。

ansible-playbook --help
Usage: ansible-playbook playbook.yml

Options:
  -e EXTRA_VARS,--extra-vars=EXTRA_VARS # 设置额外的变量,格式为key/value。-e "key=KEY",
                                        # 如果是文件方式传入变量,则-e "@param_file"
  --flush-cache          # 清空收集到的fact信息缓存
  --force-handlers       # 即使task执行失败,也强制执行handlers
  --list-tags            # 列出所有可获取到的tags
  --list-tasks           # 列出所有将要被执行的tasks
  -t TAGS,--tags=TAGS    # 以tag的方式显式匹配要执行哪些tag中的任务
  --skip-tags=SKIP_TAGS  # 以tag的方式忽略某些要执行的任务。被此处匹配的tag中的任务都不会执行
  --start-at-task=START_AT_TASK # 从此task开始执行playbook
  --step                 # one-step-at-a-time:在每一个任务执行前都进行交互式确认
  --syntax-check         # 检查playbook语法

现在执行上面的test2.yaml。

[[email protected] playbook]# ansible-playbook /root/ansible_test/playbook/test2.yml 

PLAY [web] ************************************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************************
ok: [test-openstack3]
ok: [test-openstack2]
ok: [test-openstack4]

TASK [execute date cmd] ***********************************************************************************************************************************************************************
changed: [test-openstack4]
changed: [test-openstack3]
changed: [test-openstack2]

TASK [copy fstab to /tmp] *********************************************************************************************************************************************************************
changed: [test-openstack3]
changed: [test-openstack4]
changed: [test-openstack2]

PLAY RECAP ************************************************************************************************************************************************************************************
test-openstack2            : ok=3    changed=2    unreachable=0    failed=0
test-openstack3            : ok=3    changed=2    unreachable=0    failed=0
test-openstack4            : ok=3    changed=2    unreachable=0    failed=0   

从以上结果中,可以看出:(1)默认情况下,ansible-playbook和ansible是一样的,都是同步阻塞模式,需要先在所有主机上执行完一个任务,才会继续下一个任务;(2)在执行前会自动收集fact信息;(3)从显示结果中可以判断出任务是否真的执行了,抑或者是因为幂等性而没有执行。(4)每一个play都包含数个task,且都有响应信息play recap。

1.3 playbook的内容

1.3.1 hosts和remoter_user

对于playbook中的每一个play,使用hosts选项可以定义要执行这些任务的主机或主机组,还可以使用remote_user指定在远程主机上执行任务的用户,实际上remote_user是ssh连接到被控主机上的用户,自然而然执行命令的身份也将是此用户。

例如:

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: root
      tasks: XXXXXX

虽然在hosts处可以使用","分隔主机或主机组,但官方手册上并没有介绍该方法。除此之外,有以下几种指定主机和主机组的方式:

  • all*:表示inventory中的所有主机。
  • ::取并集。例如"host1:host2:group1"表示2台主机加一个主机组。
  • :&:取交集。例如"group1:&group2"表示两个主机组中都有的主机。
  • :!:排除。例如"group1:!host1"表示group1中排除host1主机的剩余主机。
  • 通配符:例如"web*.baidu.com"。
  • 数字范围:例如"web[0-5].baidu.com"。
  • 字母范围:例如"web[a-d].baidu.com"。
  • 正则表达式:以"~"开头。例如"~web\d\.baidu\.com"。

此外,在ansible命令行或ansible-playbook命令行中,可以使用"-l"选项来限定执行任务的主机。例如:

ansile centos -l host[1:5] -m ping

表示centos主机组中只有host1到host5才执行ping模块。

还可以在某个task上单独定义执行该task的身份,这将覆盖全局的定义。

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: root
      tasks:
        - name: run a command
          shell: /bin/date
        - name: copy a file to /tmp
          copy: src=/etc/fstab dest=/tmp
          remote_user: myuser

也支持权限升级的方式。

---
    - hosts: centos6,centos7,192.168.100.59
      remote_user: yourname
      tasks:
        - name: run a command
          shell: /bin/date
        - name: copy a file to /tmp
          copy: src=/etc/fstab dest=/tmp
          become: yes
          become_method: sudo
          become_user: root    # 此项默认值就是为root,所以可省

从上面的示例可以看出remote_user实际上并不是执行任务的绝对身份,它只是ssh连接过去的身份,只不过没有指定become的时候,它正好就用此身份来运行任务。

1.3.2 task list

1.特性
每个play都包含一个hosts和一个tasks,hosts定义的是inventory中待控制的主机,tasks下定义的是一系列task任务列表,比如调用各个模块。这些task按顺序一次执行一个,直到所有被筛选出来的主机都执行了这个task之后才会移动到下一个task上进行同样的操作。

需要注意的是,虽然只有被筛选出来的主机会执行对应的task,但是所有主机(此处的所有主机表示的是,hosts选项所指定的那些主机)都会收到相同的task指令,所有主机收到指令后,ansible主控端会筛选某些主机,并通过ssh在远程执行任务。也就是说,如果查看ansible-playbook -vvvv的信息,将会发现临时任务文件会通过sftp发送到所有的被控主机上,但是只有一部分被筛选(如果进行了筛选)的主机才会ssh过去并远程执行命令。

当某一台被控主机执行某个任务出错或失败时,它将会被移除出任务轮询列表。也就是说,对于某主机来说,某任务执行失败,后续的所有任务都不会再去执行。当然,这不会影响其他的主机执行任务(除非主机的任务之间有依赖关系)。

最重要的是,ansible中的task是幂等性的,多次执行不会影响那些成功执行过的任务。另外幂等性还表现在执行失败后如果修正了playbook再次执行,将不会影响那些原本已经执行成功的任务,即使是不同主机也不会影响。仅这方面而言,ansible对于排错来说是极其友好的。当然,某些特殊的模块或者特殊定义的task并不一定总是幂等的,例如最简单的,执行一个command或者shell模块的命令,它会重复执行。但也有办法使其变得幂等,以command和shell模块为例,它们有两个选项:creates和removes,它们分别表示被控主机上指定的文件存在(不存在)时就不执行命令。

2.定义task的细节

  • (1).可以为每个task加上name项,也可以多个task依赖于一个name。

例如下面的两个例子。从两个示例中可以看出,两个task其实都是属于一个name的,第二个task无需再使用name命名。

示例一:

tasks:
    - name: do something to initialize mariadb
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

示例二:

tasks:
    - name: echo var passed by nginx
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

实际上,name只是一种描述性语句,它可以定义在任何地方。例如,定义在play的顶端。

---
- name: start a play
  hosts: localhost
  tasks:
  • (2).既然是task,那么必然会有其要执行的一个或多个任务,其本质是加载并执行ansible对应的模块。在playbook中,每调用的一个模块都称为一个action。

例如,定义一个确保服务是启动状态的task,有以下三种方法传递模块参数:

tasks:
  - name: be sure the sshd is running
    service: name=sshd state=started     # 方法一: 定义为key=value,直接传递参数给模块

    service:                             # 方法二: 定义为key: value方式
      name: sshd
      state: started

    service:                  # 方法三: 使用args内置关键字,然后定义为key: value方式
    args:
      name: sshd
      state: started

但要注意,ping模块、command和shell模块是不需要key=value格式的。对于ping命令,可以直接省略key=value。对于command和shell,只需要给定命令路径和要接上去的选项或参数即可,且无法使用上面的方法二。例如下面定义的是一个ntpdate命令,只需给定它的参数即可。

tasks:
    - name: execute command ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
    - name: ping host
      ping:

对于command或shell模块来说,有时候要考虑命令的返回状态码。如果要忽略非0状态码继续执行任务,可以使用以下两种方式:

tasks:
    - name: ignore non_zero return code
      shell: /usr/sbin/ntpdate ntp1.aliyun.com || /bin/true

或者

tasks:
    - name: another way to ignore the non_zero return code
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
      ignore_errors: true
  • (3).如果action的key=value太多,导致内容太长,可以在上一行的缩进级别基础上继续缩进表示续行。

例如,下面的owner比src多缩进了4个空格。

tasks:
  - name: Copy ansible inventory file to client
    copy: src=/etc/fstab dest=/tmp
              owner=root group=root mode=0644
  • (4).在action的value部分,可以引用已经定义的变量,可以是已定义好的自定义的变量,也可以是内置变量。变量相关内容见后文。
  • (5).使用include指令,可以将其他的playbook文件包含到此playbook文件中。include的方式见下文

1.3.3 notify和handler

ansible中几乎所有的模块都具有幂等性,这意味着被控主机的状态是否发生改变是能被捕捉的,即每个任务的changed=true或changed=false。ansible在捕捉到changed=true时,可以触发notify组件(如果定义了该组件)。

notify是一个组件,并非一个模块,它可以直接定义action,其主要目的是调用handler。例如:

tasks:
    - name: copy template file to remote host
      template: src=/etc/ansible/nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify:
        - restart nginx
        - test web page
      copy: src=nginx/index.html.j2 dest=/usr/share/nginx/html/index.html
      notify:
        - restart nginx

这表示当执行template模块的任务时,如果捕捉到changed=true,那么就会触发notify,如果分发的index.html改变了,那么也重启nginx(当然这是没必要的)。notify下定义了两个待调用的handler。handler主要用于重启服务或者触发系统重启,除此之外很少使用handler。以下是这两个handler的内容:

handlers:
    - name: restart nginx
      service: name=nginx state=restarted
    - name: test web page
      shell: curl -I http://192.168.100.10/index.html | grep 200 || /bin/false

handler的定义和tasks的定义完全一样,唯一需要限定的是handler中task的name必须和notify中定义的名称相同。

注意,notify是在执行完一个play中所有task后被触发的,在一个play中也只会被触发一次。意味着如果一个play中有多个task出现了changed=true,它也只会触发一次。例如上面的示例中,向nginx复制配置文件和复制index.html时如果都发生了改变,都会触发重启apache操作。但是只会在执行完play后重启一次,以避免多余的重启。

1.3.4 标签tag

可以为playbook中的每个任务都打上标签,标签的主要作用是可以在ansible-playbook中设置只执行哪些被打上tag的任务或忽略被打上tag的任务。

tasks:
   - name: make sure apache is running
     service: name=httpd state=started
     tags: apache
   - name: make sure mysql is running
     service: name=mysqld state=started
     tags: mysql

以下是ansible-playbook命令关于tag的选项。

  --list-tags           # list all available tags
  -t TAGS, --tags=TAGS  # only run plays and tasks tagged with these values
  --skip-tags=SKIP_TAGS # only run plays and tasks whose tags do not match these values

1.4 include和roles

如果将所有的play都写在一个playbook中,很容易导致这个playbook文件变得臃肿庞大,且不易读。因此,可以将多个不同任务分别写在不同的playbook中,然后使用include将其包含进去即可。而role则是整合playbook的方式。无论是include还是role,其目的都是分割大playbook以及复用某些细化的play甚至是task。

1.4.1 include

可以将task列表和handlers独立写在其他的文件中,然后在某个playbook文件中使用include来包含它们。除此之外,还可以写独立的playbook文件,使用include来包含这个文件。

也即是说,include可以导入两种文件:导入task、导入playbook。

1.一种是任务列表式的文件(没有tasks或handlers指令),它只能在tasks或handlers指令的子选项处使用include包含。这种方式可以传递变量到被包含的文件中。

假设某个task列表文件/yaml/a.yaml内容如下:

---
    - name: execute ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com

在同目录/yaml下有一个名为test.yaml的playbook(除了role,playbook中所有相对路径都是基于playbook的),在此playbook中使用include来包含它,如果使用相对路径将会包含同目录下的文件。

---
    - hosts: centos7
      tasks:
       - include: a.yaml

可以在include的时候传递变量给对应的文件,这样在被包含的文件中就可以引用该变量的值。

---
  - hosts: centos7
    tasks:
      - include: a.yaml sayhi="hello world"

或者

---
  - hosts: centos7
    tasks:
       - include: a.yaml
         vars:
           sayhi: "hello world"

然后可以在被包含的文件a.yaml中使用该变量。例如:

---
    - name: execute ntpdate
      shell: /usr/sbin/ntpdate ntp1.aliyun.com
    - name: say hi to world
      debug: msg="{{ sayhi }}"

执行该test.yaml,将会输出对应的变量值。

[[email protected] playbook]# ansible-playbook test_include.yaml

PLAY [web] ************************************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack4]
ok: [test-openstack3]

TASK [install ntp] ****************************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [stop ntp service] ***********************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [execute ntpdate] ************************************************************************************************************************************************************************
changed: [test-openstack3]
changed: [test-openstack4]
changed: [test-openstack2]

TASK [say hi to world] ************************************************************************************************************************************************************************
ok: [test-openstack2] => {
"msg": "hello world"
}
ok: [test-openstack3] => {
"msg": "hello world"
}
ok: [test-openstack4] => {
"msg": "hello world"
}

PLAY RECAP ************************************************************************************************************************************************************************************
test-openstack2 : ok=5 changed=1 unreachable=0 failed=0
test-openstack3 : ok=5 changed=1 unreachable=0 failed=0
test-openstack4 : ok=5 changed=1 unreachable=0 failed=0

2.另一种是include整个playbook文件,即include的动作是加载一个或多个play,所以写在顶级列表的层次。

- name: this is a play at the top level of a file
  hosts: all
  remote_user: root

  tasks:

  - name: say hi
    tags: foo
    shell: echo "hi..."

- include: load_balancers.yml  sayhi="hello world"
- include: webservers.yml
- include: dbservers.yml

    any other operations

需要说明的是,在ansible 2.4版本中,添加了includes和imports两种导入的方式,它们对静态和动态导入支持的更细化,而ansible 2.3及以前的include语句已经废弃,但仍可用。

1.4.2 roles

roles意为角色,主要用于封装playbook实现复用性。在ansible中,roles通过文件的组织结构来展现。

对于一个role,它的文件组织结构如下图所示。

    

首先需要有一个roles目录。同时,在roles目录所在目录中,还要有一个playbook文件,此处为nginx.yml,nginx.yml文件是ansible-playbook需要执行的文件,在此文件中定义了角色,当执行到角色时,将会到roles中对应的角色目录中寻找相关文件。

roles目录中的子目录是即是各个role。例如,此处只有一个名为nginx的role,在role目录中,有几个固定名称的目录(如果没有则忽略)。在这些目录中,还要有一些固定名称的文件,除了固定名称的文件,其他的文件可以随意命名。以下是各个目录的含义:

  • tasks目录:存放task列表。若role要生效,此目录必须要有一个主task文件main.yml,在main.yml中可以使用include包含同目录(即tasks)中的其他文件。
  • handlers目录:存放handlers的目录,若要生效,则文件必须名为main.yml文件。
  • files目录:在task中执行copy或script模块时,如果使用的是相对路径,则会到此目录中寻找对应的文件。
  • templates目录:在task中执行template模块时,如果使用的是相对路径,则会到此目录中寻找对应的模块文件。
  • vars目录:定义专属于该role的变量,如果要有var文件,则必须为main.yml文件。
  • defaults目录:定义角色默认变量,角色默认变量的优先级最低,会被任意其他层次的同名变量覆盖。如果要有var文件,则必须为main.yml文件。
  • meta目录:用于定义角色依赖,如果要有角色依赖关系,则文件必须为main.yml。

所以,相对完整的role的文件组织结构如下图。

             

如果是多个role,则在roles同级目录下定义多个入站(作用类似于C语言的main函数)文件(如上面的nginx.yml),并在roles目录下创建对应的role目录即可。

           

当然,如果不是使用相对路径,那么role的文件结构就无所谓了,但是roles功能开发出来,就是为了解决文件混乱和playbook臃肿问题的。所以如果可以,尽量使用推荐的role文件结构。

另外,如果role中出现的task、var、handler等和单独定义的对象同名冲突了,则优先执行role中的内容。

以下是nginx role的入站文件nginx.yml的内容。

---
  - hosts: centos7
    roles:
      - nginx

更多更详细的role用法以及组织结构,见下面的示例。

1.5 roles示例:批量自动化安装

下面演示的是使用role批量自动安装nginx和mysql(CentOS 6)或maridb(CentOS 7)的示例。由于被控节点有CentOS 6和CentOS 7两种发行版的操作系统,因此除了要挑选对应的数据库,还要让nginx的配置文件适应各操作系统,因为nginx在这两个版本的系统上配置内容有所不同。在此,nginx、mysql和mariadb是3个role,且让nginx role依赖于mysql或mariadb role。

下面的例子中,有些地方是不太合理或多余的行为,但是作为学习示例,可以很好的理解roles之间的组织结构和相关的操作。

首先是文件的结构。

其中site.yml是入站文件,用于调用nginx、mysql和mariadb这3个role,这个文件中的内容如下。它有3个作用:(1)在调用roles之前,先根据发行版配置好yum源(pre_tasks);(2)调用nginx role,此处没有调用mysql和mariadb这两个role,因为在nginx role的meta/main.yml文件中定义了nginx role依赖于这两个role,所以此处可以不用定义;(3)在执行完nginx role之后,输出一个提示信息(post_tasks)。

cat /yaml/site.yml
---
  - hosts: centos
    remote_user: root

 # 根据发行版配置好yum源,使用when进行条件判断
    pre_tasks:
        - name: config the yum repo for centos 7
          yum_repository:
              name: epel
              description: epel
              baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
              gpgcheck: no
          when: ansible_distribution_major_version == "7"

        - name: config the yum repo for centos 6
          yum_repository:
              name: epel
              description: epel
              baseurl: http://mirrors.aliyun.com/epel/6/$basearch/
              gpgcheck: no
          when: ansible_distribution_major_version == "6"

    roles:
        - nginx

# 输出over消息
    post_tasks:
      - shell: echo ‘deploy nginx/mysql over‘
        register: ok_var
      - debug: msg=‘{{ ok_var.stdout }}‘

以下是nginx role中的各文件内容。其中template复制的源文件都是从centos 6 nginx和centos 7 nginx上提取的,只不过是重新命名了而已。

/yaml/roles/nginx/tasks/main.yml
---
   - name: make sure nginx state is installed
     yum: name=nginx state=installed

   - name: template nginx.conf
# 基于变量赋值配置文件模板,检查配置文件语法,并在必要的时候触发handler
     template: src=nginx{{ ansible_distribution_major_version }}.conf.j2
                  dest=/etc/nginx/nginx.conf
                  validate="/usr/sbin/nginx -t -c %s"
     notify:
        - restart nginx

# 基于jinja2渲染模板文件,且改变时也触发重启操作
   - name: copy index.html
     template: src=index.html.j2 dest=/usr/share/nginx/html/index.html
     notify:
        - restart nginx

   - name: make sure nginx service is running
     service: name=nginx state=started

# 引用变量 nginx_port,在vars/main.yml中定义了
   - name: make sure port is open
     wait_for: port="{{ nginx_port }}"

/yaml/roles/nginx/handlers/main.yml
---
   - name: restart nginx
     service: name=nginx state=restarted

/yaml/roles/nginx/vars/main.yml
nginx_port: 80

# 定义nginx依赖于MySQL或mariadb,具体依赖于哪个,是通过条件进行判断的,centos 6表示依赖于mysql,centos 7表示依赖于mariadb
# 同时传递了两个值给变量hi_var,由于是在依赖的时候传递的,所以这两个变量可直接在依赖的role(mysql role或mariadb role)的playbook中引用
/yaml/roles/nginx/meta/main.yml
---
   dependencies:
     - { role: mysql,hi_var: "hello mysql",when: "ansible_distribution_major_version == ‘6‘" }
     - { role: mariadb,hi_var: "hello mariadb",when: "ansible_distribution_major_version == ‘7‘" }

上面拷贝了index.html.j2,其内容为:

shell> cat /yaml/roles/nginx/templates/index.html.j2
<h1>hello from {{ ansible_default_ipv4.address }}<h1>

在template执行时,它会使用jinja2引擎对文件中的变量进行替换,使得在拷贝到不同主机时,该index.html的内容是基于远程主机ip的。此处使用的变量是收集到的facts中的变量"ansible_default_ipv4.address"。

以下是mysql role中各文件的内容。注意,MySQL的my.cnf和mariadb的my.cnf默认情况下并不一样(mariadb的my.cnf默认多了一项配置"!includedir /etc/my.cnf.d",MySQL需要取消该项),所以需要分别提供。

/yaml/roles/mysql/tasks/main.yml
---
    - name: make sure mysql is installed
      yum: name=mysql-server state=installed

# 特别需要注意下面的初始化命令,由于执行的是shell模块,所以要考虑其幂等性,显然初始化动作是一定要实现幂等性的
    - name: do something to initialize mysql
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

    - name: copy my.cnf
      copy: src=my.cnf dest=/etc/my.cnf
      notify:
         - restart mysql

    - name: make sure mysql is running
      service: name=mysqld state=started

    - name: make sure mysql port is open
      wait_for:
         port: "{{ mysql_port }}"
         timeout: 10

# 这里输出了nginx/meta/main.yml中传递的变量
    - name: echo var passed by nginx
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

/yaml/roles/mysql/handlers/main.yml
---
   - name: restart mysql
     service: name=mysqld state=restarted

/yaml/roles/mysql/vars/main.yml
---
    mysql_port: 3306

以下是mariadb role中各文件的内容,和mysql大体上是一致的。注意,MySQL的my.cnf和mariadb的my.cnf默认情况下并不一样,所以需要分别提供。

/yaml/roles/mariadb/tasks/main.yml
---
    - name: make sure mariadb is installed
      yum: name=mariadb-server state=installed

    - name: do something to initialize mariadb
      file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
    - shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1

    - name: copy my.cnf
      copy: src=my.cnf dest=/etc/my.cnf
      notify:
         - restart mariadb

    - name: make sure mariadb is running
      service: name=mariadb state=started

    - name: make sure mariadb port is open
      wait_for:
         port: "{{ mariadb_port }}"
         timeout: 10

    - name: echo var passed by nginx
      shell: echo "{{ hi_var }}"
      register: var_result
    - debug: msg="{{ var_result.stdout }}"

/yaml/roles/mariadb/handlers/main.yml
---
    - name: restart mariadb
      service: name=mariadb state=restarted

/yaml/roles/mariadb/vars/main.yml
---
    mariadb_port: 3306

以下是两台机器的测试结果,一台是centos 7(192.168.100.54),一台是centos 6(192.168.100.70)。

PLAY [web] ************************************************************************************************************************************************************************************

TASK [Gathering Facts] ************************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [config the yum repo for centos7] ********************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [config the yum repo for centos7] ********************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : make sure mysql is installed] ***************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : do something to initialize mysql] **********************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : shell] **************************************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : copy my.cnf] ********************************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : make sure mysql is running] *****************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : make sure mysql port is open] ***************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : echo var passed by nginx] *******************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mysql : debug] **************************************************************************************************************************************************************************
skipping: [test-openstack2]
skipping: [test-openstack3]
skipping: [test-openstack4]

TASK [mariadb : make sure mariadb is installed] ***********************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [mariadb : do something to initialize mariadb] *******************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [mariadb : shell] ************************************************************************************************************************************************************************
changed: [test-openstack3]
changed: [test-openstack4]
changed: [test-openstack2]

TASK [mariadb : copy my.cnf] ******************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack4]
ok: [test-openstack3]

TASK [mariadb : make sure mariadb is running] *************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [mariadb : make sure mariadb port is open] ***********************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [mariadb : echo var passed by nginx] *****************************************************************************************************************************************************
changed: [test-openstack2]
changed: [test-openstack3]
changed: [test-openstack4]

TASK [mariadb : debug] ************************************************************************************************************************************************************************
ok: [test-openstack2] => {
"msg": "hello_mriadb"
}
ok: [test-openstack3] => {
"msg": "hello_mriadb"
}
ok: [test-openstack4] => {
"msg": "hello_mriadb"
}

TASK [nginx : make sure nginx state is installed] *********************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [nginx : template nginx.conf] ************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [nginx : copy index.html] ****************************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [nginx : make sure nginx service is running] *********************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [nginx : make sure port is open] *********************************************************************************************************************************************************
ok: [test-openstack2]
ok: [test-openstack3]
ok: [test-openstack4]

TASK [shell] **********************************************************************************************************************************************************************************
changed: [test-openstack2]
changed: [test-openstack3]
changed: [test-openstack4]

TASK [debug] **********************************************************************************************************************************************************************************
ok: [test-openstack2] => {
"msg": "deploy nginx/mysql over"
}
ok: [test-openstack3] => {
"msg": "deploy nginx/mysql over"
}
ok: [test-openstack4] => {
"msg": "deploy nginx/mysql over"
}

PLAY RECAP ************************************************************************************************************************************************************************************
test-openstack2 : ok=17 changed=3 unreachable=0 failed=0
test-openstack3 : ok=17 changed=3 unreachable=0 failed=0
test-openstack4 : ok=17 changed=3 unreachable=0 failed=0

相信看过上面的roles组织示例,对roles的用法和playbook就有了较深的认识。其实,ansible有一个网站专门存放了一大堆的playbook,算是playbook仓库吧。可以下载下来稍作修改就能使用,即使不使用,借鉴他们的写法也是很值得的。地址:ansible galaxy

另外,根据不同标准组织role可能会让playbook写起来更容易,例如上面的示例中,按照发行版来划分role比上面按照安装软件类型划分可能会更简单些。当然,如果在inventory中就划分好centos 6和centos 7也是可以的。哪种更方便、复用性更好就需要自行考虑了。

原文地址:https://www.cnblogs.com/hackerlin/p/12552932.html

时间: 2024-10-13 16:20:42

04.playbook应用和roles自动化批量安装示例的相关文章

Ansible系列(五):playbook应用和roles自动化批量安装示例

html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary { display: block } audio,canvas,progress,video { display: inline-block; vertical-align: baseline } audio:not([co

Cobbler实现自动化批量安装Linux系统系列一:安装先决性组件篇

随着经历的企业越来越多,服务器规划.实施及运维工作也越来越多,有时会发现,其实做为一名IT人,我们总是有些局限,尤其是在对企业IT结构规划时,由于只局限于对一种分支产品的特性了解,当所熟悉的产品不能胜任现有平台时,我们总会感觉有一些无奈,比如微软的MDT.WDS及SCCM,实话说挺不错的,但至少也只是在微软平台操作系统的部署上,当我们遇到在业务网运维平台中以Linux为主的环境时,大批量部署Linux,这时对于微软的这些部署产品可能就不能像在微软产品范围中那样如龙得水般了,这时我们也就真正理解了

自动化批量安装系统

1. 什么是PXE 严格来说,PXE 并不是一种安装方式,而是一种引导方式.进行 PXE 安装的必要条件是在要安装的计算机中必须包含一个 PXE 支持的网卡(NIC),即网卡中必须要有 PXE Client.PXE (Pre-boot Execution Environment)协议可以使计算机通过网络启动.此协议分为 Client端和 Server 端,而PXE Client则在网卡的 ROM 中.当计算机引导时,BIOS 把 PXE Client 调入内存中执行,然后由 PXE Client

Cobbler实现自动化批量安装Linux系统系列二:修改Cobbler Check时发现的问题

在上一系列介绍中,执行Cobbler检查时,提示共有7项不满足要求,我们在今天的系列介绍中,将逐一介绍如何进行配置调整,以满足Cobbler要求.   [修改rsync配置] [[email protected] yum.repos.d]# vi /etc/xinetd.d/rsync 说明1:修改下图所示配置中disable属性值为no 修改后结果如下:   [安装cman] [[email protected] yum.repos.d]# yum install cman   [安装debm

Linux自动化批量部署安装系统

运维自动化之系统安装 系统启动流程(详情见之前文档): bootloader-->kernel(initramfs)-->rootfs-->/sbin/init anaconda:系统安装工具(安装操作系统向导) gui:图形窗口 tui:curses安装;蓝色背景的文本方式窗口安装 MBR:isolinux/boot.cat 第二阶段:isolinux.bin 配置文件:isolinux/isolinux.cfg(光盘启动的安装菜单,文件当中的^代表了快捷键对应的按键) timeout

ansible roles 自动化安装

例:  ansible roles 自动化安装memcached 文件目录结构如下: cat memcached_role.yml - hosts: memcached remote_user: root roles: - memcached cat roles/memcached/vars/main.yml username: memcached groupname: memcached memcached_port: 11211 cat roles/memcached/templates/m

使用Cobbler批量安装操作系统

个人博客地址:http://www.pojun.tech/ 欢迎访问 前言 在实际生产中,我们常常会遇到这样一种情况,就是我们需要同时安装几十甚至上百台服务器,如果我们使用U盘或者光盘的方式的话,或许老板直接就将我们辞退了.这里我们介绍一种能够实现自动化安装操作系统的方式. 我们搭建Cobbler的实验环境是基于CentOS 7.3 -1611 的基础的. 同时这个实验可以帮助你一步步的完成所有的操作,不过,如果你想自定义安装的内容的话,建议你先看本文 自定义kickstart文件 部分,以便有

网络安装操作系统之——-cobbler批量安装操作系统

cobbler批量安装操作系统 环境:workstation10 cobbler server:操作系统 Centos6.6 ip:192.168.1.17 桥接物理机上(可上外网) 关闭iptables ,关闭selinux [[email protected] ~]# chkconfig iptables off [[email protected] ~]# /etc/init.d/iptables stop [[email protected] ~]# getenforce Disable

PXE+kickstart 实现Centos6.5 批量安装 (简单易学)

PXE简介 严格来说,PXE并不是一种安装方式,而是一种引导的方式.进行PXE安装的必要条件是要安装的计算机中包含一个PXE支持的网卡(NIC),即网卡中必须要有PXE client.PXE(Pre-boot Execution Environment,直译为启动前的执行环境)协议使计算机可以通过网络启动.协议分为client和server端,PXE client在网卡的ROM中,当计算机引导时,BIOS把PXE client调入内存执行,由PXE client将放置在远端的文件通过网络下载到本