lisongtao716

第1章: 安装

更换epel

Yum   -y   install epel-release

Yum   -y   install ansiible

1.1: 目录

配置文件目录:/etc/ansible/  

     主要功能:inventory主机信息配置,Ansible工具功能配置。所有的ansible的配置均放在该目录下

执行文件目录/usr/bin/

第2章: 命令用法详解

2.0.1: ansible

ansible  <host-pattern>  [options]

 

<host-pattern>:Inventory中定义的主机或主机组,或者 all 代表所有

[options]ansible的参数选项,例举如下:

-m NAME --module-name=NAME:指定执行使用的模块

-u USERNAME--user=USERNAME:指定远程主机以USERNAME运行命令

-s,--sudo:相当于linux下的sudo命令

-U SUDO_USERNAME--sudo-user=SUDO_USERNAME:使用sudo 相当于linux下的sudo命令

 

2.0.2: ansible-playbook

ansible-playbook  playbook.yml

 命令后跟事先编辑好的playbook.yml

参数:

--ask-vault-pass:加密playbook文件时提示输入的密码

-D--diff:当跟新的文件以及内容较少时,改选项可显示这些文件不同的地方,改选项结合-C用会比较好

-C--check:测试

-e EXTRA_VARSextra-vars=EXTRA_VARS:在playbook中引入外部变量

--flush-handiers:强行运行handlers,即使在任务失败的时候

-i INVERNTORY 指定读取的Inventory(资产文件)文件

--list-tags:列出所有可用的tags

--list-tasks:列出所有即将被执行的任务

--skip-tags=SKIP_TAGS:跳过指定的tags任务。

--start-at-task=START_AT_TASK:从第几条任务开始执行

--step:逐步执行playbook定义的任务,并经过人工确认后继续执行下一步任务

--syntax-check:检查Playbook的语法

-t TAGS,--tags=TAGS:指定执行该tags的任务

 

2.1: ansible命令使用详解以及场景

2.1.1: ansible

日常使用非常高的命令,

场景:非固化需求

      临时一次性操作

      二次开发接口调用

(如:查看主机是否存活,想复制某个文件到远程主机的某个目录)

2.1.2: ansible-galaxy

可以理解为pythonpip的功能,通过ansible-galaxy可以根据下载量或者关注量查找和安装优秀的roles

 

roles聚集地:https://galaxy.ansible.com

 

命令格式:

ansible-galaxy  [ init | info | install | list | remove ]  [--help] [options] ...

 

命令分为三大部分:

(1)[ init | info | install | list | remove ]

(2)init:初始化本地的roles配置,以备上传rolesgalaxy

(3)info:列表指定roles的详细信息

(4)install:下载并安装galaxy指定的roles到本地

(5)list:列出本地已下载的roles

(6)ansible2.0版本中,针对ansible-galaxy增加了login import delete setup 等功能

 

(7)help用大显示[--help]

(8)      针对第一部分的initinfo的功能

(9)例:ansible-galaxy  init --help

 

(10)参数项[options]

(11)     该部分结合第一部分的参数完成ansible-galaxy完整的功能用法,

(12)如:ansible-galaxy init [options]reles-name

(13)即:ansible init 后跟 [-f|-h|-c|-p|--offline|-s SERVER|-v|--version]参数,后跟reles-name成为一条完整的命令

 

2.1.3: anisble-pull

该指令涉及ansible的另一种工作模式:pull模式(Ansible默认使用push模式)。这和通常使用的push模式工作机制刚好相反,其适用于以下场景:1你有数量巨大的机器需要配置,即使使用高并发依旧需要花费很长时间:2你要在刚启动,没有网络连接的主机上运行ansible

 

命令格式:

ansible-pull [options] [playbook.yml]

通过ansible-pull结合Gitcrontab一并实现,其原理如下:通过crontab定期拉取指定的git版本到本地,并以指定模式自动运行预先指定好的指令

 

2.1.4: ansible-doc

ansible模块文档说明,针对每个模块都有详细的用法说明及应用案例介绍,功能和linuxman相似

用法:

列出支持的模块:

ansible-doc -l

模块功能说明:

ansible-doc ping

2.1.5: ansible-playbook

日常使用频率比较高的命令,其工作机制是通过预先编写好的playbook文件实现批量管理。要实现的功能于命令ansible一样,可以理解为按一定条件组成的ansible任务集。

2.1.6: ansible-vault

用于配置文件加密,如编写的playbook配置文件包含敏感信息,不希望其他人随意查看,ansible-vault可加密/解密这个配置文件,具体使用方法如下:

ansible-vault [create|decrypt|edit|encrypt|rekey|view] [--help] [options]

 

例子:设定如下密码,加密a.yml

ansible-vault decrypt a.yml   //然后会提示你输入密码

 

