自动化运维工具—ansible的基础知识

一、ansible简介

1、ansible 是什么?

        ansible是目前最受运维欢迎的自动化运维工具,基于Python开发,集合了众多运维工具(SaltStack puppet、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。   

        ansible是基于 paramiko 开发的,并且基于模块化工作,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。ansible不需要在远程主机上安装client/agents,因为它们是基于ssh来和远程主机通讯的。ansible目前已经已经被红帽官方收购。

        简单来说,ansible就像螺丝刀的刀柄,模块就像一枚枚刀头,用什么类型的问题就换上什么类型的刀头。

2、ansible 特点

  1. 部署简单,只需在主控端部署Ansible环境,被控端无需做任何操作;

  2. 默认使用SSH协议对设备进行管理;

  3. 有大量常规运维操作模块,可实现日常绝大部分操作;

  4. 配置简单、功能强大、扩展性强;

  5. 支持API及自定义模块,可通过Python轻松扩展;

  6. 通过Playbooks来定制强大的配置、状态管理;

  7. 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;

  8. 提供一个功能强大、操作性强的Web管理界面和REST API接口——AWX平台。

 二、ansible 任务执行

1、ansible 任务执行模式

        Ansible 系统由控制主机对被管节点的操作方式可分为两类,即ad-hocplaybook

        ad-hoc模式(点对点模式) 使用单个模块,支持批量执行单条命令。ad-hoc 命令是一种可以快速输入的命令,而且不需要保存起来的命令。就相当于bash中的一句话shell。

        playbook模式(剧本模式) 是Ansible主要管理方式,也是Ansible功能强大的关键所在。playbook通过多个task集合完成一类功能,如Web服务的安装部署、数据库服务器的批量备份等。可以简单地把playbook理解为通过组合多条ad-hoc操作的配置文件。 类似于shell脚本,可以进行多个步骤。

        role模式(角色模式) 类似于多个脚本导入。

2、ansible 执行流程

         读取配置===>抓取全量机器&分组列表===>使用host-pattern过滤机器列表===>根据参数确定执行模块和配置===>Runner执行返回===>输出结果

        简单理解就是Ansible在运行时, 首先读取ansible.cfg中的配置, 根据规则获取Inventory中的管理主机列表, 并行的在这些主机中执行配置的任务, 最后等待执行返回的结果。

3、ansible 命令执行过程

  1. 加载自己的配置文件,默认/etc/ansible/ansible.cfg

  2. 查找对应的主机配置文件,找到要执行的主机或者组;

  3. 加载自己对应的模块文件,如 command;

  4. 通过ansible将模块或命令生成对应的临时py文件(python脚本), 并将该文件传输至远程服务器;

  5. 对应执行用户的家目录的.ansible/tmp/XXX/XXX.PY文件;

  6. 给文件 +x 执行权限;

  7. 执行并返回结果;

  8. 删除临时py文件,sleep 0退出

三、ansible 配置详解

1、使用 yum 安装

[root@web ~]# yum -y install epel-release 
[root@web ~]# yum -y install ansible

2、ansible 程序结构

 安装目录如下(yum安装):   
        配置文件目录:/etc/ansible/   
        执行文件目录:/usr/bin/   
        Lib库依赖目录:/usr/lib/pythonX.X/site-packages/ansible/   
        Help文档目录:/usr/share/doc/ansible-X.X.X/   
        Man文档目录:/usr/share/man/man1/

3、ansible配置文件查找顺序

ansible与我们其他的服务在这一点上有很大不同,这里的配置文件查找是从多个地方找的,顺序如下:

  1. 检查环境变量ANSIBLE_CONFIG指向的路径文件(export ANSIBLE_CONFIG=/etc/ansible.cfg);

  2. ~/.ansible.cfg,检查当前目录下的ansible.cfg配置文件;

  3. /etc/ansible.cfg检查etc目录的配置文件。

4、ansible配置文件

        ansible 的配置文件为vi /etc/ansible/ansible.cfg,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日志的文件(默认不记录日志)

5、ansible主机清单

        在配置文件中,我们提到了资源清单,这个清单就是我们的主机清单,里面保存的是一些 ansible 需要连接管理的主机列表。我们可以来看看他的定义方式:

        


        1、 直接指明主机地址或主机名:
            # green.example.com
            # blue.example.com
            # 192.168.100.1
            # 192.168.100.10
        2、 定义一个主机组[组名]把地址或主机名加进去
            [mysql_test]
            192.168.253.159
            192.168.253.160
            192.168.253.153
            192.168.153.[199:202]
   
        3.定义一个主机组[组名]把/etc/hosts的域名解析加进去

            [web]
            web-server01
            web-server02
            [web:vars]
            ansible_ssh_root="root"
            ansible_ssh_pass="1"
    
         4. [web]
            web1
            web2
            [db]
            db1
            db2
            [host:children]
            web
            db
    
            ansibel host --list-hosts 


        需要注意的是,这里的组成员可以使用通配符来匹配,这样对于一些标准化的管理来说就很轻松方便了。我们可以根据实际情况来配置我们的主机列表,具体操作如下:

[root@web ~]# vim /etc/ansible/hosts
[web]
    web-server01
    web-server02
[web:vars]
    ansible_ssh_root="root"
    ansible_ssh_pass="1"

四、ansible 常用命令

1、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 Console界面可与用户交互的命令执行工具

    其中,我们比较常用的是/usr/bin/ansible/usr/bin/ansible-playbook

2、ansible-doc 命令

        ansible-doc 命令常用于获取模块信息及其使用帮助,一般用法如下:

[root@web ~]# ansible-doc -l             #获取全部模块的信息
[root@web ~]# ansible-doc -s MOD_NAME     #获取指定模块的使用帮助

  -h # 显示命令参数API文档
  -l  #列出可用的模块
  -M  #指定模块的路径                  
  -s #显示playbook制定模块的用法
  -v # 显示ansible-doc的版本号查看模块列表

        举例说明,如何查看一个模板的详细使用方法:

[root@web ~]# ansible-doc -l |grep shell
shell                                                         Execute shell commands on targets           
vmware_vm_shell                                               Run commands in a VMware guest operating sys...
win_shell                                                     Execute shell commands on target hosts 
[root@web ~]# ansible-doc -s shell
- name: Execute shell commands on targets
  shell:
      chdir:                 # Change into this directory before running the command.
      cmd:                   # The command to run followed by optional arguments.
      creates:               # A filename, when it already exists, this step will *not* be run.
      executable:            # Change the shell used to execute the command. This expects an absolute path to
                               the executable.
      free_form:             # The shell module takes a free form command to run, as a string. There is no
                               actual parameter named 'free form'. See the
                               examples on how to use this module.
      removes:               # A filename, when it does not exist, this step will *not* be run.
      stdin:                 # Set the stdin of the command directly to the specified value.
      stdin_add_newline:     # Whether to append a newline to stdin data.
      warn:                  # Whether to enable task warnings.

3、ansible 命令详解

        命令的具体格式如下:  

[root@web ~]# ansible <host-pattern> [-f forks] [-m module_name] [-a args]

ansible 主机清单中的主机组 -f 开启线程数 -m 模块 -a 模块需要的参数

         也可以通过ansible -h来查看帮助,下面我们列出一些比较常用的选项,并解释其含义:


`-a MODULE_ARGS` #模块的参数,如果执行默认COMMAND的模块,即是命令参数,如: “date”,“pwd”等等
`-k`,`--ask-pass` #ask for SSH password。登录密码,提示输入SSH密码而不是假设基于密钥的验证
`--ask-su-pass` #ask for su password。su切换密码
`-K`,`--ask-sudo-pass` #ask for sudo password。提示密码使用sudo,sudo表示提权操作
`--ask-vault-pass` #ask for vault password。假设我们设定了加密的密码,则用该选项进行访问
`-B SECONDS` #后台运行超时时间
`-C` #模拟运行环境并进行预运行,可以进行查错测试
`-c CONNECTION` #连接类型使用
`-f FORKS` #并行任务数,默认为5
`-i INVENTORY` #指定主机清单的路径,默认为`/etc/ansible/hosts`
`--list-hosts` #查看有哪些主机
`-m MODULE_NAME` #执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
`-o` #压缩输出,尝试将所有结果在一行输出,一般针对收集工具使用
`-s` #用 sudo 命令
`-U SUDO_USER` #指定 sudo 到哪个用户,默认为 root 用户
`-T TIMEOUT` #指定 ssh 默认超时时间,默认为10s,也可在配置文件中修改
`-u REMOTE_USER` #远程用户,默认为 root 用户
`-v` #查看详细信息,同时支持`-vvv`,`-vvvv`可查看更详细信息


4、ansible 配置公私钥

        上面我们已经提到过 ansible 是基于 ssh 协议实现的,所以其配置公私钥的方式与 ssh 协议的方式相同,具体操作步骤如下:

#1.生成私钥
[root@web ~]# ssh-keygen 
#2.向主机分发私钥
[root@web ~]# ssh-copy-id root@192.168.36.197
[root@web ~]# ssh-copy-id root@192.168.36.198

        注意,如果出现了一下报错:

-bash: ssh-copy-id: command not found

        那么就证明我们需要安装一个包:

[root@web ~]# yum -y install openssh-clients

五、ansible 常用模块

1、主机连通性测试

        使用ansible web -m ping命令来进行主机连通性测试,效果如下表示连通性正常:

[root@web ~]# ansible web -m ping
web-server01 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}
web-server02 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "ping": "pong"
}

