{"msg":"操作成功","code":200,"data":{"createBy":"admin","createTime":"2020-08-22 16:45:55","updateBy":"admin","updateTime":"2020-08-22 16:45:55","remark":null,"id":32,"articleTitle":"Ansible（五）include与roles","articleUrl":"ansible_roles","articleThumbnail":"https://www.asumimoe.com/imgfiles/20220908/5969ef61cf754d1aa6e0f5c28219aefa.jpg","articleFlag":"1","draftStatus":"1","reprintStatement":"0","articleSummary":"角色是ansible自1.2版本引入的新特性，用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲，roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中，并可以便捷地include它们的一种机制。","articleContent":"### include\n\n如果将所有的play都写在⼀个playbook中，很容易导致这个playbook⽂件变得臃肿庞⼤，且不易读。因此，可以将多个不同任务分别写在不同的playbook中，然后使⽤include将其包含进去即可。⽽role则是整合playbook的⽅式。⽆论是include还是role，其⽬的都是分割⼤playbook以及复⽤某些细化的play甚⾄是task。\n\n可以将task列表和handlers独⽴写在其他的⽂件中，然后在某个playbook⽂件中使⽤include来包含它们。除此之\n外，还可以写独⽴的playbook⽂件，使⽤include来包含这个⽂件。\n\n也即是说，include可以导⼊两种⽂件：导⼊task、导⼊playbook。\n\n1.⼀种是任务列表式的⽂件(没有tasks或handlers指令)，它只能在tasks或handlers指令的⼦选项处使⽤include包\n含。这种⽅式可以传递变量到被包含的⽂件中。\n\n假设某个task列表文件/yaml/a.yaml内容如下：\n\n```yml\n- name: execute ntpdate\n  shell: /usr/sbin/ntpdate ntp1.aliyun.com\n```\n\n在同目录下有⼀个名为test.yaml的playbook(除了role，playbook中所有相对路径都是基于playbook的)，在\n此playbook中使⽤include来包含它，如果使⽤相对路径将会包含同⽬录下的⽂件。\n\n```yml\n- hosts: centos7\n  tasks:\n    - include: a.yaml\n```\n\n可以在include的时候传递变量给对应的文件，\n\n```yml\n- hosts: centos7\n  tasks:\n    - include: a.yaml sayhi=\"hello world\"\n    \n- hosts: centos7\n  tasks:\n    - include: a.yaml\n      vars:\n        sayhi: \"hello world\"\n```\n\n然后可以在被包含的a.yaml文件中使用该变量。\n\n```yml\n- name: execute ntpdate\n  shell: /usr/sbin/ntpdate ntp1.aliyun.com\n- name: say hi to world\n  debug: msg=\"{{ sayhi }}\"\n```\n\n2.另一种是include整个playbook文件，即include的动作是加载一个或多个play，所以写在顶级列表的层次。\n\n```yml\n- name: this is a play at the top level of a file\n  hosts: all\n  remote_user: root\n  tasks:\n    - name: say hi\n      tags: foo\n      shell: echo \"hi...\"\n- include: load_balancers.yml sayhi=\"hello world\"\n- include: webservers.yml\n- include: dbservers.yml\n```\n\n### roles\n\nroles意为⾓⾊，主要⽤于封装playbook实现复⽤性。在ansible中，roles通过⽂件的组织结构来展现。\n对于⼀个role，它的⽂件组织结构如下图所⽰。\n\n```shell\ntree playbooks/\n    playbooks/  根据需要命名\n    ├── roles\n    │   ├── dbservers  根据需要命名\n    │   │   ├── defaults  \n    │   │   ├── files  存放要复制的文件\n    │   │   │   └── httpd.conf\n    │   │   ├── handlers  存放触发器任务文件\n    │   │   │   └── main.yaml\n    │   │   ├── meta  \n    │   │   │   └── main.yml\n    │   │   ├── tasks  存放任务文件\n    │   │   │   └── main.yaml\n    │   │   ├── templates  存放模板文件\n    │   │   │   └── httpd.conf\n    │   │   └── vars  存放变量定义文件\n    │   │       └── main.yaml\n    │   └── webservers\n    │       ├── files\n    │       ├── handlers\n    │       ├── tasks\n    │       ├── templates\n    │       └── vars\n    └── site.yaml  主调用文件\n```\n\n⾸先需要有⼀个roles⽬录。同时，在roles⽬录所在⽬录中，还要有⼀个playbook⽂件，此处为site.yaml，site.yaml⽂件是ansible-playbook需要执⾏的⽂件，在此⽂件中定义了⾓⾊，当执⾏到⾓⾊时，将会到\nroles中对应的⾓⾊⽬录中寻找相关⽂件。\n\nroles⽬录中的⼦⽬录是即是各个role。在role⽬录中，有⼏个固定名称的⽬\n录(如果没有则忽略)。在这些⽬录中，还要有⼀些固定名称的⽂件，除了固定名称的⽂件，其他的⽂件可以随意命\n名。以下是各个⽬录的含义：\n\n- tasks⽬录：存放task列表。若role要⽣效，此⽬录必须要有⼀个主task⽂件main.yml，在main.yml中可以使⽤\n- include包含同⽬录(即tasks)中的其他⽂件。\n- handlers⽬录：存放handlers的⽬录，若要⽣效，则⽂件必须名为main.yml⽂件。\n- files⽬录：在task中执⾏copy或script模块时，如果使⽤的是相对路径，则会到此⽬录中寻找对应的⽂件。\n- templates⽬录：在task中执⾏template模块时，如果使⽤的是相对路径，则会到此⽬录中寻找对应的模块⽂\n  件。\n- vars⽬录：定义专属于该role的变量，如果要有var⽂件，则必须为main.yml⽂件。\n- defaults⽬录：定义角⾊默认变量，角⾊默认变量的优先级最低，会被任意其他层次的同名变量覆盖。如果要有var⽂件，则必须为main.yml⽂件。\n- meta⽬录：⽤于定义角⾊依赖(dependencies)，如果要有角⾊依赖关系，则⽂件必须为main.yml。\n\n### roles示例：批量自动化安装\n\n下⾯演⽰的是使⽤role批量⾃动安装nginx和mysql(CentOS 6)或maridb(CentOS 7)的⽰例。由于被控节点有\nCentOS 6和CentOS 7两种发⾏版的操作系统，因此除了要挑选对应的数据库，还要让nginx的配置⽂件适应各操\n作系统，因为nginx在这两个版本的系统上配置内容有所不同。在此，nginx、mysql和mariadb是3个role，且让\nnginx role依赖于mysql或mariadb role。\n\n其中site.yml是⼊站⽂件，⽤于调⽤nginx、mysql和mariadb这3个role，这个⽂件中的内容如下。它有3个作⽤：(1)\n在调⽤roles之前，先根据发⾏版配置好yum源(pre_tasks);(2)调⽤nginx role，此处没有调⽤mysql和mariadb这两\n个role，因为在nginx role的meta/main.yml⽂件中定义了nginx role依赖于这两个role，所以此处可以不⽤定义;(3)\n在执⾏完nginx role之后，输出⼀个提⽰信息(post_tasks)。\n\n```yml\ncat /yaml/site.yml\n\n- hosts: centos\n  remote_user: root\n  # 根据发⾏版配置好yum源，使⽤when进⾏条件判断\n  pre_tasks:\n    - name: config the yum repo for centos 7\n      yum_repository:\n        name: epel\n        description: epel\n        baseurl: http://mirrors.aliyun.com/epel/7/$basearch/\n        gpgcheck: no\n      when: ansible_distribution_major_version == \"7\"\n    - name: config the yum repo for centos 6\n      yum_repository:\n        name: epel\n        description: epel\n        baseurl: http://mirrors.aliyun.com/epel/6/$basearch/\n        gpgcheck: no\n      when: ansible_distribution_major_version == \"6\"\n  roles:\n    - nginx\n  # 输出over消息\n  post_tasks:\n    - shell: echo 'deploy nginx/mysql over'\n      register: ok_var\n    - debug: msg='{{ ok_var.stdout }}'\n```\n\n以下是nginx role中的各⽂件内容。其中template复制的源⽂件都是从centos 6 nginx和centos 7 nginx上提取的，\n只不过是重新命名了⽽已。\n\n```yml\n/yaml/roles/nginx/tasks/main.yml\n\n- name: make sure nginx state is installed\n  yum: name=nginx state=installed\n- name: template nginx.conf\n# 基于变量赋值配置⽂件模板，检查配置⽂件语法，并在必要的时候触发handler\n  template: src=nginx{{ ansible_distribution_major_version }}.conf.j2\n                dest=/etc/nginx/nginx.conf\n                validate=\"/usr/sbin/nginx -t -c %s\"\n  notify:\n    - restart nginx\n# 基于jinja2渲染模板⽂件，且改变时也触发重启操作\n  - name: copy index.html\n  template: src=index.html.j2 dest=/usr/share/nginx/html/index.html\n  notify:\n    - restart nginx\n    - name: make sure nginx service is running\n      service: name=nginx state=started\n# 引⽤变量 nginx_port，在vars/main.yml中定义了\n    - name: make sure port is open\n      wait_for: port=\"{{ nginx_port }}\"\n\n/yaml/roles/nginx/handlers/main.yml\n\n- name: restart nginx\n  service: name=nginx state=restarted\n\n/yaml/roles/nginx/vars/main.yml\nnginx_port: 80\n\n# 定义nginx依赖于MySQL或mariadb，具体依赖于哪个，是通过条件进⾏判断的，centos 6表⽰依赖于mysql，centos 7表⽰依赖于mariadb\n# 同时传递了两个值给变量hi_var，由于是在依赖的时候传递的，所以这两个变量可直接在依赖的role(mysql role或mariadb role)的playbook中引⽤\n\n/yaml/roles/nginx/meta/main.yml\n\ndependencies:\n- { role: mysql,hi_var: \"hello mysql\",when: \"ansible_distribution_major_version == '6'\" }\n- { role: mariadb,hi_var: \"hello mariadb\",when: \"ansible_distribution_major_version == '7'\" }\n```\n\n在template执⾏时，它会使⽤jinja2引擎对⽂件中的变量进⾏替换，使得在拷贝到不同主机时，该index.html的内容\n是基于远程主机ip的。此处使⽤的变量是收集到的f acts中的变量\"ansible_def ault_ipv4.address\"。\n\n以下是mysql role中各⽂件的内容。注意，MySQL的my.cnf 和mariadb的my.cnf 默认情况下并不⼀样(mariadb的\nmy.cnf 默认多了⼀项配置\"!includedir /etc/my.cnf .d\"，MySQL需要取消该项)，所以需要分别提供。\n\n```yml\n/yaml/roles/mysql/tasks/main.yml\n\n- name: make sure mysql is installed\n  yum: name=mysql-server state=installed\n# 特别需要注意下⾯的初始化命令，由于执⾏的是shell模块，所以要考虑其幂等性，显然初始化动作是⼀定要实现幂等性的\n\n- name: do something to initialize mysql\n  file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755\n- shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1\n- name: copy my.cnf\n  copy: src=my.cnf dest=/etc/my.cnf\n  notify:\n    - restart mysql\n- name: make sure mysql is running\n  service: name=mysqld state=started\n- name: make sure mysql port is open\n  wait_for:\n    port: \"{{ mysql_port }}\"\n    timeout: 10\n\n# 这⾥输出了nginx/meta/main.yml中传递的变量\n- name: echo var passed by nginx\n  shell: echo \"{{ hi_var }}\"\n  register: var_result\n- debug: msg=\"{{ var_result.stdout }}\"\n\n/yaml/roles/mysql/handlers/main.yml\n\n- name: restart mysql\n  service: name=mysqld state=restarted\n\n/yaml/roles/mysql/vars/main.yml\n\nmysql_port: 3306\n```\n\n以下是mariadb role中各⽂件的内容，和mysql⼤体上是⼀致的。注意，MySQL的my.cnf 和mariadb的my.cnf 默认况下并不⼀样，所以需要分别提供。\n\n```yml\n/yaml/roles/mariadb/tasks/main.yml\n\n- name: make sure mariadb is installed\n  yum: name=mariadb-server state=installed\n- name: do something to initialize mariadb\n  file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755\n- shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1\n- name: copy my.cnf\n  copy: src=my.cnf dest=/etc/my.cnf\n  notify:\n    - restart mariadb\n- name: make sure mariadb is running\n  service: name=mariadb state=started\n- name: make sure mariadb port is open\n  wait_for:\n    port: \"{{ mariadb_port }}\"\n    timeout: 15\n- name: echo var passed by nginx\n  shell: echo \"{{ hi_var }}\"\n  register: var_result\n- debug: msg=\"{{ var_result.stdout }}\"\n\n/yaml/roles/mariadb/handlers/main.yml\n\n- name: restart mariadb\n  service: name=mariadb state=restarted\n\n/yaml/roles/mariadb/vars/main.yml\n\nmariadb_port: 3306\n```\n\n\n参考自：<https://www.cnblogs.com/f-ck-need-u/p/7576137.html#ansible>","categoryId":3,"viewCount":1036,"categoryName":"Ansible","author":"球接子","authorAvatar":null,"tagIds":[3],"tagNames":["Ansible"]}}