这时查看a.yml会出现乱码,只有通过以下命令解密后方可正常查看

ansible-valut decrypt a.yml    //然后会提示你输入密码

解密后方可正常查看

 

2.1.7: ansible-console

ansible为用户提供的一款交互式工具,用户可以在ansible-console虚拟出来的终端上像shell一样使用ansible内置的各种命令,这为习惯于使用shell交互方式的用户提供了良好的使用体验

 

 

 

第3章: Inventory资产文件配置及详解

3.1: 定义主机和组

inventoryansible管理主机信息的配置文件,相当于系统HOSTS文件的功能,默认存放在/etc/ansible/hosts,通过Inventory定义主机和主机组,在使用的时候也可以通过 -i或者--inventory-file指定读取

 

行为单位分割配置,详细信息可参考一下代码中的注释

# ”#”开头的行为注释行,即当时行的配置不生效

# Inventory可以直接为IP地址

192.168.159.124

# Inventory同样支持Hostname的方式后跟冒号加数字表示端口号,默认22端口

ntp.server.com:2222

# 中括号的内容表示一个分组的开始,紧随其后的主机均属于改组的成员,空行后的主机就不属于改组

web2.magedu.com 这台主机也属于[webservers]

web1.server.com

web[10:20].server.com  # [10:20]表示10-20之间的数字包含1020

 

web2.server.com[dbserver]

db-a.server.com

db-[b:f].server.com  # [b:f]表示b-f之间的所有数字(包括bf

对于每个节点,可以单独设置用户名和连接类型:

[targets]

other1.example.com  ansible_connection=ssh  ansible_ssh_user=mpdehaan

other2.example.com  ansible_connection=ssh  ansible_ssh_user=mdehaan

 

 

 

3.2: 定义主机变量

在日常生活中,通常会遇到非标准化的需求配置,如考虑到安全性问题,业务人员通常将企业内部的web服务80端口修改为其他端口号,而该功能可以直接通过修改Inventory配置来实现,在定义主机时为其添加主机变量,以便在playbook中使用对某一主机的个性化要求

 

[webserver]

web1.server.com http_port=808 maxRequestsPerChild=801 # 自定义http_port的端口为808,配置 maxRequestsPerChild=801

 

3.3: 定义组变量

Ansible支持定义组变量,主要针对大量机器的变量定义需求,赋予指定组内所有主机在playbook中可用的变量。等同于逐一给改组下的所有主机赋予同一变量

 

[groupservers]

web1.magedu.com

web2.magedu.com

 

[groupservers:vars]

ntp_server=net.magedu.com  #定义[groupservers]组中所有的主机ntp_server值为ntp.magedu.com

nfs_server=nfs.magedu.com #定义groupservers组中的所有主机nfs_server值为nfs.magedu.com

3.4: 定义组嵌套及组变量

Inventory中,组还可以包含其他组(嵌套),并且也可以向组中的主机指定变量。不过这些变量只能在ansible-playbook中使用,而ansible不支持。组于组之间可以相互调用,并且可以向组中的主机指定变量。

参考示例如下:

[apache]

httpd1.server.com

httpd2.server.com

 

[nginx]

nginx.server.com

nginx.server.com

 

[webservers:children]

apache

nginx

 

[werservers:vars]

ntp_server=ntp.magedu.com

 

ansible以简单为其核心理念,上述实现在业务日常使用并不常见,了解用法即可

 

3.5: 多重变量定义

变量除了可以写在Inventory中,也可以独立于Inventory文件之外的单独存储到YAML格式的配置文件中,这些文件通常以 .yml  .yaml为后缀或者无后缀。变量通常从一下四个位置检索

 

