(TOP)服务器部署点服务

之前写了点代码跑在阿里云上,最近发现自己博客的部署老是失败(用的git的webhook),结果一阵子没看服务器的东西,竟然忘了都有什么服务,也不知道服务的运行状态…

记录一下部署的服务过程之类的吧,权当备忘。

  1. 首先我得有项目代码,然后有个entrance之类的脚本可以很方便的把这个项目启动起来…
  2. 用什么方式启动?而且服务在运行崩溃或者服务器重启之后可以自己重新启动,这也是个问题…
  3. 有时候我需要定时跑一下服务
  4. 最后,我可以在本地远程启动、停止这些服务,方便部署。

入口脚本

我之前写了一个简单的用于webhook的脚本,主要就是serve_forever一个http服务,如果我的git仓库有push到master的动作,就会帮我执行一些因缺斯汀的事情,脚本名称叫webhook.py。

脚本执行方式

普通的执行

我可以直接

1
nohup python webhook.py > webhook.log

就可以在后台稳当的跑起来这个http服务了。

如果想要开机启动的话,开机启动的脚本都放在 /etc/init.d,所以我们需要写个脚本放这个目录下,然后用在etc下面的rc$runlevel.d里用ln添加一个软链接到该脚本,当然,这个事情在ubuntu下面可以使用update-rc.d命令:

update-rc.d supervisor defaults 99

附一个别人的链接:http://blog.csdn.net/typ2004/article/details/38712887

linux启动的时候会运行init进程,init进程会找etc/init.d下面的脚本,并且按照优先级依次执行里面的脚本,我的系统是ubuntu,这个开始启动执行代码在/etc/init.d/rc里,具体代码见附录1(主要流程就是先找etc下面rc$runlevel.d的文件,然后找到所有K开头的脚本,按照level次序执行停止脚本,然后找S开头的脚本,按照level次序执行开始脚本)

supervisor管理

如果程序运行出现异常怎么办?那就要用到进程管理神器:supervisor

安装配置

apt-get也可以装,pip也可以装(没有特殊的需求建议装全局的环境下,不要像我用pip装在了我其中一个python虚拟环境里了,导致每次用到它的时候都在在这个虚拟环境下执行…)

然后执行:

echo_supervisord_conf > /etc/supervisord.conf

这个配置文件配置了哪些程序可以用supervisor来管理

然后稍微修改一下supervisord.conf文件:

  1. 修改sock file:file=/var/run/supervisor.sock ,看一下serverurl=unix:///var/run/supervisor.sock和file=/var/run/supervisor.sock,这两个一致就可以(具体的我也忘了,好像一开始默认是指向tmp目录下的,最好修改一下这个配置吧)
  2. 修改supervisor log:logfile=/var/log/supervisord.log

我们可以看到这个配置文件已经配置了一个示例程序了,而且最后有这一段:

