深度解析 Ansible:核心组件、配置、Playbook 全流程与 YAML 奥秘(下)

文章目录

六、playbook

运行playbook方式

复制代码
ansible-playbook <filename.yml>  ... [options]
常见选项
--check (-C)只检测可能会发生的改变,但不真正执行操作
--list-hosts 列出运行任务的主机
--limit 主机列表 只针对主机列表中的主机执行
-i 指定主机清单(hosts)
-v 显示过程 -vv -vvv更详细
-t 指定执行的tags名称
示例:
ansible-playbook file.yml --check 只检测
ansible-playbook --syntax-check  file.yml 检查yaml文件是否正确
ansible-playbook file.yml --limit webserver 指定执行的机器
ansible-playbook file.yml --list-hosts  # 查看主机
ansible-playbook file.yml --list-tasks  #查看任务列表
ansible-playbook file.yml --list-tags  # 查看标签


注意 :上图中copy连续使用两次,这是错误操作,这种操作只会执行最下面的copy,其余copy不会执行!!应该将其分开,分为两个name。

Playbook VS ShellScripts

复制代码
安装httpd
SHELL脚本
#!/bin/bash
# 安装Apache
yum install --quiet -y httpd
# 复制配置文件
cp /tmp/httpd.conf /etc/httpd/conf/httpd.conf
cp/tmp/vhosts.conf /etc/httpd/conf.d/
# 启动Apache,并设置开机启动
service httpd start
chkconfig httpd on

Playbook定义
---
- hosts: all
  remote_user: root
  
  tasks:
    - name: "安装Apache"
      yum: name=httpd       yum模块:安装httpd
    - name: "复制配置文件"
      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/  copy模块: 拷贝文件
    - name: "复制配置文件"
      copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/  
    - name: "启动Apache,并设置开机启动"
      service: name=httpd state=started enabled=yes   service模块: 启动服务

忽略错误 ignore_errors

复制代码
如果一个task出错,默认将不会继续执行其他task
利用ignore_errors:yes 可以忽略次task的错误,继续指定playbook其他task
---
- hosts: all
  tasks:
     - name: error
       ignore_errors: yes

handlers和notify结合使用触发条件

handlers

是tasks列表,这些task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作

notify 此action可用于在每个play的最后被出发,这样可以避免多次有改变发生时,每次都执行指定的操作,仅在所有的变化发生完后一次性执行指定的操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作

注意:

如果多个task通知了相同的handlers,此handlers仅会在所有task结束后运行一次

只有notify对应的task发生改变才会通知handlers

handlers实在所有前面的task执行成功之后才触发,可以使用force_handlers: yes强制执行handlers

复制代码
- hosts: all
  remote_user: root
  force_handlers: yes  #强制执行handlers

  tasks:
    - name: install Apache
      yum: name=httpd state=installed
    - name: copy conf
      copy: src=/etc/httpd/conf/httpd.conf dest=/etc/httpd/conf/ backup=yes
      notify: service restart
    - name: service Apache
      service: name=httpd state=started enabled=yes

  handlers:
    - name: service restart
      service: name=httpd state=restarted
小贴士:selinux的开启导致apache更换端口后启动不成功。

playbook中tags的使用

ansible-playbook -t conf httpd.yml 【使用-t 指定标签名字】

ansible-playbook -t conf,service httpd.yml

ansible-playbook httpd.yml --list-tsgs #查看标签列表

注意:tags标签命名可以相同,不通模块下写入相同tags标签,执行时,打入标签的模块会同时执行

playbook中变量的使用

变量名:仅能由字母、数字和下划线组成,且只能以字母开头 (setup模块,显示主机所有变量)

变量的优先级:命令行中的-e > playbook中定义的变量 > 主机清单中定义的变量

变量来源

复制代码
使用setup变量

示例:var.yml

- hosts: websrvs

  remote_user: root

  tasks:

    - name: create log file

      file: name=/var/log/ {{ ansible_fqdn }} state=touch



ansible-playbook var.yml
  ansible setup facts 远程主机的所有变量都可直接调用 (系统自带变量)
       setup模块可以实现系统中很多系统信息的显示
                可以返回每个主机的系统信息包括:版本、主机名、cpu、内存
       ansible all -m setup -a 'filter="ansible_nodename"'     查询主机名
       ansible all -m setup -a 'filter="ansible_memtotal_mb"'  查询主机内存大小
       ansible all -m setup -a 'filter="ansible_distribution_major_version"'  查询系统版本
       ansible all -m setup -a 'filter="ansible_processor_vcpus"' 查询主机cpu个数
    
    2> 在/etc/ansible/hosts(主机清单)中定义变量
        普通变量:主机组中主机单独定义,优先级高于公共变量(单个主机 )
        公共(组)变量:针对主机组中所有主机定义统一变量(一组主机的同一类别)
    
   通过命令行传递变量
    在运行playbook的时候也可以传递一些变量供playbook使用
