Rundeck的命令行工具

Rundeck也提供了命令行下的操作方式,根据官方文档做了一些总结如下
dispatch

-V :打开debug调试信息
-q, --quiet :只显示error级别的日志
-C, --threadcount *COUNT* : 指定执行命令时的线程数
-K, --keepgoing :即使出现错误信息也继续执行
-F, --filter *FILTER* :设置一个node过滤的字符串
-filter-exclude-precedence *true|false* : Set the exclusion filter to have precedence or not.
-p *NAME* : 指定project名称,只有这一个参数时,dispatch将显示project下的所有node
-- *COMMAND_STRING* :指定所要执行的命令
-s, --script *SCRIPT* :指定要执行的脚本文件
-u, --url *URL* :从url中获取脚本文件并执行
-S, --stdin : 从标准输入读取脚本
-f, --follow :将命令输出同步到console,可与-q配合使用
-r, --progress :在follow模式下显示执行进度
 
执行结果
0 : 所有命令执行成功
1 : 一个或多个命令执行失败
127 : 未知的错误

示例

dispatch -F 'tags: web' -- sudo apachectl restart
dispatch -F 'hostname: web.*' -K -- apachectl status
dispatch -F 'tags: dev' -K -C 3 -- sh -c update.sh
dispatch -F 'tags: web' -s myscript.sh
dispatch -F 'tags: dev' -u http://ops.example.com/scripts/myscript.sh
echo "uname -a" | dispatch -F 'os-family: unix' --stdin
dispatch -F 'os-family: unix' -- uptime
dispatch -F 'os-family: unix' -f -- uptime
rd-jobs
rd-jobs [*action*] [*action options*]...
list : 默认的action,列出所有node
-g, --group *GROUP* : Group Name。列出group里的jobs
-i, --idlist *ID* : Job ID List. 根据jobid列出jobs,逗号分隔
-n, --name *NAME* : Job Name. 根据job name列出jobs.
-f, --file *FILE* : File path. 将jod的定义存储在文件中
-F, --format *FORMAT* : File Format. 在存储时定义文件格式,YAML或XML,默认XML
load : 上传job文件到服务器
-d, --duplicate *update|skip|create* : 上传job文件时选择update更新现有job,skip忽略已存在的job,create创建job,默认update
-r, --remove-uuids : 上传job文件时设置去掉UUID,默认值false
-f, --file *FILE* : 设置需要上传的job文件路径
-F, --format *FORMAT* : 设置需要上传的job文件格式,YAML或XML,默认xml
purge : 删除job
同list的action

示例

rd-jobs -p demo
rd-jobs -i 123 -p demo
rd-jobs -i 1,23,4 --file out.xml -p demo
rd-jobs -i 1,23,4 --file out.yaml --format yaml -p demo
rd-jobs load -f jobs.xml
rd-jobs load -f jobs.yaml -F yaml
rd-jobs load -f jobs.xml -d skip
rd-project
-a    create. 当前只支持create操作
-p    project名称,必需项
--property=value    设置project属性的值,可设置多个

示例

rd-project -a create -p production
rd-project -a create -p production --project.ssh-keypath=/path/to/keyfile --resources.source.1.config.file=/path/to/resources
rd-queue

rd-queue [*action*] [-h] [-e id] [-p project]
list : 列出正在执行的jobs,默认选项
-m, --max    设置最多结果数,默认20.
-o, --offset   取消第一个结果的展示,默认0,没看懂
follow : 根据id查看正在执行的jobs的输出
kill : 根据id杀掉正在执行的jobs
 
-e, --eid  正在执行的job id,用于kill和follow
-p    Project名称,用于list

run
run [-h] [-v] [-l level] [-F nodefilters] [-i id] [-j group/name][-- arguments]
-v : 以详细模式执行.
-l, --loglevel *LEVEL* : 设置日志级别,verbose, info, warning, error.
-F, --filter *FILTER* : node的过滤字符串
-C *COUNT* : 线程数,默认1.
-K : 当有node执行失败时继续执行下面的node.
-N : 当有node执行失败时停止执行.
-j, --job *NAME* : 指定job name或group eg: 'group/name'.
-i, --id *IDENTIFIER* : 指定job id
-- *ARGUMENTS* : Pass the specified ARGUMENTS as options to the job
-f, --follow : 跟踪执行过程中的日志输出
-r, --progress : 打印进度,follow模式可用
-q, --quiet : 安静模式,不打印输出,follow模式可用.

生成rundeck的resources文件的shell脚本

这里选择json格式的文件,首先是一个模板文件叫tl.json

"_ALLIP": {
    "username": "ffsa",
    "hostname": "_IP",
    "nodename": "_ALLIP",
    "adminip": "_ADMINIP",
    "idracmac": "_IDRACMAC",
    "mod": "_MOD",
    "sn": "_SN",
    "appname": "_APPNAME",
    "master": "_MASTER"
},

