千家信息网

运维自动化工具之Ansible

发表于:2025-01-31 作者:千家信息网编辑
千家信息网最后更新 2025年01月31日,1 安装和入门1.1 ansible安装# ansible的安装方式有多种,比如编译安装、git方式和pip安装等,这里使用yum方式安装,此种方式需要现有epel源[root@ansible ~]#
千家信息网最后更新 2025年01月31日运维自动化工具之Ansible

1 安装和入门

1.1 ansible安装
# ansible的安装方式有多种,比如编译安装、git方式和pip安装等,这里使用yum方式安装,此种方式需要现有epel源[root@ansible ~]#yum install epel-release -y[root@ansible ~]#yum install ansible -y
1.2 确认安装
[root@ansible ~]#ansible --versionansible 2.9.1  config file = /etc/ansible/ansible.cfg  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']  ansible python module location = /usr/lib/python2.7/site-packages/ansible  executable location = /usr/bin/ansible  python version = 2.7.5 (default, Aug  7 2019, 00:51:29) [GCC 4.8.5 20150623 (Red Hat 4.8.5-39)]
1.3 ansible相关文件
1.3.1 配置文件
  • /etc/ansible/ansible.cfg 主配置文件,配置ansible的工作特性
  • /etc/ansible/hosts 主机清单
  • /etc/ansible/roles/ 存放角色的目录
