第4章 playbook

普通的shell脚本

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js

 

转换为playbook之后

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_02

上面共定义了三个task。

所有任务都是使用的command模块。因为command模块最直接能表达我们的意图。

但一般来说,我们应该使用ansible提供的内置模块。

如果要用yum命令,应该用yum模块;如果要拷贝文件,应该用copy模块;如果要启动服务,应该用service模块。

 

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_03

 

我是使用的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.

错误点:

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js_04

相当于要运行2次yum模块。

注意,这只是警告,上述写法是没有问题的。脚本依然能成功。

但是在2.11之后,上述写法将会被遗弃,所以应该改为新写法。

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_05

 

最后完整的yml文件为:

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_apache_06

注意,在copy模块中,src文件一定要在ansible控制端存在,否则将报错。

 

执行脚本

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_07

 

yum模块完成服务的安装,copy模块完成服务的配置,service模块完成服务的状态维护。

 

在每一个play当中,都可以使用with_items来定义变量,并通过"{{变量名}}"的形式来直接使用。

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_08

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_09

 

用yum模块的state=present选项来确保软件被安装,或者使用state=absent来确保软件被删除。

当Ansible发现系统的现有状态与Playbook所定义的将要实现的状态一致时,Ansible将自动跳过该操作。

 

以下命令可以提前做演练,但不会真正执行,只是看看会做哪些改变

ansible-playbook -C apache.yml

ansible-playbook --check apache.yml

 

限定playbook的执行范围

方式1:

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_10

方式2:

ansible-playbook apache.yml --limit webservers

 

提前查看脚本执行时会有哪些主机受到影响

ansible-playbook apache.yml --list-hosts

该命令不会执行脚本,只是看看受影响范围。

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_apache_11

 

部署一个nodejs应用

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js_12

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应用的启动停止。

 

然后编写程序:

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js_13

// 加载 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文件。

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_14

{
    "name": "example node app",
    "description": "Example Express Node.js app.",
    "author": "echoyang",
    "dependencies": {
        "express": "3.x.x"
    },
    "engine": "node >= 0.10.6"
}

 

接着完善yml文件,将程序文件拷贝到目标主机。

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_json_15

注意,变量node_apps_location暂时没有声明,我们等会在外面指定。

少量文件的拷贝用copy模块;大量文件的拷贝用synchronize模块;如果复制的是一个压缩文件,且拷贝之后想自动解压,就用unarchive模块。

 

最后是启动nodejs程序

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js_16

这里涉及到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来指定额外变量。

 

执行之后,在目标主机看到的进程为

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_apache_17

 

访问地址

http://192.168.0.108/

ansible playbook 设置shell命令超时 在ansible -playbook 调用shell 脚本_node.js_18

 

完整的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的安装上。