Ansible--playbook基础

playbook可以理解成剧本,即一份文件可以存放多个ansible任务。后续的操作全部按照playbook中定义的动作执行

playbook使用YAML格式

YAML有自己的书写格式,操作时一定要严格按照此格式执行,后面会详细介绍其格式


playbook示例:

首先编辑yaml格式的文件,而此文件中统一定义要执行的操作:
vim  test.yaml     
- hosts: webservers   #指定操作的远程主机 
  remote_user: root   #以root身份执行以下tasks
  tasks: 
  - name: install nginx               #任务的名称,即在执行时显示的标题名称
    yum: name=nginx state=latest      #调用yum模块,与单独使用yum模块时的用法是一样的
  - name: start nginx 
    service: name=nginx enabled=true state=started  #service模块

- hosts: dbservers     #另一组远程主机
  remote_user: root
  tasks: 
  - name: install redis 
    yum: name=redis state=latest 
  - name: install conf file
    copy: src=/root/redis.conf dest=/app/ owner=redis group=root mode=0644
  - name: start redis 
    service: name=redis state=started
#以上注意hosts与name前要有短横线打头,这是yaml的格式要求
#而且tasks和其后面的具体任务要错开,即不能顶格配置name、service等

ansible-playbook  --list-hosts test.yaml
#主机检查
ansible-playbook  --list-tasks test.yaml
#任务检查
ansible-playbook  --syntax-check test.yaml
#语法检查

存在两个问题

1)只想执行test.yaml中的某一个任务怎么做

2)配置文件修改了,服务怎么重启,要知道service模块的配置中state已经配置为started了,不会再添加state为restarted

上述两个问题都需要执行任务但是只能将所有任务重新执行一遍,效率不高


问题1)的解决方案:给任务加标签

vim test.yaml
 tasks: 
  - name: install redis 
    yum: name=redis state=latest 
  - name: install conf file
    copy: src=/root/redis.conf dest=/app/ owner=redis group=root mode=0644
    tags: install    #加此标签,执行时指定此标签则只执行此任务,未加标签的任务不执行
  - name: start redis 
    service: name=redis state=started
    tags: start
#而且可以指定多个标签,多个任务也可以使用同一个标签,当调一个标签时可以执行多个任务
ansible-playbook  --list-tags test.yaml 
#查看哪些hosts打了标签
ansible-playbook  -t install,start test.yaml
#指定标签执行

问题2)的解决方案:

条件式触发任务,在配置文件被修改时会触发handlers机制

vim test.yaml
- hosts: dbservers
  remote_user: root
  tasks: 
  - name: install redis 
    yum: name=redis state=latest 
  - name: install conf file
    copy: src=/root/redis.conf dest=/etc/ owner=redis group=root mode=0644
    tags: install 
    notify: restart redis service   #条件通知,当此任务即要复制的文件被修改了notify就会通知handlers执行触发任务
  - name: start redis 
    service: name=redis state=started
    tags: start
  handlers:    #条件触发器,只有满足特定条件才会执行后续任务
  - name: restart redis service 
    service: name=redis state=restarted
#handlers依然调用service模块重启,这样只有配置文件修改才会触发handlers,才会执行此处的service。
#正常配置文件未改变的情况下不会触发此任务
ansible-playbook  -t install  test.yaml  
#将redis.conf的bind端口修改后,测试即可

还有一个问题需要注意,即如何根据实际情况调整参数

如redis.conf配置文件中有maxmemory字段,表示用于redis的内存容量,如果想将此容量调整为当前主机的内存容量的一半该怎么做。

要知道多个远程主机的内存容量不一定是一样的,有的是4G有的是16G如何根据主机自身的内存容量来配置呢?解决方案如下:

这个就用到了变量variables

facts变量:
ansible dbservers -m setup |  less
用户自定义变量:
    a、在playbook中定义变量,如下: 
    vim tree.yml  
