Ansible中playbook

一、playbook简单介绍

playbook是一个非常简单的配置管理和多主机部署系统,可以定制配置,可以按指定操作步骤有序执行,支持同步及异步方式

下面是一个基本的playbook示例

/home/melon/ansible/playbooks/nginx.yml

 1 ---
 2 - hosts: webservers
 3   vars:
 4     listenport: 8888
 5   remote_user: root
 6   tasks:
 7   - name: 安装,确保nginx是最新版本  
 8     yum: pkg=nginx state=latest
 9   - name: 同步配置文件
10     template: src=/home/melon/ansible/nginx/nginx.conf dest=/etc/nginx/nginx.conf
11     notify:
12     - restart nginx
13   - name: 确保nginx是运行的
14     service: name=nginx state=started
15   handlers:
16     - name: restart nginx 
17     service: name=nginx state=restarted

上面简单的定制了一个简单的nginx软件包管理,内容包括安装、配置模板、状态管理等

介绍:

第2行 hosts 参数的作用是定义操作的对象,可以是主机或组

第3、4行定义了属于该组的相关变量,可以在模板中进行引用,如在 nginx.conf 配置文件中使用  listen  {{ listen_port }}

第5行的 remote_user 为指定远程操作的用户名,默认为 root,支持sudu方式 通过添加sudo:yes(remote_user 在ansible1.4以上的版本才引入)

第6-14行是任务列表,playbook将按定义的配置文件从上到下顺序执行,定义的主机都会执行相同的任务,定义name标签可以增加可读性

  8行的功能是安装最新nginx,前面的action(动作)可以是ansible的任意模块,这里是yum模块,参数使用key=value格式

  10行中,在playbook中可以通过template模块对本地配置模板文件如nginx.conf进行渲染并同步到目标主机,src 为管理端模板nginx.conf文件存放的位置 dest 为目标主机nginx.conf的文件位置

  当目标主机的配置文件发生变化时,就会通知处理程序(Handlers)来触发后续动作,上面为重启nginx服务,是通过Handlers中定义的name来触发的,只会运行一次,比如上面的notify中restart nginx和Handlers中定义的name: restart nginx 保持一致

执行playbook可以通过ansible-playbook命令实现,下面表示启用10个并行进程数执行playbook

ansible-playbook /home/melon/ansible/playbooks/nginx.yml -f 10

 

二、playbook角色与包含声明

当我们写个非常大的playbook时,还可以把它拆分成多个文件

当多个playbook涉及到复用时,可以将复用的内容剥离出来,写到独立的文件当中,在用到的时候在include进来即可

tasks/test.yml

---
- name: test shell
  command: /tmp/test.sh

然后在使用的时候include

tasks:
  - include: tasks/test.yml

处理程序handlers也一样

handlers/handlers.yml

---
- name: restart nginx
  service: name=nginx state=restarted

引入时

handlers:
  - include: handlers/handlers.yml

 

角色建立在包含文件之上,抽象后更清晰、可复用。Ansible官方在GitHub上提供了大量的示例供大家参考:https://github.com/ansible/ansible-examples

角色时Ansible定制好的一种标准规范,以不同级别目录层次及文件对角色、变量、任务、处理等进行拆分,为后续功能扩展、可维护性打下基础

下面是一个playbook的目录结构

nginx
├── group_vars
│   ├── all
│   └── webservers
├── hosts
├── roles
│   ├── db
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │       └── my.cnf.j2
│   └── web
│       ├── handlers
│       │   └── main.yml
│       ├── tasks
│       │   └── main.yml
│       ├── templates
│       │   ├── default.conf
│       │   └── nginx.conf
│       └── vars
│           └── main.yml
├── site.retry
└── site.yml

 

首先是引用文件

site.yml  全局配置文件

---
- name: 部署和配置网络服务器和应用程序代码
  hosts: webservers
  roles:
    - web

- name: 部署mysql数据库和配置
  hosts: dbservers
  roles:
    - db

hosts  主机组定义文件(非必选配置,默认引用/etc/ansible/hosts的参数),如果定义了,执行时要通过"-i file"来调用,如:ansible-playbook -i hosts

[webservers]
192.168.190.131
[dbservers]
192.168.190.133

group_vars  变量定义目录(目录当中的文件名要与组名保持一致,组变量文件定义的变量只作用于该组),all代表所有主机的变量

  group_vars/all

---
server_hostname: www.example.com

 group_vars/webservers

---
worker_processes: 4
num_cpu: 4

roles  角色功能目录,这里就说web角色

角色web定义了handlers、tasks、templates、vars 4个功能类,分别用来存放处理程序、任务列表、模板、变量的配置文件main.yml(vars/main.yml中定义的变量优先级高于/nginx/group_vars/all)

handlers/main.yml

- name: restart nginx
  service: name=nginx state=restarted

templates/nginx.conf(引用定义的变量)