2、command 模块

        这个模块可以直接在远程主机上执行命令,并将结果返回本主机。

[root@web ~]# ansible web -m command -a 'chdir=/root/ ls'
web-server02 | CHANGED | rc=0 >>
anaconda-ks.cfg
yum-server.sh
web-server01 | CHANGED | rc=0 >>
anaconda-ks.cfg
yum-server.sh

        命令模块接受命令名称,后面是空格分隔的列表参数。给定的命令将在所有选定的节点上执行。它不会通过shell进行处理,比如$HOME和操作如"<",">","|",";","&" 工作(需要使用(shell)模块实现这些功能)。注意,该命令不支持| 管道命令。 下面来看一看该模块下常用的几个命令:


        chdir    # 在执行命令之前,先切换到该目录

        executable # 切换shell来执行命令,需要使用命令的绝对路径

        free_form   # 要执行的Linux指令,一般使用Ansible的-a参数代替。

        creates   # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断

        removes # 一个文件名,这个文件不存在,则该命令不执行


3、shell 模块(万金油)

        shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。

[root@web ~]# ansible web -m shell -a 'cat /etc/passwd |grep "root"'
web-server02 | CHANGED | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
web-server01 | CHANGED | rc=0 >>
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

        只要是我们的shell命令,都可以通过这个模块在远程主机上运行。

4、copy 模块

        这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。其相关选项如下:


  src     #被复制到远程主机的本地文件。可以是绝对路径,也可以是相对路径。如果路径是一个目录,则会递归复制,用法类似于"rsync"

  content  #用于替换"src",可以直接指定文件的值

  dest    #必选项,将源文件复制到的远程主机的绝对路径

  backup   #当文件内容发生改变后,在覆盖之前把源文件备份,备份文件包含时间信息

  directory_mode    #递归设定目录的权限,默认为系统默认权限

  force    #当目标主机包含该文件,但内容不同时,设为"yes",表示强制覆盖;设为"no",表示目标主机的目标位置不存在该文件才复制。默认为"yes"

  others #所有的 file 模块中的选项可以在这里使用


#复制文件
[root@web ~]# ansible web -m copy -a 'src=~/hello dest=/opt/hello'

#给定内容生成文件,并制定权限
[root@web ~]# ansible web -m copy -a 'content="I am keer\n" dest=/data/name mode=666'

#关于覆盖
[root@web ~]# ansible web -m copy -a 'content="I am keerya\n" backup=yes dest=/opt/name mode=666'

5、file 模块

        该模块主要用于设置文件的属性,比如创建文件、创建链接文件、删除文件等。下面是一些常见的命令:


  force  #需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no

  group  #定义文件/目录的属组。后面可以加上

  mode:定义文件/目录的权限

  owner  #定义文件/目录的属主。后面必须跟上

  path:定义文件/目录的路径

  recurse  #递归设置文件的属性,只对目录有效,后面跟上

  src:被链接的源文件路径,只应用于state=link的情况

  dest  #被链接到的路径,只应用于state=link的情况

  state  #状态,有以下选项:

  directory:如果目录不存在,就创建目录

  link:创建软链接

  hard:创建硬链接

  touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间

  absent:删除目录、文件或者取消链接文件


#创建目录
[root@web ~]# ansible web -m file -a 'path=/opt/app state=directory'

#创建链接文件
[root@web ~]# ansible web -m file -a 'path=/opt/name src=/opt/aaa.jpg state=link'

#删除文件
[root@web ~]# ansible web -m file -a 'path=/data/a state=absent'

6、fetch 模块

        该模块用于从远程某主机获取(复制)文件到本地。有两个选项:


  dest:用来存放文件的目录

  src:在远程拉取的文件,并且必须是一个file,不能是目录


[root@web ~]# ansible web -m fetch -a 'src=/opt/name dest=/home' 

7、cron 模块

        该模块适用于管理cron计划任务的。其使用的语法跟我们的crontab文件中的语法一致,同时,可以指定以下选项:


  day= #日应该运行的工作( 1-31, , /2, )

  hour= # 小时 ( 0-23, , /2, )

  minute= #分钟( 0-59, , /2, )

  month= # 月( 1-12, *, /2, )

  weekday= # 周 ( 0-6 for Sunday-Saturday,, )

  job= #指明运行的命令是什么

  name= #定时任务描述

  reboot # 任务在重启时运行,不建议使用,建议使用special_time

  special_time #特殊的时间范围,参数:reboot(重启时),annually(每年),monthly(每月),weekly(每周),daily(每天),hourly(每小时)

  state #指定状态,present表示添加定时任务,也是默认设置,absent表示删除定时任务

  user # 以哪个用户的身份执行


#添加计划任务
[root@web ~]# ansible web -m cron -a 'name="ntp update every 5 min" minute=*/5 job="/sbin/ntpdate 172.17.0.1 &> /dev/null"'

#删除计划任务
[root@web ~]# ansible web -m shell -a 'crontab -l'

#查看现有的计划任务
[root@web ~]# ansible web -m shell -a 'crontab -l'

8、yum 模块

        顾名思义,该模块主要用于软件的安装。其选项如下:


  name=   #所安装的包的名称

  state=  #present--->安装, latest--->安装最新的, absent---> 卸载软件。

  update_cache  #强制更新yum的缓存

  conf_file  #指定远程yum安装时所依赖的配置文件(安装本地已有的包)。

  disable_gpg_check  #是否禁止GPG checking,只用于presentor latest

  disablerepo  #临时禁止使用yum库。 只用于安装或更新时。

  enablerepo   #临时使用的yum库。只用于安装或更新时。


[root@web ~]# ansible web -m yum -a 'name=ntpdate state=present'

9、service 模块

        该模块用于服务程序的管理。其主要选项如下:


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


#开启服务并设置自启动
[root@web ~]# ansible web -m service -a 'name=sl state=started enabled=true' 