- hosts: webservers
  remote_user: root
  vars:   #定义变量,其格式是 变量名+冒号+值
  - pkgname: tree
  tasks:
  - name: install {{ pkgname }} pkg   #调用变量使用花括号
    yum: name={{ pkgname }} state=latest   #在执行任务时就可以调用变量
然后测试即可
ansible-playbook  -C tree.yml  

     b、在ansible-playbook命令中指定变量,其优先级高于playbook中定义的,如下:
     接着上述步骤a进行操作
     ansible-playbook -e "pkgname=memcached" -C tree.yml 
     #在命令行中使用-e指定变量的键值,tree.yml只是本次测试使用
     
    c、通过roles传递的变量,后续介绍
    
    d、host inventory主机列表中定义的变量:
    vim /etc/ansible/hosts 
    [webservers]
    192.168.1.106 pkgname=redis
    192.168.1.107 pkgname=redis
    #在定义主机列表时定义
    如果同一组内主机变量全部相同,即向一个组传递相同变量,还可以使用下述方法定义:
    [webservers:var]
    pkgname=redis

模板与变量引用:通常需要在模板中调用变量

template模块:jinja2语法格式,类似于copy模块

vim redis.yml  
- hosts: webservers
  remote_user: root
  tasks:
  - name: install redis maxmem
    template: src=/root/redis.conf dest=/tmp/ owner=redis mode=666 
#在此任务中我们使用template模块,其提供模板功能,用法类似于copy
vim redis.conf 
maxmemory {{ ansible_memtotal_mb /2 }}mb
#ansible_memtotal_mb是ansible内置变量,可以参与多种运算
#在控制端,定义ansible内置变量并进行除法运算,即取本本机内存空间的一半
#这样即使远程多台主机的内存大小不一致,此变量仍会取内存大小的一半并将取出的最终结果定义在此配置文件中传给远程主机
ansible-playbook  redis.yml   
#template支持嵌套脚本的文本文件这是与copy模块的主要区别
#此示例可以上述提到的根据具体主机分别设置参数的问题。关键就是使用template模块并使用正确的变量

条件测试:

when语句,只有满足when条件才会执行任务

cat dfile.yml  
- hosts: webservers
  remote_user: root
  tasks:
  - name: copy file
    copy: src=/root/diff1.txt dest=/app/
    when: ansible_default_ipv4['address'] == '172.18.251.244'  #只有满足此条件才能够执行此任务
    #此条件说明当地址为127.18.251.244时执行copy模块的操作,ansible_default_ipv4是ansible的内置变量,中括号[]表示调用变量的子键
    #
  - name: copy file2
    copy: src=/root/diff2.txt dest=/app/
    when: ansible_default_ipv4['address'] == '192.168.1.107'
    #
ansible-playbook  --syntax-check dfile.yml 
#检查语法
ansible-playbook  dfile.yml

循环:迭代

需要重复执行任务,如在远程主机上安装多个程序包

cat tomcat.yml  
- hosts: dbservers
  remote_user: root
  vars:
  - jdk_version: 1.8.0   #定义变量
  tasks:
  - name: install  pkgs
    yum: name={{ item }} state=latest   #变量的调用方法是{{ }},而item是变量,其内容就是with_items中的
    with_items: 
    - nginx
    - java-{{ jdk_version }}-openjdk   #此处使用变量调用上文的内容
    - tomcat 
    - tomcat-webapps
    - tomcat-docs-webapp
    - tomcat-admin-webapps
    #以上是在一个任务中要安装的软件包
    扩展:以上是在一个任务中安装多个软件包,如果是创建多个用户、组也是类似的方法
    总结:迭代循环配合变量,迭代的关键字段是with_items,变量的调用使用{{ }}
    
ansible-playbook  tomcat.yml   #执行操作

下面思考一个问题:

如果使用循环方式安装多个软件包,而每个软件包的版本号基本是不一样的,那如何动态的在安装软件包时添加版本号,而不是事先写好在yaml文件中?

解决上述问题需要调用字典