脚本如下,cmdb_pserver.list文件是从CMDB数据库中查询出来的服务器信息列表

#!/bin/bash

echo "{" > resources_pserver.json
cat cmdb_pserver.list |\
while read line;do
    ALLIP=`echo $line |awk '{print $1}'`
    IP=`echo $line |awk '{print $1}'|awk -F '|' '{print $1}'`
        ADMINIP=`echo $line |awk '{print $2}'`
    IDRACMAC=`echo $line |awk '{print $3}'`
    MOD=`echo $line |awk '{print $5}'`
    SN=`echo $line |awk  '{print $4}'`
        APPNAME=`echo $line |awk '{print $6}'`
        MASTER=`echo $line |awk '{print $7}'`

    #echo "===================================="
        #echo allip: $ALLIP
    #echo ip: $IP
    #echo adminip: $ADMINIP
    #echo idracmac: $IDRACMAC
    #echo mod: $MOD
    #echo sn: $SN
    #echo appname: $APPNAME
    #echo master: $MASTER

    cat tl.json |sed -e "s/_ALLIP/$ALLIP/g" -e "s/_IP/$IP/g" -e "s/_ADMINIP/$ADMINIP/g" -e "s/_IDRACMAC/$IDRACMAC/g" -e "s/_MOD/$MOD/g" -e "s/_SN/$SN/g" -e "s/_APPN
AME/$APPNAME/g" -e "s/_MASTER/$MASTER/g" >> resources_pserver.json

done

sed -i '$s/,$//' resources_pserver.json
echo "}" >> resources_pserver.json

 

初识Rundeck

  • 背景

知道rundeck是在saltstack的QQ群里面,Google了一下觉得应该适合我们现在的需求。 官方网站:http://rundeck.org

  • 安装

从安装开始:http://rundeck.org/docs/administration/installation.html 最简单的方式是下载rundeck的jar包,然后直接启动,当然首先需要java环境,貌似需要1.6及以上版本支持。

