示例

实现Tomcat war包自动更新及重启

  1. ansible-playbook /root/code/deploy.yml -e host=$remoteServerName -e backDir=${backDir} -e packageName=${packageName} -e tomcatDir=${remoteProjectDir}
  1. # 指定主机名
  2. - hosts: "{{ host }}"
  3. # 定义变量
  4. vars:
  5. service_name: tomcat
  6. service_port: 8081
  7. # 也可以通过文件来导入变量
  8. vars_files:
  9. - vars.yml
  10. # 不收集客户端信息,可以加快脚本执行速度
  11. gater_facts: no
  12. # 指定用户
  13. remote_user: root
  14. # 下面构成playbook的tasks,每个task都由 - name: 开始,name指定该任务的名称
  15. tasks:
  16. - name: shutdowm tomcat
  17. shell: source /etc/profile && bash {{ tomcatDir }}/bin/shutdown.sh
  18. register: results
  19. - name: pause
  20. pause: seconds=20
  21. - name: rm project
  22. file: path={{ tomcatDir }}/webapps/{{ packageName }} state=absent
  23. - name: upload war
  24. copy: src={{ backDir}}/{{ packageName }}.war backup=no dest={{ tomcatDir }}/webapps/
  25. # 执行notify触发对应的handlers
  26. notify:
  27. - tomcat start
  28. - tomcat status
  29. # 定义了三个handlers,和py函数类似,不会自动执行,需要notify去调用
  30. handlers:
  31. - name: tomcat shutdown
  32. shell: source /etc/profile && bash {{ tomcatDir }}/bin/shutdown.sh
  33. - name: tomcat start
  34. shell: source /etc/profile && nohup bash {{ tomcatDir }}/bin/startup.sh &
  35. - name: tomcat status
  36. 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:错误信息。

    1. - hosts: all
    2. remote_user: root
    3. gather_facts: no
    4. tasks:
    5. - name: test the register variables
    6. shell: uptime
    7. # 使用关键字register声明注册变量,上面uptime命令产生的结果,存入到results中。结果是字典形式
    8. register: results
    9. - name: print the register result
    10. # 使用debug模块,打印出上面命令的输出结果。
    11. debug: msg="{{ results.stdout }}"

when条件判断

很多任务只有在特定条件下才能执行,这就是when语句发挥作用的地方。
一个简单的实例,关闭掉ip地址为10.0.102.162服务器上的mysql服务

  1. - hosts: all
  2. remote_user: root
  3. tasks:
  4. - name: shut down the db server
  5. service: name=mysqld state=stopped
  6. when: ansible_eth0.ipv4.address == "10.0.102.162"

任务委托

默认情况下,ansible所有任务都是在我们指定的机器上面运行的,当在一个独立的集群环境配置时,这并没有什么问题。而在有些情况下,比如给某台服务器发送通知或者向监控服务器中添加被监控的主机,这个时候任务就需要在特定的主机上运行,而非一开始指定的所有主机,此时就需要ansible的委托任务。

  1. - hosts: all
  2. remote_user: root
  3. tasks:
  4. - name: stop the db server
  5. service: name=mysqld state=stopped
  6. # 这里使用了委托,仅关闭162这台服务器上,这个play仅在162这台服务器上执行。
  7. delegate_to: 10.0.102.162
  8. - name: check mysql status
  9. service: name=mysqld state=running

任务暂停

有些情况下,一些任务的运行需要等待一些状态的恢复,比如某一台主机或者应用刚刚重启,我们需要等待它上面的某个端口开启,此时我们就不得不将正在运行的任务暂停,直到其状态满足我们的需求。
这个实例中,这个任务将会每10s检查一次主机webserver1上面的80端口是否开启,如果超过了300s,80端口仍未开启,将会返回失败信息。

  1. - name: wait for webserver to start
  2. local_action:
  3. module: wait_for
  4. host: webserver1
  5. port: 80
  6. delay: 10
  7. timeout: 300
  8. state: startted

迭代

使用同一个模块循环安装软件包

  1. - hosts: centos75-2
  2. tasks:
  3. - name: 安装软件包
  4. yum: name={{ item }}
  5. with_items:
  6. - ftp
  7. - lftp
  8. - 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

  1. [root@localhost nginx]# vim roles/db/tasks/main.yml
  2. # This playbook will install Mysql and create db user and give permissions.
  3. - name: Install Mysql packag
  4. yum: name={{ item }} state=installed
  5. with_items:
  6. - mysql-community-server
  7. - MySQL-python
  8. - name: Create Mysql configuration file
  9. template: src=my.cnf dest=/etc/my.cnf
  10. notify:
  11. - restart mysqld
  12. - name: Start Mysql Servic
  13. service: name=mysqld state=started enabled=yes

templates 目录中有存放的my.cnf
2.添加handler

  1. [root@localhost nginx]# vim roles/db/handler/main.yml
  2. # Handler to handle DB tier notifications
  3. - name: restart mysqld
  4. service: name=mysqld state=restarted

3.变量

  1. - hosts: websrvs
  2. remote_user: root
  3. vars:
  4. - username: testuser1
  5. - groupname: testgroup1
  6. tasks:
  7. - name: create group
  8. group: name={{ groupname }} state=present
  9. - name: create user
  10. user: name={{ username }} group={{ groupname }} state=present


4.site

  1. [root@localhost nginx]# vim site.yml
  2. # This playbook deploys the whole application stack in this site.
  3. - name: apply common configuration to all nodes
  4. hosts: all
  5. remote_user: root
  6. roles:
  7. - common
  8. - name: configure and deploy the webservers and application code
  9. hosts: webservers
  10. remote_user: root
  11. roles:
  12. - web
  13. - name: deploy MySQL and configure the databases
  14. hosts: dbservers
  15. remote_user: root
  16. roles:
  17. - db


5.运行playbook脚本

  1. ansible-playbook site.yml

image.png

在vars和default中定义的变量有什么区别?

  1. 在(vars/main.yml)中定义的变量比在play其他地方定义vars字段的优先级高,这就造成,除非将变量座位参数显式传递给role,不然就无法覆盖变量值。
  2. 后来Ansible引入了默认role变量的概念(defaults/main.yml),它的优先级低。所以如果playbook中定义了另一个同名的变量,这个值将会被覆盖。

总结:如果你认为可能需要变更role变量的值,那么使用默认变量(defaults/main.yml)。如果你不希望修改role变量的值,那么使用常规的role变量就行了。