1.3.2 ansible主配置文件说明
[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 #日志文件,建议启用#module_name = command #默认模块,可以修改为shell模块
1.3.3 inventory主机清单说明
  • ansible的主要功用在于批量主机操作,为了便捷地使用其中的部分主机,可以在inventory file中将其分组命名
  • 默认的inventory file为/etc/ansible/hosts
  • inventory file可以有多个,且也可以通过Dynamic Inventory来动态生成
1.3.4 主机清单文件格式
  • inventory文件遵循INI文件风格,中括号中的字符为组名。可以将同一个主机同时归并到多个不同的组中
  • 如果目标主机使用非默认的SSH端口,还可以在主机名称之后使用冒号加端口号的格式来标明
  • 如果主机名称遵循相似的命名模式,还可以使用列表的方式标识各主机
【范例】:
ntp.aliyun.com[webservers]www1.abc.com:2222www2.abc.com[dbservers]db1.abc.comdb2.abc.com[websrvs]www[1:100].example.com[dbsrvs]db-[a:f].example.com[appsrvs]10.0.0.[1:100]
1.4 ansible相关工具
  • /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界面与用户交互的执行工具
利用ansible实现管理的主要方式
  • Ad-Hoc 即利用ansible命令,主要用于临时命令使用场景
  • Ansible-playbook 主要用于长期规划好的,大型项目的场景,需要有前期的规划过程
1.4.1 ansible-doc
功能:用来显示各模块的帮助信息
语法:
ansible-doc [options] [module...]-l, --list #列出可用模块-s, --snippet #显示指定模块的playbook片段
【范例】:
#列出所有模块ansible-doc -l#查看指定模块帮助用法ansible-doc ping#查看指定模块帮助用法ansible-doc -s ping
1.4.2 ansible
功能:通过ssh协议,实现对远程主机的配置管理、应用部署、任务执行等功能,建议使用前配置好key验证
语法:
ansible  [-m module_name] [-a args]
选项说明:
--version #显示版本-m module #指定模块,默认为command-v #详细过程 -vv -vvv更详细--list-hosts #显示主机列表,可简写 --list-k, --ask-pass #提示输入ssh连接密码,默认Key验证-C, --check #检查,并不执行-T, --timeout=TIMEOUT #执行命令的超时时间,默认10s-u, --user=REMOTE_USER #执行远程执行的用户-b, --become #代替旧版的sudo 切换--become-user=USERNAME #指定sudo的runas用户,默认为root-K, --ask-become-pass #提示输入sudo时的口令
1.4.2.1 ansible的host-pattern
用于匹配被控制的主机的列表All :表示所有Inventory中的所有主机
【范例】:
# allansible all -m ping# *:通配符ansible "*" -m pingansible 192.168.1.* -m ping# 或关系ansible "websrvs:appsrvs" -m pingansible "192.168.1.1:192.168.1.2" -m ping# 逻辑与#在websrvs组并且在dbsrvs组中的主机ansible "websrvs:&dbsrvs" -m ping#逻辑非#在websrvs组,但不在dbsrvs组中的主机#注意:此处为单引号ansible 'websrvs:!dbsrvs' -m ping#综合逻辑ansible 'websrvs:dbsrvs:&appsrvs:!ftpsrvs' -m ping#正则表达式ansible "websrvs:&dbsrvs" -m pingansible "~(web|db).*\.abc\.com" -m ping
1.4.2.2 ansible命令执行过程
1.加载自己的配置文件 默认/etc/ansible/ansible.cfg2.加载自己对应的模块文件,如:command3.通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件4.给文件+x执行5.执行并返回结果6. 删除临时py文件,退出
1.4.2.3 ansible的执行状态
[root@ansible ~]#grep -A 14 '\[colors\]' /etc/ansible/ansible.cfg[colors]#highlight = white#verbose = blue#warn = bright purple#error = red#debug = dark gray#deprecate = purple#skip = cyan#unreachable = red#ok = green#changed = yellow#diff_add = green#diff_remove = red#diff_lines = cyan绿色:执行成功并且不需要做改变的操作黄色:执行成功并且对目标主机做变更红色:执行失败
1.4.2.4 ansible使用范例
#以zhangsan用户执行ping存活检测ansible all -m ping -u zhangsan -k#以zhangsan sudo至root执行ping存活检测ansible all -m ping -u zhangsan -k -b#以zhangsan sudo至lisi用户执行ping存活检测ansible all -m ping -u zhangsan -k -b --become-user=lisi#以zhangsan sudo至root用户执行lsansible all -m command -u zhangsan -a 'ls /root' -b --become-user=root -k -K
1.4.3 ansible-galaxy
功能:连接https://galaxy.ansible.com 下载相应的roles
【范例】:
#列出所有已安装的galaxyansible-galaxy list#安装galaxyansible-galaxy install geerlingguy.redis#删除galaxyansible-galaxy remove geerlingguy.redis
1.4.4 ansible-pull
功能:推送ansible的命令至远程,效率无限提升,对运维要求较高
1.4.5 ansible-playbook
功能:具用于执行编写好的playbook任务
【范例】:
ansible-playbook hello.ymlcat hello.yml---# hello world yml file- hosts: websrvs  remote_user: root  tasks:    - name: hello world      command: /usr/bin/wall hello world
1.4.6 ansible-vault
功能:用于加解密yml文件
语法:
ansible-vault [create|decrypt|edit|encrypt|rekey|view]
【范例】:
ansible-vault encrypt hello.yml #加密ansible-vault decrypt hello.yml #解密ansible-vault view hello.yml #查看ansible-vault edit hello.yml #编辑加密文件ansible-vault rekey hello.yml #修改口令ansible-vault create new.yml #创建新文件
1.4.7 ansible-console
功能:
可交互执行命令,支持tab补全,ansible 2.0+新增
提示符格式:
执行用户@当前操作的主机组 (当前组的主机数量)[f:并发数]$
常用子命令:
设置并发数: forks n 例如: forks 10切换组: cd 主机组 例如: cd web列出当前组主机列表: list列出所有的内置命令: ?或help
【范例】:
[root@ansible ansible]#ansible-consoleWelcome to the ansible console.Type help or ? to list commands.root@all (3)[f:5]$ list192.168.7.71192.168.7.72192.168.7.73root@all (3)[f:5]$ cd websrvsroot@websrvs (3)[f:5]$ list192.168.7.71192.168.7.72192.168.7.73root@websrvs (3)[f:5]$ yum name=httpd state=present
1.5 ansible常用模块
参考资料:https://docs.ansible.com/ansible/latest/modules/modules_by_category.html
1.5.1 command模块
功能:在被控机执行命令,ansible的默认模块,可忽略-m选项
注意:此模块的命令不支持$VARNAME < > | ; &等,需要用shell模块实现
【范例】:
[root@ansible ~]#ansible websrvs -m command -a 'echo 123.com | passwd --stdin zhangsan'[root@ansible ~]#ansible websrvs -a 'wall echo hello'
1.5.2 shell模块
功能:近似command,用shell执行命令
【范例】:
[root@ansible ~]#ansible websrvs -m shell -a 'echo 123.com | passwd --stdin zhangsan'
1.5.3 script模块
功能:在被控机上运行ansible服务器上的脚本
【范例】:
[root@ansible ~]#ansible websrvs -m script -a '/data/test.sh'
1.5.4 copy模块
功能:从ansible服务器复制文件到被控机
【范例】:
#如目标存在,默认覆盖,此处指定先备份[root@ansible ~]#ansible websrvs -m copy -a "src=/data/test.sh dest=/tmp/test2.sh owner=zhangsan mode=600 backup=yes" #指定内容,直接生成目标文件[root@ansible ~]#ansible websrvs -m copy -a "content='test content\n' dest=/tmp/test.txt"#复制/etc/下的文件,不包括/etc/目录自身ansible srv -m copy -a "src=/etc/ dest=/backup"# 注:如果目标目录不存在会自动创建
1.5.5 fetch模块
功能:从被控机提取文件至ansible主控端,copy相反,目前不支持目录
【范例】:
[root@ansible ~]#ansible websrvs -m fetch -a 'src=/tmp/test.txt dest=/data'
1.5.6 file模块
功能:管理文件和文件属性
【范例】:
# 创建空文件[root@ansible ~]#ansible websrvs -m file -a 'path=/data/test.sh state=touch owner=hechunping mode=755'# 创建目录[root@ansible ~]#ansible websrvs -m file -a 'path=/data/dir1 state=directory owner=hechunping group=hechunping'# 创建软连接[root@ansible ~]#ansible websrvs -m file -a 'src=/data/test.sh dest=/data/test.sh-link state=link'
1.5.7 unarchive模块
功能:解包解压缩
实现有两种用法:1.将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes2.将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数:
  • copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件
  • remote_src:和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible主机上
  • src:源路径,可以是ansible主机上的路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no
  • dest:远程主机上的目标路径
  • mode:设置解压缩后的文件权限
【范例】:
# 将ansible服务器上的压缩文件解压缩到被控机上[root@ansible ~]#ansible websrvs -m unarchive -a 'src=/data/test.sh.tar.gz dest=/usr/local'# 解压被控机上的压缩文件到它本地[root@ansible ~]#ansible 192.168.7.72 -m unarchive -a 'src=/data/test.sh.tar.gz dest=/usr/local copy=no mode=0777'# 解压网络压缩文件到被控机[root@ansible ~]#ansible websrvs -m unarchive -a 'src=https://nginx.org/download/nginx-1.14.2.tar.gz dest=/usr/local copy=no'
1.5.8 archive模块
功能:打包压缩
【范例】:
[root@ansible ~]#ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=hechunping mode=0600'
1.5.9 hostname模块
功能:管理主机名
【范例】:
[root@ansible ~]#ansible 192.168.7.71 -m hostname -a 'name=web'
1.5.10 cron模块
功能:计划任务
支持时间:minute,hour,day,month,weekday
【范例】:
# 创建任务,周一至周五每天2:30执行mysql_backup.sh脚本ansible dbsrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backupmysql" job=/root/mysql_backup.sh'# 禁用计划任务ansible dbsrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backupmysql" job=/root/mysql_backup.sh disabled=yes'# 启用计划任务ansible dbsrvs -m cron -a 'hour=2 minute=30 weekday=1-5 name="backupmysql" job=/root/mysql_backup.sh disabled=no'# 删除任务ansible dbsrvs -m cron -a "name='backup mysql' state=absent"
1.5.11 yum模块
功能:管理软件包
【范例】:
# 安装[root@ansible ~]#ansible websrvs -m yum -a 'name=redis state=present'# 删除[root@ansible ~]#ansible websrvs -m yum -a 'name=redis state=absent'
1.5.12 service模块
功能:管理服务
【范例】:
# 启动,并设置开机启动[root@ansible ~]#ansible websrvs -m service -a 'name=redis state=started enabled=yes'# 停止[root@ansible ~]#ansible websrvs -m service -a 'name=redis state=stopped'# 重启[root@ansible ~]#ansible websrvs -m service -a 'name=redis state=restarted'
1.5.13 user模块
功能:管理用户
【范例】:
# 创建[root@ansible ~]#ansible websrvs -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'# 删除用户及其及目录等数据[root@ansible ~]#ansible websrvs -m user -a 'name=user1 state=absent remove=yes'
1.5.14 group模块
功能:管理组
【范例】:
# 创建[root@ansible ~]#ansible websrvs -m group -a 'name=nginx gid=88 system=yes'# 删除[root@ansible ~]#ansible websrvs -m group -a 'name=nginx state=absent'
1.5.15 setup模块
功能:返回系统状态信息
【范例】:
ansible websrvs -m setupansible websrvs -m setup -a "filter=ansible_nodename"ansible websrvs -m setup -a "filter=ansible_hostname"ansible websrvs -m setup -a "filter=ansible_domain"ansible websrvs -m setup -a "filter=ansible_memtotal_mb"ansible websrvs -m setup -a "filter=ansible_memory_mb"ansible websrvs -m setup -a "filter=ansible_memfree_mb"ansible websrvs -m setup -a "filter=ansible_os_family"ansible websrvs -m setup -a "filter=ansible_distribution_major_version"ansible websrvs -m setup -a "filter=ansible_distribution_version"ansible websrvs -m setup -a "filter=ansible_processor_vcpus"ansible websrvs -m setup -a "filter=ansible_all_ipv4_addresses"ansible websrvs -m setup -a "filter=ansible_architecture"

2 Playbook

2.1 Playbook介绍
1.playbook 剧本是由一个或多个"play"组成的列表2.play的主要功能在于将预定义的一组主机,装扮成事先通过ansible中的task定义好的角色。Task实际是调用ansible的一个module,将多个play组织在一个playbook中,即可以让它们联合起来,按事先编排的机制执行预定义的动作3.Playbook文件是采用YAML语言编写的
2.2 Playbook核心元素
  • Hosts 执行的远程主机列表
  • Tasks 任务集
  • Variables 内置变量或自定义变量在playbook中调用
  • Templates 模板,可替换模板文件中的变量并实现一些简单逻辑的文件
  • Handlers 和 notify 结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行
  • tags 标签 指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片断
2.2.1 hosts组件
功能:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机,须事先定义在主机清单中
one.example.comone.example.com:two.example.com192.168.1.50192.168.1.*Websrvs:dbsrvs #或者,两个组的并集Websrvs:&dbsrvs #与,两个组的交集websrvs:!dbsrvs #在websrvs组,但不在dbsrvs组
【范例】:
- hosts: websrvs:dbsrvs
2.2.2 remote_user组件
功能:可用于host和task中。也可以指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用sudo_user指定sudo时切换的用户
- hosts: websrvs  remote_user: root  tasks:    - name: test connection      ping:      remote_user: zhangsan      sudo: yes #默认sudo为root      sudo_user: lisi #sudo为lisi
2.2.3 task列表和action组件
1.play的主体部分是task list,task list中有一个或多个task,各个task按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个task后,再开始第二个task2.task的目的是使用指定的参数执行模块,而在模块参数中可以使用变量。模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致3.每个task都应该有其name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤。如果未提供name,则action的结果将用于输出
task两种格式:
1)action:module arguments2)module:arguments  (推荐使用)
注:shell和command模块后面跟命令,而非key=value
【范例】:
---- hosts: websrvs  remote_user: root  tasks:    - name: install httpd      yum: name=httpd    - name: start httpd      service: name=httpd state=started enabled=yes
2.2.4 其它组件
某任务的状态在运行后为changed时,可通过"notify"通知给相应的handlers任务可以通过"tags"打标签,可在ansible-playbook命令上使用-t指定进行调用
2.2.5 shell scripts VS playbook案例
### 安装Apache ####SHELL脚本实现#!/bin/bashyum install --quiet -y httpd# 复制配置文件cp /tmp/httpd.conf /etc/httpd/conf/httpd.confcp/tmp/vhosts.conf /etc/httpd/conf.d/# 启动Apache,并设置开机启动systemctl enable --now httpd#Playbook实现---- hosts: websrvs  remote_user: root  tasks:    - name: "安装Apache"      yum: name=httpd    - name: "复制配置文件"      copy: src=/tmp/httpd.conf dest=/etc/httpd/conf/    - name: "复制配置文件"      copy: src=/tmp/vhosts.conf dest=/etc/httpd/conf.d/    - name: "启动Apache,并设置开机启动"      service: name=httpd state=started enabled=yes
2.3 Playbook命令
语法:
ansible-playbook  ... [options]
常用选项
--check -C #只检测可能会发生的改变,但不真正执行操作--list-hosts #列出运行任务的主机--list-tags #列出tag--list-tasks #列出task--limit 主机列表 #只针对主机列表中的主机执行-v -vv -vvv #显示过程
【范例】:
ansible-playbook file.yml --check #只检测ansible-playbook file.ymlansible-playbook file.yml --limit websrvs
2.4 Playbook初步
【范例】:yum安装httpd
#install_httpd.yml---- hosts: websrvs  remote_user: root  tasks:    - name: "安装httpd"      yum: name=httpd state=present    - name: "复制httpd.conf配置文件"      copy: src=files/httpd.conf dest=/etc/httpd/conf    - name: "启动httpd,并设置开机启动"      service: name=httpd state=started enabled=yes
【范例】:卸载yum安装的httpd
#remove_httpd.yml---- hosts: websrvs  remote_user: root  tasks:    - name: remove httpd package      yum: name=httpd state=absent                         - name: remove apache user      user: name=apache state=absent    - name: remove data file      file: name=/etc/httpd state=absent
【范例】:创建MySQL组和用户
---# 创建MySQL组和用户- hosts: dbsrvs  remote_user: root  tasks:  - {name: 创建组, group: name=mysql system=yes gid=306}     - name: 创建用户    user: name=mysql shell=/sbin/nologin system=yes group=mysql uid=306 create_home=no
【范例】:安装mysql-5.6.46-linux-glibc2.12
[root@ansible ~]#ll /data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz -rw-r--r-- 1 root root 403177622 Dec  4 13:05 /data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz[root@ansible ~]#cat /data/ansible/files/my.cnf [mysqld]socket=/tmp/mysql.sockuser=mysqlsymbolic-links=0datadir=/data/mysqlinnodb_file_per_table=1log-bin[client]port=3306socket=/tmp/mysql.sock[mysqld_safe]log-error=/var/log/mysqld.log[root@ansible ~]#cat /data/ansible/install_mysql.yml ---# install mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz- hosts: websrvs  remote_user: root  tasks:    - name: "安装依赖包"      yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long    - name: "创建mysql组"      group: name=mysql gid=306    - name: "创建mysql用户"      user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql    - name: "将本地二进制安装包解压缩到目标主机的/usr/local目录下,并修改属主、属组为root"      unarchive: src=/data/ansible/files/mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local owner=root group=root    - name: "为解压缩的二进制包目录创建软连接"      file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link    - name: "初始化数据库"      shell: chdir=/usr/local/mysql ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql      tags: data    - name: "复制本地my.cnf配置文件到被控主机"      copy: src=/data/ansible/files/my.cnf dest=/etc/my.cnf    - name: "复制本地的mysql服务脚本到被控主机的/etc/init.d目录下"      shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld    - name: "启动mysql服务,并且设置开机启动"      shell: /etc/init.d/mysqld start;chkconfig --add mysqld;chkconfig mysqld on      tags: service    - name: "将mysql的二进制可执行程序添加到PATH变量"      copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh    - name: "执行安全加固脚本"      script: /data/ansible/files/secure_mysql.sh      tags: script
2.5 Playbook中使用handlers和notify
Handlers本质是task list ,其中的task与前述的task并没有本质上的不同,用于当关注的资源发生变化时,才会采取一定的操作.Notify对应的action可用于在每个play的最后被触发,这样可避免多次有改变发生时每次都执行指定的操作,仅在所有的变化发生完成后一次性地执行指定操作。在notify中列出的操作称为handler,也即notify中调用handler中定义的操作
【范例】:
---- hosts: websrvs  remote_user: root  tasks:    - name: "安装httpd"      yum: name=httpd state=present    - name: "复制httpd.conf配置文件,并且重启httpd"      copy: src=files/httpd.conf dest=/etc/httpd/conf      notify: restart httpd    - name: "启动httpd,并设置开机启动"      service: name=httpd state=started enabled=yes  handlers:    - name: restart httpd      service: name=httpd state=restarted
2.6 Playbook中使用tags组件
功能:在playbook文件中,可以利用tags组件,为特定task指定标签,当在执行playbook时,可以只执行特定tags的task,而非整个playbook文件
【范例】:
[root@ansible ansible]#cat install_httpd.yml---- hosts: websrvs  remote_user: root  tasks:    - name: "安装httpd"      yum: name=httpd state=present    - name: "复制httpd.conf配置文件,并且重启httpd"      copy: src=files/httpd.conf dest=/etc/httpd/conf      tags: conf                          - name: "启动httpd,并设置开机启动"      service: name=httpd state=started enabled=yes      tags: service[root@ansible ansible]#ansible-playbook -t conf,service install_httpd.yml
2.7 Playbook中使用变量
变量名:仅能由字母、数字和下划线组成,且只能以字母开头
变量定义:
key=value
【范例】:
http_port=80
变量调用方式:
通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用"{{ variable_name }}"才生效
变量来源
1)ansible的setup facts远程主机的所有变量都可以直接调用
2)通过命令行指定变量,优先级最高
ansible-playbook -e varname=value
3)在playbook文件中定义
vars:  - var1: value1  - var2: value2
4)在独立的变量yml文件中定义
- hosts: all  vars_files:    - vars.yml
5)在/etc/ansible/hosts文件中定义
主机(普通)变量:主机组中主机单独定义,优先级高于公共变量组(公共)变量:针对主机组中所有主机定义同一变量
6)在role中定义
2.7.1 使用setup模块中变量
【范例】:
[root@ansible ansible]#cat var.yml ---# var.yml- hosts: websrvs  remote_user: root  tasks:    - name: "创建日志文件"      file: name=/var/log/{{ ansible_fqdn }} state=touch[root@ansible ansible]#ansible-playbook var.yml 
2.7.2 在playbook命令行中定义变量
【范例】:
[root@ansible ansible]#cat var.yml---# var.yml- hosts: websrvs  remote_user: root  tasks:    - name: "安装包变量"      yum: name={{ pkname }} state=absent[root@ansible ansible]#ansible-playbook -e pkname=httpd var.yml
2.7.3 在playbook文件中定义变量
【范例】:
[root@ansible ansible]#cat var.yml---- hosts: websrvs  remote_user: root  vars:    - username: user1    - groupname: group1  tasks:    - name: create group      group: name={{ groupname }} state=present    - name: create user      user: name={{ username }} state=present[root@ansible ansible]#ansible-playbook var.yml
2.7.4 使用变量文件
可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高
【范例】:
[root@ansible ansible]#cat vars.yml  ---# variables filevar1: vsftpdvar2: nginx[root@ansible ansible]#cat var2.yml ---- hosts: websrvs  remote_user: root  vars_files: vars.yml  tasks:    - name: "vsftpd日志文件"      file: name=/data/{{ var1 }}.log state=touch    - name: "nginx日志文件"      file: name=/data/{{ var2 }}.log state=touch
2.7.5 主机清单文件中定义变量
2.7.5.1 主机变量
在inventory主机清单文件中为指定的主机定义变量以便于在playbook中使用
【范例】:
[websrvs]www1.abc.com http_port=80www2.abc.com http_port=8080
2.7.5.2 组(公共)变量:
在inventory主机清单文件中赋予给指定组内所有主机在playbook中可用的变量
【范例】:
[websrvs]www1.abc.comwww2.abc.com[websrvs:vars]ntp_server=ntp.aliyun.com
【范例】:
[root@ansible ansible]#vim /etc/ansible/hosts[websrvs]192.168.7.71 hname=ansible192.168.7.72 hname=web1192.168.7.73 hname=web2[websrvs:vars]http_port=808mark="-"[root@ansible ansible]#ansible websrvs -m hostname -a 'name={{ hname }}{{ mark }}{{ http_port }}'# 命令行指定变量[root@ansible ansible]#ansible websrvs -e http_port=8000 -m hostname -a 'name={{ hname }}{{ mark }}{{ http_port }}'
2.8 Template模板
模板是一个文本文件,可以作为生成文件的模板,并且模板文件中还可以嵌套jinja语法
2.8.1 jinja语言
jinja2语言使用字面量,有下面形式:字符串:使用单引号或双引号数字:整数,浮点数列表:[item1,item2,...]元组:(item1,item2,...)字典:{key1:value1,key2:value2,...}布尔型:true/false算术运算:+, -, *, /, //, %, **比较操作:==, !=, >, >=, <, <=逻辑运算:and,or,not流表达式:For,If,Whenjinja2相关说明:字面量:表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World"双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不一样的算术运算:Jinja 允许用计算值。支持下面的运算符+:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2-:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1/:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 {{ 0.5 }}//:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2%:计算整数除法的余数。 {{ 11 % 7 }} 等于 4*:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ '=' * 80 }}会打印 80 个等号的横条\**:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8比较操作符== 比较两个对象是否相等!= 比较两个对象是否不等> 如果左边大于右边,返回 true>= 如果左边大于等于右边,返回 true< 如果左边小于右边,返回 true<= 如果左边小于等于右边,返回 true逻辑运算符对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式and 如果左操作数和右操作数同为真,返回 trueor 如果左操作数和右操作数有一个为真,返回 truenot 对一个表达式取反(expr)表达式组true / false true 永远是 true ,而 false 始终是 false
2.8.2 template
template功能:可以根据和参考模块文件,动态生成相类似的配置文件template文件必须存放于templates目录下,且命名为 .j2 结尾yaml/yml 文件需和templates目录平级,目录结构如下:./├── temnginx.yml└── templates    └── nginx.conf.j2
【范例】:利用template同步nginx配置文件
# 准备templates/nginx.conf.j2文件[root@ansible ansible]#cat temnginx.yml---- hosts: websrvs  remote_user: root  tasks:    - name: "利用template模板文件配置被控主机"      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf[root@ansible ansible]#ansible-playbook temnginx.yml
【范例】:template变更替换
#修改templates/nginx.conf.j2文件[root@ansible ansible]#vim templates/nginx.conf.j2worker_processes {{ ansible_processor_vcpus }};[root@ansible ansible]#cat temnginx.yml---- hosts: websrvs  remote_user: root  tasks:    - name: "利用template模板文件配置被控主机"      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf[root@ansible ansible]#ansible-playbook temnginx.yml
【范例】:template算术运算
[root@ansible ansible]#vim templates/nginx.conf.j2worker_processes {{ ansible_processor_vcpus * 2}};worker_processes {{ ansible_processor_vcpus + 2}};
【范例】:template中使用流程控制for和if
for循环
【例1】:
[root@ansible ansible]#cat temnginx1.yml ---- hosts: websrvs  remote_user: root  vars:    nginx_vhosts:      - listen: 8081        server_name: www.hechunping.tech  tasks:    - name: "template模板文件配置被控主机"      template: src=nginx.conf1.j2 dest=/data/nginx.conf[root@ansible ansible]#cat templates/nginx.conf1.j2 {% for vhost in nginx_vhosts %}server {  listen {{ vhost.listen }};  server_name {{ vhost.server_name }};}{% endfor %}# 生成结果[root@ansible ansible]#ansible-playbook temnginx1.yml [root@ansible ansible]#cat /data/nginx.conf server {  listen 8081;  server_name www.hechunping.tech;}
【例2】:
[root@ansible ansible]#cat temnginx3.yml ---- hosts: websrvs  remote_user: root  vars:    nginx_vhosts:      - listen: 8081        server_name: "web1.hechunping.tech"        root: "/var/www/nginx/web1"      - listen: 8082        server_name: "web2.hechunping.tech"        root: "/var/www/nginx/web2"      - listen: 8083        server_name: "web3.hechunping.tech"        root: "/var/www/nginx/web3"  tasks:    - name: "template模板文件配置被控主机"      template: src=nginx.conf3.j2 dest=/data/nginx2.conf[root@ansible ansible]#cat templates/nginx.conf3.j2 {% for vhost in nginx_vhosts %}server {  listen {{ vhost.listen }};  server_name {{ vhost.server_name }};  root {{ vhost.root }};}{% endfor %}# 生成结果[root@ansible ansible]#ansible-playbook temnginx3.yml[root@ansible ansible]#cat /data/nginx2.conf server {  listen 8081;  server_name web1.hechunping.tech;  root /var/www/nginx/web1;}server {  listen 8082;  server_name web2.hechunping.tech;  root /var/www/nginx/web2;}server {  listen 8083;  server_name web3.hechunping.tech;  root /var/www/nginx/web3;}
if判断
【例1】:
[root@ansible ansible]#cat temnginx4.yml ---- hosts: websrvs  remote_user: root  vars:    nginx_vhosts:      - web1:        listen: 8080        root: "/var/www/nginx/web1"      - web2:        listen: 8080        server_name: "web2.hechunping.tech"        root: "/var/www/nginx/web2"  tasks:    - name: "template模板文件配置被控主机"      template: src=nginx.conf2.j2 dest=/data/nginx3.conf[root@ansible ansible]#cat templates/nginx.conf2.j2 {% for vhost in nginx_vhosts %}server{  listen {{ vhost.listen }};  {% if vhost.server_name is defined %}server_name {{ vhost.server_name }};  {% endif %}root {{ vhost.root }}}{% endfor %}#生成结果[root@ansible ansible]#ansible-playbook temnginx4.yml[root@ansible ansible]#cat /data/nginx3.conf server{  listen 8080;  root /var/www/nginx/web1}server{  listen 8080;  server_name web2.hechunping.tech;  root /var/www/nginx/web2}
2.9 Playbook使用when
功能:when语句,可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试
【范例】:
[root@ansible ansible]#cat when.yml ---- hosts: websrvs  remote_user: root  tasks:    - name: "打印hello redhat"      command: /usr/bin/wall hello redhat      when: ansible_os_family == "RedHat"
2.10 Playbook使用迭代with_items
迭代:当有需要重复性执行的任务时,可以使用迭代机制对迭代项的引用,固定变量名为"item"要在task中使用with_items给定要迭代的元素列表
列表元素格式:
  • 字符串
  • 字典