Inventory配置文件(默认/etc/ansible/hosts#默认位置可修改

playbookvars定义的区域

Roles中的vars目录下的文件

Roles同级目录group_varshosts_vars目录下的文件

 

假如foosball主机同属于raleighwebserver组,那么其变量在如下文件中均有效

/etc/ansible/group_vars/raleigh [.yml  .yaml  .json]

/etc/ansible/group_vars/webservers [.yml  .yaml  .json]

/etc/ansible/host_vars/foosball [.yml  .yaml  .json]

 

对于变量的读取,Ansible遵循如上优先级,因此大家设置变量是尽量沿用同一种方式,以便于维护人员管理

 

第4章: Ansible中的正则

正则表达式是各类高级语言的必定支持的方法之一,ansible也不例外。其正则功能等同于正则表达式,语法使用也和正则类同,这大大便利了运维的使用,其对于ansible的灵活性有着极大的贡献,该功能同样支持ansible-playbook,其用法也很简单

 

ansible <pattern_goes_here> -m <module_name> -a <arguments>

 

该功能主要针对Inventory的主机列表使用,我们通过一些案例可以更好的了解其功能及用法。在如下示例中主要针对webservers进行正则匹配

 

4.1: All(全量)匹配

匹配所有的主机,all* 号功能相同。如检测所有主机存活情况。

 

all * 功能相同 但 * 需要引号引起来

ansible all -m ping

ansible “*” -m ping

 

检查192.168.1.0/24网段所有主机存活状态。

 

ansible 192.168.1.* -m ping

 

4.2: 逻辑或(or)匹配

如果我们希望同时对多台主机或多个组同时执行,相互之间用“:”(冒号)分割

 

示例:

 

ansible “web1:web2” -m  ping

 

4.3: 逻辑非(!)匹配

逻辑非用感叹号(!)表示,主要针对多重条件的匹配规则,使用方法如下

 

//所有在webservers组但不在phoenix组中的主机

webserver:!phoenix

4.4: 逻辑与(&)匹配

和逻辑非一样,逻辑与也主要针对多重条件的匹配规则,知识逻辑上的判断不同。逻辑与使用&表示,示例

 

//webservers组和staging组中同时存在的主机

webservers:&staging

 

 

4.5: 多条件组合

ansible同样支持多条件的复杂组合,该情况企业用的不多,这里来个简单的小示例

 

//所有以.server.com结尾的主机

*.server.com

//one开头.com结尾的所有主机和dbserver组中的所有主机

one*.com:dbserver

4.6: 域切割

ansible底层基于python,因此也支持域切割,python字符串域切割的示例如下:

 

str = ‘123456’

print str[0:1]

通过[0:1]即可获取数值1.该功能在ansible中也支持,以如下Inventory内容为例:

[webservers]

cobweb

webbing

weber

通过截取属组下表可以获取对应变量值。

webservers[0]  #==cobweb

webservers[-1]  #==weber

webservers[0:1]  #==webserver[0],webserver[1] == cobwed,webbing

webservers[1:]  #==webbing,weber

 

 

4.7: 正则匹配

Ansible同样完整支持正则匹配功能,~ 开始表示正则匹配。

 

示例:

~(web|db).*\.example.com

 

检测bate.example.comweb.example.comgreen.example.combate.example.orgweb.example.orggreen.example.org的存活,使用如下匹配模式:

 

ansible “~(bate|web|green)\.example\.(com|org)” -m ping

 

检测inventory中所有以192.168开头的服务器存活信息:

ansible ~192\.168\.[0-9]\{\2}.[0-9]\{2,} -m ping

 

 

 

 

 

 

 

4.8: Ansible Ad-Hoc命令集

 

 

 

第5章: 常用模块

5.1: setup

该模块可以获取ansible客户端的详细信息,命令:

 

ansible  webserver(机器组名) -m setup

 

5.2: copy模块

该模块可以实现ansible主机向客户端传送文件的功能,类似scp

 

ansible webserver -m copy -a “src=/usr/local/src/test.py  dest=/tmp/  owner=root  group=root mode=0755 force=yes”

 

force:如果目标主机包含该文件,但内容不同,则设置为yes后会强制覆盖,设置为no时,只有当目标主机的目标位置不存在该文件时,才复制该文件到目标主机;默认为yes

 

backup:在覆盖之前备份源文件,备份文件包含时间。该参数有yes|no两个选项

 

注意:copy模块和rsync命令一样,如果路径使用“/”结尾,则只复制目录里的内容;如果没有“/”结尾,则包含目录在内的整个内容全部被复制

 

5.3: 复制文件模块synchronize

synchronize模块会调用rsync命令,因此首先要记得提前安装好rsync软件包。

synchronize模块用于将ansible机器的指定目录推送(push)到客户机的指定目录,命令如下

 

ansible 192.168.1.206  -m synchronize  -a  “src=/usr/local/src/ dest=/usr/local/src  delete=yes  compress=yes”

 

其中delete=yes用来实现使两边的内容一样(即以push为主),实现效果跟rsync  --delete效果是一样的。如果客户端不存在的文件或目录则增补,如果存在着不同的文件或目录则删除,以保证内容两边一样

 

compress=yes用于开启压缩,默认为开启。

 

另外,由于synchronize模块调用的是rsync命令,因此如果使用“/”结尾,则只复制目录里的内容;如果没有“/”来结尾,则包含目录在内的整个内容全部被复制

5.4: file模块

file模块主要用于设置文件或者目录的属性。

group:定义文件或者目录的属组

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

owner:定义文件或目录的属主

path:必选项,定义文件或目录的路径。

recurse:递归设置文件的属性,只对目录有效

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

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

force:强制创建软链接,有两种情况,一种是源文件不存在,但之后会建立的情况;另一种是先取消已经创建的软链接,在创建新的软联俄及,有yes|no两个选项。

state:后面链接文件的各种状态,例如下面的directorylinkhardfile和,absent

link:创建软连接

hard:创建硬链接

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

file:即使文件不存在也不会被创建

absent:删除目录,文件或链接文件。

touch:如果文件不存在,则会创建一个新文件,如果问价或者目录已经存在,则更新其最后的修改时间,这一点跟linux  touch命令一样

 

案例1:将客户端机器192.168.1.205/usr/local/src/test.py软连接到/tmp/test.py

 

ansible 192.168.1.205 -m file -a ‘src=/usr/local/src/test.py dest=/tmp/test.py state=link ’

 

案例2:将刚刚建立的软连接删除

 

ansible 192.168.1.205 -m file -a ‘path=/tmp/test.py state=absent’

 

案例3:在webserver组建立/text.txt 属组和属主均为root,权限为0755,命令:

 

ansible webserver -m file -a ‘path /text.txt state=touch owner=root group=root mode=0755’

 

案例4:在webserver 组中建立test目录,属主和属组均为root权限为0755

 

ansible webserver -m file -a ‘path=/tmp/test state=directory  ownet=root  group=root  mode=0755 ’

 

5.5: 测试连通性模块ping

用于检测被控与被控端的连通性,命令如下:

 

ansible webserver -m  ping

5.6: 创建删除用户组模块group

group模块可以在所有节点上创建自己定义的组,比如利用此模块创建一个组名为test的,gid2016的组

 

ansible webserver -m group -a ‘ gid=2016  name=test’

5.7: 创建删除用户模块user

该模块用于创建用户

案例:在指定节点上创建一个用户名为test、组为test的用户,命令如下:

 

ansible  webserver  -m  user  -a  ”name=test group=test”

 

删除用户

 

ansible  webserver -m user  -a “name=test state=absent  remove=yes” 

5.8: shell模块

shell模块是执行被控端的shell脚本文件,跟另一个模块raw的功能类似,并且支持管道符。

 

案例:执行任何在linux可执行的命令

 

ansible  webserver  -m shell  -a “ ls  -a ”

 

执行脚本:

ansible  webserver  -m shell  -a “/root/test.sh”

 

5.9: 执行脚本模块sript

script模块用于在远程被控端主机上执行本地ansible机器中的shell脚本文件,相当于scp+shell的组合命令,比如,要执行本地机器的/root/print_hello.sh

 

ansible  webserver  -m  script  -a  “/root/print_hello.sh”

 

 

 

5.10: 下载url模块get_url

get_url模块可以实现在远程主机上下载url到本地,这个模块应该在平时的工作中用的比较多,比如,webserver组中的被控端需要下载某个文件要到/tmp目录下

 

ansible  webserver  -m  get_url  -a  ‘url=路径 dest=/tmp

5.11: yum模块

用来管理linux平台的软件包操作的

 

config_file:yum的配置文件。

disable_gpg_check:关闭gpg_check

disablerepo:不启用某个源

enablerepo:启用某个源

name:要进行操作的软件包的名字,也可以传递一个url或一个本地的rpm包的路径。

statepresent|absent|lateststate状态对应了三种软件包的状态absent表示删除,剩下两个是安装

5.12: 技术任务模块cron

cron模块,就是创建计划任务,可以定义webserver组被控端机器每天凌晨11ntpdate自动对时,命令:

 

 

5.13: 开启关闭服务模块service

 

被控端服务管理,例如开启,关闭,重启服务等。

 

实例1:在webserver组中开启nginx服务,

 

ansible webserver -m service -a ‘name=nginx  state=started  enabled=yes’

 

 

 

5.14: 添加删除公钥模块authorized_key

authorized_keyansible官方新推出的一个模块,作用为添加或删除用户的SSH公钥

 

 

 

 

 

5.15: 配置文件 template

基于模板的方式生成一个文件复制到被管理的主机,这样就可以在模板语言中判断,不同的系统复制不同的配置文件,这就是template模块区别与copy模块的地方

 

5.16:  拷贝解压归档文件模块unarchive

将本地的归档文件拷贝到被管控的主机上,解压归档文件

ansible all -m unarchive -a "src=/files/wordpress.tar dest=/data/dynamic/"

 

 

5.17: 挂载模块mount

挂载和卸载模块,path指定本地挂载点,src指定需要挂载的设备

ansible 192.168.23.12 -m mount -a "path=/var/www/html src=192.168.23.25:/data/static fstype=nfs state=mounted"

 

 

5.18: 文件编辑模块:lineinfile

模块参数详解:

    path:指定要修改的配置文件

    regexp:匹配要修改的内容

    line:要增加或者修改的内容

    state:

        absent:表示删除,当匹配到时进行删除

        present:表示增加,当匹配到时进行修改,当没有匹配到时在最后增加一行,默认为此项

    backrefs:

        no:表示如果没有匹配到,则增加line;如果匹配成功,则替换line

        yes:表示如果没有匹配到,则不变line;如果匹配成功,则替换line

    backup:  

        no:表示如果没有匹配到,则增加line;如果匹配成功,则替换line;不备份原文件

        yes:表示如果没有匹配到,则增加line;如果匹配成功,则替换line;备份原文件

    insertafter(匹配的是此行):

        在匹配到的行之后添加一行

    insertbefore(匹配的是此行)

        在匹配到的行之前添加一行

 

修改nginx.conf测试:[root@nfs-server playbook]# cat modify_nginx.yml

 

---

- hosts: 192.168.2.111

  tasks:

  - name: "修改配置文件"

    lineinfile:

      dest: "/etc/nginx/conf.d/default.conf"

      regexp: \'listen       80;\'

      line: \'listen       8000;\'

      #backup: yes

      backrefs: yes

    notify:

      - reload nginx

  handlers:

    - name: reload nginx

      service: name=nginx state=reloaded

注:经测试,当不添加backerfs: yes参数时,匹配到后也会进行替换,但当匹配到的内容不存在时,会在最后增加一行;所以当不增加backerfs参数时,要确定匹配到的内容存在;

 

替换存在的行:

#ansible oms -m lineinfile -a \'path=/etc/sudoers regexp="SYSTEM,SOFTWARE" line="STAPLES_ADMIN ALL=(ROOT) NOPASSWD:NETWORKING,LOCATE,STORAGE,DELEGATING,DRIVERS,SYSTEM,SOFTWARE,SERVICES,PROCESSES,FILE" backrefs=no\'

匹配到的行后增加一行:

#ansible oms -m lineinfile -a \'dest=/etc/sudoers insertafter="Cmnd_Alias SYSTEM = /usr/sbin/reboot, /usr/sbin/halt, /usr/bin/ansible, /usr/bin/ssh" line="Cmnd_Alias FILE = /bin/mkdir,/bin/touch,/usr/bin/vim"\'

删除匹配到的行:

#ansible oms -m lineinfile -a \'path=/etc/sudoers state=absent regexp="PROCESSES,FILE"\'

 

 

 

5.19: fetch从远程主机拉取文件

5.20: 20mysql

root用户设置密码

- name: set password for root

  mysql_user: name=root password={{ mariadb_root_password }} check_implicit_admin=true

设置密码后,将密码放到~/.my.cnf文件中,mysql_db模块需要读取认证信息创建数据库:

 

credentials.j2文件内容如下:

 

[client]

user=root

password={{ mariadb_root_password }}

 

使用template模块,创建~/.my.cnf文件:

 

- name: put crendentials in ~/.my.cnf file

  template: src=credentials.j2 dest=~/.my.cnf mode=600 backup=yes

创建数据库

mariadb_databases是一个列表,比如:

 

mariadb_databases:

  - keystone

  - glance

  - cinder

  - nova_api

  - nova

  - neutron

创建数据库:

 

- name: create databases

  mysql_db: name={{ item }} state=present

  with_items: "{{ mariadb_databases | default([])}}"

  when: mariadb_databases is defined

 

第6章: Playbook

核心元素:

 

Hosts:指明运行在哪个主机上

Remote_user:以哪个用户的身份运行任务

Tasks:任务

Variables:变量

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

Handlers:由特定条件出发的任务

Roles:

 

6.0.1: 测试(只检测可能会发生的改变,但不真正执行操作

ansible-playbook --check firsh.yaml 

 

6.0.2: 定义主机和用户:

每个 playbook文件都需要指定针对哪些主机进行运维,而hosts变量则说明这个问题,users则说明了采用那个用户执行这条命令

针对webserver主机组,这里采用root用户执行命令:

 

---

- host: webserver

  remote_user: root

 

如果是AWS EC2 主机,可以采用sudo模式执行命令,

 

---

- host: webserver

 remote_user: ec2-user

 sudo: yes

 

6.0.3: 任务列表

每个playbook都会有一份任务列表(task list),说明究竟要按照怎样的顺序去执行这些命令(从上至下,依照顺序执行task)。

 

tasks

  - name: name sure apache is runing

    service: name=httpd state=running

 

每一个小task都是ansible的模块组成的

 

6.0.4: handlers

当被控端主机配置文件发生变化以后,通知处理程序handlers来触发后续动作,比如重启apache服务。在没有通知出发时handlers中定义的处理程序是不会执行的,触发是通过handlers定义的name标签来识别的,比如下面的notify中的”restart apache”handlers中的name: restart apache 内容请保持一致。

 

 

notify

   - restart apache

  - name: ensure apache is running

    service: name=httpd state=started

handlers

   - name: restart httpd

service: name=httpd state=restarted

 

6.0.5: 条件语句

when 后面使用Jinja2 表达式,结果为True则执行任务。

就是如果when 后面的结构是true 就执行 task

 

tasks:

- name: reboot redhat host

command: /usr/sbin/reboot

when: ansible_os_family == “RedHat”

 

可以对条件进行分组在比较。

 

tasks:

  - name: "shut down CentOS 6 and Debian 7 systems"

    command: /sbin/shutdown -t now

    when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or

          (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")

 

 

 

案例3

tasks:

  - shell: echo "only on Red Hat 6, derivatives, and later"

    when: ansible_os_family == "RedHat" and ansible_distribution_major_version|int  >= 6

 

 

6.0.6: 循环语句

6.0.6.1: 标准循环

示例:

tasks:

  - name: install LNMP

   yum: name={{ item }}  state=present

   with_items:

     - nginx

     - mysql-server

     - php-fpm

 

循环还支持列表,使用的是with_flattened语句。

变量文件的示例

6.0.6.2: 列表循环

---

packages_LNMP:

  - [ ‘nginx’, ‘mysql-server’, ‘php-fpm’ ]

 

- name: Install LNMP

 yum: name={{ item }} state=present

 with_flattened:

   - packeges_LNMP

 

6.0.6.3: 字典循环

 

- name: add several users

  user: name={{ item.name }} state=present groups={{ item.groups }}

  with_items:

    - { name: \'testuser1\', groups: \'wheel\' }

- { name: \'testuser2\', groups: \'root\'}

 

6.0.6.4: 文件循环

with_file 是将每个文件的文件内容作为item的值

  with_fileglob 是将每个文件的全路径作为item的值, 在文件目录下是非递归的, 如果是在role里面应用改循环, 默认路径是roles/role_name/files_directory

- copy: src={{ item }} dest=/etc/fooapp/ owner=root mode=600

      with_fileglob:

        - /playbooks/files/fooapp/*

 

 

 

 

 

 

6.1: roles

目录结构:

 

案例

 

 

 

 

 

 

 

 

 

 

 

第7章: Ansible 进阶技巧

 

 

 

 

7.1: 简介

Ansible 是一个系统自动化工具,可以用来做系统配管理,批量对远程主机执行操作指令。我自己使用 Ansible 也有一段时间了,这里总结了一些使用 Ansible 过程中使用的心得与大家分享。

7.2: Ansible 性能优化

在使用 Ansible 的过程中,当管理的服务器数量增加时,不得不面对一个无法避免的问题执行效率慢,这里列出一些解决办法。

7.2.1: 优化前的准备—收集数据

在做性能优化之前首先需要做的是收集一些统计数据,这样才能为后面做的性能优化提供数据支持,对比优化前后的结果。非常不错的是,在 github 发现一个 Ansible 任务计时插件“ansible-profile”,安装这个插件后会显示 ansible-playbook 执行每一个任务所花费的时间。Github 地址:https://github.com/jlafon/ansible-profile 这个插件安装很简单,只需要简单的三个命令即可完成安装。在你的 playbook 文件的目录下创建一个目录,目录名 callback_plugins 然后将下载的 profile_tasks.py 文件放到该目录下。

 

cd /etc/ansible

mkdir callback_plugins

cd callback_plugins

wget

https://raw.githubusercontent.com/jlafon/ansible-profile/master/callback_plugins/profile_tasks.py

现在,执行 ansible-playbook 命令就会看到 playbook 中每个 tasks 的用时情况。

7.2.1.1:  1.ansible-playbook tasks 用时情况

 

在这里,我设置了 2 个 task,1 个 task sleep 10 秒,另 1 个 task sleep 15 秒,在 PLAY RECAP 处会汇总所有 task 执行消耗的时间。

7.2.2: 关闭 gathering facts

如果您观察过 ansible-playbook 的执行过程中,您会发现 ansible-playbook 的第 1 个步骤总是执行 gather facts,不论你有没有在 playbook 设定这个 tasks。如果你不需要获取被控机器的 fact 数据的话,你可以关闭获取 fact 数据功能。关闭之后,可以加快 ansible-playbook 的执行效率,尤其是你管理很大量的机器时,这非常明显。关闭获取 facts 很简单,只需要在 playbook 文件中加上“gather_facts: no”即可。如下

---

- hosts: 172.16.64.240

gather_facts: no

 remote_user: liheng

 sudo: yes

 roles: 

 - {role: profile_test}

好的,来看关闭前后的执行时间变化。

7.2.2.1:  2. 关闭 gather_facts 前后的执行变化

 

关闭前后,执行时间相关 1 秒,因为我这里只有一台机器,所以时间差距并不是很明显。不过,从这个例子也可以看出,关闭 facts 获取后,执行速度是快了的。

7.2.3: SSH PIPElinING

SSH pipelining 是一个加速 Ansible 执行速度的简单方法。ssh pipelining 默认是关闭,之所以默认关闭是为了兼容不同的 sudo 配置,主要是 requiretty 选项。如果不使用 sudo,建议开启。打开此选项可以减少 ansible 执行没有传输时 ssh 在被控机器上执行任务的连接数。不过,如果使用 sudo,必须关闭 requiretty 选项。修改 /etc/ansible/ansible.cfg 文件可以开启 pipelining

pipelining=False

修改为

pipelining=True

修改完后,可以批量对机器执行命令试下,可以明显感受到速度的提升。

7.2.4: ControlPersist

ControlPersist 特性需要高版本的 SSH 才支持,CentOS 6 默认是不支持的,如果需要使用,需要自行升级 openssh。ControlPersist 即持久化 socket,一次验证,多次通信。并且只需要修改 ssh 客户端就行,也就是 Ansible 机器即可。

升级 openssh 的过程这里不做介绍。这里只介绍下 ControlPersist 设置的办法。

cat ~/.ssh/config

Host *

 Compression yes

 ServerAliveInterval 60

 ServerAliveCountMax 5

 ControlMaster auto

 ControlPath <a href="mailto:~/.ssh/sockets/%25r@%25h-%25p"><code>~/.ssh/sockets/%r@%h-%p</code></a>

 ControlPersist 4h

在开启了 ControlPersist 特性后,SSH 在建立了 sockets 之后,节省了每次验证和创建的时间。在网络状况不是特别理想,尤其是跨互联网的情况下,所带来的性能提升是非常可观的。有这边需求的,试试就知道了。

7.3: Ansible-playbook 技巧

7.3.1: 获取执行命令的输出 --Register

在刚开始使用 ansible-playbook 做应用程序部署的时候,因为在部署的过程中有使用到 command 或 shell 模块执行一些自定义的脚本,而且这些脚本都会有输出,用来表示是否执行正常或失败。如果像之前自己写脚本做应用程序部署的,这很好实现。但现在是用 Ansible 做,那么要怎么样做可以获取到 ansible playbook 中 command 模块的输出呢? Ansible 也提供的解决办法,这时我们就可以通过使用 register 关键字来实现,register 关键字可以存储指定命令的输出结果到一个自定义的变量中,我们通过访问这个自定义变量就可以获取到命令的输出结果。Register 的使用很方便,只需要在 task 声明 register 关键字,并自定义一个变量名就可以。如下:

1

2

3

4

5

6

7

- name: echo date

 command: date

 register: date_output

 

- name: echo date_output

 command: echo "30"

 when: date_output.stdout.split(\' \')[2] == "30"

这里第 1 个 task 是执行了一个 date 命令,register 关键字将 date 命令的输出存储到 date_output 变量名。第 2 个 task 对输出进行分析,并使用 when 对关键字对分析后的进行判断,如果匹配,则执行这个 task,不匹配就不执行。这里要重点说下的,因为 register 获取到的输出内容都是字符串,而 ansible 又是 python 写的,你可以使用 python 字符串的方法对其做处理,比如本文中使用的 split,还可以使用 find 方法。个人觉得,真是非常灵活方便。

7.3.1.1:  3.register 执行结果 1

 

这里由于条件匹配,两个 task 都执行了。然后把第 2 个 task 中的条件改动了下,使其不匹配,执行结果如下:

7.3.1.2:  4.register 执行结果 2

 

这里第 2 个 task 条件不匹配,skipping 了。

7.3.2: Delegate_to( 任务委派功能 )

场景介绍:在对一组服务器 server_group1 执行操作过程中,需要在另外一台机器 A 上执行一个操作,比如在 A 服务器上添加一条 hosts 记录,这些操作必须要在一个 playbook 联动完成。也就是是说 A 服务器这个操作与 server_group1 组上的服务器有依赖关系。Ansible 默认只会在定义好的一组服务器上执行相同的操作,这个特性对于执行批处理是非常有用的。但如果在这过程中需要同时对另外 1 台机器执行操作时,就需要用到 Ansible 的任务委派功能(delegate_to)。使用 delegate_to 关键字可以委派任务到指定的机器上运行。在 playbook 的操作如下:

 

1

2

3

4

5

6

- name: add host record

 shell: \'echo "192.168.1.100 test.xyz.com" >> /etc/hosts\'

 

- name: add host record to center server

 shell: \'echo "192.168.1.100 test.xyz.com " >> /etc/hosts\'

 delegate_to: 192.168.1.1

 

任务委派功能还可以用于以下场景:

  • 在部署之前将一个主机从一个负载均衡集群中删除。
  • 当你要对一个主机做改变之前去掉相应 dns 的记录
  • 当在一个存储设备上创建 iscsi 卷的时候
  • 当使用外的主机来检测网络出口是否正常的时候

7.3.3: 本地操作功能 --local_action

Ansible 默认只会对控制机器执行操作,但如果在这个过程中需要在 Ansible 本机执行操作呢?细心的读者可能已经想到了,可以使用 delegate_to( 任务委派 ) 功能呀。没错,是可以使用任务委派功能实现。不过除了任务委派之外,还可以使用另外一外功能实现,这就是 local_action 关键字。

1

2

- name: add host record to center server

local_action: shell \'echo "192.168.1.100 test.xyz.com " >> /etc/hosts\'

当然您也可以使用 connection:local 方法,如下:

1

2

3

- name: add host record to center server

 shell: \'echo "192.168.1.100 test.xyz.com " >> /etc/hosts\'

 connection: local

这两个操作结果是一样的。

7.3.4: Check 模式

当以— check 参数来运行 ansible-playbook 时,将不会对远程的系统作出任何修改。相对的,任何带有检测功能的模块只要支持‘检测模式’将会报告它们会做出什么改变而不是直接进行改变。其他不支持检测模式的模块将即不响应也不提出相应的报告(事实上几乎所有主要核心模块都是支持‘检测模式’)。检测模式只是一种模拟。如果你的 playbook 是以先前命令的执行结果作为条件的话,那它可能作用就不明显了。但是在正式运行前,使用 check 模式做个语法检查也是不错的。

选择性执行 task--Tag(标签)

您可能因为某些原因,会创建一个很大型的 playbook,但是你可能只想想运行其中特定部分的配置而无需要运行整个 playbook 。那么这时你可能需要用到 tag 功能。示例如下:

1

2

3

4

5

6

7

8

9

10

11

1 2

- name: yun install package

 yum: name={{ item }} state=installed

 with_items:

    - httpd

    - memcached

 tags:

    - packages

 

- name: configuration modity

 template: src=templates/src.j2 dest=/etc/foo.conf

 tags:

     - configuration

如果你只想运行 playbook 中的”configuration”和”packages”,你可以这样做

1

ansible-playbook example.yml – tags “configuration,packages”

如果你只想执行 playbook 中某个特定任务之外的所有任务,你可以这样做:

1

2

ansible-playbook example.yml – skip-tags “configuration”

tag 特性是一个不错的功能,但如果真的是要维护一个大型的 playbook,还是建议将 playbook 按功能或应用拆分成多个 playbook,然后再在主 playbook include 其他子 playbook,这样即既利于维护也方便管理

7.3.5: 错误处理

Ansible 默认会检查命令和模块的返回状态,并进行相应的错误处理,默认是遇到错误就中断 playbook 的执行,这些默认行为都是可以改变的。

忽略错误

command 和 shell 模块执行的命令如果返回非零状态码则 ansible 判定这 2 个模块执行失败,可以通过 ignore_errors 忽略返回状态码(前提是要确定这 command 与 shell 执行错误不会影响后面 task 的执行)。如下:

1

2

3

- name: this will not be counted as a failure

 command: /bin/false

 ignore_errors: yes

自定义错误判定条件

命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 failed 字符串,则判定为失败。示例如下:

1

2

3

4

- name: this command prints FAILED when it fails

 command: /usr/bin/example-command -x -y -z

 register: command_result

 failed_when: "\'FAILED\' in command_result.stderr"

ansible 会自动判断模块执行状态,command、shell 及其它模块如果修改了远程主机状态则被判定为 change 状态,不过也可以自己决定达到 changed 状态的条件,示例如下:

1

2

3

4

5

6

7

- name: copy in nginx conf

template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf

 

- name: validate nginx conf

 shell: "/data/app/nginx/sbin/nginx -t"

 register: command_result

 changed_when: command_result.stdout.find(\'successful\')

命令返回中有“successful”字符串,则为 changed 状态,下面这个设定将永远也不会达到 changed 状态。

1

2

3

- name: validate nginx conf

 shell: "/data/app/nginx/sbin/nginx -t"

 changed_when: false

7.4: 结束语

本文介绍了一些关于 Ansible 的执行性能优化与 playbook 使用的技巧,这些都是在我们使用 Ansible 过程中需要面对的问题,希望今天列出的这些内容对大家学习和使用 Ansible 能有所帮助。

7.4.1: 相关主题

  • 参考 Ansible 官方文档Ansible 权威的使用指南和操作手册,是学习 Ansible 第一手的权威资料。
  • IBM developerWorks 中国 linux 专区:为使用 linux 的开发人员准备的技术信息和资料。这里提供产品下载、how-to 信息、支持资源以及免费技术库,包含 2000 多份技术文章、教程、最佳实践、IBM Redbook 和在线产品手册。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分类:

技术点:

相关文章:

  • 2021-04-08
  • 2022-02-17
猜你喜欢
  • 2021-07-24
  • 2021-11-17
  • 2021-11-21
  • 2021-10-09
  • 2021-12-09
  • 2022-12-23
相关资源
相似解决方案