#关闭服务
[root@web ~]# ansible web -m service -a 'name=nginx state=stopped'

10、user 模块

        该模块主要是用来管理用户账号。其主要选项如下:


        `comment`  # 用户的描述信息
        `createhome`  # 是否创建家目录
        `force`  # 在使用state=absent时, 行为与userdel –force一致.
        `group`  # 指定基本组
        `groups`  # 指定附加组,如果指定为(groups=)表示删除所有组
        `home`      # 指定用户家目录
        `move_home`  # 如果设置为home=时, 试图将用户主目录移动到指定的目录
        `name`  # 指定用户名
        `non_unique`  # 该选项允许改变非唯一的用户ID值
        `password`  # 指定用户密码,对密码加密可以使用python的crypt和passlib
        `remove`  # 在使用state=absent时, 行为是与userdel –remove一致    
        `shell`  # 指定默认shell
        `state`  # 设置帐号状态,不指定为创建,指定值为absent表示删除
        `system`  # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
        `uid`  # 指定用户的uid


#添加一个用户并指定其 uid
[root@web ~]# ansible web -m user -a 'name=keer uid=11111'

#删除用户
[root@web ~]# ansible web -m user -a 'name=keer state=absent'

11、group 模块

        该模块主要用于添加或删除组。常用的选项如下:


`gid=`  #设置组的GID号 
`name=`  #指定组的名称 
`state=`  #指定组的状态,默认为创建,设置值为`absent`为删除 `system=`  #设置值为`yes`,表示创建为系统组


#创建组
[root@web ~]# ansible web -m group -a 'name=sanguo gid=12222'


#删除组
[root@web ~]# ansible web -m group -a 'name=sanguo state=absent'

12、script 模块

        该模块用于将本机的脚本在被管理端的机器上运行。该模块直接指定脚本的路径即可,我们通过例子来看一看到底如何使用的:首先,我们写一个脚本,并给其加上执行权限:

[root@web ~]# vim /tmp/df.sh
    #!/bin/bash
    date >> /tmp/disk_total.log 
    df -lh >> /tmp/disk_total.log 
[root@web ~]# chmod +x /tmp/df.sh 

然后,我们直接运行命令来实现在被管理端执行该脚本:

[root@web ~]# ansible web -m script -a '/tmp/df.sh'

13、setup 模块

        该模块主要用于收集信息,是通过调用facts组件来实现的。   facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。   

        facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等。会存在facts中的某个变量中。调用后返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。

#查看信息
[root@web ~]# ansible web -m setup -a 'filter="*mem*"'   #查看内存

#保存信息
[root@web tmp]# ansible web -m setup -a 'filter="*mem*"' --tree /tmp/facts

14 get_url模块

        用于将文件或软件从http、https或ftp下载到本地节点上,常用参数:


        dest: 指定将文件下载的绝对路径---必须
        url: 文件的下载地址(网址)---必须
        url_username: 用于http基本认证的用户名
        url_password: 用于http基本认证的密码
        validate_certs: 如果否,SSL证书将不会验证。这只应在使用自签名证书的个人控制站点上使用
        owner: 指定属主
        group: 指定属组
        mode: 指定权限


[root@web ~]# ansible -i /etc/ansible/hosts  zabbix -m get_url -a "url=ftp://10.3.131.50/soft/wechat.py dest=/tmp"

15 stat模块

        检查文件或文件系统的状态
        注意:对于Windows目标,请改用win_stat模块,参数如下:


        path:文件/对象的完整路径(必须)


name: install_apcu | Check if apcu local file is already configured.
stat: path={{ php_apcu_file_path }}
connection: local
register: php_apcu_file_result
常用的返回值判断:
exists: 判断是否存在
isuid: 调用用户的ID与所有者ID是否匹配

16 unarchive模块

        本地机器上复制存档后,将其解包。该unarchive模块将解压缩一个存档。默认情况下,它将在解包之前将源文件从本地系统复制到目标。设置remote_src=yes为解包目标上已经存在的档案。对于Windows目标,请改用win_unzip模块。常用参数:


        dest:远程绝对路径,档案应该被解压缩
        exec:列出需要排除的目录和文件
        src:指定源
        creates:一个文件名,当它已经存在时,这个步骤将不会被运行。


[root@web ~]# ansible -i /etc/ansible/hosts web -m unarchive -a 'src=/root/easy-springmvc-maven.zip dest=/tmp'

17.uri模块

         在Ansible中,uri模块是一个用于发送HTTP、HTTPS、FTP等请求的模块,可以用于获取网页内容、下载文件、上传文件等。本质上,它是一个HTTP客户端模块。使用uri模块,需要指定一些参数来定义HTTP请求。下面是一些uri模块的常用参数:


        url:必须,指定请求的URL地址。

        method:指定HTTP请求方法,默认为GET。

        headers:HTTP请求头信息。

        body:HTTP请求体。

        status_code:HTTP响应的状态码。

        return_content:指定是否返回响应内容。


- name: Get the content of a web page
  uri:
    url: https://www.example.com
    return_content: yes
  register: result

- name: Print the content of the web page
  debug:
    var: result.content

        在这个示例中,uri模块被用来获取Example Domain的网页内容,并将结果保存在result变量中。第二个任务使用debug模块输出结果。

18.lineinfile 模块

        在 Ansible 中,lineinfile 模块是用于在文件中搜索指定行,如果找到了该行则修改或添加内容,如果没有找到则添加一行新内容。使用 lineinfile 模块,需要指定以下参数:


        ath:必需,指定要修改的文件路径。

        line:必需,指定要添加或修改的行的内容。

        regexp:必需,指定搜索的正则表达式。

        state:可选,指定是否应该删除匹配行或仅匹配行。如果设置为 present,则确保文件包含该行;如果设置为 absent,则确保文件不包含该行。


- name: Add a new line to the file
  lineinfile:
    path: /etc/fstab
    line: '/dev/sdb1 /mnt/data ext4 defaults 0 0'

        在这个示例中,lineinfile 模块用于将一行新内容添加到 /etc/fstab 文件中。如果文件中已经包含了该行,则该模块不会做出任何更改。

- name: Modify an existing line in the file
  lineinfile:
    path: /etc/fstab
    regexp: '^/dev/sdb1'
    line: '/dev/sdb1 /mnt/data ext4 defaults 1 1'

        在这个示例中,lineinfile 模块用于搜索以 /dev/sdb1 开头的行,并将该行的内容修改为指定的新内容。

- name: Remove a line from the file
  lineinfile:
    path: /etc/fstab
    regexp: '^/dev/sdb1'
    state: absent

        在这个示例中,lineinfile 模块用于删除以 /dev/sdb1 开头的行。

        lineinfile 模块可以方便地操作文件中的行,使得对文件进行修改变得更加简单。需要注意的是,该模块会对文件进行修改,因此在使用前应该确保已经备份了需要修改的文件。

19.wait_for 模块

        wait_for模块是Ansible中一个非常有用的模块,它可以等待特定的条件满足,然后继续执行后续的任务。该模块可以用于等待远程主机上的某个端口、某个服务是否启动或某个文件是否存在等情况。   

        1、基于端口的方式.

- name: Wait for a TCP port to become available
  wait_for:
    host: localhost
    port: 80

        在这个示例中,wait_for模块将等待主机localhost上的TCP端口80变为可用。在等待期间,Ansible将阻塞当前任务,直到条件得到满足或达到了超时时间。默认情况下,超时时间为300秒(5分钟),可以通过timeout参数进行配置。

- name: Wait for a file to become available
  wait_for:
    path: /path/to/file
    state: present

             在这个示例中,wait_for模块将等待远程主机上的/path/to/file文件存在。使用state参数指定等待文件的状态,可以是present(存在)或absent(不存在)。

