Ansible篇-ansible-playbook inventory/roles/include用法详解

1 引言

ansible-playbook有很多巧妙的用法,在这里总结一下。
ansible中文权威指南:http://www.ansible.com.cn/docs/intro.html

2 yml语法简介

2.1 ansible剧本使用的是yaml语法

  • 1)所有的 YAML 文件(无论和 Ansible 有没有关系)开始行都应该是 —. 这是 YAML 格式的一部分, 表明一个文件的开始;
  • 2)对于 Ansible, 每一个 YAML 文件都是从一个列表开始. 列表中的每一项都是一个键值对, 通常它们被称为一个 “哈希” 或 “字典”. 所以, 我们需要知道如何在 YAML 中编写列表和字典。一个字典是由一个简单的 键: 值 的形式组成(这个冒号后面必须是一个空格):
---
#一位职工的记录
name: Example Developer
job: Developer
skill: Elite
  • 3)需要使用引号来包裹任何包含冒号的哈希值
foo: "somebody said I should put a colon here: so I did"
  • 4)Ansible 使用 “{{ var }}” 来引用变量. 如果一个值以 “{” 开头, YAML 将认为它是一个字典, 所以我们必须引用它, 像这样:
foo: "{{ variable }}"

5)把目前所学到的 YAML 例子组合在一起:

---
 - hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
 - name: ensure apache is at the latest version
    yum: pkg=httpd state=latest
 - name: write the apache config file
    template: src=/srv/httpd.j2 dest=/etc/httpd.conf
    notify:
    - restart apache
 - name: ensure apache is running
    service: name=httpd state=started
  handlers:
    - name: restart apache
      service: name=httpd state=restarted

2.2 playbook基础

  • 主机与用户

1)可以为 playbook 中的每一个 play,个别地选择操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤
2)hosts 行的内容是一个或多个组或主机的 patterns,以逗号为分隔符
3)remote_user 就是账户名

---
- hosts: webservers
  remote_user: root

4)在每一个 task 中,可以定义自己的远程用户

---
- hosts: webservers
  remote_user: root
  tasks:
    - name: test connection
      ping:
      remote_user: yourname

5)也支持从 sudo 执行命令

---
- hosts: webservers
  remote_user: yourname
  sudo: yes

可以仅在一个 task 中,使用 sudo 执行命令,而不是在整个 play 中使用 sudo

---
- hosts: webservers
  remote_user: yourname
  tasks:
    - service: name=nginx state=started
      sudo: yes

也可以登陆后,sudo 到不同的用户身份,而不是使用 root

---
- hosts: webservers
  remote_user: yourname
  sudo: yes
  sudo_user: postgres
  • Tasks列表

1)每一个 play 包含了一个 task 列表(任务列表).一个 task 在其所对应的所有主机上(通过 host pattern 匹配的所有主机)执行完毕之后,下一个 task 才会执行.有一点需要明白的是(很重要),在一个 play 之中,所有 hosts 会获取相同的任务指令,这是 play 的一个目的所在,也就是将一组选出的 hosts 映射到 task.
2)在运行 playbook 时(从上到下执行),如果一个 host 执行 task 失败,这个 host 将会从整个 playbook 的 rotation 中移除. 如果发生执行失败的情况,请修正 playbook 中的错误,然后重新执行即可.
3)每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的
4)下面是一种基本的 task 的定义,service moudle 使用 key=value 格式的参数,这也是大多数 module 使用的参数格式

tasks:
  - name: make sure apache is running
    service: name=httpd state=running

5)比较特别的两个 modudle 是 command 和 shell ,它们不使用 key=value 格式的参数,而是这样

tasks:
  - name: disable selinux
    command: /sbin/setenforce 0

6)在 action 行中可以使用变量.假设在 ‘vars’ 那里定义了一个变量 ‘vhost’ ,可以这样使用它

tasks:
  - name: create a virtual host file for {{ vhost }}
    template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
  • handlers:在发生改变时执行的操作

1)Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别.Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行.不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次.

#通过notify来触发handlers
- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache
#预先配置的handlers
handlers:
    - name: restart memcached
      service:  name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

2)handlers 会在 ‘pre_tasks’, ‘roles’, ‘tasks’, 和 ‘post_tasks’ 之间自动执行. 如果你想立即执行所有的 handler 命令,在1.2及以后的版本,你可以这样做:

