示例
实现Tomcat war包自动更新及重启
ansible-playbook /root/code/deploy.yml -e host=$remoteServerName -e backDir=${backDir} -e packageName=${packageName} -e tomcatDir=${remoteProjectDir}
# 指定主机名
- hosts: "{{ host }}"
# 定义变量
vars:
service_name: tomcat
service_port: 8081
# 也可以通过文件来导入变量
vars_files:
- vars.yml
# 不收集客户端信息,可以加快脚本执行速度
gater_facts: no
# 指定用户
remote_user: root
# 下面构成playbook的tasks,每个task都由 - name: 开始,name指定该任务的名称
tasks:
- name: shutdowm tomcat
shell: source /etc/profile && bash {{ tomcatDir }}/bin/shutdown.sh
register: results
- name: pause
pause: seconds=20
- name: rm project
file: path={{ tomcatDir }}/webapps/{{ packageName }} state=absent
- name: upload war
copy: src={{ backDir}}/{{ packageName }}.war backup=no dest={{ tomcatDir }}/webapps/
# 执行notify触发对应的handlers
notify:
- tomcat start
- tomcat status
# 定义了三个handlers,和py函数类似,不会自动执行,需要notify去调用
handlers:
- name: tomcat shutdown
shell: source /etc/profile && bash {{ tomcatDir }}/bin/shutdown.sh
- name: tomcat start
shell: source /etc/profile && nohup bash {{ tomcatDir }}/bin/startup.sh &
- name: tomcat status
shell: ps -ef|grep {{ tomcatDir }}|grep -v 'grep {{ tomcatDir }}'
使用handlers注意点
- Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。
- Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如: -meta: flush_handlers.
- 如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的—force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。
注册变量
其实就是将操作结果,包括标准输出和标准错误输出,保存到变量中,然后再根据这个变量的内容来决定下一步的操作,在这个过程中用来保存操作结果的变量就叫注册变量。
一个注册变量通常会有以下4个属性:
- changed:任务是否对远程主机造成的变更。
- delta:任务运行所用的时间。
- stdout:正常的输出信息。
stderr:错误信息。
- hosts: all
remote_user: root
gather_facts: no
tasks:
- name: test the register variables
shell: uptime
# 使用关键字register声明注册变量,上面uptime命令产生的结果,存入到results中。结果是字典形式
register: results
- name: print the register result
# 使用debug模块,打印出上面命令的输出结果。
debug: msg="{{ results.stdout }}"
when条件判断
很多任务只有在特定条件下才能执行,这就是when语句发挥作用的地方。
一个简单的实例,关闭掉ip地址为10.0.102.162服务器上的mysql服务
- hosts: all
remote_user: root
tasks:
- name: shut down the db server
service: name=mysqld state=stopped
when: ansible_eth0.ipv4.address == "10.0.102.162"
任务委托
默认情况下,ansible所有任务都是在我们指定的机器上面运行的,当在一个独立的集群环境配置时,这并没有什么问题。而在有些情况下,比如给某台服务器发送通知或者向监控服务器中添加被监控的主机,这个时候任务就需要在特定的主机上运行,而非一开始指定的所有主机,此时就需要ansible的委托任务。
- hosts: all
remote_user: root
tasks:
- name: stop the db server
service: name=mysqld state=stopped
# 这里使用了委托,仅关闭162这台服务器上,这个play仅在162这台服务器上执行。
delegate_to: 10.0.102.162
- name: check mysql status
service: name=mysqld state=running
任务暂停
有些情况下,一些任务的运行需要等待一些状态的恢复,比如某一台主机或者应用刚刚重启,我们需要等待它上面的某个端口开启,此时我们就不得不将正在运行的任务暂停,直到其状态满足我们的需求。
这个实例中,这个任务将会每10s检查一次主机webserver1上面的80端口是否开启,如果超过了300s,80端口仍未开启,将会返回失败信息。
- name: wait for webserver to start
local_action:
module: wait_for
host: webserver1
port: 80
delay: 10
timeout: 300
state: startted
迭代
使用同一个模块循环安装软件包
- hosts: centos75-2
tasks:
- name: 安装软件包
yum: name={{ item }}
with_items:
- ftp
- lftp
- wget
roles
将耦合较高的脚本化代码转变为目录结构化,一个分类,将web、db等分为各自的大组,在各个角色内定义具体的小任务,方便管理,另一方面,类似于php的类的自动加载,roles基于一个已知的文件结构,可以自动去加载某些vars_files、tasks、handlers等。
每个角色,以特定的层级目录结构进行组织: 注意:大多数都是复数”s”,除了meta
web/
files/ 存放由copy或script模块等调用的文件
templates/ template模块查找所需要的模板文件目录
handlers/ 至少应该包含一个名为main.yml文件
vars/ 至少一个main.yml
tasks/ 基本元素:至少一个名为main.yml的文件,其他的文件需要在此文件中通过include进行包含
meta/ main.yml,定义当前角色的特殊设定,及其依赖关系
default/ 设定默认变量时使用此目录中的main.yml文件
1.tasks
[root@localhost nginx]# vim roles/db/tasks/main.yml
# This playbook will install Mysql and create db user and give permissions.
- name: Install Mysql packag
yum: name={{ item }} state=installed
with_items:
- mysql-community-server
- MySQL-python
- name: Create Mysql configuration file
template: src=my.cnf dest=/etc/my.cnf
notify:
- restart mysqld
- name: Start Mysql Servic
service: name=mysqld state=started enabled=yes
templates 目录中有存放的my.cnf
2.添加handler
[root@localhost nginx]# vim roles/db/handler/main.yml
# Handler to handle DB tier notifications
- name: restart mysqld
service: name=mysqld state=restarted
3.变量
- hosts: websrvs
remote_user: root
vars:
- username: testuser1
- groupname: testgroup1
tasks:
- name: create group
group: name={{ groupname }} state=present
- name: create user
user: name={{ username }} group={{ groupname }} state=present
4.site
[root@localhost nginx]# vim site.yml
# This playbook deploys the whole application stack in this site.
- name: apply common configuration to all nodes
hosts: all
remote_user: root
roles:
- common
- name: configure and deploy the webservers and application code
hosts: webservers
remote_user: root
roles:
- web
- name: deploy MySQL and configure the databases
hosts: dbservers
remote_user: root
roles:
- db
5.运行playbook脚本
ansible-playbook site.yml
在vars和default中定义的变量有什么区别?
- 在(vars/main.yml)中定义的变量比在play其他地方定义vars字段的优先级高,这就造成,除非将变量座位参数显式传递给role,不然就无法覆盖变量值。
- 后来Ansible引入了默认role变量的概念(defaults/main.yml),它的优先级低。所以如果playbook中定义了另一个同名的变量,这个值将会被覆盖。
总结:如果你认为可能需要变更role变量的值,那么使用默认变量(defaults/main.yml)。如果你不希望修改role变量的值,那么使用常规的role变量就行了。