一、ansible简介
1、ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。
-
2、ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是ansible所运行的模块,ansible只是提供一种框架。
-
主要包括:
(1)、连接插件connection plugins:负责和被监控端实现通信;
(2)、host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
(3)、各种模块核心模块、command模块、自定义模块;
(4)、借助于插件完成记录日志邮件等功能;
(5)、playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。
3、ansible的安装
ansible依赖于Python 2.6或更高的版本、paramiko、PyYAML及Jinja2。
(1)、编译安装
解决依赖关系
# yum -y install python-jinja2 PyYAML python-paramiko python-babel python-crypto
# tar xf ansible-1.5.4.tar.gz
# cd ansible-1.5.4
# python setup.py build
# python setup.py install
# mkdir /etc/ansible
# cp -r examples/* /etc/ansible
(2) 、rpm包安装
# yum install ansible
注意:不同版本的ansible的功能差异可能较大。
二、ansible中的模块使用和简单的格式执行
ansible -m MOD_nAME指明模块
-a MOD_ARGS 向模块传递参数
-f FORKS 一次可管理多少主机
-C 预运行,不真正运行
--list -host 列出主机
-u USERNAME 指明用户名
-c 指明连接方式,默认smart
这些命令使用ansible简单的格式执行
1、生成安全连接秘钥
ansible通过ssh实现配置管理、应用部署、任务执行等功能,因此,需要事先配置ansible端能基于密钥认证的方式联系各被管理节点。
ansible和目标主机命令执行要使用ssh,所以第一步就要生成安全连接秘钥。
[root@rs1 ~]# ssh-keygen -t rsa -P "" #生成安全连接秘钥
[root@rs1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.6 #使用安全连接秘钥连接1号目标主机
root@192.168.1.6's password: #输入目标主机密码
[root@rs1 ~]# ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.12 #使用安全连接秘钥连接2号目标主机
root@192.168.1.12's password: #输入目标主机密码
2、添加本地解析
[root@rs1 ~]# vim /etc/hosts 添加本地解析
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.6 vs
192.168.1.12 rs2
3、定义目标主机组
/etc/ansible/hosts文件支持使用以下变量设置相关的远程主机信息:
ansible_ssh_host #用于指定被管理的主机的真实IP
ansible_ssh_port #用于指定连接到被管理主机的ssh端口号,默认是22
ansible_ssh_user #ssh连接时默认使用的用户名
ansible_ssh_pass #ssh连接时的密码
ansible_sudo_pass #使用sudo连接用户时的密码
ansible_sudo_exec #如果sudo命令不在默认路径,需要指定sudo命令路径
ansible_ssh_private_key_file #秘钥文件路径,秘钥文件如果不想使用ssh-agent管理时可以使用此选项
ansible_shell_type #目标系统的shell的类型,默认sh
ansible_connection #SSH 连接的类型: local , ssh , paramiko,在 ansible 1.2 之前默认是 paramiko ,后来智能选择,优先使用基于 ControlPersist 的 ssh (支持的前提)
ansible_python_interpreter #用来指定python解释器的路径,默认为/usr/bin/python 同样可以指定ruby 、perl 的路径
ansible_*_interpreter #其他解释器路径,用法与ansible_python_interpreter类似,这里"*"可以是ruby或才perl等
目标主机组:
[root@rs1 ~]# cd /etc/ansible
[root@rs1 ansible]# ls
ansible.cfg hosts roles
[root@rs1 ansible]# vim hosts#编辑文件
[websrvs]#添加web组
192.168.1.6
192.168.1.12
[dbsrvs] #定义db组
192.168.1.12
[root@rs1 ansible]# ansible all --list-hosts#列出目标主机
hosts (2):
192.168.1.12
192.168.1.6
[root@rs1 ansible]# ansible all -m ping -C# 对所有目标主机预运行ping测试
192.168.1.12 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.6 | SUCCESS => {
"changed": false,
"ping": "pong"
}
[root@rs1 ansible]# ansible all -m ping # 对所有目标主机ping测试
192.168.1.12 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.6 | SUCCESS => {
"changed": false,
"ping": "pong"
}
4、模块文档
[root@rs1 ansible]# ansible-doc -l #列出目标主机模块文档
[root@rs1 ansible]# ansible-doc -s group 获取设置组命令文档
1、定义期望的目标状态
2、操作必须是幂等的,操作次数必须相等
5、group组模块使用
对目标主机创建组,并传递参数
[root@rs1 ansible]# ansible all -m group -a "gid=3000 name=mygrp state=present system=no" #对所有目标主机创建组,m是加载group模块,a是传递参数,state是创建还是删除
192.168.1.6 | SUCCESS => {
"changed": true,
"gid": 3000,
"name": "mygrp",
"state": "present",
"system": false
}
192.168.1.12 | SUCCESS => {
"changed": true,
"gid": 3000,
"name": "mygrp",
"state": "present",
"system": false
}
6、user用户模块使用
对目标主机创建用户,并传递参数
[root@rs1 ansible]# ansible all -m user -a "uid=5000 name=testuser state=present groups=mygrp shell=/bin/tcsh"对所有目标主机创建用户,m是加载user模块,a是传递参数,state是创建还是删除,groups是附加组,shell是默认shell
192.168.1.6 | SUCCESS => {
"changed": true,
"comment": "",
"createhome": true,
"group": 5000,
"groups": "mygrp",
"home": "/home/testuser",
"name": "testuser",
"shell": "/bin/tcsh",
"state": "present",
"system": false,
"uid": 5000
}
192.168.1.12 | SUCCESS => {
"changed": true,
"comment": "",
"createhome": true,
"group": 5000,
"groups": "mygrp",
"home": "/home/testuser",
"name": "testuser",
"shell": "/bin/tcsh",
"state": "present",
"system": false,
"uid": 5000
}
7、copy复制模块使用
对目标主机拷贝本地文件,并传递参数,指明src源文件位置和dest目标文件位置
[root@rs1 ansible]# ansible-doc -s copy#查询copy使用文档
[root@rs1 ansible]# ansible all -m copy -a "src=/etc/fstab dest=/tmp/fstab.ansible mode=600"
对所有目标主机拷贝本地文件,m是使用copy模块,a是传递参数,src源文件位置,dest目标文件位置,mode权限(加了'/'就是目录)
192.168.1.6 | SUCCESS => {
"changed": true,
"checksum": "4367ba689c50b4ab956ce0704f048f4fb0cc1a28",
"dest": "/tmp/fstab.ansible",
"gid": 0,
"group": "root",
"md5sum": "c6ac458a97ee2f7ed913fdc8b17e9394",
"mode": "0600",
"owner": "root",
"size": 465,
"src": "/root/.ansible/tmp/ansible-tmp-1534522522.24-76431722279920/source",
"state": "file",
"uid": 0
}
192.168.1.12 | SUCCESS => {
"changed": true,
"checksum": "4367ba689c50b4ab956ce0704f048f4fb0cc1a28",
"dest": "/tmp/fstab.ansible",
"gid": 0,
"group": "root",
"md5sum": "c6ac458a97ee2f7ed913fdc8b17e9394",
"mode": "0600",
"owner": "root",
"size": 465,
"src": "/root/.ansible/tmp/ansible-tmp-1534522522.23-209859323698602/source",
"state": "file",
"uid": 0
}
copy模块设置属主属组用法
[root@rs1 ansible]# ansible all -m copy -a "content='hi tere\n' dest=/tmp/hi.txt owner=testuser group=mygrp"#对所有目标主机拷贝本地文件,m是使用copy模块,a是传递参数,content创建文档到dest目标文件位置,设置属主属组
192.168.1.6 | SUCCESS => {
"changed": true,
"checksum": "50dbdebeaa8c0f1c3cccfcae54ef71fc2c0e4fa8",
"gid": 3000,
"group": "mygrp",
"mode": "0644",
"owner": "testuser",
"path": "/tmp/hi.txt",
"size": 8,
"state": "file",
"uid": 5000
}
192.168.1.12 | SUCCESS => {
"changed": true,
"checksum": "50dbdebeaa8c0f1c3cccfcae54ef71fc2c0e4fa8",
"gid": 3000,
"group": "mygrp",
"mode": "0644",
"owner": "testuser",
"path": "/tmp/hi.txt",
"size": 8,
"state": "file",
"uid": 5000
}
8、fetch复制模块
从远程单一主机复制到本地主机
使用文档:ansibile-doc -s fetch
9、command模块执行命令
对目标主机执行命令
[root@rs1 ansible]# ansible all -m command -a "ifconfig"#对所有目标主机,m使用模块,command命令模块,a传递参数 执行ifconfig命令
192.168.1.12 | SUCCESS | rc=0 >>
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
.............
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
.............
192.168.1.6 | SUCCESS | rc=0 >>
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
...............
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
...............
注意:command缺点是无法解析管道命令
10、shell模块使用
shell模块解决了command模块的缺点,对传递参数用shell解析并执行
[root@rs1 ansible]# ansible all -m shell -a "echo 123 | passwd --stdin testuser"#对所有目标主机使用shell解析传递参数中的管道命令
192.168.1.6 | SUCCESS | rc=0 >>
更改用户 testuser 的密码 。
passwd:所有的身份验证令牌已经成功更新。
192.168.1.12 | SUCCESS | rc=0 >>
更改用户 testuser 的密码 。
passwd:所有的身份验证令牌已经成功更新。
11、file模块文件属性命令
对目标主机,传递参数,创建文件、目录和软连接
[root@rs1 ansible]# ansible all -m file -a "path=/var/tmp/hello.dir state=directory"#对所有目标主机使用file模块创建hello.dir目录
192.168.1.12 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/var/tmp/hello.dir",
"size": 6,
"state": "directory",
"uid": 0
}
192.168.1.6 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/var/tmp/hello.dir",
"size": 6,
"state": "directory",
"uid": 0
}
[root@rs1 ansible]# ansible all -m file -a"src=/etc/fstab path=/var/tmp/fstab.link state=link"#对所有目标主机使用file模块创建fstab文件的符号连接
192.168.1.12 | SUCCESS => {
"changed": true,
"dest": "/var/tmp/fstab.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 10,
"src": "/etc/fstab",
"state": "link",
"uid": 0
}
192.168.1.6 | SUCCESS => {
"changed": true,
"dest": "/var/tmp/fstab.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 10,
"src": "/etc/fstab",
"state": "link",
"uid": 0
}
12、cron模块计划任务
对目标主机,传递参数,设置计划任务
[root@rs1 ansible]# ansible all -m crom -a "minute=*/3 job='/usr/sbin/update 192.168.1.1 &> /dev/null' name=none state=present"#对所有目标主机 ,m使用模块,crom计划任务,创建任务每三分钟同步时间
13、yum模块安装软件程序包
rpm软件的安装
[root@rs1 ansible]# ansible all -m yum -a "name=ngix state=instlled"#对所有主机安装ngix
14、service模块管理目标服务
对目标主机,传递参数,管理服务。
[root@rs1 ansible]# ansible all -m service -a"name=httpd state=started"#对所有主机启动httpd服务
[root@rs1 ansible]# ansible all -m service -a"name=httpd state=stoped"#对所有主机停止httpd服务
15、script模块脚本管理
[root@rs1 ansible]# vim /tmp/test.sh#编写一个测试脚本
对目标主机,传递参数,执行本地bash脚本
#!binbash
#
echo "ansible script" > /tmp/ansible.txt
[root@rs1 ansible]# ansible all -m script -a "/tmp/test.sh"#所有目标主机执行本地bash脚本
注意:ansible普通命令用法很难复用
三、playbook
- playbook解决了ansible普通命令难以复用的缺点,使用yaml格式保存,所有首先要了解YAML。
- playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色。从根本上来讲,所谓task无非是调用ansible的一个module。将多个play组织在一个playbook中,即可以让它们联同起来按事先编排的机制同唱一台大戏。
1、YAML介绍
YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。
YAML Ain't Markup Language,即YAML不是XML。不过,在开发的这种语言时,YAML的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。其特性:
YAML的可读性好
YAML和脚本语言的交互性好
YAML使用实现语言的数据类型
YAML有一个一致的信息模型
YAML易于实现
YAML可以基于流来处理
YAML表达能力强,扩展性好
2、YAML语法
YAML的语法和其他高阶语言类似,并且可以简单表达清单、散列表、标量等数据结构。其结构(Structure)通过空格来展示,序列(Sequence)里的项用"-"来代表,Map里的键值对用":"分隔。
- 服务安装示例(redis服务)
[root@rs1 ~]# mkdir playbooks#创建目录
[root@rs1 ~]# cd playbooks
[root@rs1 playbooks]# ls
[root@rs1 playbooks]# vim first.yaml#创建一个新的以.yaml 结尾的playbooks
- hosts: all #定义目标主机
remote_user: root#使用用户
tasks: #任务
- name: install redis#将要执行的第一个任务
yum: name=redis state=latest#执行任务的设置
- name: name: start redis#将要执行的第二个任务
service: name=redis state=started#执行任务的设置
[root@rs1 playbooks]# ansible-playbook --syntax-check first.yaml#语法检查
playbook: first.yaml
[root@rs1 playbooks]# ansible-playbook --list-hosts first.yaml#此playbooks涉及到那些主机
playbook: first.yaml
play #1 (all): all TAGS: []
pattern: [u'all']
hosts (2):
192.168.1.12
192.168.1.6
[root@rs1 playbooks]# ansible-playbook --list-hosts --list-tasks first.yaml#涉及到的主机上将要执行的任务(标签为空)
playbook: first.yaml
play #1 (all): all TAGS: []
pattern: [u'all']
hosts (2):
192.168.1.12
192.168.1.6
tasks:
install redis TAGS: []
start redis TAGS: []
start redis TAGS: []
[root@rs1 playbooks]# ansible-playbook -C first.yaml #预执行
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.6]
ok: [192.168.1.12]
TASK [install redis] ***********************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
TASK [start redis] *************************************************************
changed: [192.168.1.6]
changed: [192.168.1.12]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=3 changed=2 unreachable=0 failed=0
192.168.1.6 : ok=3 changed=2 unreachable=0 failed=0
[root@rs1 playbooks]# ansible-playbook first.yaml #执行
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [install redis] ***********************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
TASK [start redis] *************************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=3 changed=2 unreachable=0 failed=0
192.168.1.6 : ok=3 changed=2 unreachable=0 failed=0
- 配置文件传递示例(redis服务):
[root@rs1 playbooks]# cp 192.168.1.6/etc/redis.conf ./
[root@rs1 playbooks]# ls
192.168.1.6 first.yaml redis.conf
[root@rs1 playbooks]# ansible 192.168.1.6 -m fetch -a "src=/etc/redis.conf dest=./ " #复制目标主机里面的redis配置文件到本机
[root@rs1 playbooks]# cp 192.168.1.6/etc/redis.conf ./#拷贝复制过来的配置文件到当前目录
[root@rs1 playbooks]# ls
192.168.1.6 first.yaml redis.conf
[root@rs1 playbooks]# vim redis.conf#编辑
......
bind 0.0.0.0#监听所有端口
.....
requirepass foobared#启用密码认证功能,密码是foobared
.....
-
handlers:用特定条件触发使用
用于当关注的资源发生变化时采取一定的操作。“notify”这个action可用于在每个play的最后被触发,这样可以避免多次有改变发生时每次都执行指定的操作,取而代之,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作。
[root@rs1 playbooks]# cp first.yaml second.yaml#备份一下
[root@rs1 playbooks]# vim second.yaml #编辑
- hosts: all
remote_user: root
tasks:
- name: install redis
yum: name=redis state=latest
- name: copy config file #任务2复制文件
copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf owner=r
edis#复制文件到目标主机目录下
notify: restart redis#通知handlers触发
- name: start redis
service: name=redis state=started
handlers:#定义触发任务
- name: restart redis#触发任务一
service: name=redis state=restarted#重新启动redis
[root@rs1 playbooks]# ansible-playbook --syntax-check second.yaml#语法检查
playbook: second.yaml
[root@rs1 playbooks]# ansible-playbook second.yaml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [install redis] ***********************************************************
ok: [192.168.1.6]
ok: [192.168.1.12]
TASK [copy config file] ********************************************************
changed: [192.168.1.6]
changed: [192.168.1.12]
TASK [start redis] *************************************************************
ok: [192.168.1.6]
ok: [192.168.1.12]
RUNNING HANDLER [restart redis] ************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=5 changed=2 unreachable=0 failed=0
192.168.1.6 : ok=5 changed=2 unreachable=0 failed=0
- tags标签的使用
只执行标签里面的任务
[root@rs1 playbooks]# vim second.yaml
- hosts: all
remote_user: root
tasks:
- name: install redis
yum: name=redis state=latest
- name: copy config file
copy: src=/root/playbooks/redis.conf dest=/etc/redis.conf owner=redis
notify: restart redis
tags: configfile #添加任务标签
- name: start redis
service: name=redis state=started
handlers:
- name: restart redis
service: name=redis state=restarted
[root@rs1 playbooks]# ansible-playbook -t configfile second.yaml #只执行标签里面的任务
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [copy config file] ********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=2 changed=0 unreachable=0 failed=0
192.168.1.6 : ok=2 changed=0 unreachable=0 failed=0
四、Ansible基础元素
1、 变量variables
- 变量命名:变量名仅能由字母、数字和下划线组成,且只能以字母开头。
(1)facts可直接调用
- facts是由正在通信的远程目标主机发回的信息,这些信息被保存在ansible变量中。要获取指定的远程主机所支持的所有facts
[root@rs1 playbooks]# ansible 192.168.1.6 -m setup# setup模块获取目标主机信息
[root@rs1 playbooks]# vim thir.yaml#编辑
- hosts: 192.168.1.6
remote_user: root
tasks:
- name: copy file
copy: content={{ansible_env}} dest=/tmp/ansible.env#指定变量保存到目标主机目录下
[root@rs1 playbooks]# ansible-playbook --syntax-check thir.yaml#语法检查
[root@rs1 playbooks]# ansible-playbook thir.yaml
PLAY [192.168.1.6] *************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.6]
TASK [copy file] ***************************************************************
changed: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.6 : ok=2 changed=1 unreachable=0 failed=0
(2)ansible-playbook命令的命令行自定义变量
在运行playbook的时候也可以传递一些变量供playbook使用
[root@rs1 playbooks]# vim forth.yaml
- hosts: all
remote_user: root
tesks:
- name: install package {{pkgname}} #定义安装程序包任务
yum: name={{pkgname}} state=latest#安装什么包,由自定义变量提供
[root@rs1 playbooks]# ansible-playbook --syntax-check forth.yaml 语法检查
[root@rs1 playbooks]# ansible-playbook -e pkgname=memcached forth.yaml#指定安装包安装
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [install package] *********************************************************
changed: [192.168.1.6]
changed: [192.168.1.12]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=2 changed=1 unreachable=0 failed=0
192.168.1.6 : ok=2 changed=1 unreachable=0 failed=0
(3)Inventory主机文件清单
ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名。默认的inventory file为/etc/ansible/hosts。
主机文件清单可以有多个,且也可以通过Dynamic Inventory来动态生成。
inventory文件格式遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中;此外,当如若目标主机使用了非默认的SSH端口,还可以在主机名称之后使用冒号加端口号来标明。
ntp.xxx.com
[webservers]
www1.xxx.com:2222
www2.xxx.com
[dbservers]
db1.xxx.com
db2.xxx.com
db3.xxx.com
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机,
例如:[webservers]
www[01:50].xxx.com
[databases]
db-[a:f].xxx.com
[root@rs1 ansible]# vim hosts
........
[websrvs]
www[1:7].hehe.com#定义主机清单
[root@rs1 ansible]# ansible websrvs --list-host
hosts (7):
www1.hehe.com
www2.hehe.com
www3.hehe.com
www4.hehe.com
www5.hehe.com
www6.hehe.com
www7.hehe.com
为目标主机创建用户
[root@rs1 playbooks]# vim fif.yaml #编辑文件
- hosts: all
remote_user: root
tasks:
- name: add user
user: name=test system=no state=present
- name: set password
shell: echo test | passwd --stdin test
[root@rs1 playbooks]# ansible-playbook --syntax-check fif.yaml#语法检查
[root@rs1 playbooks]# ansible-playbook --syntax-check fif.yaml
playbook: fif.yaml
[root@rs1 playbooks]# ansible-playbook fif.yaml
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [add user] ****************************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
TASK [set password] ************************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=3 changed=2 unreachable=0 failed=0
192.168.1.6 : ok=3 changed=2 unreachable=0 failed=0
(4)主机变量
可以在inventory中定义主机时为其添加主机变量以便于在playbook中使用。
[root@rs1 playbooks]# vim /etc/ansible/hosts
[websrvs]
192.168.1.6 ansible_ssh_user=test ansible_ssh_pass=test
192.168.1.12 ansible_ssh_user=test ansible_ssh_pass=test
[root@rs1 playbooks]# ansible websrvs -m ping#对目标主机ping测试
192.168.1.12 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.6 | SUCCESS => {
"changed": false,
"ping": "pong"
}
[root@rs1 playbooks]# ansible websrvs -m command -a "whoami"#用户名返回测试
192.168.1.12 | SUCCESS | rc=0 >>
test
192.168.1.6 | SUCCESS | rc=0 >>
test
注意: 一个组定义了指定用户 ,将会影响其他组指定用户会变的
(5)组变量
组变量是指赋予给指定组内所有主机上的在playboo中可用的变量。
自定义变量传递:
组变量定义方法一:
[websrvs]
192.168.1.6 http_port=8000
192.168.1.12 http_port=10080
组变量定义方法二:
[websrvs]
192.168.1.6
192.168.1.12
[websrvs:vars]
http_port=8080
[root@rs1 ~]# cd /root/playbooks/
[root@rs1 playbooks]# vim vars.yaml
- hosts: websrvs
remote_user: root
vars:
- pbvar: playbook variable testing #变量声明
tasks:
- name: command line variables
copy: content={{ cmdvar }} dest=/tmp/cmd.var #命令行变量引用,保存到指定文件
- name: playbook variables
copy: content={{ pbvar }} dest=/tmp/pb.var #变量引用,保存到指定文件
- name: host iventory variables
copy: content={{ http_port }} dest=/tmp/hi.var #主机列表定义引用,保存到指定文件
[root@rs1 playbooks]# vim /etc/ansible/hosts
[root@rs1 playbooks]# ansible-playbook -e cmdvar="command line variable testing" vars.yaml #执行命令测试
PLAY [websrvs] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.12]
ok: [192.168.1.6]
TASK [command line variables] **************************************************
changed: [192.168.1.6]
changed: [192.168.1.12]
TASK [playbook variables] ******************************************************
changed: [192.168.1.12]
changed: [192.168.1.6]
TASK [host iventory variables] *************************************************
changed: [192.168.1.6]
changed: [192.168.1.12]
PLAY RECAP *********************************************************************
192.168.1.12 : ok=4 changed=3 unreachable=0 failed=0
192.168.1.6 : ok=4 changed=3 unreachable=0 failed=0
(6)组嵌套
inventory中,组还可以包含其它的组,并且也可以向组中的主机指定变量。不过,这些变量只能在ansible-playbook中使用,而ansible不支持。例如:
[apache]
httpd1.xxx.com
httpd2.xxx.com
[nginx]
ngx1.xxx.com
ngx2.xxx.com
[webservers:children]
apache
nginx
[webservers:vars]
ntp_server=ntp.xxx.com
2、模板模块template
文本文档脚本,使用模板语言编写,支持Jinja2表达式语法
[root@rs1 playbooks]# cp redis.conf redis.conf.j2
[root@rs1 playbooks]# vim redis.conf.j2 #编辑文件
....
bind {{ ansible_ens33.ipv4.address }} #编辑模板段变量
.....
[root@rs1 playbooks]# vim template.yaml #编辑playbook
- hosts: 192.168.1.6
remote_user: root
tasks:
- name: install config file
template: src=/root/playbooks/redis.conf.j2 dest=/tmp/redis.conf
[root@rs1 playbooks]# ansible-playbook template.yaml#执行
PLAY [192.168.1.6] *************************************************************
TASK [Gathering Facts] *********************************************************
ok: [192.168.1.6]
TASK [install config file] *****************************************************
changed: [192.168.1.6]
PLAY RECAP *********************************************************************
192.168.1.6 : ok=2 changed=1 unreachable=0 failed=0
客户端:
[root@vs ~]# vim /tmp/redis.conf
.......
bind 192.168.1.6 #已把客户主机ip写入redis里面了
........
示例二:
不同主机,得到不同的配置
vim listen.conf
listen {{ http_port }}
vim httpd.yaml
- hosts:websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd state=latest
- name: install config file
template: src=/root/playbooks/mylisten.conf dest=/etc/httpd/conf.d/mylinsten.conf
- name: start httpd
service: name=httpd state=started
ansible-playbook --syntax-check httpd.yaml
ansible-playbook httpd.yaml
3、when语句条件测试语句:
如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试。
在task后添加when子句即可使用条件测试;when语句支持Jinja2表达式语法。
when:在task中使用,jinja2的语法格式
.- name: install conf file
template:src=files
when:什么时候执行任务
判断当前系统是debian系统,就按照Apache2
示例:
vim os.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: install httpd
yum: name=httpd state=latest
when:ansible_os_family ==" RedHat"#判断是否是红帽系统
- name: install apche2
apt: name=apache2 state=latest
when: ansible_os_family == "Debian"#判断是否是debian系统
ansible-playbook -c os.yaml
when语句中还可以使用Jinja2的大多“filter”,例如要忽略此前某语句的错误并基于其结果(failed或者sucess)运行后面指定的语句,可使用类似如下形式:
tasks:
- command: /bin/false
register: result
ignore_errors: True
- command: /bin/something
when: result|failed
- command: /bin/something_else
when: result|success
- command: /bin/still/something_else
when: result|skipped
此外,when语句中还可以使用facts或playbook中定义的变量
4、迭代
- 当有需要重复性执行的任务时,可以使用迭代机制。其使用格式为将需要迭代的内容定义为item变量引用,并通过with_items语句来指明迭代的元素列表即可。
示例:安装多个程序包
vim iter.yaml
- hosts: websrvs
remote_user: root
tasks:
- name: instsll {{ item }} package
yum: name= {{ item }} state=latest#安装with_items里面的程序包
with_items:
- tomcat
- tomcat-webapps
- mariadb-server
ansible-playbook iter.yaml
5、角色:roles
ansilbe自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
自包含的目录,以特定的层级目录结构化组织
mkdir -pv /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
示例:利用roles安装nginx,并配置启动
cd /etc/ansible
vim roles/nginx/templates/vhost1.conf.j2 #编辑模板文件
server{
lisen 8080;
server_name {{ anible_fqdn }}; 获取主机名
location / {
root "/ngxdata/vhost1";
}
}
vim roles/nginx/files/index.html#编辑测试页
<h1>vhost</h1>
vim roles/nginx/handers/main.yml #编辑触发文件
- name: restart nginx
service: name=nginx state=restarted
vim roles/nginx/vars/main.yml#编辑变量文件
ngxroot: /ngxdata/vhost1 #这里定义必须是字典模式,不加'-'
vim /etc/ansible/roles/nginx/tasks/main.yml
- name: install nginx
yum: name=nginx state=latest
when: ansible_os_family == "RedHat"#检查是否是红帽系统
- name: install conf
temlate: src=vhost1.conf.j2 dest=/etc/nginx/conf.d/vhost1.conf#传递模板文件
tags: conf 标签
notify: restart nginx
-name: install site home directory
file: path={{ ngxroot }} state=directory
-name: install index page
copy: src=index.html dist={{ ngxroot }}/#拷贝本地index测试页到目标主机的nginx根目录
-name: start nginx
service:name=nginx state=started#启动nginx
cd
vim nginx.yml
- hosts: websrvs
remote_user: root
roles:
- nginx #调用角色
ansible-playbook -syntax-check nginx.yml #语法检查
ansible-playbook nginx.yml #执行
四、配置文件设置常用设置
配置文件设置
vim ansible.cfg
[defaults]
forks=5 一次管控多少主机
sudo_user=root 切换到那个管理员
ask_pass=true 切换时候是否需要密码
remote_port =22 远程端口
roles_path 角色存放位置
module_name 不指明时候 调用默认模块
客户端主机主动到ansible服务器获取配置用ansible-vcs第三方软件来实现,实际应用中较少使用。