深度解析 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文件
相关推荐
Karoku0661 天前
【自动化部署】Ansible循环
linux·运维·数据库·docker·容器·自动化·ansible
W u 小杰1 天前
Ansible基本用法
服务器·网络·ansible
运维小文1 天前
ansible剧本快速上手
linux·运维·python·自动化·ansible·幂等性·剧本
记得多喝水o1 天前
Ansible自动化运维 技术与最佳实践
运维·自动化·ansible
Karoku0661 天前
【自动化部署】Ansible Playbook 基础应用
运维·网络·docker·容器·自动化·ansible·consul
运维小文2 天前
ansible的流程控制
python·自动化·ansible·脚本
高hongyuan5 天前
Ansible 简介及常用命令 安装部署tomcat -单机版
运维·自动化·ansible
澜堇5 天前
深入理解 Ansible Playbook:组件与实战
linux·运维·ansible
MavenTalk6 天前
阿里云免费SSL证书调整为3个月后,自动升级SSL证书方案
python·阿里云·云计算·ansible·ssl
LCL_188 天前
ansible自动化运维(四)jinjia2模板
linux·运维·自动化·ansible·jinjia2