tasks:
   - shell: some tasks go here
   - meta: flush_handlers
   - shell: some other tasks
  • 执行playbook
#-f的意思是开启10个并发的进程
ansible-playbook playbook.yml -f 10

3 inventory

https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html

  • 例1 同一功能的主机可以写在同一组
#方括号[ ]中是组名,用于对系统进行分类,便于对不同系统进行个别的管理。
[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com
  • 例2 一组相似的 hostname , 可简写
[webservers]
www[01:50].example.com
[databases]
db-[a:f].example.com
  • 例 3 假设你有一些静态IP地址,希望设置一些别名,但不是在系统的 host 文件中设置,又或者你是通过隧道在连接,那么可以设置如下:
jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
  • 例 4 对于每一个 host,你还可以选择连接类型和连接用户名:
[targets]

localhost              ansible_connection=local
other1.example.com     ansible_connection=ssh        ansible_ssh_user=mpdehaan
other2.example.com     ansible_connection=ssh        ansible_ssh_user=mdehaan
  • 例 5 主机变量——分配变量给主机很容易做到,这些变量定义后可在 playbooks 中使用:
[atlanta]
host1 http_port=80 maxRequestsPerChild=808
host2 http_port=303 maxRequestsPerChild=909
  • 例 6 也可以定义整个组的变量
[atlanta]
host1
host2

[atlanta:vars]
ntp_server=ntp.atlanta.example.com
proxy=proxy.atlanta.example.com
  • 例 7 把一个组作为另一个组的子成员。可以把一个组作为另一个组的子成员,以及分配变量给整个组使用. 这些变量可以给 /usr/bin/ansible-playbook 使用,但不能给 /usr/bin/ansible 使用:
[atlanta]
host1
host2

[raleigh]
host2
host3

[southeast:children]
atlanta
raleigh

[southeast:vars]
some_server=foo.southeast.example.com
halon_system_timeout=30
self_destruct_countdown=60
escape_pods=2

[usa:children]
southeast
northeast
southwest
northwest
  • 例 8 分文件定义Host和Group变量。在 inventory 主文件中保存所有的变量并不是最佳的方式.还可以保存在独立的文件中,这些独立文件与 inventory 文件保持关联
  • 1)假设有一个主机名为 ‘foosball’, 主机同时属于两个组,一个是 ‘raleigh’, 另一个是 ‘webservers’. 那么以下配置文件(YAML 格式)中的变量可以为 ‘foosball’ 主机所用.依次为 ‘raleigh’ 的组变量,’webservers’ 的组变量,’foosball’ 的主机变量:
/etc/ansible/group_vars/raleigh
/etc/ansible/group_vars/webservers
/etc/ansible/host_vars/foosball

  • 2)还可以为一个主机,或一个组,创建一个目录,目录名就是主机名或组名.目录中的可以创建多个文件, 文件中的变量都会被读取为主机或组的变量.如下 ‘raleigh’ 组对应于 /etc/ansible/group_vars/raleigh/ 目录,其下有两个文件 db_settings 和 cluster_settings, 其中分别设置不同的变量:
/etc/ansible/group_vars/raleigh/db_settings
/etc/ansible/group_vars/raleigh/cluster_settings
  • inventory参数说明
ansible_ssh_host
      将要连接的远程主机名.与你想要设定的主机的别名不同的话,可通过此变量设置.

ansible_ssh_port
      ssh端口号.如果不是默认的端口号,通过此变量设置.

ansible_ssh_user
      默认的 ssh 用户名

ansible_ssh_pass
      ssh 密码(这种方式并不安全,我们强烈建议使用 --ask-pass 或 SSH 密钥)

ansible_sudo_pass
      sudo 密码(这种方式并不安全,我们强烈建议使用 --ask-sudo-pass)

ansible_sudo_exe (new in version 1.8)
      sudo 命令路径(适用于1.8及以上版本)

ansible_connection
      与主机的连接类型.比如:local, ssh 或者 paramiko. Ansible 1.2 以前默认使用 paramiko.1.2 以后默认使用 'smart','smart' 方式会根据是否支持 ControlPersist, 来判断'ssh' 方式是否可行.