#mkdir /usr/local/rundeck
#cd /usr/local/rundeck
#wget http://dl.bintray.com/rundeck/rundeck-maven/rundeck-launcher-2.4.0.jar
#java -XX:MaxPermSize=256m -Xmx1024m -jar rundeck-launcher-2.4.0.jar
设置环境变量
#vi /etc/profile
添加export RDECK_BASE=/usr/local/rundeck
#source /etc/profile
启动之后rundeck会在安装目录下新建一些文件夹
#tree -L 1 rundeck/
rundeck/
|-- etc
|-- libext
|-- projects
|-- rundeck-launcher-2.4.0.jar
|-- server
|-- tools
`-- var

6 directories, 1 file

启动之后会发现rundeck使用主机名作为URL地址,需要自己修改一下两个配置文件,将主机名修改为IP地址,也可再次修改服务端口,改好之后应该是像下面这样。

#more /usr/local/rundeck/etc/framework.properties
# framework.properties -
#

# ----------------------------------------------------------------
# Server connection information
# ----------------------------------------------------------------

framework.server.name = 192.168.100.100
framework.server.hostname = 192.168.100.100
framework.server.port = 4440
framework.server.url = http://192.168.100.100:4440
# Username/password used by CLI tools.
framework.server.username = admin
framework.server.password = admin

# ----------------------------------------------------------------
# Installation locations
# ----------------------------------------------------------------

rdeck.base=/usr/local/rundeck

framework.projects.dir=/usr/local/rundeck/projects
framework.etc.dir=/usr/local/rundeck/etc
framework.var.dir=/usr/local/rundeck/var
framework.tmp.dir=/usr/local/rundeck/var/tmp
framework.logs.dir=/usr/local/rundeck/var/logs
framework.libext.dir=/usr/local/rundeck/libext

# ----------------------------------------------------------------
# SSH defaults for node executor and file copier
# ----------------------------------------------------------------

framework.ssh.keypath = /root/.ssh/id_rsa
framework.ssh.user = root

# ssh connection timeout after a specified number of milliseconds.
# "0" value means wait forever.
framework.ssh.timeout = 0
#more /usr/local/rundeck/server/config/rundeck-config.properties
#loglevel.default is the default log level for jobs: ERROR,WARN,INFO,VERBOSE,DEBUG
loglevel.default=INFO
rdeck.base=/usr/local/rundeck

#rss.enabled if set to true enables RSS feeds that are public (non-authenticated)
rss.enabled=false
grails.serverURL=http://192.168.100.100:4440
dataSource.dbCreate = update
dataSource.url = jdbc:h2:file:/usr/local/rundeck/server/data/grailsdb;MVCC=true
将rundeck链接为服务
#ln -s /usr/local/rundeck/server/sbin/rundeckd /etc/init.d/
OK,现在可以启动了
#/etc/init.d/rundeck start
查看日志
root@RUNDECK:/usr/local/rundeck# tail -f /usr/local/rundeck/var/log/service.log 
2015-01-23 10:24:43.224:INFO:oejs.Server:jetty-7.6.0.v20120127
2015-01-23 10:24:45.509:INFO:oejw.StandardDescriptorProcessor:NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet
2015-01-23 10:24:46.390:INFO:/:Initializing Spring root WebApplicationContext
2015-01-23 10:24:58,708 INFO  BootStrap - Starting Rundeck 2.4.0-1...
2015-01-23 10:24:58,712 INFO  BootStrap - using rdeck.base config property: /usr/local/rundeck
2015-01-23 10:24:58,722 INFO  BootStrap - loaded configuration: /usr/local/rundeck/etc/framework.properties
2015-01-23 10:24:58,797 INFO  BootStrap - RSS feeds disabled
2015-01-23 10:24:59.841:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/usr/local/rundeck/server/exp/webapp/},/usr/local/rundeck/server/exp/webapp
2015-01-23 10:24:59.947:INFO:/:Initializing Spring FrameworkServlet 'grails'
2015-01-23 10:25:00.002:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:4440
说明服务已启动,现在可以从前台访问了,http://192.168.100.100:4440
  • 配置NODE

第一次访问rundeck会提示你新建一个Project,按照提示新建,我只输入了project name,其余默认,然后create。 到这里,该添加nodes了,我使用ssh key免密码登陆,首先需要设置好rundeck服务器到其他node服务器的ssh认证,步骤省略,在设置好之后,按照http://rundeck.org/2.4.0/man5/resource-xml.html这里说的,编辑下面这个文件

#more /usr/local/rundeck/projects/Project_A/etc/resources.xml
<?xml version="1.0" encoding="UTF-8"?>

<project>
  <node name="192.168.100.100" description="Rundeck server node" tags="" hostname="192.168.100.100" osArch="amd64" osFamily="unix" osName="Linux" osVersion="3.11.0-15-generic" username="root"/>
  <node name="192.168.100.101" type="Node" tags="web" role="web" description="web" hostname="192.168.100.101:11223" osArch="amd64" osFamily="unix" osName="Linux" osVersion="3.11.0-15-generic" username="root"/>
  <node name="192.168.100.102" type="Node" tags="wap" role="wap" description="wap" hostname="192.168.100.102:11223" osArch="amd64" osFamily="unix" osName="Linux" osVersion="3.11.0-15-generic" username="root"/>
</project>

第一个node是rundeck服务器的信息,后面两个是添加进去的node信息,现在在前台的就可以看到了。

  • 配置用户

接下来需要添加用户,rundeck默认有两个用户角色,一个是admin,一个是user,所有用户(包括admin)都必须属于user,在/usr/local/rundeck/server/config/realm.properties文件里可以看到

# more realm.properties 
#
# This file defines users passwords and roles for a HashUserRealm
#
# The format is
#  <username>: <password>[,<rolename> ...]
#
# Passwords may be clear text, obfuscated or checksummed.  The class 
# org.mortbay.util.Password should be used to generate obfuscated
# passwords or password checksums
#
# This sets the temporary user accounts for the Rundeck app
#
admin:admin,user,admin
user:user,user

冒号前是用户名,后面是密码,再后面便是用户的角色,用逗号分隔。 我只想给用户read和run的权限,这块琢磨了很久,也不知道我的方法对不对。我没有找到新建用户组在哪里配置,只能一个一个添加用户,还好用户不多。参考了:http://rundeck.org/docs/administration/authenticating-users.html 和 http://rundeck.org/docs/administration/access-control-policy.html 新建用户

# cd /usr/local/rundeck
# java -cp server/lib/jetty-all-7.6.0.v20120127.jar org.eclipse.jetty.util.security.Password username passwd
passwd
OBF:1kwa1v251rwd1uvc1ljv1xfn1zen1xff1llv1uuu1rwh1v291svo1j611lxl1kqp1jyb
MD5:dd9162bbad929f64b0fa3
CRYPT:UMbF7fN.

给用户赋权限,可以新建多个下面的文件,每个用户对应一个文件

# cd /usr/local/rundeck/etc
# more username.aclpolicy 
description: username.
context:
  project: '.*'
for:
  resource:
    - allow: read
  job:
    - match:
        group: '.*'
        name: '.*'
      allow: [run,read]
by:
  username: username

---

description: username.
context:
  application: 'rundeck'
for:
  resource:
    - allow: read
  project:
    - allow: read
  storage:
    - allow: read
by:
  username: username

这样新用户就可以登陆了,现在系统中有三个用户,一个是admin,一个是user,一个是新建的username,记得在realm.properties文件中修改admin和user的密码。

  • 建立工作流

环境:nginx通过upstream代理两个glassfish节点 新建一个project名为wap_deploy,在project中建立如下几个job: 1,kick_out_192.168.0.1:7001 负责从nginx的upstream中踢出192.168.0.1:7001节点,workflow里的shell脚本如下

#!/bin/bash

NODE=$1
grep -q -E "#[[:blank:]]*server $NODE" /usr/local/nginx/conf/nginx.conf

if [ $? -eq 0 ];then
    echo ''$NODE' had been Kicked already'
else
    /bin/sed -i '/server '$NODE';/s/^/#/' /usr/local/nginx/conf/nginx.conf
    /etc/init.d/nginx reload

    if [ $? -eq 0 ];then
        echo ''$NODE' had been Kicked from nginx configuration successfully'
    fi
fi

Arguments里写upstream中定义的节点即可,这里是192.168.0.1:7001 2,kick_out_192.168.0.2:7001 内容同上,shell脚本可复用,改变Arguments为192.168.0.2:7001即可。 3,add_in_192.168.0.1:7001 负责把部署好的节点重新加入upstream,workflow里的shell脚本如下

#!/bin/bash
NODE=$1

/bin/sed -i '/server '$NODE';/s/^#//' /usr/local/nginx/conf/nginx.conf

if [ $? -eq 0 ];then
    echo ''$NODE' had been Added to nginx configuration successfully'
fi

/etc/init.d/nginx reload

Arguments里写upstream中定义的节点即可,这里是192.168.0.1:7001 4, add_in_192.168.0.2:7001 内容同上,shell脚本可复用,改变Arguments为192.168.0.2:7001即可。 5,deploy_wap_192.168.0.1 负责从hudson上取出打包好的war程序,复制到部署目录并执行部署,共三个过程。 workflow中先添加“kick_out_192.168.0.1:7001”job,以便从upstream中踢出节点。 然后第二步定义部署过程,shell脚本如下

#/bin/bash

source /etc/profile

SVN_SERVER=$1
HUDSON_JOB=$2
WAR_NAME=$3
DOMAIN=$4
CSL_PORT=$5
GNAME=$6
CONTEXTROOT=$7

if [ -e /usr/local/glassfish3/glassfish/domains/$DOMAIN/deployment/$WAR_NAME ];
 then
    cd /usr/local/glassfish3/glassfish/domains/$DOMAIN/deployment/
    /bin/cp $WAR_NAME $WAR_NAME'_'`date +%Y%m%d%H%M`
    scp $SVN_SERVER:/usr/local/hudson/jobs/$HUDSON_JOB/workspace/target/$WAR_NAME /usr/local/glassfish3/glassfish/domains/$DOMAIN/deployment/

else
    scp $SVN_SERVER:/usr/local/hudson/jobs/$HUDSON_JOB/workspace/target/$WAR_NAME /usr/local/glassfish3/glassfish/domains/$DOMAIN/deployment/
fi

if [ $? -eq 0 ];then
    echo $WAR_NAME ' had been copied successfully'
fi

/usr/local/glassfish3/glassfish/bin/asadmin --user admin --passwordfile /home/abc/p.txt --port $CSL_PORT deploy --force --name=$GNAME  --contextroot /$CONTEXTROOT /usr/local/glassfish3/glassfish/domains/$DOMAIN/deployment/$WAR_NAME

Arguments略多,第一个为hudson服务器的IP(需配置免密登陆),第二个是hudson的工程名,第三个是war包名称,第四个是部署到glassfish的哪个domain,第五个是所在domain的控制台端口,第六个是asadmin的–name参数,第七个是部署路径(为空则部署在根目录)。如:192.168.0.3 wap wap.war domain1 4800 wap wap 第三步,添加“add_in_192.168.0.1:7001”job,以便把节点加入upstream中。 6, deploy_wap_192.168.0.2 步骤同deploy_wap_192.168.0.1,修改Arguments即可。 7, deploy_wap 这是最后一个job,在workflow里面添加deploy_wap_192.168.0.1和deploy_wap_192.168.0.2两个job即可。 在需要部署的时候,开发人员需要做的只是在hudson上打好包,然后登陆rundeck,进入wap_deploy运行deploy_wap这个job即可,在Log output中也可以查看部署过程中生成的日志。 这样做节省了从服务器上下载及上传war包的时间,也避免了在运维人员在服务器上的误操作,旧的war包更规范的保存在服务器上,方便回退时使用,在rundeck的project日志中可以看到部署的频率及人员,为之后的优化提供参考。