实验前准备:各主机之间实现ssh相互登录,关闭防火墙,SELinux,同步时间
Playbook:YAML(可读性高,用来表达数据序列的格式)格式,任务(task)
可以用YAML脚本批量执行计划好的命令,从而实现运维自动化,避免重复运维配置等工作
基本数据结构:标量、数组、关联数组
Playbook的核心元素:
Hosts:主机
Tasks:任务列表
Variables
Templates:包含了模板语法的文本文件;
Handlers:由特定条件触发的任务;
Roles(非核心)
playbook的基础组件:
- Hosts:运行指定任务的目标主机;
remoute_user: 在远程主机上执行任务的用户;
sudo_user:
- tasks:任务列表
模块,模块参数;
格式:(1) action: module arguments
(2) module: arguments
先把官网的简单几个语法给说明下。
#这个是你选择的主机
- hosts: webservers
#这个是变量
vars:
- http_port: 80
- max_clients: 200
#远端的执行权限
remote_user: root
tasks:
#利用yum模块来操作
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
#触发重启服务器
notify: restart apache
- name: ensure apache is running
service: name=httpd state=started
#这里的restart apache 和上面的触发是配对的。这就是handlers的作用。相当于tag
handlers:
- name: restart apache
service: name=httpd state=restarted
可以继续定义主机
- hosts: webs
remote_user: root
…
…
\注意:shell和command模块后面直接跟命令,而非key=value类的参数列表;
(1) 某任务的状态在运行后为changed时,可通过“notify”通知给相应的handlers;
(2) 任务可以通过tags打标签,而后可在ansible-playbook后使用-t进行调用,且多个任务可使用同一个标签,一个任务也可用多个标签;
(3)一定要注意yaml格式,前面的空格要对齐,不然总会出错,创建好playbook先进行语法,playbook文件一般是以.yaml或者.yml结尾,不以这两个结尾也可以识别
playbook的使用方法:
(1) 测试
ansible-playbook --check 或 -C file.yml 只检测可能会发生的改变,但不真正执行操作;
ansible-playbook --list-hosts file.yaml 查看任务主机
ansible-playbook --list-tasks file.yaml 查看所有任务
ansible-playbook --syntax-check file.yml 检查配置文件语法是否有错
(2) 运行 ansible-playbook file.yaml
标签tags
用ansible写playbook的朋友可能会发现,当配置工作很多时,如果在中间过程出错了,修改后想重新执行,前面的一大堆步骤让人感觉很烦躁。虽然提供了“retry”文件,但是却只是根据host来判断重新执行,仍然不够方便;又或者,中间的某些步骤特别耗时,比如下载一个很大的数据包,每次执行特别浪费时间,想要特别的跳过。怎么办?我猜你就是把不需要的部分给注释掉了。有没有更好的办法呢?
ansible的playbool中有一个关键字,叫做tags。tags是什么?就是打标签。tags可以和一个play(就是很多个task)或者一个task进行捆绑。然后,ansible-playbook提供了“--skip-tags”和“--tags” 来指明是跳过特定的tags还是执行特定的tags。
下面请看例子。
有时候只想用这个文件中的复制配置文件的功能,而不想再每一项都检查,虽然也没什么问题。
- hosts: wserver
remote_user: root
tasks:
- name: install httpd redhat
yum: name=httpd state=present
- name: copy httpd configuration
copy: src=/root/httpd dest=/etc/
tags: config #加了一个tags.
- name: start httpd
service: name=httpd state=started
- name: boot httpd start
service: name=httpd enabled=yes
当执行 ansible-playbook httpd.yml --tags="config" ,则只会执行 copy命令。
那么复制完配置文件以后应该重载配置文件才对。可是就算再添加一个任务,因为我们指定了标签也不会执行。那么就可以用handlers啦。
handlers
也只有其关注的条件满足时,才会被触发执行。这里的条件其实就是发生修改。
如果我们复制配置文件和远程主机上的一样,那就不会触发了。
Handlers 也是一些 task 的列表,通过名字来引用,它们和一般的 task 并没有什么区别。
Handlers 是由通知者进行 notify, 如果没有被 notify,handlers 不会执行。
不管有多少个通知者进行了 notify,等到 play 中的所有 task 执行完成之后,handlers 也只会被执行一次。
Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了。
- hosts: wserver
remote_user: root
tasks:
- name: install httpd redhat
yum: name=httpd state=present
- name: start httpd
service: name=httpd state=started
- name: copy httpd configuration
copy: src=/root/httpd dest=/etc/
notify:
- reload httpd #添加了一行这个。用以触发名称为reload httpd handlers。
tags: config
- name: boot httpd start
service: name=httpd enabled=yes
handlers: reload httpd \或者reload httpd换行修改为- name: reload httpd
service: name=httpd state=reloaded
notify: 条件式触发,只要配置文件改变了,就会通知给handlers
tags: chfredis 配置文件改变了,要重新复制配置文件到远程主机,给这个任务增加一个标签
notify: restartredis 条件式触发,只要配置文件改变了,就会通知给handlers
[root@node1 ~]$ ansible-playbook --list-tags file.yml 查看添加的标签
[root@node1 ~]$ ansible-playbook file.yml ---执行操作
ansible-playbook httpd.yml --tags="config" 或者
注:可以定义多个notify
- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify: restart memcached
- name: copy httpd configuration
copy: src=/root/httpd dest=/etc/
notify: reload httpd
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: relad httpd
service: name=apache state=restarted
variables(变量):
(1) facts:可直接调用;
注意:可使用setup模块直接获取目标主机的facters;
示例:
[root@node1 ~]$ ansible dbs -m setup -a "filter=ansible_*_mb"
172.18.253.32 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1336, 变量---值
备注:常用的内建变量
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep vcpu
"ansible_processor_vcpus": 4, ---cpu核心数
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep fqdn
"ansible_fqdn": "node4.magedu.com", ---主机名
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep memtotal
"ansible_memtotal_mb": 1823, ---系统的总内存
[root@node1 ~]#ansible 172.18.21.200 -m setup |grep version
"ansible_bios_version": "6.00",
"ansible_distribution_major_version": "7", ---系统版本
"ansible_distribution_version": "7.4",
[root@node1 ~]#ansible 172.18.21.7 -m setup|grep -A 2 "default_ipv4"
"ansible_default_ipv4": {
"address": "172.18.21.7", ---使用的ip地址
"alias": "ens38",
(2) 用户自定义变量:
(a) 在playbook中定义变量的方法:
vars:
- var1: value1
- var2: value2
vars_fies:
- /path-to-file.yml
变量引用:{{ variable }}
示例:
通过vars关键字定义:
- hosts: dbs
remote_user: root
vars:
- packname: mariadb
tasks:
- name: install package {{ packname }}
yum: name={{ packname }} state=latest
通过vars_files关键字引入变量文件:
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/nginx_vars.yml
/vars/nginx_vars.yml示例:
http_port: 80
server_name: localhost
cert_file: /etc/nginx/ssl/nginx.crt
key_file: /etc/nginx/ssh/nginx.key
conf_file: /etc/nginx/conf/default.conf
会发现安装mariadb
(b) ansible-playbook命令的命令行中的 -e VARS(如,“packname=tree”), --extra-vars=VARS
[root@node1 ~]$ ansible-playbook -e "packname=tree" -C var.yaml
干跑会发现不是安装mariadb了,而是tree
(3) 通过roles传递变量;
(4) Host Inventory
(a) 用户自定义变量
(i) 向不同的主机传递不同的变量;IP/HOSTNAME varaiable=value var2=value2
(ii) 向组中的主机传递相同的变量;[groupname:vars] variable=value,在/etc/ansible/hosts的主机下定义组变量
示例:
[root@node1 ~]$ vim /etc/ansible/hosts ---在主机清单中定义变量
[websrvs]
172.18.21.100 packname=memcached 不同的主机设置不同的变量
172.18.21.200 packname=haproxy
[root@node1 ~]$ ansible-playbook -C pkg.yaml ---在这里要将剧本中的变量vars定义去掉,否则不会生效,说明剧本中的变量优先于主机清单中的变量
或者
[root@node1 ~]$ vim /etc/ansible/hosts ---也可以这样定义在同一个组内的主机定义相同的变量
[dbs]
172.18.21.100
172.18.21.200
[dbs:vars]
packname=memcached
[root@node1 ~]$ ansible-playbook -C pkg.yaml ---测试
总结:
自定义变量有三种方式:分别是在playbook中、命令行和主机清单配置文件中定义,在命令行中定义的变量优先于在playbook中定义的变量,在playbook中定义的变量优先于在主机清单中定义的变量,调用变量要使用双大括号,并且大括号前后都要有空格,以上定义的变量都是自定义变量
注意变量名里面不能使用-,否则会报错,下划线可以使用,注意空格使用
调用变量有两种方式:roles调用变量和setupsetup模块直接获取目标主机的facters后面介绍
(6) 主机变量 (此处着重了解)
以下是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等其他语言
示例如下:
[test]
192.168.1.1 ansible_ssh_user=root ansible_ssh_pass='P@ssw0rd'
192.168.1.2 ansible_ssh_user=breeze ansible_ssh_pass='123456'
192.168.1.3 ansible_ssh_user=bernie ansible_ssh_port=3055 ansible_ssh_pass='456789'
上面的示例中指定了三台主机,三台主机的用密码分别是P@ssw0rd、123456、45789,指定的ssh连接的用户名分别为root、breeze、bernie,ssh 端口分别为22、22、3055 ,这样在ansible命令执行的时候就不用再指令用户和密码等了。这样不安全,一般不这样使用
template模块:
基于模板方式生成一个文件复制到远程主机,将模板的文件中变量值转换成对应的主机指定关键字符串的确定值,并将模板文件复制过去
*src=
*dest=
owner=
group=
mode=
带*必须有此参数
模板:templates为文本文件,嵌套有脚本(使用模板编程语言Jinja2编写)
模块示例:
模板配置文件nginx.conf.j2
Worker_porcesses {{ ansible_precossor_vcpus }}
#注意空格哦。替换Worker_porcesses的值;
此变量执行ansible all -m setup (收集到的远程主机的变量) 即可查看到
Worker_porcesses {{ ansible_precossor_vcpus +1 }}
此表达式也可。此处只为表示可支持算数运算。
Jinja2 语言:
字面量:
字符串:使用单引号或双引号;
数字:整数,浮点数
列表:[item1,item2 …..]
元组:(item1item2…,)
字典:{key1:value,key2:value….}
布尔型: true/filase
算数运算:
+,- , * , / , // , % **
比较操作:
==, != , >= ,<=
逻辑运算:
and,or, not,
流表达式
For、IF、when
示例: (用ansible-playbook调用此文件,ansible不能直接用templates调用)
[root@node1 ~]$ ansible 172.18.251.90 -m setup |grep processor
或者使用
[root@node1 ~]$ ansible 172.18.251.90 -m setup -a "filter=*_processor_*"
"ansible_processor": [
"ansible_processor_cores": 2,
"ansible_processor_count": 2,
"ansible_processor_threads_per_core": 1,
"ansible_processor_vcpus": 4,
[root@node1 ~]$ cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.jj2
[root@node1 ~]$ vim /etc/nginx/nginx.conf.jj2 模板配置文件nginx.conf.jj2
worker_processes {{ ansible_processor_cores }} 这行修改为:调用这个内建变量
[root@node1 ~]$ vim ng.yml
1 - hosts: dbs
2 remote_user: root
3 tasks:
4 - name: install nginx
5 yum: name=nginx state=present
6 - name: install conf file
7 template: src=/etc/nginx/nginx.conf.jj2 dest=/etc/nginx/nginx.conf
8 - name: start nginx
9 service: name=nginx state=started
注:
template模块核心是模板,copy就是简单复制的意思.template模块首先使用变量渲染jinja2模板文件成普通文件,然后再复制过去.而copy模块不支持
条件测试:复杂环境的批量判断操作
示例:
when语句:在task中使用,jinja2的语法格式
- hosts: dbs
remote_user: root
tasks:
- name: install conf file to centos7
template: src=files/nginx.conf.c7.jj2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "7"
- name: install conf file to centos6
template: src=files/nginx.conf.c6.jj2 dest=/etc/nginx/nginx.conf
when: ansible_distribution_major_version == "6"
循环:迭代,需要重复执行的任务
对迭代项的引用,固定变量名为”item“,而后,要在task中使用with_items给定要迭代的元素列表;例:
- hosts: webs
remote_user: root
tasks:
- name: install some packages
yum: name={{ item }} state=present
with_items:
- nginx
- memcached
- php-fpm
- name: add some groups
group: name={{ item }} state=present
with_items:
- group11
- group12
- group13
- name: add some users
user: name={{ item.name }} group={{ item.group }} state=present
with_items:
- { name: 'user11', group: 'group11' }
- { name: 'user12', group: 'group12' }
- { name: 'user13', group: 'group13' }
就是利用item和with_items相当与一个数组,一次完成多个重复的、属性相同指令,加版本号的方法也类似
如下:实现将tomcat的两个不同的配置文件拷贝到远程主机
- hosts: webs
remote_user: root
vars:
- jdk_version: 1.8.0
tasks:
- name : install {{ item }} package
yum : name= {{ item }} state =installed
with_items:
- nginx
- java-{{ jdk_version }}-openjdk
- tomcat
- tomcat-webapps
- tomcat-docs_webapp
- tomcat-admin-webapps
- name : config tomcat
copy : src ={{ item.file }} dest={{ item.conf }}
with_items:
- { file: '/data/tomcat-users.xml', conf: '/etc/tomcat-user.xml' }
- { file: '/data/server.xml', conf: '/etc/server.xml' }
角色(roles):分类组织调用各个应用各个模块
roles 用于层次性、结构化地组织playbook。roles 能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量(vars)、文件(file)、任务(tasks)、模块(modules)及触发处理器(handlers)放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。
角色集合
/etc/ansible/roles/下可有多个按应用分类的角色,如:
mysql/
httpd/
nginx/
memcached/
目录层级结构
每个角色,以特定的层级目录结构进行组织:如 mysql/下
Files/ #存放有copy或script模块等调用的文件;’
Tepmlates/ #template模块查找所需要模板文件目录;
Tasks/ #定义任务;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。
Handlers/ #定义触发器;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。
Vars/ #定义变量;至少应该包含一个名为main.yml的文件;其他的文件需要在此文件中通过,include进行包含。
Meta/ #定义变量;至少应该包含一个名为main.yml的文件;定义当前角色的特殊设定及其依赖关系;其他的文件需要在此文件中通过include进行包含。
Default/ #设定默认变量时使用此目录中的main.yml文件。
调用角色
在playbook调用角色方法1:
- hosts: webservers
remote_user: root
roles:
- mysql
- memcached
- nginx
在playbook调用角色方法2:传递变量给角色
- hosts:
remote_user:
roles:
- { role: nginx, username: nginx等变量 }
键role用于指定角色名称;后续的k/v用于传递变量给角色;
还可以基于条件测试实现角色调用;
roles:
- { role: nginx, when: "ansible_distribution_major_version == '7' " }
层级结构展示
示例1:利用ansible角色安装nginx
[root@centos7 ~]# mkdir /etc/ansible/roles/nginx/{files,tasks,templates,handlers,vars,default,mata} –pv
#创建固定目录结构
[root@centos7 ~]# tree /etc/ansible/roles/nginx/
/etc/ansible/roles/nginx/
├── default
├── files
├── handlers
├── mata
├── tasks
├── templates
└── vars
[root@centos7 ~]# cd /etc/ansible/roles/nginx/
[root@centos7 nginx]# vim tasks/main.yml #创建任务
- name: install nginx package
yum: name=nginx state=present
- name: install conf file
template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
#此处源文件可不写绝对路径,系统自查找。
- name: start nginx
service: name=nginx state=started
[root@centos7 ~]# cp /etc/nginx/nginx.conf.j2 ./templates/nginx.conf.j2
#将配置文件拷贝至templates目录内。
[root@centos7 ~]# cd /apps/yaml/
[root@centos7 yaml]# cat roles.yml #创建调用文件
- hosts: web
remote_user: root
roles:
- nginx
[root@centos7 yaml]#ansible-playbook roles.yml #利用ansible-playbook执行。
示例2:变量调用
利用定义变量使远程主机的nginx服务运行用户变更为daemon
[root@centos7 ~]# vim /etc/ansible/roles/nginx/vars/main.yml
username: daemon
[root@centos7 ~]# vim /etc/ansible/roles/nginx/templates/nginx.conf.j2
user {{ username }}; # 将此处原有用户修改为变量
[root@centos7 ~]# cd /apps/yaml/
[root@centos7 yaml]#ansible-playbook roles.yml
[root@centos7 yaml]#ansible-playbook -e"username=adm" roles.yml
#也可以直接利用命令行传递变量参数给剧本文件。
示例3:在playbook调用角色方法:传递变量给角色
不在vars下定义,role下传递
[root@centos7 yaml]vim roles.yml
- hosts:web
remote_user:root
roles:
- {role: nigix, username: nginx }
#在调用nginx角色是使用变量username:nginx时服务运行用户为nginx
键role:用于指定角色名称;后续的键值对用户传递变量给角色
[root@centos7 yaml]# ansible-playbook roles.yml
还可以基于条件测试实现角色调用;
[root@centos7 yaml]vim roles.yml
- hosts:web
remote_user: root
roles:
{role: nigix, username: nginx ,when: “ansible_distribution_major_version ==’7’”}
#基于条件测试调用变量赋予nginx。
[root@centos7 yaml]#ansible-playbook -t instconf roles.yml
示例5:角色安装
[root@centos7 ~]# mkdir /etc/ansible/roles/memcached/tasks -pv
[root@centos7 ~]# vim /etc/ansible/roles/memcached/tasks/main.yml
- name: install package
yum: name=memcached state=present
- name: start memecached
service: name=memcached state=started
[root@centos7 ~]# cd/apps/yaml/
[root@centos7 yaml]# cat mem.yml
- hosts: web
remote_user: root
roles:
- { role: nginx, when: ansible_distribution_version == '7' }
#系统为centos7时调用执行nginx
- { role: memcached, when: ansible_distribution_version == '6' }
#系统为centos7时调用执行memcached
示例6:角色变量调整memcached内存大小
利用变量使远程主机上的Memcahed的缓存大小占用系统内存大小的三分之一。
[root@centos7 ~]# cd /etc/ansible/roles/memcached/
[root@centos7 memcached]#ls
handlers/ tasks/ templates/
[root@centos7 memcached]#cat tasks/main.yml
- name: install package
yum: name=memcached state=present
- name: start memecached
service: name=memcached state=started
- name: install conf file
template: src=memcached.j2 dest=/etc/sysconfig/memcached
notify: restart memcached
tags: restart
[root@centos7 memcached]# scp 172.16.254.216:/etc/sysconfig/memcached
./templates/memcached.j2
[root@centos7 memcached]#vim templates/memcached.j2
PORT="11211"
USER="memcached"
MAXCONN="1024"
CACHESIZE="{{ ansible_memtotal_mb//3 }}"
#变量设置内存的3分之一 此变量为远程主机的总内存//3 指除3取商
便为远程主机的三分之一
[root@centos7 memcached]#vim handlers/main.yml
- name: restart memcached
service: name=memcached state=restarted
[root@centos7 memcached]#cd /apps/yaml/
[root@centos7 yaml]#ansible-playbook mem.yml #执行剧本
关于更多ansible的介绍和查看ansible官网:http://www.ansible.com.cn