【范例】:
---- hosts: 192.168.7.71  remote_user: root  tasks:    - name: "备份文件"      copy: src=/data/{{ item }} dest=/backup/{{ item }}      with_items:        - nginx.conf        - nginx2.conf#上面语句的功能等同于下面的语句- name: "备份/data/nginx.conf文件到/backup目录"  copy: src=/data/nginx.conf dest=/backup- name: "备份/data/nginx2.conf文件到/backup目录"  copy: src=/data/nginx2.conf dest=/backup
迭代嵌套子变量:在迭代中,还可以嵌套子变量,关联多个变量在一起使用
【范例】:
---- hosts: websrvs  remote_user: root  tasks:    - name: "创建组"      group: name={{ item }} state=present      with_items:        - a1        - a2        - a3    - name: "创建用户"      user: name={{ item.name }} group={{ item.group }} state=present      with_items:        - { name: 'a1',group: 'a1' }        - { name: 'a2',group: 'a2' }        - { name: 'a3',group: 'a3' }

3 roles角色

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中
roles:多个角色的集合,可以在roles目录下为每个role建立单独的子目录
roles├── httpd├── mysql├── nginx└── redis
3.1 Ansible Roles目录编排
roles目录结构如下所示

每个角色,以特定的层级目录结构进行组织
roles目录结构
playbook.ymlroles/   project/     tasks/     handlers/     files/     templates/     vars/     defaults/     meta/
注:playbook文件需要和roles目录同级
roles各目录作用
/roles/project/ :项目名称,有以下子目录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文件
3.2 创建role
创建role的步骤
(1) 创建以roles命名的目录(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建(4) 在playbook文件中,调用各角色
【范例】:roles的目录结构
role_httpd.ymlroles/├── httpd│   ├── files│   │   ├── httpd.conf│   │   └── index.html│   ├── handlers│   │   └── main.yml│   └── tasks│       ├── config.yml│       ├── index.yml│       ├── install.yml│       ├── main.yml│       └── service.yml
3.3 playbook调用角色
调用角色方法1:
---- hosts: websrvs  remote_user: root  roles:    - mysql    - memcached    - nginx
调用角色方法2:
键role用于指定角色名称,后续的k/v用于传递变量给角色
---- hosts: all  remote_user: root  roles:    - mysql    - { role: nginx, username: nginx }
调用角色方法3:
还可以基于条件测试实现角色调用
---- hosts: all  remote_user: root  roles:    - { role: nginx, username: nginx, when: ansible_distribution_major_version == '7' }
3.4 roles中tags使用
#nginx-role.yml---- hosts: websrvs  remote_user: root  roles:    - { role: nginx ,tags: [ 'nginx','web' ], when: ansible_distribution_major_version == "6" }    - { role: httpd ,tags: [ 'httpd','web' ] }    - { role: mysql ,tags: [ 'mysql','db' ] }    - { role: mariadb ,tags: [ 'mariadb','db' ] }[root@ansible ansible]#ansible-playbook --tags="nginx,httpd,mysql" nginx-role.yml
3.5 实战案例
3.5.1 案例1:实现httpd角色
[root@ansible ansible]#pwd/data/ansible[root@ansible ansible]#ls roles/httpd/files  handlers  tasks# 创建角色[root@ansible ansible]#cd roles/httpd/[root@ansible httpd]#cat tasks/main.yml - include: install.yml- include: config.yml- include: index.yml- include: service.yml[root@ansible httpd]#cat tasks/install.yml - name : install httpd package  yum:    name: httpd[root@ansible httpd]#cat tasks/config.yml - name: config file  copy:     src: httpd.conf    dest: /etc/httpd/conf    backup: yes[root@ansible httpd]#cat tasks/index.yml - name: index.html  copy:    src: index.html    dest: /var/www/html[root@ansible httpd]#cat tasks/service.yml - name: start service  service:    name: httpd    state: started    enabled: yes[root@ansible httpd]#cat handlers/main.yml - name: restart  service:    name: httpd    state: restarted# 在files目录下准备两个文件[root@ansible httpd]#ls files/httpd.conf  index.html[root@ansible httpd]#tree ././├── files│   ├── httpd.conf│   └── index.html├── handlers│   └── main.yml└── tasks    ├── config.yml    ├── index.yml    ├── install.yml    ├── main.yml    └── service.yml3 directories, 8 files# 在playbook中调用角色[root@ansible httpd]#cat ../../role_httpd.yml ---# httpd role- hosts: appsrvs  remote_user: root  roles:    - role: httpd# 运行playbook[root@ansible httpd]#ansible-playbook ../../role_httpd.yml 
3.5.2 案例2:实现nginx角色
[root@ansible ~]#ls /data/ansible/roles/nginx/files  handlers  tasks  templates  vars# 创建task文件[root@ansible ~]#cd /data/ansible/roles/nginx/[root@ansible nginx]#cat tasks/main.yml - include: install.yml- include: config.yml- include: file.yml- include: service.yml[root@ansible nginx]#cat tasks/install.yml - name: install  yum: name=nginx[root@ansible nginx]#cat tasks/config.yml - name: config file for centos7  template:    src: nginx7.conf.j2    dest: /etc/nginx/nginx.conf  when: ansible_distribution_major_version=="7"  notify: restart- name: config file for centos8  template:    src: nginx8.conf.j2    dest: /etc/nginx/nginx.conf  when: ansible_distribution_major_version=="8"  notify: restart[root@ansible nginx]#cat tasks/file.yml - name: index.html  copy:    src: index.html    dest: /usr/share/nginx/html[root@ansible nginx]#cat tasks/service.yml - name: start service  service:    name: nginx    state: started    enabled: yes# 创建handlers文件[root@ansible nginx]#cat handlers/main.yml - name: restart  service:    name: nginx    state: restarted# 创建两个template文件[root@ansible nginx]#cat templates/nginx7.conf.j2# For more information on configuration, see:#   * Official English Documentation: http://nginx.org/en/docs/#   * Official Russian Documentation: http://nginx.org/ru/docs/user {{user}}; #修改此行worker_processes {{ansible_processor_vcpus**2}}; #修改此行error_log /var/log/nginx/error.log;pid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;events {    worker_connections 1024;}http {    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '                      '$status $body_bytes_sent "$http_referer" '                      '"$http_user_agent" "$http_x_forwarded_for"';    access_log  /var/log/nginx/access.log  main;    sendfile            on;    tcp_nopush          on;    tcp_nodelay         on;    keepalive_timeout   65;    types_hash_max_size 2048;    include             /etc/nginx/mime.types;    default_type        application/octet-stream;    # Load modular configuration files from the /etc/nginx/conf.d directory.    # See http://nginx.org/en/docs/ngx_core_module.html#include    # for more information.    include /etc/nginx/conf.d/*.conf;    server {        listen       80 default_server;        listen       [::]:80 default_server;        server_name  _;        root         /usr/share/nginx/html;        # Load configuration files for the default server block.        include /etc/nginx/default.d/*.conf;        location / {        }        error_page 404 /404.html;            location = /40x.html {        }        error_page 500 502 503 504 /50x.html;            location = /50x.html {        }    }# Settings for a TLS enabled server.##    server {#        listen       443 ssl http2 default_server;#        listen       [::]:443 ssl http2 default_server;#        server_name  _;#        root         /usr/share/nginx/html;##        ssl_certificate "/etc/pki/nginx/server.crt";#        ssl_certificate_key "/etc/pki/nginx/private/server.key";#        ssl_session_cache shared:SSL:1m;#        ssl_session_timeout  10m;#        ssl_ciphers HIGH:!aNULL:!MD5;#        ssl_prefer_server_ciphers on;##        # Load configuration files for the default server block.#        include /etc/nginx/default.d/*.conf;##        location / {#        }##        error_page 404 /404.html;#            location = /40x.html {#        }##        error_page 500 502 503 504 /50x.html;#            location = /50x.html {#        }#    }}[root@ansible nginx]#cat templates/nginx8.conf.j2# For more information on configuration, see:#   * Official English Documentation: http://nginx.org/en/docs/#   * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_processes {{ansible_processor_vcpus+2}}; #修改此行error_log /var/log/nginx/error.log;pid /run/nginx.pid;# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.include /usr/share/nginx/modules/*.conf;events {    worker_connections 1024;}http {    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '                      '$status $body_bytes_sent "$http_referer" '                      '"$http_user_agent" "$http_x_forwarded_for"';    access_log  /var/log/nginx/access.log  main;    sendfile            on;    tcp_nopush          on;    tcp_nodelay         on;    keepalive_timeout   65;    types_hash_max_size 2048;    include             /etc/nginx/mime.types;    default_type        application/octet-stream;    # Load modular configuration files from the /etc/nginx/conf.d directory.    # See http://nginx.org/en/docs/ngx_core_module.html#include    # for more information.    include /etc/nginx/conf.d/*.conf;    server {        listen       80 default_server;        listen       [::]:80 default_server;        server_name  _;        root         /usr/share/nginx/html;        # Load configuration files for the default server block.        include /etc/nginx/default.d/*.conf;        location / {        }        error_page 404 /404.html;            location = /40x.html {        }        error_page 500 502 503 504 /50x.html;            location = /50x.html {        }    }# Settings for a TLS enabled server.##    server {#        listen       443 ssl http2 default_server;#        listen       [::]:443 ssl http2 default_server;#        server_name  _;#        root         /usr/share/nginx/html;##        ssl_certificate "/etc/pki/nginx/server.crt";#        ssl_certificate_key "/etc/pki/nginx/private/server.key";#        ssl_session_cache shared:SSL:1m;#        ssl_session_timeout  10m;#        ssl_ciphers HIGH:!aNULL:!MD5;#        ssl_prefer_server_ciphers on;##        # Load configuration files for the default server block.#        include /etc/nginx/default.d/*.conf;##        location / {#        }##        error_page 404 /404.html;#            location = /40x.html {#        }##        error_page 500 502 503 504 /50x.html;#            location = /50x.html {#        }#    }}# 创建变量文件[root@ansible nginx]#cat vars/main.yml user: daemon# 在files目录下创建index.html文件[root@ansible nginx]#cat files/index.html 

hello nginx

# 目录结构如下[root@ansible nginx]#tree ././├── files│ └── index.html├── handlers│ └── main.yml├── tasks│ ├── config.yml│ ├── file.yml│ ├── install.yml│ ├── main.yml│ └── service.yml├── templates│ ├── nginx7.conf.j2│ └── nginx8.conf.j2└── vars └── main.yml5 directories, 10 files# 在playbook中调用角色[root@ansible nginx]#cat ../../role_nginx.yml ---# nginx role- hosts: appsrvs roles: - role: nginx# 运行playbook[root@ansible nginx]#ansible-playbook /data/ansible/role_nginx.yml
3.5.3 案例3:实现多角色的选择
[root@ansible nginx]#cat /data/ansible/role_httpd_nginx.yml---- hosts: appsrvs  roles:    - { role: httpd,tags: [httpd,web], when: ansible_distribution_major_version=="7" }    - { role: nginx,tags: [nginx,web], when:     ansible_distribution_major_version=="8" }[root@ansible nginx]#ansible-playbook -t nginx /data/ansible/role_httpd_nginx.yml
0