示例:var.yml
- hosts: websrvs
  remote_user: root
  tasks:
    - name: install package
      yum: name={{ pkname }} state=present
      
ansible-playbook --e pkname=httpd var.yml
 
通过命令行指定变量,优先级最高
在playbook中定义
示例:var.yml
- hosts: websrvs
  remote_user: root
vars:
  - username: user1
  - groupname: group1
tasks:
  - name: create group
    group: name={{ groupname }} state=present
  - name: create user
    user: name={{ username }} state=present

ansible-playbook var.yml
ansible-playbook -e "username=user2 groupname=group2" var2.yml
    
变量文件中引用
cat vars.yml
var1: httpd
var2: nginx

cat var.yml
- hosts: web
  remote_user: root
  vars_files:
    - vars.yml
  tasks:
    - name: create httpd log
      file: name=/app/{{ var1 }}.log state=touch
    - name: create nginx log
      file: name=/app/{{ var2 }}.log state=touch
      
hostname app_81.magedu.com  hostname 不支持"_",认为"_"是非法字符
hostnamectl set-hostname app_80.magedu.com  可以更改主机名
在role中定义

变量命名:
    变量名仅能由字母、数字和下划线组成,且只能以字母开头

变量定义:key=value
    示例:http_port=80

变量调用方式:
    1> 通过{{ variable_name }} 调用变量,且变量名前后必须有空格,有时用"{{ variable_name }}"才生效

    2> ansible-playbook --e 选项指定
       ansible-playbook test.yml -e "hosts=www user=magedu"
在主机清单中定义变量,在ansible中使用变量
vim /etc/ansible/hosts
[appsrvs]
192.168.38.17 http_port=817 name=www
192.168.38.27 http_port=827 name=web

调用变量
ansible appsrvs -m hostname -a'name={{name}}'  更改主机名为各自被定义的变量 

针对一组设置变量
[appsrvs:vars]
make="-"

ansible appsrvs -m hostname -a 'name={{name}}{{mark}}{{http_port}}'  ansible调用变量

针对主机和主机组的变量
主机变量
可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用
[websrvs]
www1.magedu.com http_port=80 maxRequestsPerChild=808
www2.magedu.com http_port=8080 maxRequestsPerChild=909

组变量
组变量是指赋予给指定组内所有主机上的在playbook中可用的变量
    [websrvs]
    www1.magedu.com
    www2.magedu.com

    [websrvs:vars]
    ntp_server=ntp.magedu.com
    nfs_server=nfs.magedu.com

普通变量
    [websrvs]
    192.168.99.101 http_port=8080 hname=www1
    192.168.99.102 http_port=80 hname=www2

公共(组)变量
    [websvrs:vars]
    http_port=808
    mark="_"

    [websrvs]
    192.168.99.101 http_port=8080 hname=www1
    192.168.99.102 http_port=80 hname=www2
    ansible websvrs --m hostname --a 'name={{ hname }}{{ mark }}{{ http_port }}'

组嵌套
inventory中,组还可以包含其它的组,并且也可以向组中的主机指定变量。
这些变量只能在ansible-playbook中使用,而ansible命令不支持
    [apache]
    httpd1.magedu.com
    httpd2.magedu.com
    
    [nginx]
    ngx1.magedu.com
    ngx2.magedu.com
    
    [websrvs:children]
    apache
    nginx
    
    [webservers:vars]
    ntp_server=ntp.magedu.com

invertory参数

复制代码
invertory参数:用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量
    ansible_ssh_host
    ansible_ssh_port
    ansible_ssh_user
    ansible_ssh_pass
    ansbile_sudo_pass

示例:
    cat /etc/ansible/hosts
    [websrvs]
    192.168.0.1 ansible_ssh_user=root ansible_ssh_pass=magedu
    192.168.0.2 ansible_ssh_user=root ansible_ssh_pass=magedu

模板templates

文本文件,嵌套有脚本(使用模板编程语言编写)

jinja2语言,使用字面量,有下面形式:

字符串:使用单引号或者双引号

数字:整数,浮点数

列表:[item1,itme2,...]

元组:(item1,itme2,...)