user nginx;
worker_processes {{ worker_processes  }};
{% if num_cpus == 2 %}
worker_cpu_affinity 01 10;
{% elif num_cpus == 4 %}
worker_cpu_affinity 1000 0100 0010 0001;
{% else %}
worker_cpu_affinity 1000 0100 0010 0001;
{% endif %}
...........

tasks/main.yml

- name: 安装最新nginx
  yum: pkg=nginx state=latest

- name: 同步配置文件
  template: src=nginx.conf dest=/etc/nginx/nginx.conf
  notify: restart nginx

- name: 同步配置文件
  template: src=default.conf dest=/etc/nginx/conf.d/default.conf
  notify: restart nginx

- name: 确保nginx已经启动
  service: name=nginx state=started

 

运行角色(用-i hosts引用定义的角色)

ansible-playbook -i hosts site.yml -f 10

 

三、Facts

Facts类似于Saltstack的Grains功能,实时获取远程主机的各种信息

命令

ansible webservers -m setup
192.168.190.131 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.190.131", 
            "172.17.42.1"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::20c:29ff:feb2:95cc", 
            "fe80::427:e1ff:fee3:2634"
        ], 
        "ansible_architecture": "x86_64", 
        "ansible_bios_date": "07/02/2015", 
        "ansible_bios_version": "6.00", 
        "ansible_cmdline": {
            "KEYBOARDTYPE": "pc", 
            "KEYTABLE": "us", 
            "LANG": "en_US.UTF-8", 
            "SYSFONT": "latarcyrheb-sun16", 
..................

在模板中引用Facts信息

{{ ansible_architecture }}
{{ ansible_cmdline.KEYTABLE }}

 

本地Facts

当获取的目标信息不能满足我们的功能需求时,我们可以通过本地的Facts来实现,只需要在目标设备/etc/ansible/facts.d 目录定义JSON、INI 或可执行文件的JSON输出,文件扩展名要求使用".fact"

例如在目标机器192.168.190.131上定义3个变量

/etc/ansible/facts.d/test_fact.fact

[general]
max_memory_size=32
max_user_processes=3730
open_files=65535

然后执行命令查看:

ansible webservers -m setup -a "filter=ansible_local"

结果可以看到刚刚我们在192.168.190.131定义的变量

返回的JSON层次结构:test_fact(facts文件名前缀)>general(INI的节名)>key:value(INI的键与值),在模板中的调用方式

{{ ansible_local.test_fact.general.max_memory_size }}

 

注册变量

变量的另一个用途是将一条命令的运行结果保存到变量中供后面的playbook使用,示例:

- hosts: webservers
  tasks:
    - shell: /var/test.sh
      register: foo_result
      ignore_errors: True

    - shell: /usr/test.sh
      when: foo_result.rc == 5

上面示例说明:定义一个foo_result变量,变量的值为执行的shell:/var/test.sh的运行结果,ignore_errors: True 为忽略错误,变量注册完成后,playbook就可以在模板使用了,

when: foo_result.rc == 5 表示当执行命令后的resultcode(返回码)等于5时执行上面的命令

 

条件语句

  有时候一个playbook的结果取决于一个变量,或者取决于上一个任务的执行结果,下面介绍When声明

tasks:
  - name: "when test"
    command: /srv/test.sh
    when: ansible_os_family == "Debian"

上面例子表示:通过Facts本地变量 ansible_os_family 是否为Debian,为True时将执行上一条语句 command: /srv/test.sh ,为False时该语句不会触发,

 

- hosts: webservers
  tasks:
    - shell: /var/test.sh
      register: foo_result
      ignore_errors: True

    - shell: /usr/test.sh
      when: foo_result|failed

    - shell: /home/test.sh
      when: foo_result|success

    - shell: /srv/test.sh
      when: foo_result|skipped

when: foo_result|success的意思是当变量foo_result执行结果为成功状态时,将执行/home/test.sh ,其他同理。

 

循环

有时一个任务会做很多事情,如创建很多用户、安装很多包、或重复轮询特定的步骤,知道某结果条件为止

- name: add user
  user: name={{ item }} state=present groups=wheel
  with_item:
    - testuser1
    - testuser2

####################
- name: add testuser1
  user: name=testuser1 state=present groups=wheel
- name: add testuser2
  user: name=testuser2 state=present groups=wheel

上面示例上下实现的功能是一样的,上面使用了循环,实现一个批量创建系统用户的功能,with_item会自动循环执行上面的语句,循环的次数为with_item的元素个数,里面的元素会分别替换{{ item }}项

元素还支持字典形式

- name: add tuser
  user: name={{ item.name }} state=present groups={{ item.groups }}
  with_items:
    - { name: 'testuser1', groups: 'wheel' }
    - { name: 'testuser2', groups: 'root' }

 

posted @ 2017-03-27 09:55  J_hong  阅读(750)  评论(0)    收藏  举报