UUBlog

UUBlog

配置jenkins源

1
2
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo
sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key

直接 yum install jenkins是安全版本非最新版。

可以去 https://pkg.jenkins.io/redhat-stable/
下载自己喜欢的版本
比如我安装最新版

1
yum install https://pkg.jenkins.io/redhat-stable/jenkins-2.89.4-1.1.noarch.rpm

vim /etc/sysconfig/jenkins 编辑下配置文件

我主要改了端口和home目录

启动

1
systemctl start/enable jenkins

http://120.79.138.224:10086/generic-webhook-trigger/invoke?token=offence-reporting-service
https://wiki.jenkins.io/display/JENKINS/CloudBees+Docker+Build+and+Publish+plugin

#参考资料

关注公众号 尹安灿

Supervisor简述

关于Java进程监控,一直都是要搞的。至于怎么实现,一直比较纠结,也就拖了很久。

最近看到supervisor,感觉还不错,打算试试。

简单简单一句话描述supervisor的作用的话。

可以把一个命令变成daemon进程管理,可以实现异常重启

另外还提供了API,这为提供WEB式管理提供了便利,官方有带了一个简陋的web界面,也有一些第三方的似乎看起来也不错。

通过supervisor运行的,都成为supervisor的子进程,它也是通过这个去管理进程,比通过pid文件管理更稳定。因为有时候进程异常退出,pid存放的数据就是错的,有可能导致其它进程被意外终结。

支持的平台

Supervisor works on just about everything except for Windows.

准确点说,基本UNIX-Like系统都支持。

主要组件

supervisord

supervisor的服务进程,响应客户端的命令、管理子进程

使用的时候要读取配置文件。寻找配置文件的优先级如下:

1
2
3
4
5
6
$CWD/supervisord.conf
$CWD/etc/supervisord.conf
/etc/supervisord.conf
/etc/supervisor/supervisord.conf (since Supervisor 3.3.0)
../etc/supervisord.conf (Relative to the executable)
../supervisord.conf (Relative to the executable)

不过建议还是启动的时候,制定配置文件所在的绝对路径。

supervisorctl

supervisor的命令行客户端

配置项在 [supervisorctl]

Web Server

supervisor的web服务,web提供少量功能管理supervisor。

配置[inet_http_server]

XML-RPC

API接口

介绍:XML-RPC API Documentation

安装

  • sudo pip install supervisor

or

  • esay_install supervisor

安装完运行echo_supervisord_conf,如果能输出配置,那就安装完成了。

使用说明

配置

其实在echo_supervisord_conf后,前面几行就有官方的配置说明文档链接:http://supervisord.org/configuration.html

不过未免巨细无遗了。

根据需求,我们需要监控进程,需要可以在线管控进程状态,简单配置几项就行了。配置文件语法是Windows-INI Style。

创建配置

启动supervisord组件的时候,它会从前面提到的搜寻文件路径,按优先级去找配置文件。为了避免加载到非我们修改的配置,建议启动的时候-c指定一些配置文件。