- name: Wait for a service to become available
  wait_for:
    host: localhost
    port: 80
    timeout: 60
    msg: "Waiting for service to become available"

        在这个示例中,wait_for模块将等待主机localhost上的TCP端口80变为可用,并输出自定义消息“Waiting for service to become available”。如果等待超时,Ansible将失败并输出相应的错误消息。

        2、基于进程的方式

- name: Wait for a process to start
  wait_for:
    path: /usr/bin/process
    search_regex: running

         在这个示例中,wait_for模块将等待名为process的进程启动并输出特定的字符串running。如果进程未启动或未输出指定字符串,则任务将一直阻塞直到满足条件或超时。可以使用timeout参数设置超时时间,默认为300秒(5分钟)。

- name: Wait for a process to start
  wait_for:
    path: /usr/bin/process
    search_regex: running
    timeout: 60
    msg: "Waiting for process to start"

         在这个示例中,如果等待超时,将输出自定义消息“Waiting for process to start”。

        3、基于文件的方式

- name: 等待文件产生
  wait_for:
    path: /path/to/file
    state: present
    timeout: 60

         在这个例子中,wait_for模块将等待文件“/path/to/file”出现,并在60秒后超时。如果文件在60秒内出现,则任务将继续执行。如果文件在60秒内未出现,则任务将失败。

20.synchronize 模块

        synchronize 模块是 Ansible 的一个模块,用于将本地目录或文件与远程主机上的目录或文件进行同步。相比于 copytemplate 等模块,synchronize 可以更快地将大量文件或目录同步到远程主机,因为它使用了 rsync 协议。下面是 synchronize 模块的一些常用参数及其含义:


  src: 要同步的本地目录或文件的路径。

  dest: 要同步到的远程主机上的目录或文件的路径。

  mode: 同步模式,可以是 push(将本地文件同步到远程主机)、pull(将远程主机上的文件同步到本地)或 rsync(使用 rsync 协议同步文件)。

  rsync_opts: 传递给 rsync 命令的选项。例如,可以使用 -av 选项以归档模式同步文件,使用 -z 选项启用压缩等等。

  delete: 是否在同步时删除远程主机上不存在的文件。默认为 no,不删除。


- name: Sync local directory to remote host
  synchronize:
    src: /path/to/local/directory
    dest: /path/to/remote/directory
    mode: push
    rsync_opts: "-avz"
    delete: yes

         

这个示例会将本地目录 /path/to/local/directory 同步到远程主机的 /path/to/remote/directory 目录下,使用 rsync 协议进行同步,并启用压缩。同时,将删除远程主机上不存在的文件。

        需要注意的是,synchronize 模块需要安装 rsync 工具。如果目标主机上没有安装 rsync,可以使用 Ansible 的 raw 模块或 command 模块来安装它。

21.git 模块

        Ansible的git模块允许在远程主机上操作git仓库,可以clone/pull/push git仓库。在Ansible中,使用git模块可以方便地维护代码库的版本控制。下面是git模块的一些常用选项:


  repo:git仓库的URL,必需选项;

  dest:本地文件系统上的目标目录,可以是绝对路径或相对路径;

  version:表示要使用的版本,可以是分支名、标签名或提交哈希值;

  force:如果true,则会强制执行git操作,即使目标文件夹已经存在;

  update:如果true,则在执行操作时使用git pull命令更新代码库;

  recursive:如果true,则递归地拉取子模块;

  key_file:ssh私钥文件路径;

  accept_hostkey:如果yes,则在第一次连接到远程仓库时自动接受主机密钥;

  clone:如果yes,则会使用git clone命令克隆仓库,默认为yes

  bare:如果yes,则会使用git clone --bare命令克隆裸仓库,即不包含工作树。

  key_file_type:ssh私钥文件类型;

  reference:指定本地代码库的路径,可以加快克隆速度;

  depth:指定克隆时获取历史记录的深度;

  recursive_after:指定拉取子模块的时间,可以是alwayson-changenever

  rebase:如果true,则在更新操作时使用git pull --rebase命令。


- name: Clone a git repository
  git:
    repo: https://github.com/ansible/ansible.git
    dest: /home/user/ansible

        上述代码会将ansible的git仓库克隆到/home/user/ansible目录下。

22.mount 模块

        mount 模块是 Ansible 提供的一个用于挂载文件系统的模块,可以在远程主机上挂载本地或者网络上的文件系统。该模块的常用参数包括:


  src: 指定需要挂载的文件系统。可以是本地文件系统的设备文件,比如 /dev/sdb1,也可以是网络文件系统的位置,比如 server:/share

  path: 指定挂载点的路径。

  fstype: 指定文件系统的类型。如果不指定,则根据挂载点自动判断文件系统类型。

  state: 指定挂载状态。可选值为 mountedunmounted,默认为 mounted

  opts: 指定挂载选项。选项可以用逗号分隔,比如 rw,noatime


- name: Mount NFS filesystem
  hosts: all
  become: true
  vars:
    nfs_mount: "server:/share"
    nfs_path: "/mnt/nfs"
    nfs_opts: "rw,hard,intr"
  tasks:
    - name: Ensure NFS mount directory exists
      file:
        path: "{{ nfs_path }}"
        state: directory

    - name: Mount NFS filesystem
      mount:
        src: "{{ nfs_mount }}"
        path: "{{ nfs_path }}"
        fstype: nfs
        opts: "{{ nfs_opts }}"
        state: mounted

        这个 playbook 在远程主机上创建了 /mnt/nfs 目录,并将 server:/share 挂载到该目录下。挂载选项为 rw,hard,intr,文件系统类型为 NFS。如果文件系统已经被挂载,不会进行任何操作。如果挂载点已经存在但未挂载,将会尝试挂载。如果挂载失败,则任务将会失败。

23.template 模块

        template 模块是 Ansible 中的一个常用模块,用于在目标主机上生成文件。它将一个源文件作为模板,在生成目标文件时将其渲染,使用用户定义的变量来填充模板中的占位符,从而生成目标文件。template 模块的主要参数如下:


  src:源模板文件的路径,相对于 Ansible 控制节点。

  dest:目标文件的路径,相对于目标主机。

  owner:目标文件的所有者。

  group:目标文件的组。

  mode:目标文件的权限。

  backup:是否创建备份文件。

  validate:用于验证生成的文件是否正确的命令或脚本。

  vars:用于在模板中填充变量的字典。

  setype:用于在 SELinux 中设置目标文件类型的字符串。

  selevel:用于在 SELinux 中设置目标文件级别的字符串。


- name: Generate config file
  template:
    src: /path/to/template.conf.j2
    dest: /etc/app/config.conf
    owner: appuser
    group: appgroup
    mode: 0644
    vars:
      key1: value1
      key2: value2

        在这个例子中,template 模块将 /path/to/template.conf.j2 文件作为模板,渲染后生成 /etc/app/config.conf 文件,使用 appuser 用户和 appgroup 组作为所有者和组,设置权限为 0644,并且使用 vars 参数填充了模板中的变量。

六、Ansible playbook 简介

        playbook 是 ansible 用于配置,部署,和管理被控节点的剧本。通过 playbook 的详细描述,执行其中的一系列 tasks ,可以让远端主机达到预期的状态。playbook 就像 Ansible 控制器给被控节点列出的的一系列 to-do-list ,而被控节点必须要完成。也可以这么理解,playbook 字面意思,即剧本,现实中由演员按照剧本表演,在Ansible中,这次由计算机进行表演,由计算机安装,部署应用,提供对外服务,以及组织计算机处理各种各样的事情。