字典:{key1:value1,key2:value2,...}

布尔型:true/false

算术运算:+,-,*,/,//,%,**

比较操作:==,!=,>,>=,<,<=

逻辑运算:and,or,not

流表达式:For If When(循环语句)

小记:在模板目录template下写入模板文件,文件中可以直接调用setup变量(src可以直接书写模板目录下的文件)

迭代与条件判断

when

条件测试:如果需要根据变量,facts或此前任务的执行结果来作为某task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用,jinja2的语法格式

when语句

在task后添加when子句即可使用户条件测试;when语句支持jinji2表达式语法

示例:

  • name: 'shutdown redhad flavored systems'
    command: /sbin/shutdown -h now
    when: ansible_os_family == "RedHat"

迭代:with_items

迭代:当有需要重复执行的任务时,可以使用迭代机制

对迭代项的引用,固定变量名为"iftem"

要在task中使用with_items给定要迭代的元素列表

列表格式:

字符串

字典

迭代嵌套子变量


playbook中template模板对于for if 循环的使用

复制代码
for
yml文件
---
- hosts: web server
  remote_user: root
  vars:
    ports:
      - listen_port: 84
      - listen_port: 85
      - listen_port: 86

  tasks:
    - name: copy conf
      template: src=for1.conf.j2 dest=/data/for1.conf
模板文件:
{% for port in ports %}   #port自定义变量
server{
        listen {{ port.listen_port }}
}
{% endfor %}
&&
yml文件
---
- hosts: web
  remote_user: root
  vars:
    ports:
      - web1:
        port: 81
        name: web1.magedu.com
        rootdir: /data/website1
      - web2:
        port: 82
        name: web2.magedu.com
        rootdir: /data/website2

  tasks:
    - name: copy conf
      template: src=for2.conf.j2 dest=/data/for2.conf

模板文件:
{% for p in ports %}    #p自定义变量
server{
        listen {{ p.port }}
        servername {{ p.name }}
        documentroot {{ p.rootdir }}
}
{% endfor %}

if
yml文件
---
- hosts: web
  remote_user: root
  vars:
    ports:
      - web1:
        port: 81
        name: web1.magedu.com
        rootdir: /data/website1
      - web2:
        port: 82
        #name: web2.magedu.com
        rootdir: /data/website2

  tasks:
    - name: copy conf
      template: src=if.conf.j2 dest=/data/if.conf

模板文件:
{% for p in ports %}
server{
        listen {{ p.port }}
{% if p.name is defined %} #如果p.name被定义就执行下面的servername,否则不执行
        servername {{ p.name }}
{% endif %}
        documentroot {{ p.rootdir }}
}
{% endfor %}

roles

ansible自1.2版本引入的新特性,用于层次性,结构化地组织playbook。roles能够根据层次结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于主机构建服务的场景中,但也可以使用于构建守护进程等场景中

复杂场景:建议使用roles,代码复用度高

变更指定主机或主机组

如命令不规范,维护和传承成本大

某些功能需要多个playbook,通过includes可以实现
roles的使用

复制代码
roles目录结构
playbook.yml
roles
project/
tasks/
files/
vars/  不常用
defaults/  不常用
templates/
handlers/
meta/  不常用
roles各目录的作用
/roles/project/:项目名称,有以下目录
files/:存放由copy模块或scripts模块等调用的文件
template/:template模块查找所需要模板文件的目录
tasks/:定义tasks,roles的基本元素,至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行调用
handlers/:至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行调用
vars/:定义变量,至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行调用
meta/:定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过include进行调用
default/:设定默认变量时使用此目录中的main.yml文件
相关推荐
风清再凯1 天前
自动化工具ansible,以及playbook剧本
运维·自动化·ansible
IT乌鸦坐飞机1 天前
ansible部署数据库服务随机启动并创建用户和设置用户有完全权限
数据库·ansible·centos7
遇见火星14 天前
如何使用Ansible一键部署MinIO集群?
ansible
粥周粥14 天前
ANSIBLE
ansible
码农101号14 天前
Linux中ansible模块补充和playbook讲解
linux·运维·ansible
码农101号14 天前
Linux的Ansible软件基础使用讲解和ssh远程连接
ansible
烟雨书信15 天前
ANSIBLE运维自动化管理端部署
运维·自动化·ansible
碎碎-li15 天前
ANSIBLE(运维自动化)
运维·自动化·ansible
@donshu@18 天前
Linux运维-ansible-python开发-获取inventroy信息
linux·运维·ansible
Kendra91922 天前
Ansible
ansible