1
2
[include]
files = /etc/supervisor/*.ini

表示会把/etc/supervisor/下面的ini配置文件也包含进来,所以我们只需要创建自己的ini配置就可以了,我给程序命名为tech_hikyson_cn_webhook_hexo_deploy,执行的命令为python webhook.py,具体的配置见附录2

使用

配置好之后就可以启动supervisor:

supervisord -c /etc/supervisord.conf

附几个小命令:ps -ef|grep supervisord 查看进程是否存在,使用 supervisorctl status 可以查看进程管理的状态,kill -9 [12345进程id]杀死进程

使用supervisor启动/停止我们刚才配置的程序:

supervisorctl start tech_hikyson_cn_webhook_hexo_deploy
supervisorctl stop tech_hikyson_cn_webhook_hexo_deploy

我们想让supervisor开机启动:

创建启动脚本/etc/init.d/supervisor,内容见附录3,主要就是启动supervisor,ubuntu下的开机启动服务在文件头上必须声明init info:

1
2
3
### BEGIN INIT INFO
...
### END INIT INFO

这样,我们就可以利用supervisor,在程序崩溃的时候,开机的时候(开始运行supervisor,supervisor启动自动运行我们的脚本)都可以执行我们的脚本

定时任务

使用crontab,crontab是linux自带的cron工具的配置文件,使用crontab -e就可以编辑自己的定时任务了,用户root,ubuntu系统下编辑的文件路径是:/var/spool/cron/crontabs/root
crontab的定时任务有一套自己的规则:

1
2
3
4
5
6
7
8
9
┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of month (1 - 31)
│ │ │ ┌───────────── month (1 - 12)
│ │ │ │ ┌───────────── day of week (0 - 6) (Sunday to Saturday;
│ │ │ │ │ 7 is also Sunday on some systems)
│ │ │ │ │
│ │ │ │ │
* * * * * command to execute

具体看wikihttps://en.wikipedia.org/wiki/Cron#CRON_expression

1
2
//每小时执行一次爬虫
0 * * * * cd /root/develop/ScrapyForAndroidDashboard/ScrapyForAndroidDashboard && /root/develop/pythonenv/scrapyforandroiddashboard/bin/python /root/develop/ScrapyForAndroidDashboard/ScrapyForAndroidDashboard/entrance.py >> /root/develop/ScrapyForAndroidDashboard/scrapyforandroiddashboard.log

远程部署

我们希望每次部署服务不需要到服务器机器上执行命令,而是自己写好一些部署脚本,然后本地执行就可以部署服务

我们需要fabric,传说中python的三大神器之一。

我们可以编写一些简单的python代码,使用fabric提供的api远程执行服务器命令,具体的使用方式:http://python.jobbole.com/87241/

一般来说我就定义build方法和deploy方法,build方法可以让服务器用git拉取我们最新的代码并做一些准备工作,deploy就把代码跑起来(使用supervisor,还记得吧?)即可。

类似这样:deploy:run("supervisorctl start " + supervisor_task_name)

写完收工~

我也该去查一下webhook总是失败的原因了…

附录

[附录1]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# Is there an rc directory for this new runlevel?
if [ -d /etc/rc$runlevel.d ]
then
case "$runlevel" in
0|6)
ACTION=stop
;;
S)
ACTION=start
;;
*)
ACTION=start
;;
esac

# First, run the KILL scripts.
if [ makefile = "$CONCURRENCY" ]
then
if [ "$ACTION" = "start" ] && [ "$previous" != N ]
then
startup stop
fi
elif [ "$previous" != N ]
then
# Run all scripts with the same level in parallel
CURLEVEL=""
for s in /etc/rc$runlevel.d/K*
do
# Extract order value from symlink
level=${s#/etc/rc$runlevel.d/K}
level=${level%%[a-zA-Z]*}
if [ "$level" = "$CURLEVEL" ]
then
continue
fi
CURLEVEL=$level
SCRIPTS=""
for i in /etc/rc$runlevel.d/K$level*
do
# Check if the script is there.
[ ! -f $i ] && continue

#
# Find stop script in previous runlevel but
# no start script there.
#
suffix=${i#/etc/rc$runlevel.d/K[0-9][0-9]}
previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix
previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
#
# If there is a stop script in the previous level
# and _no_ start script there, we don't
# have to re-stop the service.
#
[ -f $previous_stop ] && [ ! -f $previous_start ] && continue

# Stop the service.
SCRIPTS="$SCRIPTS $i"
done
startup stop $SCRIPTS
done
fi

if [ makefile = "$CONCURRENCY" ]
then
if [ S = "$runlevel" ]
then
startup boot
else
startup $ACTION
fi
else
# Now run the START scripts for this runlevel.
# Run all scripts with the same level in parallel
CURLEVEL=""
for s in /etc/rc$runlevel.d/S*
do
# Extract order value from symlink
level=${s#/etc/rc$runlevel.d/S}
level=${level%%[a-zA-Z]*}
if [ "$level" = "$CURLEVEL" ]
then
continue
fi
CURLEVEL=$level
SCRIPTS=""
for i in /etc/rc$runlevel.d/S$level*
do
[ ! -f $i ] && continue

suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}
if [ "$previous" != N ]
then
#
# Find start script in previous runlevel and
# stop script in this runlevel.
#
stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix
previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
#
# If there is a start script in the previous level
# and _no_ stop script in this level, we don't
# have to re-start the service.
#
if [ start = "$ACTION" ] ; then
[ -f $previous_start ] && [ ! -f $stop ] && continue
else
# Workaround for the special
# handling of runlevels 0 and 6.
previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix
#
# If there is a stop script in the previous level
# and _no_ start script there, we don't
# have to re-stop the service.
#
[ -f $previous_stop ] && [ ! -f $previous_start ] && continue
fi

fi
SCRIPTS="$SCRIPTS $i"
done
startup $ACTION $SCRIPTS
done
fi
fi

[附录2]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[program:tech_hikyson_cn_webhook_hexo_deploy]
command=python webhook.py
directory=/root/develop/tech_hikyson_cn_hexo_webhook
startsecs=0
stopwaitsecs=0
autostart=true
autorestart=true
user=root
redirect_stderr=false
stdout_logfile=/var/log/supervisor/tech_hikyson_cn_webhook_hexo_deploy/access.log
stdout_logfile_maxbytes=3MB
stdout_logfile_backups=10
stdout_capture_maxbytes=3MB
stdout_events_enabled=false
stderr_logfile=/var/log/supervisor/tech_hikyson_cn_webhook_hexo_deploy/error.log
stderr_logfile_maxbytes=3MB
stderr_logfile_backups=10
stderr_capture_maxbytes=3MB
stderr_events_enabled=false

[附录3]

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
### BEGIN INIT INFO
# Provides: supervisor
# Required-Start: $remote_fs $network $named
# Required-Stop: $remote_fs $network $named
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start/stop supervisor
# Description: Start/stop supervisor daemon and its configured
# subprocesses.
### END INIT INFO
[这里是supervisor路径]/bin/supervisord -c /etc/supervisord.conf