cat tomcat.yml  
- hosts: dbservers
  remote_user: root
  tasks:
  - name: install  pkgs
    yum: name={{ item.name }}-{{ item.version }} state=latest   #item是使用循环的固定变量,此处item变量调用字典内容
    with_items:    #此处即所谓的字典,定义好软件包名称和版本号
    - { name: 'nginx', version: 1.10.2 }
    - { name: 'tomcat',version: 7.0.69 } 
#在一个任务中使用字典安装软件
ansible-playbook  -C tomcat.yml

再来看下面这个例子:循环加字典的使用
在控制端修改了两份文件:tomcat-users.xml和 server.xml
现在要是先的是将此二份文件通过copy模块复制到远程主机
cat tomcat.yml 
- hosts: dbservers
  remote_user: root
  tasks:
  - name: install config file 
    copy: src={{ item.file }} dest={{ item.conf }}
    with_items:
    - { file: '/root/server.xml',conf: '/etc/tomcat/server.xml' }
    - { file: '/root/tomcat-users.xml',conf: '/etc/tomcat/tomcat-users.xml' }
#在字典中我们定义file和conf
ansible-playbook  tomcat.yml
#完成上述步骤,就可以到远程主机上查看指定路径的文件是否已经修改过

roles  角色:

vim /etc/ansible/ansible.cfg 
roles_path    = /etc/ansible/roles   #roles的路径

/etc/ansible/roles/nginx/   
#其中nginx就是一个角色,在nginx目录下应该具有特定的目录层级结构,如:handlers  tasks  templates  vars
cat /etc/ansible/roles/nginx/tasks/main.yml    #tasks是nginx角色的一个任务模块,main.yml是固定格式不能改变
- name: install nginx pkg
  yum: name=nginx state=latest
- name: start nginx service 
  service: name=nginx state=started enabled=true
  #此任务模块完成两个动作,安装nginx和启动nginx
  
然后配置playbook文件
cat websrv.yml 
- hosts: webservers
  remote_user: root
  roles:   #不需要像以前那样配置tasks之类的,而是直接指定角色
  - nginx 
  #对webservers的主机以root身份调用nginx角色,而nginx橘色定义了两个task任务

ansible-playbook  -C websrv.yml 
#测试

总结:创建角色nginx,配置playbook文件,而此文件只需调用角色即可,具体操作已经在角色的模块中定义好了

示例:
基于模板生成nginx配置文件
第一步定义nginx内的变量                    #定义变量,将被templates模板调用
cat /etc/ansible/roles/nginx/vars/main.yml 
nginx_server_port: 8888
nginx_server_name: www.abc.com
nginx_doc_root: /webdata
第二步配置nginx下的模板文件                #定义模板文件,调用vars变量,此模板将用于生成nginx服务的配置文件
cat /etc/ansible/roles/nginx/templates/web-conf.j2 
server {
        listen {{ nginx_server_port }}
        server_name {{ nginx_server_name }}

        location  / {
                root {{ nginx_doc_root }}
        }
}
第三步定义nginx下的任务文件                #定义多项任务,安装nginx、配置文件、创建文件、开启服务
cat /etc/ansible/roles/nginx/tasks/main.yml  
- name: install nginx pkg
  yum: name=nginx state=latest
- name: install conf file
  template: src=web-conf.j2 dest=/etc/nginx/conf.d/web.conf
- name: create datadir
  file: path={{ nginx_doc_root }} state=directory    #此目录即nginx模板文件中将使用的
- name: start nginx service 
  service: name=nginx state=started enabled=true
第四步配置playbook文件                #定义webservers组中主机以root身份调用nginx角色,而nginx角色能做什么上述三个步骤已定义
cat /root/websrv.yml 
- hosts: webservers
  remote_user: root
  roles:
  - nginx
第五步测试i
ansible-playbook   websrv.yml 
#执行完上述操作,在远程webservers主机的/etc/nginx/conf.d/web.conf文件中就会有nginx模板下web-conf.j2文件的内容
#
相关文章
相关标签/搜索