*这里为了方便管理配置文件,我把它放到/etc/supervisor/supervisor.conf program的配置文件放到 ./conf.d/*.conf *

1
2
# mkdir -p /etc/supervisor/conf.d/
# echo_supervisord_conf > /etc/supervisor/supervisor.conf

修改配置

  • vim /etc/supervisor/supervisor.conf

主要改动如下内容:

1
2
3
4
5
[inet_http_server]         ; inet (TCP) server disabled by default
port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface
username=onecer ; default is no username (open server)
password=youpassword ; default is no password (open server)

这里port,如果你想可以通过外网IP+端口访问web dashboard,那就改为*:9001或者0.0.0.0:9001

这里我打算到时候用nginx做反向代理,绑定域名,所以就无所谓,127.0.0.1 。

username和password就是管理账户。

1
2
[include]
files = conf.d/*.conf

这里原本是ini后缀的,但是我想入乡随俗,在linux就改为conf后缀的配置文件吧。用的相对路径,如果我们加载的是/etc/supervisor/supervisor.conf 那这个就表加载/etc/supervisor/conf.d/目录下所有的conf文件。

事实这个可以省了,program配置直接写在主配置文件里面。不过,如果程序多的话,还是建议分开。像nginx一样,这样利于以后维护各个配置。

主配置里面有很多program的配置示例,可以复制一个过去修改即可使用。

  • 新建一个配置vim /etc/supervisor/conf.d/java_room_status.conf

复制主配置里面一段program的配置出来贴上,稍作修改即可。

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
[program:roomstatus_dev]
command=/usr/bin/java -jar /data/www/room/devshixin.jar ; the program (relative uses PATH, can take args)
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
;numprocs=1 ; number of processes copies to start (def 1)
;directory=/tmp ; directory to cwd to before exec (def no cwd)
;umask=022 ; umask for process (default None)
;priority=999 ; the relative start priority (default 999)
autostart=true ; start at supervisord start (default: true)
;startsecs=1 ; # of secs prog must stay up to be running (def. 1)
;startretries=3 ; max # of serial start failures when starting (default 3)
autorestart=unexpected ; when to restart if exited after running (def: unexpected)
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
;stopsignal=QUIT ; signal used to kill process (default TERM)
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
;stopasgroup=false ; send stop signal to the UNIX process group (default false)
;killasgroup=false ; SIGKILL the UNIX process group (def false)
;user=chrism ; setuid to this UNIX account to run the program
;redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/var/log/dev_room.log ; stdout log path, NONE for none; default AUTO
stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
stdout_logfile_backups=10 ; # of stdout logfile backups (0 means none, default 10)
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stdout_events_enabled=false ; emit events on stdout writes (default false)
stderr_logfile=/var/log/err_dev_room.log ; stderr log path, NONE for none; default AUTO
stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
;stderr_events_enabled=false ; emit events on stderr writes (default false)
;environment=A="1",B="2" ; process environment additions (def no adds)
;serverurl=AUTO ; override serverurl computation (childutils)

参考资料

关注公众号 尹安灿

Pyrsync

调用rsync同步文件,从yaml文件读取配置。简化rsync使用,和方便管理备份项更改。未来将提供web界面添加yaml配置。

安装依赖

sudo pip install -r requirements.txt

sudo yum install -y rsync

使用说明

  • 新建项目yaml配置文件 cp playbook/default.yaml.template playbook/default.yaml

  • 配置好项目使用哪个账户复制,ip、备份目录之类的。

  • 要提前做好要备份的主机公钥认证,好让rsync不用输入密码。

  • 执行 ./pyrsync.py

yaml配置文件说明

  • actor 项说明
作用
name 做了ssh公钥认证登录的用户
IP 要备份的内容所在的服务器IP
port ssh端口
action rsync的参数项可以自由写 如:-avz –delete
  • execute 项说明 脚本统一放在script目录

填写脚本文件名,理论支持shell,Python等,
一定要在脚本开头定义好解析器。如bash #!/bin/bash

作用
pre-local 同步前在本机执行
pre-remote 同步前在远程机执行
post-remote 同步后在远程机执行
post-local 同步后在本机执行
  • playbook剧本sences场景项说明

  • 一个场景配置一个目录、和一个排除文件,排除文件目录在exclude,填写文件名即可。排除支持通配符,一行一个筛选项。cvs.txt是例子。

作用
item 要备份的目录
savepath 保存到本地的目录
exclude 描述排除文件的文件名 在exclude目录

使用场景

我要定时对 192.168.168.19上的三个项目的uploads目录进行同步备份。

分别是

  • /data/web1/uploads
  • /data/web2/uploads
  • /data/web3/uploads

还要定时导出MySQL数据库test2,到/data/sql,并同步备份过来。但是过滤掉.git目录、.svn目录。

备份内容保存到本地 /backup/node1 目录

根据上面信息,可以配置一个如下的yaml文件。

test.yaml (名字可以随意取,后缀一定得是yaml)

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
actor:
name: root
ip: 192.168.168.19
port: 22
action: -avz

execute:
pre-local:
pre-remote: test.sh
post-remote:
post-local:

playbook:
sences:
- 1:
item: /data/web1/uploads
savepath: /backup/web1
exclude: cvs.txt
- 2:
item: /data/web2/uploads
savepath: /backup/web2
exclude: cvs.txt
- 3:
item: /data/web3/uploads
savepath: /backup/web3
exclude: cvs.txt
- 4:
item: /data/sql
savepath: /backup/sql
exclude: cvs.txt

上面pre-remote的test.sh内容如下

1
2
3
#!/bin/bash

mysqldump -uroot -predhat test2 > /data/sql/test2.sql

备份前目录情况如下:

远程机/data/ :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/data
├── .git
│   └── 11
├── sql
├── web1
│   ├── .git
│   │   └── master
│   └── uploads
│   └── web1.html
├── web2
│   ├── .svn
│   │   └── entries
│   └── uploads
│   └── web2.png
└── web3
└── uploads
└── web3.php

10 directories, 6 files

本机 /backup/node1/:

1
2
3
node1

0 directories, 0 files

现在执行./pyrsync.py

执行后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/backup/
├── sql
│   └── sql
│   └── test2.sql
├── web1
│   └── uploads
│   └── web1.html
├── web2
│   └── uploads
│   └── web2.png
└── web3
└── uploads
└── web3.php

8 directories, 4 files

项目地址: https://github.com/onecer/Pyrsync

关注公众号 尹安灿

项目地址: https://github.com/onecer/Pyrsync

readme: https://uublog.com/article/20170630/pyrsync-readme/

===========================================================================

打算用rsync同步,刚刚在写shell的时候,尝试了下,项目多了,目录多了。shell代码就眼花缭乱。

所以,这样封装了一下,备份的项目用yaml描述。100行代码,可以更方便的去管理备份源。

项目代码:

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
#!/usr/bin/env python
# coding:utf-8

# Author: phan

import os
import yaml
import commands
import time
import codecs

# 配置区域
# 日志路径
LOGFILE = '/var/log/pyrsync.log'
# 是否开启日志
ENABLE_LOG = True
# 啰嗦模式
VERBOSE_MODE = True

# 自定义常量
BASEDIR = os.path.dirname(__file__)

# 获取目录文件列表
def get_file_lists(dirpath):
filelists = []
for filename in os.listdir(dirpath):
filelists.append(os.path.join(dirpath,filename))
return filelists

# 获取当前时间
def get_time():
return time.strftime('%Y-%m-%d %H:%M:%S ',time.localtime(time.time()))

# 记录日志
def logger(line):
if ENABLE_LOG:
if os.path.isfile(LOGFILE):
with codecs.open(LOGFILE,'a','utf-8') as f:
f.write("{time}{logline}\n".format(time=get_time(), logline=line))
else:
with codecs.open(LOGFILE,'w','utf-8') as f:
f.write("{time}{logline}\n".format(time=get_time(), logline=line))

# 记录命令日志
def logger_commands(status,result):
logger('result:{status}'.format(status=status))
if VERBOSE_MODE:
logger(result)

# 执行命令
def runcommand(commandline):
return commands.getstatusoutput(commandline)

# 部署场景
def deploy_sences(isLocal,shellfile,actor=''):
commandline = os.path.join(BASEDIR, 'script', shellfile)
if isLocal:
(status,result) = runcommand(commandline)
logger_commands(status,result)
else:
upload_script = 'scp {command} {name}@{ip}:/tmp/pyrsync_{scriptName}'.format(
command=commandline,
name=actor['name'],
ip=actor['ip'],
scriptName=os.path.basename(commandline)
)
(status,result) = runcommand(upload_script)
logger_commands(status, result)
commandline = 'ssh {name}@{ip} "chmod u+x /tmp/pyrsync_{command} && /tmp/pyrsync_{command} && rm -f /tmp/pyrsync_{command}"'.format(
name=actor['name'],
ip=actor['ip'],
command=os.path.basename(commandline),
)
(status,result) = runcommand(commandline)
logger_commands(status, result)

# 同步文件
def sync_files(actor,sence):
rsyncCommand = 'rsync {action} --exclude-from="{exclude}" {name}@{ip}:{path} {savepath}'.format(
action=actor['action'],
exclude=os.path.join(BASEDIR,'exclude',sence['exclude']),
name=actor['name'],
ip=actor['ip'],
port=actor['port'],
path=sence['item'],
savepath=sence['savepath']
)
logger('Command:{command}'.format(command=rsyncCommand))
(status,result) = runcommand(rsyncCommand)
logger_commands(status,result)

# 执行剧本
def play_playbooks(filelists):
for filelist in filelists:
if os.path.isfile(filelist) and os.path.splitext(filelist)[-1]=='.yaml':
with open(filelist,'r') as f:
playbook = yaml.load(f)
sences = playbook['playbook']['sences']
for sence in sences:
if playbook['execute']['pre-local']:
deploy_sences(True,playbook['execute']['pre-local'])
if playbook['execute']['pre-remote']:
deploy_sences(False, playbook['execute']['pre-remote'],playbook['actor'])
sync_files(playbook['actor'],sence)
if playbook['execute']['post-remote']:
deploy_sences(False,playbook['execute']['post-remote'],playbook['actor'])
if playbook['execute']['post-local']:
deploy_sences(True,playbook['execute']['post-local'])

if __name__=='__main__':
play_playbooks(get_file_lists(os.path.join(BASEDIR,'playbook')))

配置格式如下:

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
actor:
name: root
ip: 192.168.168.19
port: 22
action: -avz

execute:
pre-local:
pre-remote: test.sh
post-remote:
post-local:

playbook:
sences:
- 1:
item: /data/web1/uploads
savepath: /backup/web1
exclude: cvs.txt
- 2:
item: /data/web2/uploads
savepath: /backup/web2
exclude: cvs.txt
- 3:
item: /data/web3/uploads
savepath: /backup/web3
exclude: cvs.txt
- 4:
item: /data/sql
savepath: /backup/sql
exclude: cvs.txt

安装

Pyrsync

调用rsync同步文件,从yaml文件读取配置。简化rsync使用,和方便管理备份项更改。未来将提供web界面添加yaml配置。

安装依赖

sudo pip install -r requirements.txt

sudo yum install -y rsync

使用说明

  • 新建项目yaml配置文件 cp playbook/default.yaml.template playbook/default.yaml

  • 配置好项目使用哪个账户复制,ip、备份目录之类的。

  • 要提前做好要备份的主机公钥认证,好让rsync不用输入密码。

  • 执行 ./pyrsync.py

关注公众号 尹安灿

最近公司大部分项目从SVN过渡到Git。所以代码自动化部署也有了更多的想象空间。

之前使用SVN更新代码到开发环境的时候,都是用crontab定时svn update。间隔是一分钟,虽然一分钟不算长,甚至有时候等待并不需要这么久。

但是总归是无法做到及时更新。算是自动主动更新,而Git有webhook的存在,就可以做到触发式更新。

我们代码是放在 git.oschina.net 码云上。

原理

每次git提交的时候,都会触发webhook,webhook会访问我们设置的URL。

URL触发我们的更新代码。

所以,我们还需要架一个网站,提供一个webhook访问的URL,访问的时候触发代码。

实践

时间原因,轮子就不自己造了,所以,我找到一份还不错的webhook管理平台。

安装git-webhook

环境: Centos7

这里用docker部署

1
2
3
4
5
6
7
8
9
10
11
12
# 安装启动docker
# yum install docker
# systemctl restart docker
# systemctl enable docker
# 安装 Docker Compose
# yum install docker-compose
# 下载源码
# git clone https://github.com/NetEaseGame/git-webhook.git
# 修改配置
# cd git-webhook
# cp app/config_docker_example.py app/config.py
# vim app/config.py

GITHUB: GitHub 登陆配置,可以到 OAuth applications 自行申请,登陆 Callback 地址为: your_domain/github/callback.

配置好后,就可以执行

1
# docker-compose up

第一次启动的时候会docker会pull几个需要的镜像,所以时间要长点。

以后启动的话,可以用docker-compose up -d 用deamon方式启动。

Nginx配置

启动后,docker 暴露出来的端口是 18340.访问的话,就是 http://ip:18340

所以我打算给它绑定一个域名,让它访问要更方便一点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 80;
server_name webhook.xxx.com;

root html;
index index.html index.htm index.php;

location / {
proxy_pass http://127.0.0.1:18340/;

#Proxy Settings
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

至此git-webhook就安装好了。

用github账号登录进去,先添加服务器,再添加git仓库。得到的url填到git.oschina.net webhook那里就行了。

  • 添加好项目后,在箭头方向复制URL

复制路径

  • 登录码云,填写URL到webhook那里

填写URL

参考资料

关注公众号 尹安灿

GIT可以选择有很多,国外有github,国内有coding和git.oschina.net。

因为不可描述的原因,我们选了国内的。注册和管理其实和github很像。

我再做了ssh公钥认证后,将远程仓库git clone一份回本地。这样它就会自动生成一个.git目录了。

其实自己在本地现有的项目下用git remote add 也是可以的,但是感觉要略为麻烦点。

将SVN仓库代码更新至最新,复制多一份。

进入SVN代码目录,删除原来SVN的隐藏目录,.svn,这个内容占了很大空间。

1
find . -type d -name ".svn"|xargs rm -rf

将内容复制的到git目录,并提交去远程仓库。

1
2
3
git add -A
git commit -m "first commit"
git push origin master

done.

关注公众号 尹安灿

归类到工具吧,算是可以提升效率的东西。自己也折腾过,VIM配置插件还是挺麻烦的。直到看到这个,一键配置,这个项目再github居然有3K的star。

https://github.com/wklken/k-vim

安装方法不赘述,帮助文档有。

用来写Python和其它脚步,做些小修改,算是一个好的补充吧。毕竟大部分时候还是专业的IDE比较方便。

关注公众号 尹安灿

本机装了MariaDB,很久不用,把密码给忘记了。

然后刚刚把密码恢复了下,记录一份这里方便以后索引。

  1. 停止MySQL服务。

# systemctl stop mysql 我是Ubuntu 这里服务名是这个

  1. 用无权限管理方式启动

# mysqld_safe --skip-grant-tables &

  1. 登录修改密码

# mysql -uroot

修改密码的SQL

1
2
3
4
> use mysql;
> update user set password=PASSWORD("gjdEdufD93J") where User='root';
> flush privileges;
> quit
  1. 停止mysql进程

/etc/init.d/mysql stop

  1. 启动服务 systemctl restart mysql

done.

全部流程记录

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
fate phan # systemctl stop mysql
fate phan # mysqld_safe --skip-grant-tables &
[1] 14391
fate phan # 170527 11:46:39 mysqld_safe Logging to syslog.
170527 11:46:39 mysqld_safe Starting mysqld daemon with databases from /var/lib/mysql

fate phan # mysql -uroot
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 10.0.29-MariaDB-0ubuntu0.16.04.1 Ubuntu 16.04

Copyright (c) 2000, 2016, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> update user set password=PASSWORD("gjdEdufD93J") where User='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [mysql]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

MariaDB [mysql]> quit
Bye
fate phan # /etc/init.d/mysql stop
[ ok ] Stopping mysql (via systemctl): mysql.service.
fate phan # systemctl restart mysql

参考资料

关注公众号 尹安灿

写了一个脚本用fabric发布和运行java包。需要用到nohup,或者screen -d -m命令。

我习惯了nohup,但是执行完毕,没有出错,但是程序也压根没有执行。

最后才找到资料说是fabric执行nohup命令的时候,过早关闭session,导致出问题。

官方推荐的做法是在命令后面增加一点延迟,比如&& sheep 1或者用screen命令。

关注公众号 尹安灿

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
#!/usr/bin/env python
#coding:utf-8

from random import randint

"""
词的频次统计
统计重复的词的次数,用字典的形式展现
"""

data = [randint(0,10) for _ in xrange(0,20)]

print data

## 常规处理
# 根据键生成一个字典,赋值0
ddata = dict.fromkeys(data,0)

print ddata
# 迭代统计
for x in data:
ddata[x]+=1

print ddata

## 用collections 的counter

from collections import Counter

ddata2 = Counter(data)

# 统计最高的4位
print ddata2.most_common(4)

输出:

1
2
3
4
5
[1, 0, 5, 6, 6, 4, 8, 7, 3, 1, 2, 10, 9, 5, 9, 3, 10, 9, 5, 4]
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0, 10: 0}
{0: 1, 1: 2, 2: 1, 3: 2, 4: 2, 5: 3, 6: 2, 7: 1, 8: 1, 9: 3, 10: 2}
[(5, 3), (9, 3), (1, 2), (3, 2)]

关注公众号 尹安灿

0%