运维自动化之ansible-使用示例
也可参考:https://www.cnblogs.com/keerya/p/7987886.html
本章内容:
运维自动化发展历程及技术应用
ansible 命令使用
ansible 常用模块使用
YAML语法简介
ansible playbook基础
playbook 变量,tags,handlers使用
playbook模板templates
playbook 条件判断 when
playbook 字典 with_items
ansible roles
云计算,运维自动化发展历程及技术应用
IaaS: Intrastructure as a Service 基础设施即服务
提供给消费者的服务时对多有计算机基础设施的利用,包括处理CPU,内存,存储
和其他基本的计算资源,用户能够部署和运行任意软件,包括操作系统和应用程序。
消费者不管理或控制任何云计算基础设施,但能控制操作系统的选择,存储空间,部署
的应用,也有可能获得有限制的网络组件,例如路由器、防火墙、负载均衡器等,的控制
PaaS:Platform as a Service 平台即服务
提供给消费者的服务是把客户采用提供的开发语言和工具(如java,python,.net等)
开发的或收购的应用程序部署到供应商的云计算基础设施上去。客户不需要管理或者控制底层
的云基础设施,包括网络,服务器,操作系统,存储等,但客户能控制部署的应用程序,也可能
控制运行应用程序的托管环境配置
SaaS:Software as a Serveice 软件即服务
提供给客户的服务时运营商运行在云计算基础设施上的应用程序,用户可以在各种
设备上通过客户端界面访问,如浏览器,消费者不需要管理或控制任何云计算基础设施,
包括网络,服务器,操作系统,存储等;
常用自动化运维工具
ansible:python Agentless中小型应用环境,通过ssh实现,无需部署代理程序
Saltstack:python 一般需部署agent,执行效率更高
Puppet:ruby 功能强大,配置复杂,适合大型环境
Fabric:python agentless
chef:ruby
cfengine
func
ansible特性:----------------------------------------------------------------------
模块化:调用特定的模块,完成特定任务
有Paramiko(基于ssh的python实现),pyYAML,jinja2 三个关键模块
支持自定义模块
基于python语言实现
部署简单,基于python和ssh,
安全,基于openssh
支持playbook 编排任务
具有幂等性,一个任务执行1遍和执行n遍效果一样,不因重复执行带来意外情况
无需代理,不依赖PKI(无需ssl)
可使用任务编程语言写模块
YAML格式,编排任务,支持丰富的数据结构
交强大的多层解决方案
ansible主要组成部分:
invenroty: ansible管理主机的清单,存放于/etc/ancible/hosts
modules: ansible执行命令的功能模块,多数为内置核心模块,也可以自定义
ansible playbook: 任务剧本,编排定义ansible任务集合的配置文件,由ansible顺序
执行,通常是JSON格式的YML文件
plugins: 模块功能的补充,如连接类型插件,循环插件,变量插件,过滤插件等
API: 供第三方程序调用的应用程序编程接口
ansible: 组合Inventory api modules plugins 的绿框,可以理解为是ansible的命令工具
其为核心执行工具
ansible命令执行来源:
USER 普通用户,即system administrator
CMDB(配置管理数据库)API调用
Public/private cloud API调用
user -> ansible playbook -> ansible
利用ansible实现管理的方式:
ad-hoc 即ansible命令,用户临时命令使用场景
ansible-playbook 主要用于长期规划好的,大型项目的场景,需要由前提的规划
absible-playbook 执行过程:
将已有编排好的任务集写入ansible-palybook
通过ansible-playbook 命令分拆任务逐条ansible命令,按预定规则逐条执行
ansible主要操作对象:
host主机
network网路设备
注意事项:
执行ansible的主机一般称为主控端,中控,master或堡垒机
主控端python版本需要2.6或以上
被控端python版本小于2.4需要安装python-simplejson
被控端如开启selinux,需要安装libselinex-python
windows不能作为主控端
ansible安装:
1 rpm包安装,epel源
yum install ansible
2 编译安装:
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
3 git方式:
git clone git://github.com/ansible/ansible.git --recursive
cd ./ansible
source ./hacking/env-setup
4 pip安装: pip是安装Python包的管理器,类似yum
yum install python-pip python-devel
yum install gcc glibc-devel zibl-devel rpm-bulid openssl-devel
pip install --upgrade pip
pip install ansible --upgrade
5 确认安装版本:
ansible --version
相关文件:
配置文件:
/etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性
/etc/ansible/hosts 主机清单
/etc/ansible/roles/ 存放roles的目录
程序:
/usr/bin/ansible 主程序,临时命令执行工具
/usr/bin/ansible-doc 查看配置文档,模块功能查看工具
/usr/bin/ansible-galaxy 下载、上传优秀代码或roles模块的官网平台
/usr/bin/ansible-playbook 定制自动化任务,编排剧本工具
/usr/bin/ansible-pull 远程执行命令的工具
/usr/bin/ansible-vault 文件机密工具
/usr/bin/ansible-console 基于console界面与用户交互的执行工具
主机清单:
Inventory :主机清单
默认的Inventory file为: /etc/ansible/hosts
inventory file可以有多个,且也可以通过dynamic inventory 来动态生成
主机清单:Inventory
/etc/ansible/hosts文件格式:
inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时
归并到多个不同的组中;此外,如果目标主机使用了非默认的ssh端口,还可以在主机名
之后使用 :端口号 来标明
例如:
[webservers]
192.168.65.128
192.168.65.132
www.test1.com
www.test2.com
[dbservers]
192.168.65.150:2222
192.168.65.160
db1.test.com
db2.test.com
注意: 如果使用name来标明主机,那么就必须提供能供解析的name-server,或者修改
本地host文件。/etc/hosts
如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
例如:
[webs]
www.test[1:100].com 1-100
ca.test[a:f].com a-f
ansible配置文件:
/etc/ansible/ansible.cfg 一般保持默认
[defaults]
#inventory = /etc/ansible/hosts 主机列表配置文件
#library = /usr/share/my_modules/ 库文件存放目录
#remote_tmp = $HOME/.ansible/tmp 临时py命令文件存放的远程主机目录
#local_tmp = $HOME/.ansible/tmp 本机的临时命令执行目录
#forks = 5 默认并发数
#sudo_user = root 默认sudo用户
#ask_sudo_pass = True 每次执行ansible命令是否询问ssh密码
#ask_pass = True
#remote_port = 22
#host_key_checking = False 检查对应服务器的host_key,建议取消注释
#log_path = /var/log/ansible.log 日志文件
ansible-doc 显示模块帮助
ansible-doc [options][modules]
-a 显示所有模块的文档
-l --list 列出可用模块
-s --snippet 显示指定模块的playbook片段
示例:
ansible-doc -l
ansible-doc ping
ansible-doc -s ping
ansible命令:---------------------------------------------------------------------
通过ssh实现配置管理,应用部署,任务执行等功能,建议配置ansible端能基于秘钥
认证的方式联系各被管理节点
ansible <host-pattern> [-m module_name] [-a 'args']
--version 显示版本
-m module 指定模块,默认为command
-v -vv -vvv 显示详细过程
-list-hosts 显示主机列表,可简写 --list
-k --ask-pass 提示连接密码,默认key验证
-K --ask-become-pass 提示输入sudo密码
-C --check 检查,并不执行
-T --timeout= 执行命令的超时时间,默认10s
-u --user=REMOTE_USER 执行远程命令执行的用户
-b --bacome 代替旧版的sudo 切换
示例:
ansible centos6 -m shell -u hello -k -a 'ls -l /data/f1'
ansible all -m command -u wang --become-user=root -a 'ls /root' -b –k -K
host-pattern 匹配主机的列表
all 表示所有inventory中的所有主机
ansible all -m ping
* 通配符,任意长度任意字符
ansible "*" -m ping
ansible 192.168.65.* -m ping
ansible 1* -m ping
ansible "c*" -m ping
如单独使用或者使用时字符串较短 如1-2个字符,建议使用""
否则容易语法错误
: 或
ansible "centos6:centos7" -m ping
ansible "centos6:192.168.65.132" -m ping
ansible "centos6:192.168.65.132:centos7" -m ping
:& 逻辑与
ansible "webs:&dbs" -m ping
表示在webs组里,并且在dbs组里的主机
:! 逻辑非
ansible 'webs:!centos6' -m shell -a 'echo hello'
表示在webs组中,但不在centos6中的主机
注意: :& 用"" '' 都可以
:! 只能使用''
综合逻辑:
ansible 'webs:dbs:¢os6:!centos7' -m ping
正则表达式:
ansible '~centos(6|7)' -m ping
ansible '~(web|db).*\.magedu\.com' -m ping
ansible命令的执行过程:
1 加载自己的配置文件 默认/etc/ansible/ansible.cfg
2 加载自己对应的模块文件,如shell、 copy
3 通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器
的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/xxx.Py文件
4 给文件+x 执行权限
5 执行并返回结果
6 删除临时py文件,sleep 0 退出
执行状态:
绿色: 执行成功并且不需要做改变的操作
×××: 执行成功并且对目标主机做变更
红色: 执行失败
ansible 常用模块:------------------------------------------------------------------
command:默认模块,可忽略 -m 选项,在远程主机上执行命令,
ansible webs -a 'rpm -q httpd'
ansible webs -m command -a 'rm -f /data/*'
常用选项:
chdir=/DIR cd到/DIR目录下执行
creates=filename 如果filename文件存在,将不执行 不存在--> 执行
removes=filename 如果filename文件不存在,将不执行 存在_--> 执行
注意:command模块不支持 $name < > | ; & 等特殊用法,用shell模块实现
shell: 和command 相似,用shell执行命令,支持 $name < > | ; & 等特殊用法
ansible webs -m shell -a 'echo magedu | passwd --stdin hello'
调用bash执行命令
但是类似 cat /tmp/stanley.md |awk -F'|' '{print $1 $2}' &>/tmp/example.txt
这样的复杂命令就算使用shell模块也可能失败,而且存在引号冲突问题,
解决办法:写到脚本中,copy到远程,执行,再把需要的结果拉回执行命令的机器
常用选项:
chdir
creates
removes
script:运行脚本
ansible webs -m script -a f1.sh
常用选项: chdir
creates
removes
--some-arguments 1234 提供运行参数
copy: 从本地复制文件到远程主机
常用选项:
backup=yes|no 如果目标存在,是否备份
src= 源文件,本地
dest= 目标路径,远程主机
group= 所属组
owner= 所有者
mode= 设置权限
ansible webs -m copy -a 'src=/etc/fstab dest=f2 backup=yes'
ansible webs -m shell -a 'ls /root'
如果不指明路径,默认复制到家目录下
ansible dbs -m copy -a 'src=/root/f2 dest=/data/cat backup=yes mode=000'
fetch: 从远程主机复制文件到本地主机,与copy相反
只能复制单个文件,目录可先tar在fetch
选项:
src=
dest=
会在dest目录下生成多个主机名命名的目录,且会将源文件的路径一并生成
如:
ansible dbs -m fetch -a 'src=/etc/passwd dest=/data/bak'
[root@Centos6 /data]#tree
.
└── bak
├── 192.168.65.150
│ └── etc
│ └── passwd
└── 192.168.65.160
└── etc
└── passwd
5 directories, 2 files
file: 设置文件属性
选项:
path= dest= name= 等价,指明文件路径
state
=derictory 如果不存在则创建目录
=file 如果不存在默认不创建
=touch 默认,创建文件或目录
=absent 递归删除
=link 软链接
=hard 硬链接
group= 所属组
owner= 所有者
src= 源,创建链接文件需指明
mod= 权限
示例:
创建文件:
ansible dbs -m file -a 'path=/data/f1 state=touch'
创建目录:
ansible dbs -m file -a 'path=/data/dir1 state=directory'
删除文件或目录
ansible dbs -m file -a 'path=/data/dir1 state=absent'
创建链接
ansible dbs -m file -a 'src=/data/f1 path=/data/f1.link state=touch'
注意:不支持通配符*操作,一次只能操作一个文件或目录
hostname: 管理主机名
ansible 192.168.65.150 -m hostname -a 'name=NAME'
yum: 管理程序包
常用选项:
name= 包名
state=
present installed latest 安装
absent removed 卸载
list= installed name
disable_gpg_check=yes|no 禁用gpgcheck 默认no
update_cache=yes|no 是否清楚缓存默认no
安装程序包:
ansible dbs -m yum -a 'name=vsftpd,httpd'
卸载程序包
ansible dbs -m yum -a 'name=vsftpd,httpd state=absent'
查看包列表:
ansible dbs -m yum -a 'list=NAME or intalled'
rpm包直接使用yum安装:
ansible dbs -m copy -a 'src=rpmfile dest=/path/'
ansible dbs -m yum -a 'name=/path/rpmfile disable_gpg_check=yes'
cron: 计划任务
时间格式选项:minute hour day month weekday
选项: job= 作业内容
name= 作业标签
user= 用户
disabled=true|false yes|no 禁用或者启用
state= 默认present 启用
absent 删除
示例:
新建计划任务:
ansible dbs -m cron -a 'minute=* job="wall hello there" name=wall'
禁用计划任务
ansible dbs -m cron -a 'disabled=yes job="wall hello there" name=wall'
启用:
disabled=no或false
删除:
ansible dbs -m cron -a 'job="wall hello there" name=wall state=absent'
service:服务管理
常用选项:
name= 服务名
state=
reloaded
restarted
running
started
stopped
enabled=yes|no 开机启动
示例:
启动并设置开机启动服务
ansible dbs -m service -a 'name=httpd state=started enabled=yes'
关闭:
ansible dbs -m service -a 'name=httpd state=stopped enabled=no'
user: 用户管理模块
常用选项:
create_home=no 不创建家目录,默认yes
comment="" 描述信息
group= 主组
groups= 附加组
home= 手工设置家目录位子
name= 用户名
password= 密码
shell= shell类型
system=yes|no 是否是系统该用户
uid= uid
state=absent 删除用户,默认present
remove=yes 删除家目录,state=absent时使用
示例:
新建账号:
ansible dbs -m user -a 'name=lily uid=1080 home=/data/home/ comment="a beauty girl" groups=root'
删除账号:
ansible dbs -m user -a 'name=lily state=absent remove=yes'
group: 组管理模块
常用选项:
gid= gid
name= 组名
state=absent 删除 默认present
system=yes|no 是否系统账号,默认no
ansible系列命令:----------------------------------------------------------------
ansible
ansible-doc
ansible-playbook
ansible-vault
ansible-console
ansible-galaxy
ansible-pull
ansible-galaxy:
连接https://galaxy.ansible.com 下载相应的roles
查看已安装的galaxy
ansible-galaxy list [role_name]
ansible-galaxy list "Stouts grafana"
安装roles
ansible-galaxy install "Stouts grafana"
删除roles
ansible-galaxy remove "Stouts grafana"
ansible-pull:
推送命令至远程,效率无限提升,对运维要求较高
ansible-playbook:
类似shell,用来解释执行编写playbook文件,通常是yml后缀,如:
ansible-playbook hello.yml
[root@Centos6 ~]#cat hello.yml
---
- hosts: dbs
remote_user: root
tasks:
- name: hello
command: /usr/bin/wall hello there
ansible-vault:
功能:加密解密yml文件
ansible-vault [create|encrypt|decrypt|edit|view|rekey]
ansible-vault encrypt hello.yml 加密
ansible-vault view hello.yml 可以查看加密文件,需要输入密码
ansible-vault decrypt hello.yml 解密
ansible-vault edit hello.yml 编辑加密文件
ansible-vault rekey hello.yml 修改口令
ansible-vault create new.yml 创建新文件
ansible-console:2.0+新增,可交互执行命令,支持tab
工作台介绍:
[root@Centos6 ~]#ansible-console
Welcome to the ansible console.
Type help or ? to list commands.
root@all (5)[f:5]$
执行用户@当前操作的主机组(当前组的主机数量)[f:并发数]$
设置并发数: forks n 例如:forks 10
切换组: cd 主机组 例如:cd webs
列出当前组主机列表:list
列出所有的内置命令:?或help
退出: exit
示例:
root@dbs (2)[f:5]$ shell ls /data
root@dbs (2)[f:5]$ yum name=htop state=present
palybook:------------------------------------------------------------------------
playbook示例: 安装并启动httpd服务
---
- hosts: dbs
remote_user: root
tasks:
- name: install package
yum: name=httpd
- name: tempalte conf6
template: src=httpd.conf6.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "6"
notify: reload conf
- name: tempalte conf7
template: src=httpd.conf7.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "7"
notify: reload conf
- name: test web6
when: ansible_distribution_major_version == "6"
shell: echo "welcome to web centos6" > /var/www/html/index.html
- name: test web7
when: ansible_distribution_major_version == "7"
shell: echo "welcome to web centos7" > /var/www/html/index.html
- name: start service
service: name=httpd state=started
- name: testnet
shell: ping -c2 -w2 172.20.0.1
tags: testnet
handlers:
- name: reload conf
service: name=httpd state=reloaded
palybook:
一组ansible指令的集合,类似shell脚本
采用YAML语言编写
一般使用.yml 后缀 如:hello.yml
通过ansible-playbook解释执行,如ansible-playbook hello.yml
YAML语言:
可读性好
和脚本语言的交互性好
使用实现语言的数据模型
有一个一致的信息模型
易于实现
可以基于流来处理
表达能力强,扩展性好
官方地址:http://www.yaml.org
YAML语法简介:
在单一档案中,可用连续三个连字号(---)区分多个档案。另外,还有选择性的
连续三个点号(...)来表示档案结尾
次行开始正常些playbook的内容,一般建议写明该playbook的功能
使用#号注释代码
缩进必须是统一的,不能空格和tab混用
缩进的级别必须一致,同样的缩进表示同样的级别,程序判断配置的级别是通过缩进
结合换行来实现
k/v(键值对)的值可同行写也可以换行些,同行使用: 分隔
v可以是个字符串,也可以是另一个列表
一个完整的代码块功能需要最少元素包括name:task
一个name只能包括一个task
文件后缀通常为yml或yaml
YAML列表:
list:列表,其所有元素均使用 - 打头
列表的每一项可以有多行,如
- name:
yum:
notify:
when:
YAML字典:
dictionary:字典,通常由多个key与value构成
如:
- { name: install httpd,yum: name=httpd }
playbook核心元素:
hosts: 执行的远程主机列表
remote_user:指定用户身份
tasks: 任务集
varniables:内置变量或自定义变量在playbook中调用
templates: 模板,可以替换模板文件中的变量并实现一些简单逻辑的文件
handlers: 和notify结合使用,如果notify:A当前task执行发生修改操作,
则触发执行handlers中定义的A操作
tags: 标签,指定某条任务执行,用于选择运行playbook中的部分代码。
如:
ansible-playbook -t install httpd.yml
注意: 多个task可以使用同一个tags
hosts: 列表必须事先定义在主机清单中
可以使用 *,:,:&,:!来定义列表
如:
webs:dbs
webs:!dbs
remote_user:
指明执行命令的用户身份
且支持在task中以sudo方式执行
例如:
- host: webs
remote_user: root
tasks:
- name: test ping
ping:
remote_user: hello
sudu: yes
sudu_user: lily 如不知指明,默认sudo为root
task列表和action:
play的主体部分是task list,task list 中的各任务按次序逐个在host中指定
的所有主机上执行,即在所有主机上完成第一个任务后在开始第二个。在运行自上
而下某playbook时,如果中途发生错误,多有已执行任务都会回滚,因此,在更正
playbook后重新执行一次即可
task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量,模块执行是
幂等的,这意味着多次执行是安全的,因为其结果均一致
每个task都应该有其name,用于playbook的执行结果输出
如果未提供name,则action的结果将用于输出
格式:
1 action: module arguments
2 module: arguments
某任务的状态在运行后卫changed时,可通过notify通知给相应的handlers任务。
任务可通过tags打标签,而后可在ansible-playbook命令中使用 -t 选项指定执行
如果命令或脚本的退出码不为零,可以使用下方方式使整个playbook继续执行,而不是回滚
tasks:
- name: test
shell: false ||/bin/true
或者:
tasks:
- name: test
shell: false
ignore_error: true
运行playbook:
ansible-playbook name.yml
常用选项:
--check|-C 只检测可能发生的改变,不真正执行
--list-hosts 列出运行任务的主机
--limit 主机列表,只针对主机列表中的主机执行
-v -vv -vvv 显示详细信息
-t tags 只执行tags标记的task
playbook变量:
变量名:仅能由字母、数字和下划线组成,且只能以字母开通
变量来源:
1 ansible setup facts 远程主机的所有变量都可直接调用
ansible all -m setup list
ansible webs -m setup |grep cpu
"ansible_processor_vcpus": 1, cpu数量
ansible all -m setup|grep distribution
ansible_distribution_major_version 主版本号
ansible all -m setup |grep os_family
"ansible_os_family": "RedHat", 版本体系
ansible all -m setup |grep memtotal
"ansible_memtotal_mb": 980, 内存大小
2 在/etc/ansible/hosts中定义
普通变量:主机组中主机单独定义,优先级高于公共变量
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
公共(组)变量:针对主机组中所有主机定义统一变量:
[websvrs:vars]
http_port=808
mark=“_”
[websrvs]
192.168.99.101 http_port=8080 hname=www1
192.168.99.102 http_port=80 hname=www2
3 通过命令行指定变量,优先级最高
ansible-playbook -e varname=VALUE
4 在playbook中定义
vars:
- var1: value1
- var2: value2
5 在role中定义
6 使用专用变量文件:
vars.yml
var1: httpd
var2: vsftpd
test.yml
---
- host: webs
remote_user: root
vars_files:
- vars.yml
ansible变量优先级:
命令行 -e --> playbook定义的变量 -->主机清单中定义的变量
变量定义:
key=value1
http_port=80
变量调用方式:
通过{{ variable_name }}调用变量,且变量名前后必须有空格,有时用
"{{ variable_name }}" 才生效
示例:
vim testvar.yml
---
- hosts: dbs
remote_user: root
vars:
- var1: httpd
- var2: vsftpd
tasks:
- name: status
service: name={{ var1 }} state=reloaded
- name: rpm status
shell: rpm -q "{{ var2 }}"
ansible-playbook -e 'var1=dhcp var2=tftp' testvar.yml
在配置文件中指定变量
ansible websvrs –m hostname –a ‘name={{ hname }}{{ mark }}{{ http_port }}’
在命令行执行变量
ansible websvrs –e http_port=8000 –m hostname –a ‘name={{ hname }}{{ mark }}{{ http_port }}’
hostvars可以在当前操作主机中输出其他主机中的facts信息
--- - name: "play 1: Gather facts of test71" hosts: test71 remote_user: root - name: "play 2: Get facts of test71 when operating on test70" hosts: test70 remote_user: root tasks: - debug: msg: "{{hostvars['test71'].ansible_ens35.ipv4}}"
inventory_hostname 获取被操作的当前主机主机名(inventory文件中的名称)
[test_group] 10.1.1.60 test70.zsythink.net ansible_host=10.1.1.70 test71 anisble_host=10.1.1.71
执行结果
# ansible test_group -m debug -a "msg={{inventory_hostname}}" test70.zsythink.net | SUCCESS => { "changed": false, "msg": "test70.zsythink.net" } 10.1.1.60 | SUCCESS => { "changed": false, "msg": "10.1.1.60" } test71 | SUCCESS => { "changed": false, "msg": "test71" }
play_hosts获取当前play所操作的所有主机的主机名列表
--- - hosts: test70,test71 remote_user: root gather_facts: no tasks: - debug: msg: "{{play_hosts}}"
执行得到
TASK [debug] ************************* ok: [test70] => { "msg": [ "test71", "test70" ] } ok: [test71] => { "msg": [ "test71", "test70" ] }
4 groups 获取play操作的清单中分组列表
5 group_names 获取当前操作的主机的分组名
转自文章:http://www.zsythink.net/archives/2715
templates:
文本文件,嵌套有脚本
使用jinja2语言,使用字面量,有下面形式:
字符串:使用单引号或双引号
数字:整数,浮点数
列表:[item1,item2..]
元组:(item1,item2,...)
字典:{key1:value1,key2:value2,..}
布尔型:true/false
算术运算:+,-,*,/,//,%,**
比较操作:==,!=,>,>=,<,<=
逻辑运算:and or not
流表达式: for if when
根据模块文件动态生成对应的配置文件
mkdir ansible/templates
在playbook同级的目录中建立templates目录,模板文件必须位于templates目录下,后缀为.j2
使用时src就可以使用默认路径,src=文件名,
template模块只能在playbook使用,不能在ansible命令行使用
使用template同步配置文件,在.j2 文件中支持使用ansible setup模块中的所有变量
且支持算术运算
例如:
Listen {{ ansible_memtotal_mb//7 }}
Listen {{ ansible_memtotal_mb+6 }}
注意:不支持两个变量之间的算术运算:
例如:
Listen {{ ansible_memtotal_mb//ansible_distribution_major_version }}
Listen {{ ansible_memtotal_mb+ansible_distribution_major_version }}
when:
when语句使用jinja2表达式语法
用在playbook中,只有当when:语句为真时,此task才执行
例如:
- name: tempalte conf7
template: src=httpd.conf7.j2 dest=/etc/httpd/conf/httpd.conf
when: ansible_distribution_major_version == "7"
with_items: 迭代
当有需要重复性执行的任务时,可以使用迭代机制
对迭代项的引用,固定变量名为"item"
要在task中使用with_items给定要迭代的元素列表
列表格式
字符串
字典
示例:
[root@Centos6 ~/ansible]#vim createuser.yml
---
- hosts: dbs
remote_user: root
tasks:
- name: create user
user: name={{ item }}
tags: create
with_items:
- user1
- user2
- user3
- name: delete user
user: name={{ item }} state=absent remove=yes
tags: delete
with_items:
- user1
- user2
- user3
示例2:
vim test_item1.yml
---
- hosts: dbs
remote_user: root
tasks:
- name: touch some file
file: name=/data/{{ item }} state=touch
with_items:
- file1
- file2
- file3
tags: touch
- name: delete some files
file: name=/data/{{ item }} state=absent
with_items:
- file1
- file2
- file3
tags: del
item 嵌套:
例如: 要求新建3个目录dir1,dir2,dir3
并且新建3个空文件,file1,file2,file3分别位于对应的目录
vim test_items2.yml
---
- hosts: dbs
remote_user: root
tasks:
- name: mkdir
file: name=/data/{{ item }} state=directory
with_items:
- dir1
- dir2
- dir3
- name: touch file
file: name=/data/{{ item.dir }}/{{ item.file }} state=touch
with_items:
- { dir: dir1,file: file1 }
- { dir: dir2,file: file2 }
- { dir: dir3,file: file3 }
loop循环
下面是一个简单的标准loop循环的例子:
[root@localhost playbook]$vim loop-useradd.yaml --- - hosts: all tasks: - name: add several users user: name: "{{ item }}" state: present groups: "wheel" loop: - testuser1 - testuser2
如果变量是一个Yaml列表,则可以循环这个列表:
loop: "{{ somelist }}"
所以上面的例子也可以改成:
--- - hosts: all tasks: - name: add several users user: name: "{{ item }}" state: present groups: "wheel" loop: [ testuser3,testuser4]
循环实际上相当于下面的语句:
- name: add user testuser1 user: name: "testuser1" state: present groups: "wheel" - name: add user testuser2 user: name: "testuser2" state: present groups: "wheel"
也可以循环一个字典,例如:
- name: add several users user: name: "{{ item.name }}" state: present groups: "{{ item.groups }}" loop: - { name: 'testuser1', groups: 'wheel' } - { name: 'testuser2', groups: 'root' }
更多loop和with_items循环参考https://www.dazhuanlan.com/2019/12/19/5dfb1edecdfcc/
playbook中的for和if:
说明: 使用jinja2 语法:
仅适合.j2 文件
{% for p in ports %}
代码段
{% endfor %}
{% if p is defined %}
代码段
{% endif %}
类似shell中的for使用,其中p可以任意指定, ports 代表变量,需要与playbook主
脚本中的vars:下的变量一致
if 为真 代码段执行,反之不执行 defined :被定义
示例1:
yml vim for1.yml
---
- hosts: dbs
remote_user: root
vars:
- ports:
- 1001
- 1002
- 1003
tasks:
- name: copy file
template: src=for1.j2 dest=/data/for1.conf
j2 vim templates/for1.j2
{% for p in ports %}
server {
listen {{ p }}
}
{% endfor%}
结果: [root@2-centos6 /data]#cat for1.conf
server {
listen 1001
}
server {
listen 1002
}
server {
listen 1003
}
示例2:
yml vim for2.yml
---
- hosts: dbs
remote_user: root
vars:
- infos:
- group: boy
name: tom
age: 18
likes: read
- group: girl
name: lily
age: 19
likes: boy
- group: man
name: big dog
age: 35
likes: girl
- group: women
name: cherry
age: 41
likes: monny
tasks:
- name: copy file
template: src=for2.j2 dest=/data/for2.conf
j2 vim tempaltes/for2.conf
{% for p in infos %}
group: {{ p.group }}
the winner is:
name: {{ p.name }}
age: {{ p.age }}
likes: {{ p.likes }}
{% endfor %}
结果: [root@2-centos6 /data]#cat for2.conf
group: boy
the winner is:
name: tom
age: 18
likes: read
group: girl
the winner is:
name: lily
age: 19
likes: boy
group: man
the winner is:
name: big dog
age: 35
likes: girl
group: women
the winner is:
name: cherry
age: 41
likes: monny
示例3:
yml: vim for3.yml
---
- hosts: dbs
remote_user: root
vars:
- webs:
- addr: 10.magedu.com
port: 810
- addr: 20.magedu.com
port: 820
rootdir: /data/root20/
- addr: 30.magedu.com
port: 830
rootdir: /data/root30/
tasks:
- name: copy file
template: src=for3.j2 dest=/data/for3.conf
j2: vim templates/for3.j2
website list:
{% for p in webs %}
website: {{ p.addr }}
port: {{ p.port }}
{% if p.rootdir is defined %}
rootdir: {{ p.rootdir }}
{% endif%}
{% endfor%}
结果: [root@2-centos6 /data]#cat for3.conf
website list:
website: 10.magedu.com
port: 810
website: 20.magedu.com
port: 820
rootdir: /data/root20/
website: 30.magedu.com
port: 830
rootdir: /data/root30/
roles:---------------------------------------------------------------------------
将原本playbook中的各个tasks,handlers,vars,拆分成单独的小模块
而playbook主文件:
main.yml中使用
- include:(旧)
- import_tasks: (新)
调用模块
目录编排:
[root@Centos6 ~/ansible/roles]#tree
.
└── nginx
├── files
├── handlers
├── tasks
├── templates
└── vars
roles下新建目录即为项目名称:需包含以下子目录
files/: 存放copy或script模块等调用的文件
templates/: template模块查找所需要的模板文件的目录
tasks/: 定义task,role的基本元素,至少应该包含一个名为main.yml的文件,
其他的文件需要在此文件中通过include包含
handlers/: 至少应该包含一个名为main.yml的文件,其他的文件需要在此文件中通过include包含
vars/: 定义变量。至少应该包含一个名为main.yml的文件
其他的文件需要在此文件中通过include包含
meta/: 定义当前角色的特殊设定及其依赖关系,至少应该包含一个名为main.yml的文件
其它文件需在此文件中通过include进行包含
default/: 设定默认变量时使用此目录中的main.yml文件
创建role的步骤:
1 创建以roles命名的目录
2 在roles目录中分别创建以各角色名称命名的目录,如nginx
3 在每个角色命名的目录中分别创建files,handlers,meta,tasks,templates和vars目录
如用不到的空目录,也不可不用创建
4 角色编辑
5 在playbook文件中,调用各角色
role创建示例:
[root@Centos6 ~/ansible/roles]#tree
.
└── nginx
├── files
│ └── f1
├── handlers
│ └── main.yml
├── tasks
│ ├── copyfile.yml
│ ├── groupadd.yml
│ ├── main.yml
│ ├── start.yml
│ ├── templ.yml
│ ├── useradd.yml
│ └── yum.yml
├── templates
│ └── nginx.conf.j2
└── vars
role创建:
cd roles/nginx
cd tasks/
vim groupadd.yml
- name: create group nginx
group: name=nginx system=yes gid=80
vim useradd.yml
- name: add user nginx
user: name=nginx uid=80 system=yes shell=/sbin/nologin
vim yum.yml
- name: install package
yum: name=nginx
vim templ.yml
- name: copy conf
template: src=nginx.conf.j2 dest=
when: ansible_distribution_major_version == "6"
notify: reload conf
vim copyfile.yml
- name: copy file
copy: src=f1 dest=/var/lib/nginx
vim start.yml
- name: start service
service: name=nginx state=started enabled=yes
vim main.yml
- import_tasks: groupadd.yml
- import_tasks: useradd.yml
- import_tasks: yum.yml
- import_tasks: templ.yml
- import_tasks: copyfile.yml
- import_tasks: start.yml
cd handlers/
vim mian.yml
- name: reload conf
service: name=nginx state=reloaded
cp /etc/nginx/nginx.conf templates/nginx.conf.j2
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus*10 }};
touch files/f1
role调用:调用roles的playbook 要与roles目录在一个目录中
vim nginx.role.yml
---
- hosts: dbs
remote_user: root
roles:
- role: nginx
引用另外一个role中的单个任务,如下,使用完整路径引用即可
vim main.yml
- include: group.yml
- include: user.yml
- include: yum.yml
- include: templ.yml
- include: start.yml
- include: roles/httpd/tasks/copyfile.yml
role调用中的tags使用:
vim some_role.yml
- hosts: webs
remote_user: root
roles:
- { role: nginx,tags: ['web','nginx'] }
- { role: httpd,tags: ['web','httpd'],when: ansible_distribution_major_version == "7" }
- { role: app,tags: ['app'] }
ansible-playbook -t web some_role.yml 挑标签执行
在role中使用tag的另外一种方式,和上面其实一样
tasks: - name: view /tmp attr shell: ls -ld /tmp tags: ls,tmp,shell - name: exec id cmd shell: id tags: id,shell
ansible预置了5个特殊tag,分别为always、never(2.5版本中新加入的)、tagged、untagged、all
当我们把任务的tags的值指定为always时,那么这个任务就总是被执行,除非使用--skip-tags选项明确指定不执行对应的任务
--- - name: Add administrator user user: name: {{admin_user}} shell: /bin/bash state: present - name: Config administrator password for administrator user user: name: {{admin_user}} password: {{admin_user_passwd}} - name: Delete administrator user user: name: {{admin_user}} state: absent tag: delete_admin_user - name: Modify root passwd user: name: root password: {{root_passwd}} tag: modify_root_pwd,always
当执行ansible-playbook --tags delete_admin_user test.yaml后,不但执行了delete_admin_user的标签任务,还执行了拥有always标签的任务。
如果不想执行标签中包含always的任务,使用--skip-tags always选项,就会跳过所有包含always标签的任务。
对于never标签,其作用与always正好相反。
对于tagged、untagged、all三个特殊标签,并非像always和never一样作为标签值存在,而是在调用标签时使用
ansible-playbook --tags tagged test.yaml
上述命令表示只执行有标签的任务,没有任何标签的任务不会执行。
ansible-playbook --skip-tags tagged test.yaml
上述命令表示跳过包含标签的任务,即使拥有always标签,也会跳过。
ansible-playbook --tags untagged test.yaml
上述命令表示只执行没有标签的任务,但拥有always标签的任务,仍然会被执行。
ansible-playbook --skip-tags untagged test.yaml
上述命令表示跳过没有标签的任务。
在调用标签之前,如果要概览playbook中都有哪些标签,可以使用--list-tags选项。
ansible中include_tasks和import_tasks
区别一
- import_tasks(Static)方法会在playbooks解析阶段将父task变量和子task变量全部读取并加载
- include_tasks(Dynamic)方法则是在执行play之前才会加载自己变量
可能有点懵,举例说明
下面两个例子是test.yml里的task调用test2.yml,不同之处是一个使用import_tasks另一个使用include_tasks
import_tasks:在执行tasks之前,ansible解释器会先加载test.yml里的变量同时再加载test2.yml里的变量
include_tasks:ansible会在完全执行完test.yml里的task后才会加载test2.yml里的变量
区别二
- include_tasks方法调用的文件名称可以加变量
- import_tasks方法调用的文件名称不可以有变量
例子可参考:ansible中include_tasks和import_tasks
推荐资料:
http://galaxy.ansible.com
https://galaxy.ansible.com/explore#/
http://github.com/
http://ansible.com.cn/
https://github.com/ansible/ansible
https://github.com/ansible/ansible-examples