ansible_ssh_private_key_file
      ssh 使用的私钥文件.适用于有多个密钥,而你不想使用 SSH 代理的情况.

ansible_shell_type
      目标系统的shell类型.默认情况下,命令的执行使用 'sh' 语法,可设置为 'csh' 或 'fish'.

ansible_python_interpreter
      目标主机的 python 路径.适用于的情况: 系统中有多个 Python, 或者命令路径不是"/usr/bin/python",比如  \*BSD, 或者 /usr/bin/python
      不是 2.X 版本的 Python.我们不使用 "/usr/bin/env" 机制,因为这要求远程用户的路径设置正确,且要求 "python" 可执行程序名不可为 python以外的名字(实际有可能名为python26).

      与 ansible_python_interpreter 的工作方式相同,可设定如 ruby 或 perl 的路径....

4 roles和include

4.1 include

  • 在多个 play 或者多个 playbook 中重用同一个 task 列表,可以使用 include files 做到这一点。
tasks:
  - include: tasks/foo.yml

//或者还可以给include传递变量,即参数化的 include
tasks:
  - include: wordpress.yml wp_user=timmy
  - include: wordpress.yml wp_user=alice
  - include: wordpress.yml wp_user=bob
 
//1.0版之后支持结构化的变量
tasks:
  - include: wordpress.yml
    vars:
        wp_user: timmy
        some_list_variable:
          - alpha
          - beta
          - gamma

  • 也可用来将一个 playbook 文件导入另一个 playbook 文件
- 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
- include: webservers.yml
- include: dbservers.yml

4.2 roles

roles是组织 playbook的最好的方式!Roles 基于一个已知的文件结构,去自动的加载某些 vars_files,tasks 以及 handlers。基于 roles 对内容进行分组,使得我们可以容易地与其他用户分享 roles 。

  • 项目的结构举例如下,(当然,也可以不按照这种结构对playbook进行管理,但是极力推荐使用这种方式)
site.yml
webservers.yml
fooservers.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
   webservers/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/

该项目结构对应的一个playbook可能是这样的:

---
- hosts: webservers
  roles:
     - common
     - webservers

这个 playbook 为一个角色 ‘x’ 指定了如下的行为:
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。

  • 也可以使用参数化的 roles,这种方式通过添加变量来实现,比如:
---
- hosts: webservers
  roles:
    - common
    - { role: foo_app_instance, dir: '/opt/a',  port: 5000 }
    - { role: foo_app_instance, dir: '/opt/b',  port: 5001 }
  • 当一些事情不需要频繁去做时,你也可以为 roles 设置触发条件,像这样:
---

- hosts: webservers
  roles:
    - { role: some_role, when: "ansible_os_family == 'RedHat'" }
  • 如果你希望定义一些 tasks,让它们在 roles 之前以及之后执行,你可以这样做:
---

- hosts: webservers

  pre_tasks:
    - shell: echo 'hello'

  roles:
    - { role: some_role }

  tasks:
    - shell: echo 'still busy'

  post_tasks:
    - shell: echo 'goodbye'
  • 角色默认变量:要创建默认变量,只需在 roles 目录下添加 defaults/main.yml 文件。这些变量在所有可用变量中拥有最低优先级,可能被其他地方定义的变量(包括 inventory 中的变量)所覆盖。
  • 角色依赖:你可以自动地将其他 roles 拉取到现在使用的 role 中。”角色依赖” 保存在 roles 目录下的 meta/main.yml 文件中。这个文件应包含一列 roles 和 为之指定的参数,下面是在 roles/myapp/meta/main.yml 文件中的示例:
---
dependencies:
  - { role: common, some_parameter: 3 }
  - { role: apache, port: 80 }
  - { role: postgres, dbname: blarg, other_parameter: 12 }

5 变量的优先级

  • extra vars (在命令行中使用 -e)优先级最高
  • 然后是在inventory中定义的连接变量(比如ansible_ssh_user)
  • 接着是大多数的其它变量(命令行转换,play中的变量,included的变量,role中的变量等)
  • 然后是在inventory定义的其它变量
  • 然后是由系统发现的facts
  • 然后是 “role默认变量”, 这个是最默认的值,很容易丧失优先权
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章