第4章 playbook
普通的shell脚本
转换为playbook之后
上面共定义了三个task。
所有任务都是使用的command模块。因为command模块最直接能表达我们的意图。
但一般来说,我们应该使用ansible提供的内置模块。
如果要用yum命令,应该用yum模块;如果要拷贝文件,应该用copy模块;如果要启动服务,应该用service模块。
我是使用的ansible 2.9做的测试,执行上述剧本时,会发出警告,说不能在yum模块中使用循环,错误如下:
[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions is deprecated. Instead of using a loop to supply multiple items and specifying `name: "{{ item }}"`, please use `name: ['httpd', 'httpd-devel']` and remove the loop. This feature will be removed in version 2.11. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
错误点:
相当于要运行2次yum模块。
注意,这只是警告,上述写法是没有问题的。脚本依然能成功。
但是在2.11之后,上述写法将会被遗弃,所以应该改为新写法。
最后完整的yml文件为:
注意,在copy模块中,src文件一定要在ansible控制端存在,否则将报错。
执行脚本
yum模块完成服务的安装,copy模块完成服务的配置,service模块完成服务的状态维护。
在每一个play当中,都可以使用with_items来定义变量,并通过"{{变量名}}"的形式来直接使用。
用yum模块的state=present选项来确保软件被安装,或者使用state=absent来确保软件被删除。
当Ansible发现系统的现有状态与Playbook所定义的将要实现的状态一致时,Ansible将自动跳过该操作。
以下命令可以提前做演练,但不会真正执行,只是看看会做哪些改变
ansible-playbook -C apache.yml
ansible-playbook --check apache.yml
限定playbook的执行范围
方式1:
方式2:
ansible-playbook apache.yml --limit webservers
提前查看脚本执行时会有哪些主机受到影响
ansible-playbook apache.yml --list-hosts
该命令不会执行脚本,只是看看受影响范围。
部署一个nodejs应用
1、首先通过rpm_key模块,导入一个GPG key,本次导入的是Remi源中的key。
2、因为没有rpm模块,因此借助command模块,执行rpm命令,安装remi源。同时借助creates选项,用以验证是否安装成功。
如果安装成功,必须存在/etc/yum.repos.d/remi.repo文件;
如果/etc/yum.repos.d/remi.repo文件已经存在,则不再安装。
3、使用yum模块安装epel源。
4、关闭防火墙。(因为我是CentOS 7,所以是firewalld,如果是CentOS 6,则改为iptables)
5、在epel源中搜索npm包,并通过yum模块安装。安装npm,会自动安装node。
6、设置npm的源为淘宝。
7、关闭npm的https。
8、安装forever工具,用于管理nodejs应用的启动停止。
然后编写程序:
// 加载 express 模块 var express = require('express'), var app = express(); // 响应 "/" 请求 app.get('/', function (req, res) { res.send('Hello World!'); }); // 在80端口监听 app.listen(80) console.log('Express server started successfully.')
在yml文件的同级目录下,创建app目录,并在app目录下创建app.js,内容为上。
同时要在app目录下,创建package.json文件,该文件要声明nodejs应用所需的依赖,好比python程序的requirements.txt文件。
{ "name": "example node app", "description": "Example Express Node.js app.", "author": "echoyang", "dependencies": { "express": "3.x.x" }, "engine": "node >= 0.10.6" }
接着完善yml文件,将程序文件拷贝到目标主机。
注意,变量node_apps_location暂时没有声明,我们等会在外面指定。
少量文件的拷贝用copy模块;大量文件的拷贝用synchronize模块;如果复制的是一个压缩文件,且拷贝之后想自动解压,就用unarchive模块。
最后是启动nodejs程序
这里涉及到forever的使用方式,具体请百度。
还有注意点,变量node_apps_location的使用方式。
在文档中,使用的是{{ node_apps_location }},发现执行时不好使,百度之后,发现需要改为(node_apps_location)方式。
执行playbook
ansible-playbook nodejs.yml --extra-vars="node_apps_location=/usr/local/opt/node"
通过--extra-vars来指定额外变量。
执行之后,在目标主机看到的进程为
访问地址
http://192.168.0.108/
完整的yml文件为
---
- hosts: "192.168.0.108"
tasks:
- name: 导入Remi GPG密钥
rpm_key: "key={{ item }} state=present"
with_items:
- "http://rpms.famillecollet.com/RPM-GPG-KEY-remi"
- name: Install Remi repo.
command: "rpm -Uvh --force {{ item.href }} creates={{ item.creates }}"
with_items:
- { href: "http://rpms.famillecollet.com/enterprise/remi-release-7.rpm", creates: "/etc/yum.repos.d/remi.repo" }
- name: 安装epel源
yum: name=epel-release state=present
- name: 关闭防火墙
service: name=firewalld state=stopped
- name: 安装nodejs和npm
yum: name=npm state=present enablerepo=epel
- name: 使用淘宝的npm源
command: npm config set registry https://registry.npm.taobao.org
- name: 关闭npm的https
command: npm config set strict-ssl false
- name: 安装forever(用于启动nodejs app)
npm: name=forever global=yes state=latest
- name: 确保node.js app的目录存在
file: "path={{ node_apps_location }} state=directory"
- name: 复制node.js app整个目录到目标主机
copy: "src=app dest={{ node_apps_location }}"
- name: 安装package.json文件中定义的依赖关系
npm: "path={{ node_apps_location }}/app"
- name: 获取正在运行的node.js app列表
command: forever list
register: forever_list
changed_when: false
- name: 启动node.js app
command: "forever start {{ node_apps_location }}/app/app.js"
when: "forever_list.stdout.find('(node_apps_location)/app/app.js') == -1"
我感觉remi源既能用在php,也能用在npm的安装上。