ansible基础

一、ansible

1.1、ansible

ansible基于Python开发,集合了众多运维工具(puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。ansible目前已经已经被红帽官方收购,是自动化运维工具中大家认可度最高的,并且上手容易,学习简单。是每位运维工程师必须掌握的技能之一。

1.2、ansible特点

部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;
默认使用SSH协议对设备进行管理;
有大量常规运维操作模块,可实现日常绝大部分操作;
配置简单、功能强大、扩展性强;
支持API及自定义模块,可通过Python轻松扩展;
通过Playbooks来定制强大的配置、状态管理;
轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。

1.3、ansible架构图

ansible架构图
Ansible:Ansible核心程序。
HostInventory:记录由Ansible管理的主机信息,包括端口、密码、ip等。
Playbooks:“剧本”YAML格式文件,多个任务定义在一个文件中,定义主机需要调用哪些模块来完成的功能。
CoreModules:核心模块,主要操作是通过调用核心模块来完成管理任务。
CustomModules:自定义模块,完成核心模块无法完成的功能,支持多种语言。
ConnectionPlugins:连接插件,Ansible和Host通信使用

1.4、ansible任务执行

# 1、ad-hoc模式(点对点模式)
使用单个模块,支持批量执行单条命令。ad-hoc 命令是一种可以快速输入的命令,而且不需要保存起来的命令。就相当于bash中的一句话shell。
# playbook模式(剧本模式)
是Ansible主要管理方式,也是Ansible功能强大的关键所在。playbook通过多个task集合完成一类功能,如Web服务的安装部署、数据库服务器的批量备份等。可以简单地把playbook理解为通过组合多条ad-hoc操作的配置文件。
简单理解就是Ansible在运行时, 首先读取ansible.cfg中的配置, 根据规则获取Inventory中的管理主机列表, 并行的在这些主机中执行配置的任务, 最后等待执行返回的结果。

二、ansible搭建

2.1、环境

ip hostname 备注
192.168.13.211 vm-master-01 ansible控制端
192.168.13.12 vm-master-02 ansible被控制端
192.168.13.225 vm-master-03 ansible被控制端

2.2、安装

# 官方文档
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#installing-ansible-on-rhel-centos-or-fedora
yum install epel-release
yum install ansible
# ansible 帮助信息
ansible-doc -a                      # 显示所有模块文档
ansible-doc -l;--list               # 列出可用模块
ansible-doc -s                      # 显示指定模块的playbook片段
eg:
 ansible-doc -l
ansible-doc ping
ansible-doc -s ping

2.3、ansible配置文件

inventory = /etc/ansible/hosts      #这个参数表示资源清单inventory文件的位置
library = /usr/share/ansible        #指向存放Ansible模块的目录,支持多个目录方式,只要用冒号(:)隔开就可以
forks = 5       #并发连接数,默认为5
sudo_user = root        #设置默认执行命令的用户
remote_port = 22        #指定连接被管节点的管理端口,默认为22端口,建议修改,能够更加安全
host_key_checking = False       #设置是否检查SSH主机的密钥,值为True/False。关闭后第一次连接不会提示配置实例
timeout = 60        #设置SSH连接的超时时间,单位为秒
log_path = /var/log/ansible.log     #指定一个存储ansible日志的文件(默认不记录日志)

2.4、ansible常用命令

/usr/bin/ansible  Ansibe AD-Hoc 临时命令执行工具,常用于临时命令的执行
/usr/bin/ansible-doc   Ansible 模块功能查看工具
/usr/bin/ansible-galaxy  下载/上传优秀代码或Roles模块 的官网平台,基于网络的
/usr/bin/ansible-playbook  Ansible 定制自动化的任务集编排工具
/usr/bin/ansible-pull  Ansible远程执行命令的工具,拉取配置而非推送配置(使用较少,海量机器时使用,对运维的架构能力要求较高)
/usr/bin/ansible-vault  Ansible 文件加密工具
/usr/bin/ansible-console  Ansible基于Linux Consoble界面可与用户交互的命令执行工具

2.5、ansible控制端环境配置

# ansible控制端上进行操作
# 1、生成私钥
ssh-keygen 
# 2、向主机分发私钥
ssh-copy-id root@vm-master-01
ssh-copy-id root@vm-master-02
ssh-copy-id root@vm-master-03
# 3、配置hosts
[root@vm-master-01 ansible]# cat /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22
vm-master-02 ansible_ssh_host=192.168.13.12 ansible_ssh_port=22
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22

三、ansible基本使用

ansible通过ssh实现配置管理、应用部署、任务执行等功能,建议配置ansible端能基于密钥认证的方式联系各个管理节点:
ansible <host-pattern> [-m module_name] [-a args]
--version  显示版本
-m module 指定模块,默认为command
-v 详细过程 -vv -vvv更为详细
--list-hosts 显示主机列表,可简写为--list
-k,--ask-pass tishi 提示输入ssh链接密码,默认key验证
-C,--check 检查,并不执行
-T,-timeout=TIMEOUT 执行命令的超时时间,默认10s
-u,--user=REMOTE_USER  远程执行的用户
# ansible的host-pattern匹配主机的列表
# 1、All: 表示所有Inventory中的所有主机
        ansible all -m ping
#2、*: 通配符
        ansible "*" -m ping
        ansible 10.10.0.* -m ping
        ansible "*srs" -m ping
# 3、或
        ansible "web1:web2" -m ping
        ansible "192.168.1.10:192.168.1.11" -m ping
# 4、逻辑与
        ansible "web1:&web2" -m ping  # 在web1并且在web2组中的主机
# 5、逻辑非
        ansible 'web1:!web2' -m ping # 在web1组中但不在web2组中
# 6、正则
        ansible "~(wa|we).*\.baidu\.com" -m ping

ansible命令执行过程:


ansible命令执行过程

3.1、command模块

# 远程执行命令,command模块是默认情况下的模块,这个模块不支持shell变量和管道
ansible vm-master-01 -m command -a "ls /"                         <可自行>
ansible vm-master-01 -m command -a "ls / | grep data"       <有管道、不可执行>

3.2、shell模块

# 支持shell变量和管道
ansible vm-master-01 -m shell -a "ls /" 
ansible vm-master-01 -m shell -a "ls / | grep data"

3.3、yum模块

ansible PROD -m yum -a 'name=vsftpd state=present'
常用参数介绍:
name=  #所安装的包的名称
state=  #present--->安装, latest--->安装最新的, absent---> 卸载软件。
update_cache  #强制更新yum的缓存
conf_file  #指定远程yum安装时所依赖的配置文件(安装本地已有的包)。
disable_pgp_check  #是否禁止GPG checking,只用于presentor latest。
disablerepo  #临时禁止使用yum库。 只用于安装或更新时。
enablerepo  #临时使用的yum库。只用于安装或更新时。

3.4、service模块

ansible vm-master-02 -m service -a "name=vsftpd state=started enabled=yes"
常用参数介绍:
arguments #命令行提供额外的参数
enabled #设置开机启动。
name= #服务名称
runlevel #开机启动的级别,一般不用指定。
sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。(定义在剧本中。)
state #有四种状态,分别为:started--->启动服务, stopped--->停止服务, restarted--->重启服务, reloaded--->重载配置

3.5、file模块

# file模块用于查看文件的属性,修改文件属性,查询文件是否被修改等
ansible vm-master-03 -m file -a 'path=/etc/passwd'  -------------->查看文件属性
ansible vm-master-02 -m file -a 'path=/tmp/fzh state=touch mode=755 owner=fzh' --------------->创建文件
ansible vm-master-02 -m file -a 'dest=/tmp/fzh state=absent' ------------------->删除文件。
ansible vm-master-02 -m file -a 'dest=/tmp/test.sh mode=777' ------------------->修改远程服务器上文件的属性。
ansible vm-master-02 -m file -a 'dest=/tmp/test mode=755 owner=fzh group=fzh state=directory' ------->在客户端相应位置下创建目录:fzh。(make -p)
ansible vm-master-02 -m file -a 'dest=/tmp/fzh state=absent' --------------->删除远程服务器上的文件,这里是目录。

3.6、copy模块

# 从控制节点上拷贝文件到“受控节点”上
ansible vm-master-02 -m copy -a 'src=/root/test.sh dest=/tmp/ mode=600 owner=fzh group=fzh'
(把本地/root/test文件cp到PROD主机下的/tmp目录下。)
常用参数介绍:
src    #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"
content   #用于替换"src",可以直接指定文件的值
dest    #必选项,将源文件复制到的远程主机的绝对路径
backup   #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息
directory_mode    #递归设定目录的权限,默认为系统默认权限
force    #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"
others    #所有的 file 模块中的选项可以在这里使用

3.7、script模块

# 远程节点执行本地脚本,脚本位于控制节点,相当于scp+shell
ansible test -m script -a "/root/hostname.sh"

3.8、synchronize模块

# 将控制节点的某个目录推送到受控制节点目录下
ansible test -m synchronize -a 'src=/root/test dest=/tmp/ compress=yes'

3.9、fetch模块

# 将vm-master-02的/root/vm-master-02.txt文件cp到本机的/root目录下
[root@vm-master-01 ~]# ansible vm-master-02 -m fetch -a "src=/root/vm-master-02.txt dest=/root/ flat=yes" 
ansible还有很多模块,在此不一一介绍,具体可以参考中文指南:
http://www.ansible.com.cn/docs/intro_adhoc.html#managing-packages

四、ansible-playbook

4.1、ansible-playbook

playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。通过 playbook 的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态。执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作时候,执行的ad-hoc命令是不适合的,这时最好使用playbook。playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822。

4.2、ansible-playbook yaml文件格式

---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: exec shell
    shell: hostname
  - name: create dir
    file:
      path: /root/dir
      state: directory
# 解析
host:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts,也可以自己编辑,在运行的时候加上-i选项,指定清单的位置即可。
remote_user:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。
tasks:指定远端主机将要执行的一系列动作,相当于任务列表。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。tasks 包含 name 和要执行的模块,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。
name:每个task都有对应的name,当我们省略name时,默认以当前任务调用的模块的名称作为任务的名称,不过建议不要省略name,因为当任务存在name时,可读性比较高。
# 执行上述任务
# 1、–list-hosts: 显示执行任务的主机列表,实际并不执行
ansible-playbook -i /etc/ansible/hosts --list-hosts /etc/ansible/test.yaml 
# 2、--syntax-check: 语法检测,实际并不执行。执行结果显示playbook名称即表示没有语法错误。
ansible-playbook -i /etc/ansible/hosts /etc/ansible/test.yaml --syntax-check
# 3、--check: 任务预演,实际并不执行
ansible-playbook -i /etc/ansible/hosts /etc/ansible/test.yaml  --check
# 执行结果:
绿色代表执行成功,系统保持原样
黄色代表系统代表系统状态发生改变
红色代表执行失败,显示错误输出
执行过程有三个步骤:
1、收集facts (收集对应目标主机的信息)
2、执行tasks
3、报告结果
执行结果如下图:
ansible-playbook执行结果

4.3、handlers

4.3.1、handlers初识

handlers是和tasks平级的另一种任务。但handlers中的任务会被tasks中的任务调用。只有当tasks中的任务真正执行(黄色,有改变),handlers中被调用的任务才会被执行。当服务的配置文件发生改变,需要重启的时候,handlers就能解决此类问题。格式见下:
[root@vm-master-01 ansible]# cat handlers.yaml 
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    notify: handler1
  - name: create dir2
    file: path=/root/dir2
          state=directory
    notify: handler2

  handlers:
  - name: handler1
    file: path=/root/dir1/file1
          state=touch
  - name: handler2
    file: path=/root/dir2/file2
          state=touch
# 解释:
通过notify关键字关联tasks和handlers,handlers被执行的顺序与在playbook中定义的顺序是相同的,与被调用执行的顺序无关。当所有task执行完毕后,才会执行handlers。如果想改变这种顺序需要meta模块。

4.3.2、handlers meta

[root@vm-master-01 ansible]# cat handlers.yaml 
---
- hosts: vm-03
 remote_user: root
 tasks:
 - name: create dir1
   file: path=/root/dir1
         state=directory
   notify: handler1

 - name: create dir2
   file: path=/root/dir2
         state=directory
   notify: handler2

 - meta: flush_handlers

 - name: create dir3
   file: path=/root/dir3
         state=directory
   notify: handler3

 handlers:
 - name: handler1
   file: path=/root/dir1/file1
         state=touch

 - name: handler2
   file: path=/root/dir2/file2
         state=touch

 - name: handler3
   file: path=/root/dir2/file3
         state=touch

ansible-playbook -i /etc/ansible/hosts /etc/ansible/handlers.yaml执行结果见下:


meta flush_handlers
#从上面结果可以看出:
meta是一种特殊的任务,可以影响ansible内部的工作顺序,"meta: flush_handlers"表示立即执行之前的task所对应的handler。当对应的handler执行完毕后,接着执行meta下面后续的task,这些task执行完毕后,在执行对应的handlers。

4.3.3、一个task对应多个handlers<listen>

[root@vm-master-01 ansible]# cat handlers2.yaml 
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    notify: handler-group

  handlers:
  - name: handler1
    listen: handler-group
    file: path=/root/dir1/file1
          state=touch

  - name: handler2
    listen: handler-group
    file: path=/root/dir1/file2
          state=touch

  - name: handler3
    listen: handler-group
    file: path=/root/dir1/file3
          state=touch

ansible-playbook -i /etc/ansible/hosts /etc/ansible/handlers2.yaml执行结果如下:


listen
可以将"listen"和“notify”后面的handler-group看成组,命中组的handler就可以被调用执行。
注意:如果不采用上面listen的方式,当定义多个具有相同name的handlers时,只会有一个handler会被执行。

4.4、tags

tags: 为任务列表中的指定任务打上标签,然后可以选择性的执行某一部分或者某一类的任务。

4.4.1、tags定义

[root@vm-master-01 ansible]# cat cat tags.yaml 
cat: cat: No such file or directory
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    notify: handler1
    tags: t1

  - name: create dir2
    file: path=/root/dir2
          state=directory
    notify: handler2
    tags: t2

  - name: create dir3
    file: path=/root/dir3
          state=directory
    notify: handler3
    tags: t3

  handlers:
  - name: handler1
    file: path=/root/dir1/file1
          state=touch

  - name: handler2
    file: path=/root/dir2/file2
          state=touch

  - name: handler3
    file: path=/root/dir3/file3
          state=touch

ansible-playbook -i /etc/ansible/hosts --tags=t3 /etc/ansible/tags.yaml执行结果如下:


tags
从结果可以看出:只有tags: t3的task和其handler被执行了,也可以一次性指定多个标签
# t2、t3执行
ansible-playbook -i /etc/ansible/hosts --tags t2,t3 /etc/ansible/tags.yaml
# --skip-tags指定不执行的task<下面:t2不执行,t1、t3执行>
ansible-playbook -i /etc/ansible/hosts --skip-tags="t2" /etc/ansible/tags.yaml
# 定义标签的方式:
[root@vm-master-01 ansible]# cat tags2.yaml 
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    notify: handler1
    tags:
    - t1

  - name: create dir2
    file: path=/root/dir2
          state=directory
    notify: handler2
    tags: ['t2']

  - name: create dir3
    file: path=/root/dir3
          state=directory
    notify: handler3
    tags:
    - t3
    - t4

  - name: create dir4
    file: path=/root/dir4
          state=directory
    tags: t5,t6

  - name: create dir4
    file: path=/root/dir4
          state=directory
    tags: ['t7', 't8']

  handlers:
  - name: handler1
    file: path=/root/dir1/file1
          state=touch

  - name: handler2
    file: path=/root/dir2/file2
          state=touch

  - name: handler3
    file: path=/root/dir3/file3
          state=touch

4.4.2、tags查看

ansible-playbook -i /etc/ansible/hosts --list-tags /etc/ansible/tags.yaml

4.4.3、相同标签

[root@vm-master-01 ansible]# cat tags3.yaml    
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    tags:
    - t1
    - dir

  - name: create dir2
    file: path=/root/dir2
          state=directory
    tags: ['t2', 'dir']

上面两个task都有标签:dir,我们可以以另一种方式表示:

[root@vm-master-01 ansible]# cat tags4.yaml 
---
- hosts: vm-03
  remote_user: root
  tags: dir
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    tags:
    - t1

  - name: create dir2
    file: path=/root/dir2
          state=directory
    tags: ['t2']
当我们执行:ansible-playbook -i /etc/ansible/hosts --tags=dir /etc/ansible/tags4.yaml,两个tasks都会被执行,结果见下:
tags

4.4.4、内置tags

4.4.4.1、always

当tags=always时,我们用ansible-playbook执行任务,即便我们没有指定--tags=always,这个任务也会被执行,除非使用了'--skip-tags'。

4.4.4.2、never

和always相反,我们执行所有任务的时候,加了never标签的任务不执行。

4.4.4.3、tagged

# 下面命令表示只执行有标签的任务,没有任何标签的任务不会被执行。这里加了never标签的不会执行
ansible-playbook --tags tagged tags.yaml
# 下面命令表示跳过包含标签的任务,即使对应的任务包含always标签,也会被跳过
ansible-playbook --skip-tags tagged tags.yaml

4.4.4.4、untagged

# 下面命令表示只执行没有标签的任务,但是如果某些任务包含always标签,那么这些任务也会被执行
ansible-playbook --tags untagged tags.yaml
# 下面命令表示跳过没有标签的任务。意思是只执行有标签的任务。但是加了never标签的任务不会被执行
ansible-playbook --skip-tags untagged tags.yaml

4.4.4.5、all

特殊标签all表示所有任务会被执行,不用指定,默认情况下就是使用这个标签。

4.5、ignore_errors

# 假如ansible-playbook中的某个task出错,则按照顺序执行的后续任务都不会再执行,假如是handler报错,则不会影响剩下的流程,如果需要忽略此错误,可以用ignore_errors
[root@vm-master-01 ansible]# cat ignore_errors.yaml 
---
- hosts: vm-03
  remote_user: root
  tasks:
  - name: create dir1
    file: path=/root/dir1
          state=directory
    notify: handler1

  - name: create dir2
    command: hostnameeeeee
    notify: handler2
    ignore_errors: True

  - name: create dir3
    file: path=/root/dir3
          state=directory
    notify: handler3

  handlers:
  - name: handler1
    file: path=/root/dir1/file1
          state=touch

  - name: handler2
    file: path=/root/dir2/file2
          state=touch

  - name: handler3
    file: path=/root/dir3/file3
          state=touch

执行命令: ansible-playbook -i /etc/ansible/hosts /etc/ansible/ignore_errors.yaml 结果如下:


ignore_errors
在第二个任务,人为制造一个报错,由于目录/root/dir2/不存在,所以handler2也会出错,但只在第二个任务处添加"ignore_errors: True"后,后续的步骤都没背中断,即便handler2有报错,也没有影响后续的步骤。

4.6、limit

# 当有多台主机被命中时,限制其中的某一台执行playbook,但必须在命中的主机列表中:
[root@vm-master-01 ansible]# cat limit.yaml 
---
- hosts: test
  remote_user: root

  tasks:
  - name: limit test
    command: hostname

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/limit.yaml --limit vm-master-02的结果如下:


limit
虽然test命中了三台主机,但使用limit可以限制playbook在指定的主机上执行。

4.7、playbook变量

# 1、变量名:
    仅能由字母、数字、下划线组成,且只能以字母开头
# 2、变量来源:
    1.1、 ansible setup facts 远程主机的所有变量都可直接调用
    1.2、/etc/ansible/hosts定义
            1.2.1、普通变量:主机组中主机单行定义,优先级高于公共变量
            1.2.2、公共(组)变量:针对主机组中所有主机定义的统一变量
    1.3、命令行指定的变量,优先级最高
    1.4、playbook中定义
    1.5、role中定义

4.7.1、命令行变量

# 1、var_command_line.yaml文件内容
[root@vm-master-01 ansible]# cat var_command_line.yaml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

执行命令:ansible-playbook -i /etc/ansible/hosts -e "prefix=pre1" -e "var=command-line-var" -e "suffix=suf1" /etc/ansible/var_command_line.yaml结果如下:


命令行变量

4.7.2、playbook变量

# 1、var_playbook.yaml文件内容
[root@vm-master-01 ansible]# cat var_playbook.yaml 
---
- hosts: test
  remote_user: root
  vars:
    - prefix: pre2
    - var: playbook-var
    - suffix: suf2

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_playbook.yaml结果如下:


playbook变量

4.7.3、普通变量

# 1、/etc/ansible/hosts文件内容
[root@vm-master-01 ansible]# head -n 4 /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22 prefix=vm01_pre3 var=common-var suffix=vm01_suf3
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22 prefix=vm03_pre3 var=common-var suffix=vm03_suf3
# 2、var_common.yaml文件内容
[root@vm-master-01 ansible]# cat var_common.yaml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_common.yaml结果如下:


普通变量

4.7.4、公共(组)变量

# 1、hosts文件内容
[root@vm-master-01 ansible]# head -n 7 hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22
[test:vars]
prefix=test_pre4
var=group-var
suffix=test_suf4
# 2、var_group.yaml文件内容
[root@vm-master-01 ansible]# cat var_group.yaml
---
- hosts: test
  remote_user: root

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_group.yaml结果若下:


公共变量

4.7.5、变量优先级比较

# 1、hosts文件内容
[root@vm-master-01 ansible]# head -n 8 /etc/ansible/hosts
[test]
vm-master-01 ansible_ssh_host=192.168.13.211 ansible_ssh_port=22 prefix=vm01_pre3 var=common-var suffix=vm01_suf3
vm-master-03 ansible_ssh_host=192.168.13.225 ansible_ssh_port=22 prefix=vm03_pre3 var=common-var suffix=vm03_suf3
[test:vars]
prefix=test_pre4
var=group-var
suffix=test_suf4
# 2、var_priority.yaml文件内容
[root@vm-master-01 ansible]# cat /etc/ansible/var_priority.yaml
---
- hosts: test
  remote_user: root
  vars:
    - prefix: pre2
    - var: playbook-var
    - suffix: suf2
  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

命令行传入变量执行命令:ansible-playbook -i /etc/ansible/hosts -e "prefix=pre1" -e "var=command-line-var" -e "suffix=suf1" /etc/ansible/var_priority.yaml结果如下:


命令行传入变量-命令行变量优先级最高

命令行不传入变量执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_priority.yaml 结果如下:


命令行不传入变量-playbook变量优先级最高
# 只修改/etc/ansible/var_priority.yaml将playbook变量删掉:
[root@vm-master-01 ansible]# cat /etc/ansible/var_priority.yaml 
---
- hosts: test
  remote_user: root

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt

命令行不传入变量数执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/var_priority.yaml 结果如下:


命令行不传入变量同时playbook不定义变量-普通变量优先级高于公共(组)变量
补充:对于"ansible setup facts"中的变量,我们可以借助于:ansible vm-01 -m setup命令查看,我做了实验,但没有截图在这里,他的优先级要高于普通变量低于playbook变量

由以上例子可证明优先级排序为:命令行变量>playbook变量>ansible setup facts中的变量>普通变量>公共(组)变量,在执行playbook时会使用优先级高的变量。

4.7.6、将变量写入单独的yaml文件中

[root@vm-master-01 ansible]# cat vars.yaml 
prefix: file_pre5
var: var-file
suffix: file_suf5
[root@vm-master-01 ansible]# cat var_file.yaml 
---
- hosts: test
  remote_user: root
  vars_files:
    - vars.yaml

  tasks:
    - name: exec shell echo {{ var }}
      shell: echo {{ prefix }}_{{ var }}_{{ suffix }} > /tmp/var.txt
# 此时的变量相当于playbook的变量,优先级也一样,变量文件和var_file.yaml放在同级目录。

4.8、templates

4.8.1、templates语法

文本文件,嵌套有脚本(使用模版编程语言编写)
jinja2语言,使用字面量,有下面形式:
        字符串:使用单引号或双引号
        数字:整数,浮点数
        列表:[item1,item2,...]
        元组:{item1,item2,...}
        字典:{key1:value1,key2:value2,...}
        布尔型:true、false
算术运算:+,-,*,/,//,%,**
比较操作:==,!=,>,>=,<,<=
逻辑运算:and,or,not
流表达式:for if when
template文件必须以.j2结尾

4.8.2、一个例子

需要在vm-03上安装nginx,并将其开启的worker进程数量在auto(cpu的核心数)的基础上+2

# 1、ansible setup模块确定auto的变量名称
[root@vm-master-01 ansible]# ansible vm-03 -m setup | grep ansible_processor_vcpus
[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
        "ansible_processor_vcpus": 8,    # vm-03有8个core
# 2、nginx.conf.j2配置<次文件放在templates目录下,templates目录和nginx.yaml文件平级,执行playbook时会自动寻找到对应名称的模版文件>
[root@vm-master-01 ansible]# head -n 6 templates/nginx.conf.j2  
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user nginx;
worker_processes {{ ansible_processor_vcpus + 2 }};  # ansible_processor_vcpus由"1"获取
# 3、nginx.yaml
[root@vm-master-01 ansible]# cat nginx.yaml 
---
- hosts: vm-03
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: copy templates nginx.conf.j2
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    - name: start nginx
      service: name=nginx state=started enabled=true

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/nginx.yaml结果如下:


带有templates的yaml执行过程

nginx worker开启的数量为:8+2

执行命令:ansible vm-03 -m shell -a "grep worker_processes /etc/nginx/nginx.conf"查看vm-03上nginx的配置文件:


vm-03中nginx配置文件中worker_processes的值

4.9、when

1、条件测试:如果需要根据变量、facts或者此前任务的执行结果来做为某个task执行与否的前提时要用到条件测试,通过when语句实现,在task中使用jinja2的语法格式
2、使用:在task后添加when子句即可使用条件测试;when语句支持jinja2表达式语法
3、例子:
        name: "if RedHat exec command"
        command: hostname
        when: ansible_os_family == "RedHat"
# 1、需求:我们修改上面nginx配置文件的需求,假如vm-03中"ansible_os_family!=RedHat",我们就不传递vm-01上修改过的nginx.conf文件,而使用vm-03上原有的配置文件
# 2、说明:vm-03上ansible_os_family为"RedHat",可以通过setup模块获取,作为演示:我已经卸载了vm-03上面已经安装过的nginx
# 2、nginx.yaml
[root@vm-master-01 ansible]# cat nginx.yaml 
---
- hosts: vm-03
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: copy templates nginx.conf.j2
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      when: ansible_os_family != "RedHat"
    - name: start nginx
      service: name=nginx state=started enabled=true

执行相关命令结果如下:


when使用
从上面例子可以看出:由于when条件不成立,并没有执行template操作。

4.10、with_items

with_items表迭代:当有重复执行的任务时,可以使用迭代机制
        使用固定变量"item"作为迭代项的引用
使用with_items给定迭代的元素列表:
        字符串
        字典等
# 下面yaml文件将在vm-03主机的/tmp目录下创建三个文件:f1、f2、f3
[root@vm-master-01 ansible]# cat with_items.yaml 
---
- hosts: vm-03
  remote_user: root
  tasks:
    - name: create files
      file: name=/tmp/{{ item }} state=touch
      when: ansible_os_family == "RedHat"
      with_items:
        - f1
        - f2
        - f3

执行命令:ansible-playbook -i /etc/ansible/hosts /etc/ansible/with_items.yaml得到的结果如下:


with_items

4.11、for流程控制

# 1、for.yaml文件内容
[root@vm-master-01 ansible]# cat for.yaml 
---
- hosts: vm-03
  remote_user: root
  vars:
    people:
      - name: zhangsan
        age: 23
        high: 1.68
      - name: lisi
        high: 1.70
      - name: wangwu
        age: 25
        high: 1.71

  tasks:
    - name: copy file
      template: src=for1.txt.j2 dest=/tmp/for1.txt
# 2、for1.txt.j2文件内容:
[root@vm-master-01 ansible]# cat templates/for1.txt.j2 
{% for p in people %}
info of people {
    name: {{ p.name }}
  {% if p.age is defined %}
    age: {{ p.age }}
  {% endif %}
  hige: {{ p.high }}
}
{% endfor %}

执行yaml文件并查看vm-03下的文件/tmp/for1.txt的内容:


for

4.12、register

假如有这样一个需求,使用shell命令检查nginx进程是否存在,当不存在时就重启。我们可以通过register将使用ps命令抓取的进程数赋值给info,然后通过info的相应字段(从下面截图中应该可以看出相应的字段为info.stdout)来判断进程数是否为0,为0则重启。
[root@vm-master-01 ansible]# cat sum_process_nginx.yml 
---
- hosts: vm-master-03
  gather_facts: no
  tasks:
    - name: get nginx process
      shell: ps -ef | grep nginx | grep -v grep | wc -l
      register: info
    - name: display vars
      debug:
        var: info
    - name: if sum(nginx process) < 1 then start it
      service: name=nginx
               state=started
      when: info.stdout == "0"
    - name: check if nginx started success or not
      shell: systemctl status nginx

执行命令:ansible-playbook sum_process_nginx.yml结果如下:


register

五、ansible-playbook生产实践

5.1、说明

基于上面介绍,对于nginx的安装,做一个生产级别的介绍

5.2、项目结构

[root@vm-master-01 ansible]# pwd
/etc/ansible
[root@vm-master-01 ansible]# tree ./
./
├── ansible.cfg
├── hosts
├── nginx_role.yml
└── roles
    ├── mysql
    ├── nginx
    │   ├── files
    │   │   └── index.html
    │   ├── handlers
    │   │   ├── main.yml
    │   │   └── restart.yml
    │   ├── tasks
    │   │   ├── copyfile.yml
    │   │   ├── group.yml
    │   │   ├── main.yml
    │   │   ├── start.yml
    │   │   ├── template.yml
    │   │   ├── user.yml
    │   │   └── yum.yml
    │   ├── templates
    │   │   └── nginx.conf.j2
    │   └── vars
    │       └── main.yml
    ├── redis
    └── supervisor
        ├── files
        ├── handlers
        ├── tasks
        ├── templates
        └── vars

15 directories, 15 files
下面我分别贴下没个文件的内容。

5.2.1、role

关于role的各个目录做下简要的概述

files:存放由copy、script模块等调用的文件
templates:template模块查找所需要模块文件的目录
tasks:定义task,至少包含一个名为main.yml的文件,其他文件需要再次文件中通过include进行包含
handlers:至少应该包含一个名为main.yml的文件,其他文件需要在此文件中通过include进行包含
vars:定义变量,至少包含一个名为main.yml的文件,其他文件需要在此文件中通过include进行包含
meta:定义当前角色的特殊设定以及其依赖关系,至少应该包含一个名为main.yml的文件,其它文件需要在此文件中通过include进行包含
default:设定默认变量时使用此目录中的main.yml文件
[root@vm-master-01 ansible]# cat nginx_role.yml 
- hosts: vm-03
  remote_user: root
  roles:
    - { role: nginx, tags: ['app', 'ops'], when: ansible_os_family == 'RedHat' }
    - { role: mysql, tags: 'app' }

5.2.2、files目录

[root@vm-master-01 files]# ls
index.html
[root@vm-master-01 files]# cat index.html 
nginx playbook

5.2.3、handlers目录

[root@vm-master-01 handlers]# ls
main.yml  restart.yml
[root@vm-master-01 handlers]# cat main.yml 
- include: restart.yml
[root@vm-master-01 handlers]# cat restart.yml 
- name: nginx restart
  service: name=nginx state=restarted

5.2.4、tasks目录

[root@vm-master-01 tasks]# ls
copyfile.yml  group.yml  main.yml  start.yml  template.yml  user.yml  yum.yml
[root@vm-master-01 tasks]# cat copyfile.yml 
- name: copy index.html
  copy: src=index.html dest=/usr/share/nginx/html/
  notify: nginx restart
[root@vm-master-01 tasks]# cat group.yml 
- name: create group
  group: name={{ username }} gid=88
[root@vm-master-01 tasks]# cat main.yml 
- include: group.yml
- include: user.yml
- include: yum.yml
- include: template.yml
- include: start.yml
- include: copyfile.yml
[root@vm-master-01 tasks]# cat start.yml 
- name: start service
  service: name=nginx state=started enabled=yes
[root@vm-master-01 tasks]# cat template.yml 
- name: copy file
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
[root@vm-master-01 tasks]# cat user.yml 
- name: create user
  user: name={{ username }} group={{ groupname }} system=yes shell=/sbin/nologin
[root@vm-master-01 tasks]# cat yum.yml 
- name: install nginx
  yum: name=nginx

5.2.5、templates目录

[root@vm-master-01 templates]# ls
nginx.conf.j2
[root@vm-master-01 templates]# cat nginx.conf.j2 
# For more information on configuration, see:
#   * Official English Documentation: http://nginx.org/en/docs/
#   * Official Russian Documentation: http://nginx.org/ru/docs/

user {{ username }};
worker_processes {{ ansible_processor_vcpus + 2 }};
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 4096;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80;
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }

# Settings for a TLS enabled server.
#
#    server {
#        listen       443 ssl http2;
#        listen       [::]:443 ssl http2;
#        server_name  _;
#        root         /usr/share/nginx/html;
#
#        ssl_certificate "/etc/pki/nginx/server.crt";
#        ssl_certificate_key "/etc/pki/nginx/private/server.key";
#        ssl_session_cache shared:SSL:1m;
#        ssl_session_timeout  10m;
#        ssl_ciphers HIGH:!aNULL:!MD5;
#        ssl_prefer_server_ciphers on;
#
#        # Load configuration files for the default server block.
#        include /etc/nginx/default.d/*.conf;
#
#        error_page 404 /404.html;
#            location = /40x.html {
#        }
#
#        error_page 500 502 503 504 /50x.html;
#            location = /50x.html {
#        }
#    }

}

5.2.6、vars目录

[root@vm-master-01 vars]# ls
main.yml
[root@vm-master-01 vars]# cat main.yml 
groupname: nginx
username: nginx

5.3、执行playbook

执行命令:ansible-playbook -i /etc/ansible/hosts --tags=app nginx_role.yml结果如下:


playbook执行过程

5.4、浏览器访问

浏览器查看playbook执行结果

六、注意

1、我上面执行ansible或ansible-playbook时,结果中多处有提示:[WARNING]: Invalid characters were found in group names but not replaced, use -vvvv to see details
是因为我hosts中资源清单的组中有使用符号“-",这不符合相关语法规范,修改掉即可。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容