zoukankan      html  css  js  c++  java
  • 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。

    [root@test-openstack1 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"。
    • 正则表达式:以"~"开头。例如"~webd.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,将会输出对应的变量值。

    [root@test-openstack1 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也是可以的。哪种更方便、复用性更好就需要自行考虑了。

  • 相关阅读:
    vue中的 computed 和 watch 的区别
    mysql8.0 初始化数据库及表名大小写问题
    sql server alwayson 调整数据文件路径
    zabbix 自定义监控 SQL Server
    mysql 创建用户及授权
    mysql 设置从库只读模式
    mysql8.0 主从复制安装及配置
    centos8.0安装mysql8.0
    centos8替换阿里数据源
    npm publish 报错 【you or one of your dependencies are requesting a package version that is forbidden by your security policy】
  • 原文地址:https://www.cnblogs.com/hackerlin/p/12552932.html
Copyright © 2011-2022 走看看