七、Ansible playbook使用场景

        执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但是有时一个设施过于复杂,需要大量的操作时候,执行的ad-hoc命令是不适合的,这时最好使用playbook。就像执行shell命令与写shell脚本一样, 也可以理解为批处理任务,不过playbook有自己的语法格式。使用playbook你可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用Ansible的过程中,你也会发现,你所处理的大部分操作都是编写playbook。可以把常见的应用都编写成playbook,之后管理服务器会变得十分简单。

八、Ansible playbook格式

1、格式简介

        playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与OrenBen-Kiki也是这语言的共同设计者。   YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。以下为playbook常用到的YMAL格式:   

        1、文件的第一行应该以 "---" (三个连字符)开始,表明YMAL文件的开始。   

        2、在同一行中,#之后的内容表示注释,类似于shell,python和ruby。   

        3、YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。   

        4、同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。   

        5、play中hosts,variables,roles,tasks等对象的表示方法都是键值中间以":"分隔表示,":"后面还要增加一个空格。

---
#安装与运行mysql服务
- hosts: node1
  remote_user: root
  tasks:  
    - name: install mysql-server package
      yum: name=mysql-server state=present
    - name: starting mysqld service
      service: name=mysql state=started

        文件名称应该以.yml结尾,像我们上面的例子就是mysql.yml。其中,有三个部分组成:

   host部分:使用 hosts 指示使用哪个主机或主机组来运行下面的 tasks ,每个 playbook 都必须指定 hosts ,hosts也可以使用通配符格式。主机或主机组在 inventory 清单中指定,可以使用系统默认的/etc/ansible/hosts,也可以自己编辑,在运行的时候加上-i选项,指定清单的位置即可。在运行清单文件的时候,–list-hosts选项会显示那些主机将会参与执行 task 的过程中。

   remote_user:指定远端主机中的哪个用户来登录远端系统,在远端系统执行 task 的用户,可以任意指定,也可以使用 sudo,但是用户必须要有执行相应 task 的权限。

   tasks:指定远端主机将要执行的一系列动作。tasks 的核心为 ansible 的模块,前面已经提到模块的用法。tasks 包含 name要执行的模块,name 是可选的,只是为了便于用户阅读,不过还是建议加上去,模块是必须的,同时也要给予模块相应的参数。

        使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言 | 绿色代表执行成功,系统保持原样 | 黄色代表系统代表系统状态发生改变 | 红色代表执行失败,显示错误输出 执行有三个步骤:

        1、收集facts

        2、执行tasks

        3、报告结果

2、核心元素

        Playbook的核心元素:


  Hosts:主机组;

  Tasks:任务列表;

  Variables:变量,设置方式有四种;

  Templates:包含了模板语法的文本文件;

  Handlers:由特定条件触发的任务;


3、基本组件

        Playbooks配置文件的基础组件:


  Hosts:运行指定任务的目标主机

  remote_user:在远程主机上执行任务的用户;

  sudo_user

  tasks:任务列表


  模块,模块参数


      格式:     

      action: module arguments     

      module: arguments     

      注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;



  handlers:任务,在特定条件下触发;接收到其它任务的通知时被触发;


        (1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;   

        (2) 任务可以通过“tags“打标签,而后可在ansible-playbook命令上使用-t指定进行调用;

        1.定义playbook
[root@web ~]# cd /etc/ansible
[root@web ansible]# vim nginx.yml
---
- hosts: web
  remote_user: root
  tasks:
    - name: install nginx
      yum: name=nginx state=present
    - name: copy nginx.conf
      copy: src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf backup=yes
      notify: reload    #当nginx.conf发生改变时,通知给相应的handlers
      tags: reloadnginx   #打标签
    - name: start nginx service
      service: name=nginx state=started
      tags: startnginx   #打标签

  handlers:  #注意,前面没有-,是两个空格
    - name: reload
      service: name=nginx state=restarted  #为了在进程中能看出来
        2.运行前三部曲
#检查错误
[root@web ~]# ansible-playbook nginx.yml --syntax-check

#列出所有任务
[root@web ~]# ansible-playbook nginx.yml --list-task

#列出在那些机器执行
[root@web ~]# ansible-playbook nginx.yml --list-hosts

#运行
[root@web ~]# ansible-playbook nginx.yml

       运行过程如图:

        3.测试标签

        我们在里面已经打上了一个标签,所以可以直接引用标签。但是我们需要先把服务关闭,再来运行剧本并引用标签:

4、variables 部分

        variables是变量,有四种定义方 法,现在我们就来说说这四种定义方法:

        1. facts :可直接调用

         我们有说到setup这个模块,这个模块就是通过调用facts组件来实现的。我们这里的variables也可以直接调用facts组件。具体的facters我们可以使用setup模块来获取,然后直接放入我们的剧本中调用即可。


        ansible_all_ipv4_addresses:仅显示ipv4的信息 ---> [u'192.168.95.143']
        ansible_eth0['ipv4']['address']:仅显示ipv4的信息 ---> eth0 的ip地址
        ansible_devices:仅显示磁盘设备信息
        ansible_distribution:显示是什么系统,例:centos,suse等
        ansible_distribution_version:仅显示系统版本
        ansible_machine:显示系统类型,例:32位,还是64位
        ansible_eth0:仅显示eth0的信息
        ansible_hostname:仅显示主机名
        ansible_kernel:仅显示内核版本
        ansible_lvm:显示lvm相关信息
        ansible_memtotal_mb:显示系统总内存
        ansible_memfree_mb:显示可用系统内存
        ansible_memory_mb:详细显示内存情况
        ansible_swaptotal_mb:显示总的swap内存
        ansible_swapfree_mb:显示swap内存的可用内存
        ansible_mounts:显示系统磁盘挂载情况
        ansible_processor:显示cpu个数(具体显示每个cpu的型号)
        ansible_processor_vcpus:显示cpu个数(只显示总的个数)
        ansible_python_version:显示python版本


        批量修改主机 host 文件:

---
- hosts: web  
  vars:        
    IP: "{{ ansible_eth0['ipv4']['address'] }}"  
  tasks:        
  - name: 将原有的hosts文件备份          
    shell: mv /etc/hosts /etc/hosts_bak        
  - name: 将ansible端的hosts复制到各自机器上          
    copy: src=/root/hosts dest=/etc/ owner=root group=root mode=0644        
  - name: 在新的hosts文件后面追加各自机器内网ip和hostname          
    lineinfile: dest=/etc/hosts line="{{ IP }}  {{ ansible_hostname }} "
        2.用户自定义变量

        我们也可以直接使用用户自定义变量,想要自定义变量有以下两种方式:

        1. 通过命令行传入

        ansible-playbook命令的命令行中的-e VARS, --extra-vars=VARS,这样就可以直接把自定义的变量传入。

          2.在playbook中定义变量

        我们也可以直接在playbook中定义我们的变量:

vars:
  - var1: value1
  - var2: value2
        2.1 定义剧本

        我们就使用全局替换把我们刚刚编辑的文件修改一下:

        2.2 拷贝配置文件

        我们想要在被监管的机器上安装什么服务的话,就直接在我们的server端上把该服务的配置文件拷贝到我们的/tmp/目录下。这样我们的剧本才能正常运行。我们就以keepalived服务为例:

[root@web ansible]# cp /etc/keepalived/keepalived.conf /tmp/keepalived.conf
        2.3. 运行剧本,变量由命令行传入
        2.4. 修改剧本,直接定义变量

        ,我们可以直接在剧本中把变量定义好,这样就不需要在通过命令行传入了。以后想要安装不同的服务,直接在剧本里把变量修改一下即可。

        2.5运行定义过变量的剧本

        我们刚刚已经把变量定义在剧本里面了。现在我们来运行一下试试看:

        3. 通过roles传递变量

        具体的,我们下文中说到 roles 的时候再详细说明。

        4.Host Inventory

        我们也可以直接在主机清单中定义。定义的方法如下:

        1.向不同的主机传递不同的变量:

  IP/HOSTNAME varaiable=value var2=value2

        2.向组中的主机传递相同的变量:

  [groupname:vars]
  variable=value

        Ansible Inventory 内置参数:

        使用内置变量把用户名密码写在Inventory中,也就是/etc/ansible/hosts文件里,缺点就是暴露了账号密码,不安全。如果有多个主机需要使用同样的变量,可以用组变量的形式,书写格式如下:

[web]
192.168.100.10
192.168.100.11
192.168.100.12 
[web:vars]  #给名为webservers的组定义一个变量,:vars是固定格式
ansible_ssh_port=22
ansible_ssh_user='root'
ansible_ssh_pass='1234.com'

5、模板 templates

        模板是一个文本文件,嵌套有脚本(使用模板编程语言编写)。Jinja2`:Jinja2是python的一种模板语言,以Django的模板语言为原本。通常来说,模板都是通过引用变量来运用的。 模板支持:


  字符串:使用单引号或双引号;
  数字:整数,浮点数;
  列表:[item1, item2, ...]
  元组:(item1, item2, ...)
  字典:{key1:value1, key2:value2, ...}
  布尔型:true/false
  算术运算:+, -, *, /, //, %, **
  比较操作:==, !=, >, >=, <, <=
  逻辑运算:and, or, not


        1. 定义模板,我们直接把之前定义的/tmp/nginx.conf改个名,然后编辑一下,就可以定义成我们的模板文件了:

[root@web ansible]# cd /tmp
[root@web tmp]# mv nginx.conf nginx.conf.j2
[root@web tmp]# vim nginx.conf.j2
    worker_processes  {{ ansible_processor_vcpus }};
    listen       {{ nginxport }};

        2. 修改剧本,我们现在需要去修改剧本来定义变量:

        3.运行剧本 ,上面的准备工作完成后,我们就可以去运行剧本了:

[root@web ansible]# ansible-playbook nginx.yml -t reloadnginx

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [copy nginx.conf] *********************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

PLAY RECAP *********************************************************************
192.168.37.122             : ok=2    changed=0    unreachable=0    failed=0   
192.168.37.133             : ok=2    changed=0    unreachable=0    failed=0 

6、条件测试

        when语句:在task中使用,jinja2的语法格式。 举例如下:

tasks:
- name: install conf file to centos7
  template: src=files/nginx.conf.c7.j2
  when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
  template: src=files/nginx.conf.c6.j2
  when: ansible_distribution_major_version == "6"

        循环:迭代,需要重复执行的任务;   对迭代项的引用,固定变量名为"item",而后,要在task中使用with_items给定要迭代的元素列表; 举例如下:

tasks:
- name: unstall web packages
  yum: name={{ item }} state=absent
  with_items:
  - httpd
  - php
  - php-mysql

7、字典

        ansible playbook 还支持字典功能。举例如下:

- name: install some packages
  yum: name={{ item }} state=present
  with_items:
    - nginx
    - memcached
    - php-fpm
- name: add some groups
  group: name={{ item }} state=present
  with_items:
    - group11
    - group12
    - group13
- name: add some users
  user: name={{ item.name }} group={{ item.group }} state=present
  with_items:
    - { name: 'user11', group: 'group11' }
    - { name: 'user12', group: 'group12' }
    - { name: 'user13', group: 'group13' }

8、角色订制:roles

        1.简介

        对于以上所有的方式有个弊端就是无法实现复用假设在同时部署Web、db、ha 时或不同服务器组合不同的应用就需要写多个yml文件。很难实现灵活的调用。   roles 用于层次性、结构化地组织playbook。roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

        2.角色集合

        角色集合:roles/ mysql/ httpd/ nginx/ files/:存储由copy或script等模块调用的文件; tasks/:此目录中至少应该有一个名为main.yml的文件,用于定义各task;其它的文件需要由main.yml进行“包含”调用; handlers/:此目录中至少应该有一个名为main.yml的文件,用于定义各handler;其它的文件需要由main.yml进行“包含”调用; vars/:此目录中至少应该有一个名为main.yml的文件,用于定义各variable;其它的文件需要由main.yml进行“包含”调用; templates/:存储由template模块调用的模板文本; meta/:此目录中至少应该有一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要由main.yml进行“包含”调用; default/:此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;

        3.角色定制实例
        3.1. 在roles目录下生成对应的目录结构
[root@web ansible]# cd roles/
[root@web roles]# ls
[root@web roles]# mkdir -pv ./{nginx,mysql,httpd}/{files,templates,vars,tasks,handlers,meta,default}
[root@web roles]# tree
.
├── httpd
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
├── mysql
│   ├── default
│   ├── files
│   ├── handlers
│   ├── meta
│   ├── tasks
│   ├── templates
│   └── vars
└── nginx
    ├── default
    ├── files
    ├── handlers
    ├── meta
    ├── tasks
    ├── templates
    └── vars
        3.2. 定义配置文件

        我们需要修改的配置文件为/tasks/main.yml,下面,我们就来修改一下:

[root@web roles]# vim nginx/tasks/main.yml
- name: cp rpm for nginx
  copy: src=nginx-1.10.2-1.el7.ngx.x86_64.rpm dest=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm
- name: install
  yum: name=/tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm state=latest
- name: conf
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
  tags: nginxconf
  notify: new conf to reload
- name: start service
  service: name=nginx state=started enabled=true
        3.3. 放置我们所需要的文件到指定目录

        因为我们定义的角色已经有了新的组成方式,所以我们需要把文件都放到指定的位置,这样,才能让配置文件找到这些并进行加载。   rpm包放在files目录下,模板放在templates目录下:

[root@web nginx]# cp /tmp/nginx-1.10.2-1.el7.ngx.x86_64.rpm ./files/
[root@web nginx]# cp /tmp/nginx.conf.j2 ./templates/
[root@web nginx]# tree
.
├── default
├── files
│   └── nginx-1.10.2-1.el7.ngx.x86_64.rpm
├── handlers
├── meta
├── tasks
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars
        3.4. 修改变量文件 ​​​​​​​

        我们在模板中定义的变量,也要去配置文件中加上:

[root@web nginx]# vim vars/main.yml
nginxprot: 9999
        3.5. 定义handlers文件

        我们在配置文件中定义了notify,所以我么也需要定义handlers,我们来修改配置文件:

[root@web nginx]# vim handlers/main.yml
- name: new conf to reload
  service: name=nginx state=restarted
        3.6. 定义剧本文件

        接下来,我们就来定义剧本文件,由于大部分设置我们都单独配置在了roles里面,所以,接下来剧本就只需要写一点点内容即可:

[root@web ansible]# vim roles/roles.yml 
- hosts: web
  remote_user: root
  roles:
    - nginx
        3.7. 启动服务

        剧本定义完成以后,我们就可以来启动服务了:

[root@web ansible]# ansible-playbook roles.yml

PLAY [web] *********************************************************************

TASK [setup] *******************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [nginx : cp] **************************************************************
ok: [192.168.37.122]
ok: [192.168.37.133]

TASK [nginx : install] *********************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

TASK [nginx : conf] ************************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

TASK [nginx : start service] ***************************************************
changed: [192.168.37.122]
changed: [192.168.37.133]

RUNNING HANDLER [nginx : new conf to reload] ***********************************
changed: [192.168.37.122]
changed: [192.168.37.133]

PLAY RECAP *********************************************************************
192.168.37.122             : ok=6    changed=4    unreachable=0    failed=0   
192.168.37.133             : ok=6    changed=4    unreachable=0    failed=0  

九、Ansible使用jinja2管理配置文件以及jinja2语法简介

       1、Jinja2介绍

        Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity。它能完全支持unicode,并具有集成的沙箱执行环境,应用广泛。jinja2使用BSD授权Jinja2的语法是由variables(变量)和statement(语句)组成,如下;

        1.1.variables:可以输出数据
 my_variables 

        {{ some_dudes_name | capitalize }}

        1.2.statements: 可以用来创建条件和循环等
if语句:
{% if my_conditional %} 
...
{% endif %}
for 语句:
{% for item in all_items %}
`item` 
……
{% endfor %}

        从上面第二个variables的例子中可以看出,jinja2支持使用带过滤器的Unix型管道操作符,有很多的内置过滤器可供使用。我们可以仅仅用一堆简单if和for就可以建立几乎任何的常规配置文件,不过如果你有意更进一步,jinja2 documentation (Jinja — Jinja Documentation (3.2.x))包含了很多有趣的东西可供了解。我们可以看到ansible允许在模板中使用诸如绘制时间此类的一些额外的模板变量  。

        第一个例子:引用变量 ,总调度yml文件:

# cat site.yml 
---
- hosts: 192.168.19.154
  user: root
  vars:
  - PROJECT: "JAVA"
    SWITCH: "ON"
    DBPORT: "8080"
  tasks:
  - name: create{{ PROJECT }}directory
    file: path=/data/{{ PROJECT }} state=directory
  - name: template transfor java
    template: src=order.j2 dest=/data/{{ PROJECT }}/order.conf

        其他yml文件,如下:  

# cat templates/order.j2 
project: {{ PROJECT }}
switch: {{ SWITCH }}
dbport: {{ DBPORT }}


测试:
# ansible-playbook templates.yml --syntax-check
playbook: templates.yml

执行:

PLAY [192.168.19.154] **********************************************************

TASK [Gathering Facts] *********************************************************
ok: [192.168.19.154]

TASK [createJAVAdirectory] *****************************************************
changed: [192.168.19.154]

TASK [template transfor java] **************************************************
changed: [192.168.19.154]

PLAY RECAP *********************************************************************
192.168.19.154             : ok=3    changed=2    unreachable=0    failed=0 

#cat /data/JAVA/order.conf
project: JAVA
switch: ON
dbport: 8080

         为远程主机生成服务器列表,加入该列表从192.168.13.201 web01.test.com 到192.168.13.211 web11.test.com 结束,如果手动添加就很不科学了,这里需要使用jinja2语法的for循环通过模板批量生成对应的配置文件,如下:

        ansible目录结构:

#cd /etc/ansible/roles/test_hosts
.
├── meta
│   └── main.yml
├── tasks
│   ├── file1.yml
│   └── main.yml
├── templates
│   └── test1.j2
└── vars
    └── main.yml

         第二个例子:for 语句各个目录下yml文件内容:

# cat tasks/file1.yml 
- name: ansible jinja2 template for hosts config
  template: src=test1.j2 dest=/etc/httpd/conf/httpd.conf.test
  
# cat tasks/main.yml 
- include: file1.yml

# cat templates/test1.j2 
{% for id in range(201,212) %}
192.168.13.{{ id }} web{{ "%02d" |format(id-200) }}.test.com
{% endfor %}
解释:
{{ id }} 提取for循环中对应的变量id值
"%02d"   调用的是python内置的字符串格式化输出(%d格式化整数)因为是01,02这种格式,所以是保留2位,故用02
然后将结果通过管道符 “|” 传递给format 函数做二次处理。

        第三个例子:if语句

        说明:如果定义端口号,就绑定定义的端口号,如果不定义端口号,就绑定默认端口号

ansible目录结果
#cd /etc/ansible/roles/mysql_cnf
#tree
.
├── meta
│   └── main.yml
├── tasks
│   └── main.yml
├── templates
│   └── test3.j2
└── vars

        主要的yml文件是templates目录下面的test3.j2  

# cat templates/test3.j2 
{% if PORT %}
bind_address=10.0.90.27:{{ PORT }}
{% else %}
bind_address=10.0.90.27:3306
{% endif %}

         playbook主文件

# cat jinj2_test.yml 
---
- hosts: 10.0.90.27
  user: root
  gather_facts: false
  vars:
    PORT: 3136
  tasks:
    - name: copy file to client
      template: src=/etc/ansible/roles/mysql_cnf/templates/test3.j2 dest=/root/my.cnf

         执行:

# ansible-playbook jinj2_test.yml
PLAY [10.0.90.27] **************************************************************
TASK [copy file to client] *****************************************************
changed: [10.0.90.27]
PLAY RECAP *********************************************************************
10.0.90.27                 : ok=1    changed=1    unreachable=0    failed=0

         查看

# cat my.cnf 
bind_address=10.0.90.27:3136

         如果将vars变量去掉,执行结果:

# cat my.cnf 
bind_address=10.0.90.27:3306
        1.3.Jinja default()设定2、ansible使用jinja

        精通程序编码的朋友皆知,default()默认值的设定有助于程序的健壮性和简洁性。所幸Jinja也支持该功能,上面的例子中生成Mysql配置文件中的端口定义,如果指定则PORT=3136,否则PORT=3306,我们将该案例改造为使用default()试试

        编辑/etc/ansible/roles/mysql_cnf/templates/test3.j2内容如下,这种方法更简介。

        bind_address=10.0.90.27:{{ PORT | default(3306) }}

       2.生成apache多主机配置

        2.1.创建目录,创建好之后
#cd /etc/ansible/roles/apache_conf
# tree ./
./
├── meta
│   └── main.yml
├── tasks
│   ├── file.yml
│   └── main.yml
├── templates
│   └── apache.config.j2
└── vars
    └── main.yml
        2.2.创建tasks调度文件
#cat file.yml 
- name: ansible jinja2 template for apache config
  template: src=apache.config.j2 dest=/etc/httpd/conf/httpd.conf.template
  
#cat main.yml 
- include: file.yml
        2.3.创建apache的jinja2模板文件
#cat apache.config.j2 
NameVirtualHost *:80
{% for vhost in apache_vhost %}
<VirtualHost *:80>
ServerName {{ vhost.servername }}
DocumentRoot {{ vhost.documentroot }}
{% if vhost.serveradmin is defined %}
ServerAdmin {{ vhost.serveradmin }}
{% endif %}
<Directory "{{ vhost.documentroot }}">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
{% endfor %}
        2.4.创建变量
#cat vars/main.yml
apache_vhost:
- {servername: "apache.test1.com", documentroot: "/data/test1/"}
- {servername: "apache.test2.com", documentroot: "/data/test2/"}
        2.5.创建总调度yml文件
#cat /etc/ansible/apache_test.yml 
---
- hosts: 10.0.90.27
  user: root
  gather_facts: no
  roles:
   - { role: apache_conf }
        2.6.测试
#ansible-playbook apache_test.yml --syntax-check

playbook: apache_test.yml
        2.7.执行测试
#ansible-playbook apache_test.yml 
PLAY [10.0.90.27] **************************************************************
TASK [apache_conf : include] ***************************************************
included: /etc/ansible/roles/apache_conf/tasks/file.yml for 10.0.90.27
TASK [apache_conf : ansible jinja2 template for apache config] *****************
changed: [10.0.90.27]
PLAY RECAP *********************************************************************
10.0.90.27                 : ok=2    changed=1    unreachable=0    failed=0
        2.8.到客户端查看
#cat httpd.conf.template 
NameVirtualHost *:80
<VirtualHost *:80>
ServerName apache.test1.com
DocumentRoot /data/test1/
<Directory "/data/test1/">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>
<VirtualHost *:80>
ServerName apache.test2.com
DocumentRoot /data/test2/
<Directory "/data/test2/">
AllowOverride All
Options -Indexes FollowSymLinks
Order allow,deny
Allow from all
</Directory>
</VirtualHost>

       3.ansible使用jiaja2生成nginx一个模板多种不同配置

        说明:为2台Nginx Proxy,1台Nginx Web通过一套模板生成对应的配置

        3.1.ansible目录结构
# cd roles/nginx_conf/
#tree
.
├── files
├── meta
│   └── main.yml
├── tasks
│   ├── file.yml
│   └── main.yml
├── templates
│   └── nginx.conf.j2
└── vars
    └── main.yml
        3.2.tasks目录下文件内容
#cat tasks/file.yml 
- name: nginx.j2 template transfer example 
  template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf.template
  
#cat tasks/main.yml 
- include: file.yml
        3.3.nginx模板文件
#cat templates/nginx.conf.j2 
{% if nginx_use_proxy %}
{% for proxy in nginx_proxies %}
upstream {{ proxy.name }}
   #server 127.0.0.1:{{ proxy.port }};
   server {{ ansible_eth0.ipv4.address }}:{{ proxy.port }};
}
{% endfor %}
{% endif%}
server {
    listen 80;
    servername {{ nginx_server_name }};
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name {{ nginx_server_name }};
    ssl_certificate /etc/nginx/ssl/{{ nginx_ssl_cert_name }};
    ssl_certificate_key /etc/nginx/ssl/{{ nginx_ssl_cert_key }};
    root {{ nginx_web_root }};
    index index.html index.html;
{% if nginx_use_auth %}
   auth_basic  "Restricted";
   auth_basic_user_file /etc/nginx/{{ project_name }}.htpasswd;
{% endif %}
{% if nginx_use_proxy %}
{% for proxy in nginx_proxies %}
   location {{ proxy.location }} {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://{{ proxy.name }};
      break;
}
{% endfor %}
{% endif %}
{% if nginx_server_static %}
   location / {
       try_files $url $url/ =404;
}
{% endif %}
}
        3.4.ansible变量文件
cat vars/main.yml 
nginx_server_name: www.testnginx.com
nginx_web_root: /data/html/
nginx_proxies:
- name: suspicious
  location: /
  port: 1234
- name: suspicious-api
  location: /api
  port: 4567
        3.5.ansible主playbook文件
#cat nginx_test.yml 
##The first roles
- name: Nginx Proxy Server's Config Dynamic Create
  hosts: "10.0.90.25:10.0.90.26"
  remote_user: root
  vars:
    nginx_use_proxy: true
    nginx_ssl_cert_name: ifa.crt
    nginx_ssl_cert_key: ifa.key
    nginx_use_auth: true
    project_name: suspicious
    nginx_server_static: true
  gather_facts: true
  roles:
     -  role: nginx_conf
##The second roles
- name: Nginx WebServer's Config Dynamic Create
  hosts: 10.0.90.27
  remote_user: root
  vars:
    nginx_use_proxy: false
    nginx_ssl_cert_name: ifa.crt
    nginx_ssl_cert_key: ifa.crt
    nginx_use_auth: false
    project_name: suspicious
    nginx_server_static: false
  gather_facts: false
  roles:
     -  role: nginx_conf
        3.6.测试并执行
#ansible-playbook nginx_test.yml --syntax-check
playbook: nginx_test.yml

执行:
# ansible-playbook nginx_test.yml
PLAY [Nginx Proxy Server's Config Dynamic Create] ******************************

TASK [setup] *******************************************************************
ok: [10.0.90.25]
ok: [10.0.90.26]

TASK [nginx_conf : include] ****************************************************
included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.25, 10.0.90.26

TASK [nginx_conf : nginx.j2 template transfer example] *************************
changed: [10.0.90.26]
changed: [10.0.90.25]

PLAY [Nginx WebServer's Config Dynamic Create] *********************************

TASK [nginx_conf : include] ****************************************************
included: /etc/ansible/roles/nginx_conf/tasks/file.yml for 10.0.90.27

TASK [nginx_conf : nginx.j2 template transfer example] *************************
changed: [10.0.90.27]

PLAY RECAP *********************************************************************
10.0.90.25                 : ok=3    changed=1    unreachable=0    failed=0   
10.0.90.26                 : ok=3    changed=1    unreachable=0    failed=0   
10.0.90.27                 : ok=2    changed=1    unreachable=0    failed=0
        3.7.查看检测执行结果

        到Nginx Proxy 服务器查看配置文件:

#cat nginx.conf.template 
upstream suspicious
   #server 127.0.0.1:1234;
   server 10.0.90.26:1234;
}
upstream suspicious-api
   #server 127.0.0.1:4567;
   server 10.0.90.26:4567;
}
server {
    listen 80;
    servername www.testnginx.com;
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name www.testnginx.com;
    ssl_certificate /etc/nginx/ssl/ifa.crt;
    ssl_certificate_key /etc/nginx/ssl/ifa.key;
    root /data/html/;
    index index.html index.html;
   auth_basic  "Restricted";
   auth_basic_user_file /etc/nginx/suspicious.htpasswd;
   location / {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://suspicious;
      break;
}
   location /api {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-Proto http;
      proxy_set_header X-Url-Scheme $scheme;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_set_header X-NginX-Proxy true;
      proxy_redirect off;
      proxy_pass http://suspicious-api;
      break;
}
   location / {
       try_files $url $url/ =404;
}
}

​​​​​​​        到Nginx Web 服务器上查看配置文件:

#cat nginx.conf.template 
server {
    listen 80;
    servername www.testnginx.com;
    access_log off;
    error_log /etc/nginx/nginx_error.log;
    rewrite ^ https://$server_name$request_uri? permanent;
}
server {
    listen 443 ssl;
    server_name www.testnginx.com;
    ssl_certificate /etc/nginx/ssl/ifa.crt;
    ssl_certificate_key /etc/nginx/ssl/ifa.crt;
    root /data/html/;
    index index.html index.html;
}

        到这里,就结束了。用同样的模板通过简单的if和变量设置就可以完成不同类型主机的Nginx conf配置,所以一方面在了解Ansible强大的模板功能的同时,也需要看到模板质量的重要性。

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一些自动化运维学习书籍的推荐: 1. 《自动化运维:原理、实践与案例》(作者:谢涛) - 该书从自动化运维的理论和实践角度出发,详细介绍了自动化运维的思想、方法和工具,并通过实际案例帮助读者理解和掌握自动化运维的实现和应用。 2. 《Ansible 自动化运维指南》(作者:刘明) - 该书详细介绍了 Ansible 自动化运维工具的原理、使用和实践,包括 Ansible 的架构、模块、剧本、变量、模板等内容,帮助读者快速掌握 Ansible 的使用和应用。 3. 《Docker容器与容器云》(作者:周立) - 该书主要介绍了 Docker 容器技术的原理、使用和实践,包括 Docker 的架构、镜像、容器、网络、数据卷等内容,同时也介绍了容器云的概念和实现方式,帮助读者了解和掌握 Docker 技术和容器云的应用。 4. 《SaltStack自动化运维实战》(作者:孙宏亮) - 该书主要介绍了 SaltStack 自动化运维工具的原理、使用和实践,包括 SaltStack 的架构、模块、状态、批量命令等内容,通过实际案例帮助读者了解和掌握 SaltStack 的使用和应用。 5. 《Python自动化运维:技术与最佳实践》(作者:刘江南) - 该书主要介绍了 Python 在自动化运维中的应用,包括 Python 基础知识、Python 在自动化运维中的应用和实践、Python 在监控和告警中的应用等内容,帮助读者了解和掌握 Python 在自动化运维中的应用和实践。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值