Linux CentOS升级Python 3.6版本方法

由于软件环境的需要较高版本的python,默认CentOS6是2.6版本,CentOS7是2.7版本。这里要顺带提一下,有网友提到在CentOS6中无法安装Seafile云盘一键包的原因,因为需要默认最低是Python2.7版本才可以。而且在这篇文章中,老左调试的一个软件需要Python3以上版本,所以我准备安装Python 3.6。
备注:建议我们不熟悉的网友不要直接在生产环境中直接安装,可以先在测试环境安装看看是否可行。

第一、安装必备环境包

yum -y groupinstall development zlib zlib-devel

未分类

第二、下载和安装python3.6

wget https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz
tar xJf Python-3.6.0.tar.xz
cd Python-3.6.0
./configure
make
make install

未分类

第三、检查是否成功

which python3
python3 -V

未分类

第四、创建软链接

cd /usr/bin
mv python python.backup
ln -s /usr/local/bin/python3 /usr/bin/python

然后我们重启下机器,再看看当前的python是不是3.6
未分类
这样python可以升级安装到3.6版本。

使用virtualenv搭建Python下的Flask开发环境,ubu测试有效

Flask 依赖两个外部库:Werkzeug 和 Jinja2 。不过使用virtualenv就可以搞定这一切。

下面重点介绍一下环境搭建的步骤:

如果你在 Mac OS X 或 Linux 下,下面两条命令可能会适用:

$ sudo easy_install virtualenv

或更好的:

$ sudo pip install virtualenv

上述的命令会在你的系统中安装 virtualenv。它甚至可能会存在于包管理器中, 如果你用的是 Ubuntu,可以尝试:

$ sudo apt-get install python-virtualenv

virtualenv 安装完毕后,执行:

$ virtualenv venv
New python executable in venv/bin/python
Installing distribute............done.

现在,无论何时你想在某个项目上工作,只需要激活相应的环境。在 OS X 和 Linux 上,执行如下操作:

$ . venv/bin/activate

下面的操作适用 Windows:

$ venvscriptsactivate

无论通过哪种方式,你现在应该已经激活了 virtualenv(注意你的 shell 提示符显示的是当前活动的环境)。

现在你只需要键入以下的命令来激活 virtualenv 中的 Flask:

$ pip install Flask

几秒钟后,一切都搞定了。

然后deactivate退出当前环境。

使用python下的Flask应用

Flask是一个使用 Python 编写的轻量级 Web 应用框架。在学习过程中进行一些总结:

1. 一个最小的Flask应用 flask_test1.py:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

执行python flask_test1.py即可,在浏览器中使用127.0.0.1:5000即可访问

配置外部可访问,将脚本中的app.run()改写成app.run(host=’0.0.0.0′),如此就可以在外面使用运行脚本的服务器地址访问了,如192.168.2.22:5000

2. Flask的路由 flask_test2.py:

@app.route('/projects/')
def projects():
    return 'The project page'

@app.route('/about')
def about():
    return 'The about page'

if __name__ == '__main__':
    app.run(host='0.0.0.0')

运行脚本后,使用127.0.0.1:5000/projects 和127.0.0.1:5000/about即可得到不同的消息处理方式

也可以使用通配的方式书写路由,如下

@app.route('/user/<username>')
def show_user_profile(username):
    return 'User %s' % username

运行脚本后,使用127.0.0.1:5000/user/projects 和127.0.0.1:5000/user/about都会进入到show_user_profile()这个函数里面进行处理

3. Flask的Http方法:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        do_the_login()
    else:
        show_the_login_form()

运行脚本后可以使用get和post方法分别向login这个路由下发送消息。

Python Flask框架连接Mysql 学习笔记

认识Flask框架

Flask 是一个 Python 语言的微型网络开发框架。微框架中的 “微” 意味着 Flask 旨在保持核心简单而易于扩展。Flask 不会替你做出太多决策——比如使用何种数据库。而那些 Flask 所选择的——比如使用何种模板引擎则很容易替换。

Flask 基于 WerkzeugWSGI 工具箱和 Jinja2 模板引擎。实验中你将会知道 Jinja2 给予我们极大的方便,比如可以传递变量参数等。让我们的表示层动态的展示你想展示的信息,更详细的说明可参考Python Flask Web框架。

认识 MySQL 和简单的 SQL 语句

MySQL 作为一种关系型数据库,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择 MySQL 作为网站数据库。并且实验楼已经安装好 MySQL,故实验时只需使用即可。

我们要用到的 SQL 语句包括 select 语句,insert into 语句,create 语句,order by 子句,

Limit限制语法,natural join 语法。

创建myproject文件夹并激活virtualenv:

mkdir myprojectcdmyprojectvirtualenv venv. venv/bin/activate

在 virtualenv 中安装 Flask:

pipinstall -i http://mirrors.aliyuncs.com/pypi/simple flask

测试连接数据库代码:

插入数据:

importMySQLdbdb=MySQLdb.connect("localhost","root","","recommend")cursor=db.cursor()sql="create table user_anime(user int,anime int)"cursor.execute(sql)db.close()

简单说明一下上面的代码:

第一行导入连接 MySQL 的库

第二行通过指定参数(ip,用户名,密码,数据库)连接到某一个数据库

第三行使用 cursor() 方法获取操作游标

第四行为要执行的 SQL 语句,这句是创建一个名为 user_anime 表

第五行为执行 SQL 语句

查询Mysql 并取出数据

love=[]

DB=MySQLdb.connect("localhost","root","","recommend")

#获得数据库游标

c=DB.cursor()

#下面代码为实现从数据库中得到用户user所喜欢的番剧编号,以便判断重复

love=[]

#sql语句

sql="select anime_id  from user_anime where user_id=%s"%user

c.execute(sql)

#得到结果集

results=c.fetchall()

for line in results:

love.append(line[0])

基于Python的Flask的开发实战(第二节程序的基本结构)

1. 初始化

所有的flask程序都必须创建一个程序实例

web服务器使用wsgi接口协议,把接收客户端的请求都转发给这个程序实例来进行处理。这个程序实例就是flask对象

from flask import Flask
app = Flask(__name__)
#__name__决定程序的根目录,以便以后能找到相对于程序根目录的资源文件位置

2. 路由和视图函数

程序实例需要知道接收请求后,需要知道url请求应该运行哪些代码。所以保存了一个url和python函数的映射关系;这个映射关系就叫做路由

flask程序中路由的写法:

2.1 使用app.route装饰器,把修饰的函数注册为路由。例如

@app.route('/')
def index():
    return "<h1>Hello World</h1>"

#函数的名字不是必须写index的,只是和装饰器关联的时候写的函数名而已

#把index函数注册为程序根路径的处理程序。函数的返回值称为响应,是客户端接收的内容。

像index这样的函数称为试图函数,试图函数返回的响应可以是包含html的简单字符串,也可以是复杂的东西

2.2 可变url部分映射,使用特定的装饰器语法就可以

@app.route('/user/<name>')
def user(name):
    return "<h1>hello %s</h1>"%(name)

装饰器中的指定可变内容为name,name对user(name)函数中的传递参数,这2个部分内容必须一致

调用试图函数时候,flask会自动的将动态部分作为参数传入参数,这个函数中,参数用于生成个人的欢迎信息

#备注:路由中的动态部分默认使用字符串类型,可以使用int,float,path来定义;例如;path类型也是字符串,但不把斜线视作分隔符,而将其当做动态片段的一部分

3. 启动服务器

调用程序实例app的run方法启动flask集成开发的web服务器

if __name__ == "__main__":
    app.run(debug=True)

debug=True代表的是调试模式,这个flask自带的run方法开启的服务器不适合在生产中使用,此处只用来测试

4. 一个完整的Flask程序

啥也不说,先上例子hello.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>HelloWorld</h1>'

@app.route('/user/<name>')
def user(name):
    return "<h1>hello %s</h1>"%name



if __name__ == "__main__":
    app.run(debug=True)

默认会开启服务器本机5000端口;127.0.0.1:5000

执行脚本python hello.py

浏览器测试http://127.0.0.1:5000/

     http://127.0.0.1:5000/user/xiaobai

5. 请求上下文

Flask使用请求上下文,临时把某些对象变为全局可用;例如

from flask import request

@app.route('/')
def index():
    user_agent = request.headers.get('User-Agent')
    return '<h1>your browser is %s</h1>'%(user_agent)

在这个视图函数中,我们把request当做全局变量使用,flask使用请求上下文让特定的变量在一个线程中全局可访问。于此同时却不会干扰其他线程

session:请求上下文;用户会话,用于存储请求之间需要“记住”的值的词典

激活请求上下文的后就可以使用request和session变量了

6. 程序上下文

current_app:程序上下文;当前激活程序的程序实例

g:程序上下文;处理请求时用作临时存储的对象

7. 请求映射关系表

接收请求,处理请求,,,之间有个映射表,要不然不知道该去执行什么代码。URL映射

from hello import app
print app.url_map
Map([<Rule '/' (HEAD, OPTIONS, GET) -> index>,
  <Rule '/static/<filename>' (HEAD, OPTIONS, GET) -> static>,
  <Rule '/user/<name>' (HEAD, OPTIONS, GET) -> user>])

8. 请求钩子

有的时候在处理请求之前和之后,执行某些特定的代码是很有用的,这就用到了请求钩子

例如在请求之前创建数据库连接或者redis连接;或者是系统里面用户请求处理之前先验证用户的身份,是否激活,激活执行什么操作,没激活用户一直绑到固定页面去直到激活

为了避免每个试图函数中都使用重复的代码,flask提供了注册通用函数的功能;

也就是说只要写一个请求钩子-函数,整个程序实例全局都被应用了。

例如:在所有请求之前先验证下用户的认证状态

@before_app_request
def before_request():
    if current_user.is_authenticated:
        current_user.ping()
        if not current_user.confirmed and request.endpoint[:5] != 'auth.' and request.endpoint != 'static':
            return redirect(url_for('auth.unconfirmed'))

常见的4种钩子:

  • before_first_request:注册一个函数,在处理第一个请求之前运行

  • before_request:注册一个函数,每次请求之前运行

  • after_request:注册一个函数,没有未处理的异常抛出,每次请求之后运行

  • teardown_request:注册一个函数,有未处理的异常抛出,每次请求之后运行

在请求钩子和视图函数之间共享数据一般使用程序上下文g;

例如before_request处理程序可以从数据库中加载已登录用户,将其保存到g.user中,随后调用试图函数,试图函数再从g.user中获取用户

9. 基于Flask的http响应

flask调用试图函数处理请求,并把返回值作为响应的内容.大多情况下是一个简单的字符串或者json字符串;返回字符串常用于给对方提供接口的时候使用

http响应中很重要的一个内容是状态码,flask默认设置为200,这个代码表明请求已经被成功处理了

如果试图函数返回的响应需要不同的状态码,可以把状态码加到后面返回

例如

@app.route('/')
def index():
    return '<h1>Bad Request</h1>',400

试图函数返回的响应还可以接受第三个参数,第三个参数是一个字典类型的首部,可以添加到http响应中去,一般不用添加

如果不想返回这种好多个元素的元祖,可以使用Response对象来标准化下返回。

例如:创建一个响应对象,然后设置cookie

from flask import make_response

@app.route('/')
def index():
    response = make_response('<h1>This document carries a cookie!</h1>')
    response.set_cookie('answer',42)
    return response

还有一种特殊的响应类型,flask提供了一种基于302的跳转响应,这个响应由redirect函数来提供。指向的地址由Location首部提供,重定向的响应可以使用3个值形式的返回值生成。也可以再Response对象中设定

例如:

from flask import redirect

@app.route('/')
def index():
    return redirect('http://www.example.com')

还有一种特殊的响应类型,flask提供了一种错误响应。这个由abort函数来提供。abort抛出404异常,抛出异常后把控制权移交给web服务器

例如:

from flask import abort

@app.route('/user/<id>')
def get_user(id):
    user = load_user(id)
    if not user:
        abort(404)
    return '<h1>Hello,%s</h1>'%(user.name)

10. flask的扩展flask-script

这个例子主要是讲如何把flask扩展添加到程序中,并使用

例如下面你的例子是添加flask-script扩展,使用命令行参数增强程序的功能

使用命令行方式启动web服务器,而不是修改文件,给run方法传递参数

安装扩展

pip install flask-script

使用flask-script扩展,并把hello.py文件改为命令行参数启动的形式#添加的扩展默认会安装到flask.ext命名空间中

from flask import Flask
from flask.ext.script import Manager

app = Flask(__name__)
manager = Manager(app)

@app.route('/')
def index():
    return '<h1>HelloWorld</h1>'

@app.route('/user/<name>')
def user(name):
    return "<h1>hello %s</h1>"%name



if __name__ == "__main__":
    manager.run()

flask-script扩展中添加了一个Manager的类,以上例子中,这个扩展初始化的方法是,把程序实例作为参数传递给构造函数来初始化主类的实例。后续其他flask扩展也基本是这个套路

这样修改之后,程序就可以使用一组基本的命令行选项来启动和调试了

python hello.py shell#在flask应用上下文环境中运行python shell,方便测试和调试web环境
python hello.py runserver#运行flask开发服务器,app.run()
python hello.py -h#显示帮助信息
python hello.py runserver --help
  usage: hello.py runserver [-h] [-t HOST] [-p PORT] [--threaded]
  [--processes PROCESSES] [--passthrough-errors] [-d]
  [-r]

python hello.py runserver -h 0.0.0.0 -p 80#这样就开启了本机的80端口,别的机器可以远程访问了

Python Flask 框架 终极部署教程,超详细。Uwsgi+Nginx+mysql+Supervisor+Virtualenv, 基于阿里云默认Linux

我发现网上还没完整详细版本的Flask 部署教程,而我在部署中遇到很多坑,所以在这里写下来,完整的教程以下是部署流程:

处理本地的代码

假设你已经完成了项目的开发,本地已经安装了git,那么首先将你的代码提交到git;

#进项目根目录
pip freeze > requirements.txt  #导flask 全部包,方便新环境下一次性安装。
git init # 之前如果没有做,那么需要做
git add --all #提交所有修改后的文件
git remote add origin http:xxxx.git  #这一步如果之前没做,那么你需要做。
git commmit -w 'first commit'

安装Mysql

现在进入服务器正式开始搭建环境,首先安装mysql.

新鲜出炉的阿里云需要更新下apt.
apt-get update
然后安装mysql, 注意一定记住root 密码,还要在配置文件中设置字符为UTF8!
增加新的数据库,注意名字和你项目的一样,
create database xxx;

安装虚拟环境 Vitualenv

pip install virtualenvwrapper #直接安装虚拟环境容器来顺便安装virtualenv
注意需要先修改环境变量。否则命名无法使用
vim ~/.bashrc   在最底部增加
#这是为了让 WORKON 命令能用。
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh

然后你需要用 mkvirtualenv xxx   来创建一个叫xxx 的python 虚拟环境
workon xxx #切换到你的虚拟环境
在这个环境里,你可以升级你的python 到python3, 当然根据你的需求。

安装 Git 拿到全部源码

现在在服务器上安装git 拿到源码
apt install git
git init
git remote add origin http:xxx.git
git pull origin master # 拿到全部源码

正式部署源码

进去项目根目录:
pip install -r requirements.txt  #导入你项目的flask 依赖
pip manager.py db migerate #初始化数据库  
# 这里如果出现初始化失败,那么清空你的 migration 文件夹,你会丢掉你的测试数据,当然有不丢的办法
pip manager.py db upgrade #导入数据库,代码迁移完成

安装Nginx

apt install nginx #安装nginx 
贴下配置文件位于: /etc/nginx/conf.d/xxx.conf
# 配置nginx与uwsgi的通信方式和名称,mysite就是名称
upstream xxx {
    # nginx使用socket的方式与uwsgi进行通信
    # 这里指向你项目的目录下的socket文件,
    # 这个socket文件不需要单独创建,在运行的时候会自动创建。
    server unix:///srv/xxx/xxx.sock;
}
# 配置服务器
server {
    # 监听的端口号
    listen 80;
    # 域名或者本机的ip地址
    server_name dev.wudizu.com 47.104.22.138;
    charset     utf-8;
    # 最大的上传大小
    client_max_body_size 75M;  
    # adjust to taste

    # 访问根目录下的任何url的配置
    location / {
        # 指定访问哪个upstream
        uwsgi_pass wudi;
        # 包括uwsgi参数的文件
        include     /etc/nginx/uwsgi_params;
    }
    location /static {
        alias /srv/xxx/static;
   }

}

安装Uwsgi

pip install uwsgi

贴下配置文件:


[uwsgi]
chdir           = /srv/xxx
# 模块
module          = firstweb   #注意这里一定要你写的flask 首页文件名
# python的虚拟环境
home            = /root/.virtualenvs/flask-py2

# 是否启用mater模式
master          = true

# 进程数
processes       = 10

# socket文件地址

socket          = /srv/xxx/xxx.sock

# wsgi文件

wsgi-file       = /srv/xxx/xxx.ini

# wsgi文件中的app变量

callable        = app

# socket文件的权限

chmod-socket    = 666

安装Supervisor

sudo pip install supervisor
# supervisor的程序名字
[program:mysite]
# supervisor执行的命令
command=uwsgi --ini mysite_uwsgi.ini
# 项目的目录
directory = /srv/xxx 
# 开始的时候等待多少秒
startsecs=0
# 停止的时候等待多少秒
stopwaitsecs=0# 自动开始
autostart=true
# 程序挂了后自动重启
autorestart=true
# 输出的log文件
stdout_logfile=/srv/xxx/log/supervisord.log
# 输出的错误文件
stderr_logfile=/srv/xxx/log/supervisord.err

[supervisord]
# log的级别
loglevel=info

# 使用supervisorctl的配置
[supervisorctl]
# 使用supervisorctl登录的地址和端口号
serverurl = http://127.0.0.1:9001

# 登录supervisorctl的用户名和密码
username = admin
password = 123

[inet_http_server]
# supervisor的服务器
port = :9001
# 用户名和密码
username = admin
password = 123

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


然后使用supervisor运行uwsgi:
supervisord -c supervisor.conf

使用supervisorctl管理supervisord:supervisor是一个C/S模型,跟redis一样,有一个服务器,也有一个客户端命令用来管理服务的,使用以下命令进入到命令界面:
supervisorctl -c supervisor.conf

指定的文件必须和supervisord服务端保持一致。 一些常用的命令有:
supervisorctl -c supervisor.conf
> status    # 查看状态
> start program_name # 启动程序
> restart program_name # 重新启动程序
> stop program_name # 停止程序
> reload # 重新加载配置文件
> quit # 退出当前的客户端

Python进程管理工具Supervisor

Linux下安装pip

wget https://bootstrap.pypa.io/get-pip.py
python get-pip.py
pip -V  #查看pip版本

Supervisor是基于Python的进程管理工具,可以更简单的监听、启停、重启服务器上的一个或多个后台进程,是Linux服务器管理的高效工具

Supervisor管理的进程,当一个进程意外被杀死,supervisort监听到进程挂掉后,会自动将它重新拉起
其进程自动恢复的功能,不再需要自己写shell脚本来控制

Supervisor 有两个主要的组成部分:

  • supervisord,运行Supervisor时会启动一个进程supervisord,它负责启动所管理的进程,并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启
  • supervisorctl,是命令行管理工具,可以用来执行stop、start、restart等命令,来对这些子进程进行管理

安装setuptools

wget --no-check-certificate https://pypi.python.org/packages/source/s/setuptools/setuptools-12.0.3.tar.gz#md5=f07e4b0f4c1c9368fcd980d888b29a65
tar -zxvf setuptools-12.0.3.tar.gz
cd setuptools-12.0.3
python setup.py install

安装pip

easy_install pip

安装supervisor

easy_install supervisor

测试是否安装成功

echo_supervisord_conf

创建配置文件

echo_supervisord_conf > /etc/supervisord.conf

如果出现没有权限的问题,可以使用这条命令

sudo su - root -c "echo_supervisord_conf > /etc/supervisord.conf"

supervisor安装完成后会生成三个执行程序:

* supervisortd【supervisor的守护进程服务(用于接收进程管理命令)】 
* supervisorctl【客户端(用于和守护进程通信,发送管理进程的指令)】 
* echo_supervisord_conf【生成初始配置文件程序】

配置文件说明

想要了解怎么配置需要管理的进程,只要打开 supervisord.conf 就可以了,里面有很详细的注释信息

打开配置文件

vim /etc/supervisord.conf

默认的配置文件是下面这样的,但是这里有个坑需要注意,supervisord.pid 以及 supervisor.sock 是放在 /tmp 目录下

但是 /tmp 目录是存放临时文件,里面的文件是会被 Linux 系统删除的

一旦这些文件丢失,就无法再通过 supervisorctl 来执行 restart 和 stop 命令了,

将只会得到 unix:///tmp/supervisor.sock 不存在的错误
因此可以单独建一个文件夹,来存放这些文件,比如放在 /etc/supervisord.d/
默认情况下,进程的日志文件达到50MB时,将进行分割,最多保留10个文件,当然这些配置也可以对每个进程单独配置

创建文件夹

mkdir -p /etc/supervisord.d

创建日志目录

mkdir -p /var/log/supervisor/
supervisord.conf
; Sample supervisor config file.
;
; For more information on the config file, please see:
; http://supervisord.org/configuration.html
;
; Notes:
;  - Shell expansion ("~" or "$HOME") is not supported.  Environment
;    variables can be expanded using this syntax: "%(ENV_HOME)s".
;  - Quotes around values are not supported, except in the case of
;    the environment= options as shown below.
;  - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
;  - Command will be truncated if it looks like a config file comment, e.g.
;    "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".

[unix_http_server]
; 修改为/etc/supervisord.d目录,避免被系统删除
file=/etc/supervisord.d/supervisor.sock   ; the path to the socket file
;chmod=0700                 ; socket file mode (default 0700)
;chown=nobody:nogroup       ; socket file uid:gid owner
;username=user              ; default is no username (open server)
;password=123               ; default is no password (open server)

;[inet_http_server]         ; inet (TCP) server disabled by default
;port=127.0.0.1:9001        ; ip_address:port specifier, *:port for all iface
;username=user              ; default is no username (open server)
;password=123               ; default is no password (open server)

[supervisord]
; logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
; 修改为 /var/log 目录,避免被系统删除
logfile=/var/log/supervisor/supervisord.log ;
; 日志文件多大时进行分割
logfile_maxbytes=50MB        ; max main logfile bytes b4 rotation; default 50MB
; 最多保留多少份日志文件
logfile_backups=10           ; # of main logfile backups; 0 means none, default 10
loglevel=info                ; log level; default info; others: debug,warn,trace
; 修改为/etc/supervisord.d目录,避免被系统删除
pidfile=/etc/supervisord.d/supervisord.pid ; supervisord pidfile; default supervisord.pid
nodaemon=false               ; start in foreground if true; default false
minfds=1024                  ; min. avail startup file descriptors; default 1024
minprocs=200                 ; min. avail process descriptors;default 200
;umask=022                   ; process file creation umask; default 022
; 设置启动supervisord的用户,一般情况下不要轻易用root用户来启动,除非你真的确定要这么做
user=root                 ; default is current user, required if root
;identifier=supervisor       ; supervisord identifier, default is 'supervisor'
;directory=/tmp              ; default is not to cd during start
;nocleanup=true              ; don't clean up tempfiles at start; default false
;childlogdir=/tmp            ; 'AUTO' child log dir, default $TEMP
;environment=KEY="value"     ; key value pairs to add to environment
;strip_ansi=false            ; strip ansi escape codes in logs; def. false

; The rpcinterface:supervisor section must remain in the config file for
; RPC (supervisorctl/web interface) to work.  Additional interfaces may be
; added by defining them in separate [rpcinterface:x] sections.

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

; The supervisorctl section configures how supervisorctl will connect to
; supervisord.  configure it match the settings in either the unix_http_server
; or inet_http_server section.

[supervisorctl]
; 必须和'unix_http_server'里面的设定匹配
; 修改为/etc/supervisor目录,避免被系统删除
;serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL  for a unix socket
serverurl=unix:///etc/supervisord.d/supervisor.sock ;
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
;username=chris              ; should be same as in [*_http_server] if set
;password=123                ; should be same as in [*_http_server] if set
;prompt=mysupervisor         ; cmd line prompt (default "supervisor")
;history_file=~/.sc_history  ; use readline history if available

; The sample program section below shows all possible program subsection values.
; Create one or more 'real' program: sections to be able to control them under
; supervisor.

;[program:theprogramname]
;command=/bin/cat              ; 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=/a/path        ; 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=/a/path        ; 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)

; The sample eventlistener section below shows all possible eventlistener
; subsection values.  Create one or more 'real' eventlistener: sections to be
; able to handle event notifications sent by supervisord.

;[eventlistener:theeventlistenername]
;command=/bin/eventlistener    ; 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)
;events=EVENT                  ; event notif. types to subscribe to (req'd)
;buffer_size=10                ; event buffer queue size (default 10)
;directory=/tmp                ; directory to cwd to before exec (def no cwd)
;umask=022                     ; umask for process (default None)
;priority=-1                   ; the relative start priority (default -1)
;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        ; autorestart 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=false         ; redirect_stderr=true is not allowed for eventlisteners
;stdout_logfile=/a/path        ; 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_events_enabled=false   ; emit events on stdout writes (default false)
;stderr_logfile=/a/path        ; 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_events_enabled=false   ; emit events on stderr writes (default false)
;environment=A="1",B="2"       ; process environment additions
;serverurl=AUTO                ; override serverurl computation (childutils)

; The sample group section below shows all possible group values.  Create one
; or more 'real' group: sections to create "heterogeneous" process groups.

;[group:thegroupname]
;programs=progname1,progname2  ; each refers to 'x' in [program:x] definitions
;priority=999                  ; the relative start priority (default 999)

; The [include] section can just contain the "files" setting.  This
; setting can list multiple files (separated by whitespace or
; newlines).  It can also contain wildcards.  The filenames are
; interpreted as relative to this file.  Included files *cannot*
; include files themselves.

[include]
files = /etc/supervisord.d/config/*.ini

使用include

在配置文件的最后,有一个 [include] 的配置项,跟 Nginx 一样,可以 include 某个文件夹下的所有配置文件,这样我们就可以为每个进程或相关的几个进程的配置单独写成一个文件

[include]
files = /etc/supervisord.d/config/*.ini

创建进程的配置文件

编辑/etc/supervisord.d/config/matrix.ini

[group:matrix]
programs = matrix.print

[program:matrix.print]
; 启动命令,可以看出与手动在命令行启动的命令是一样的
command=python /data/demo/demo.py
numprocs=1
numprocs_start=0
priority=999
; 在supervisord启动的时候也自动启动
autostart=true
; 启动3秒后没有异常退出,就当作已经正常启动了
startsecs=3
; 启动失败自动重试次数,默认是3
startretries=3
exitcodes=0,2
stopsignal=QUIT
stopwaitsecs=60
directory=/data/demo
user=root
; 默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
stopasgroup=false
; 默认为false,向进程组发送kill信号,包括子进程
killasgroup=false
redirect_stderr=true
;stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/data/demo/data.log
; 日志文件多大时进行分割
stdout_logfile_maxbytes=250MB
; 最多保留多少份日志文件
stdout_logfile_backups=10
stderr_logfile=/data/demo/data.err
stderr_logfile_maxbytes=250MB
stderr_logfile_backups=10
; 可以通过 environment 来添加需要的环境变量,一种常见的用法是修改 PYTHONPATH
environment=PYTHONPATH="/data/demo"

创建测试脚本&日志目录

mkdir -p /data/demo

/data/demo/demo.py

vi /data/demo/demo.py
# -*- coding: utf-8 -*-
import os
import time

while 1:
   f = open('data.log', 'a+')
   time.sleep(5)
   f.write('This is a Test!')

启动supervisor

supervisord -c /etc/supervisord.conf

查看supervisor是否启动成功

ps -ef | grep '/etc/supervisord.conf'
root     23542     1  0 17:46 ?        00:00:00 /usr/bin/python /usr/bin/supervisord -c /etc/supervisord.conf
root     23566 23079  0 17:54 pts/0    00:00:00 grep /etc/supervisord.conf

查看supervisord.log

tail -f /var/log/supervisor/supervisord.log
2017-10-31 17:46:18,672 CRIT Set uid to user 0
2017-10-31 17:46:18,678 INFO RPC interface 'supervisor' initialized
2017-10-31 17:46:18,678 CRIT Server 'unix_http_server' running without any HTTP authentication checking
2017-10-31 17:46:18,679 INFO daemonizing the supervisord process
2017-10-31 17:46:18,679 INFO supervisord started with pid 23542
2017-10-31 17:48:14,042 INFO spawned: 'matrix.print' with pid 23555
2017-10-31 17:48:17,047 INFO success: matrix.print entered RUNNING state, process has stayed up for > than 3 seconds (startsecs)

supervisord.conf配置文件参数说明

[unix_http_server]
file=/tmp/supervisor.sock   ;UNIX socket 文件,supervisorctl 会使用
;chmod=0700                 ;socket文件的mode,默认是0700
;chown=nobody:nogroup       ;socket文件的owner,格式:uid:gid

;[inet_http_server]         ;HTTP服务器,提供web管理界面
;port=127.0.0.1:9001        ;Web管理后台运行的IP和端口,如果开放到公网,需要注意安全性
;username=user              ;登录管理后台的用户名
;password=123               ;登录管理后台的密码

[supervisord]
logfile=/tmp/supervisord.log ;日志文件,默认是 $CWD/supervisord.log
logfile_maxbytes=50MB        ;日志文件大小,超出会rotate,默认 50MB,如果设成0,表示不限制大小
logfile_backups=10           ;日志文件保留备份数量默认10,设为0表示不备份
loglevel=info                ;日志级别,默认info,其它: debug,warn,trace
pidfile=/tmp/supervisord.pid ;pid 文件
nodaemon=false               ;是否在前台启动,默认是false,即以 daemon 的方式启动
minfds=1024                  ;可以打开的文件描述符的最小值,默认 1024
minprocs=200                 ;可以打开的进程数的最小值,默认 200

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ;通过UNIX socket连接supervisord,路径与unix_http_server部分的file一致
;serverurl=http://127.0.0.1:9001 ; 通过HTTP的方式连接supervisord

; [program:xx]是被管理的进程配置参数,xx是进程的名称
[program:xx]
command=/opt/apache-tomcat-8.0.35/bin/catalina.sh run  ; 程序启动命令
autostart=true       ; 在supervisord启动的时候也自动启动
startsecs=10         ; 启动10秒后没有异常退出,就表示进程正常启动了,默认为1秒
autorestart=true     ; 程序退出后自动重启,可选值:[unexpected,true,false],默认为unexpected,表示进程意外杀死后才重启
startretries=3       ; 启动失败自动重试次数,默认是3
user=tomcat          ; 用哪个用户启动进程,默认是root
priority=999         ; 进程启动优先级,默认999,值小的优先启动
redirect_stderr=true ; 把stderr重定向到stdout,默认false
stdout_logfile_maxbytes=20MB  ; stdout 日志文件大小,默认50MB
stdout_logfile_backups = 20   ; stdout 日志文件备份数,默认是10
; stdout 日志文件,需要注意当指定目录不存在时无法正常启动,所以需要手动创建目录(supervisord 会自动创建日志文件)
stdout_logfile=/opt/apache-tomcat-8.0.35/logs/catalina.out
stopasgroup=false     ;默认为false,进程被杀死时,是否向这个进程组发送stop信号,包括子进程
killasgroup=false     ;默认为false,向进程组发送kill信号,包括子进程

;包含其它配置文件
[include]
files = relative/directory/*.ini    ;可以指定一个或多个以.ini结束的配置文件

supervisorctl命令介绍

# 停止某一个进程,program_name 为 [program:x] 里的 x
supervisorctl stop program_name
# 启动某个进程
supervisorctl start program_name
# 重启某个进程
supervisorctl restart program_name
# 结束所有属于名为 groupworker 这个分组的进程 (start,restart 同理)
supervisorctl stop groupworker:
# 结束 groupworker:name1 这个进程 (start,restart 同理)
supervisorctl stop groupworker:name1
# 停止全部进程,注:start、restart、stop 都不会载入最新的配置文件
supervisorctl stop all
# 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程
supervisorctl reload
# 根据最新的配置文件,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启
supervisorctl update
# 查看进程的状态
supervisorctl status

查看进程状态

supervisorctl status
matrix:matrix.print              RUNNING   pid 23555, uptime 0:10:00

查看supervisord所在路径

which supervisord

使用浏览器来管理

supervisor 同时提供了通过浏览器来管理进程的方法,只需要注释掉如下几行就可以了
;[inet_http_server]         ; inet (TCP) server disabled by default
;port=192.168.3.244:9001        ; (ip_address:port specifier, *:port for ;all iface)
;username=user              ; (default is no username (open server))
;password=123               ; (default is no password (open server))
[supervisorctl]
...
;serverurl=http://192.168.3.244:9001 ; use an http:// url to specify an inet socket
;username=chris              ; should be same as http_username if set
;password=123                ; should be same as http_password if set

访问浏览器地址栏:http://192.168.3.244:9001/

未分类

开机自动启动Supervisord

Linux在启动的时候会执行/etc/rc.local里面的脚本,所以在这里添加执行命令就可以

# 如果是 Ubuntu 添加以下内容
/usr/local/bin/supervisord -c /etc/supervisord.conf
# 如果是 Centos 添加以下内容
/usr/bin/supervisord -c /etc/supervisord.conf

启用rc.local服务

sudo systemctl enable rc-local.service

Ceph的Python接口

参考文章

ceph的python_api文档: http://docs.ceph.com/docs/master/rados/api/python/

连接ceph集群

import rados
cluster = rados.Rados(conffile='/etc/ceph/ceph.conf')
cluster.connect()

创建与删除池

# 列出可用的池
pools = cluster.list_pools()
for pool in pools:
    print pool
# 创建池test
cluster.create_pool('test')
# 删除池
cluster.delete_pool('test')
# 判断是否存在一个池
cluster.pool_exists('test')

列出池中所有的文件名

ioctx = cluster.open_ioctx('test')
# 列出test池中的所有文件名
object_iterator = ioctx.list_objects()
while True :
    try :
        rados_object = object_iterator.next()
        print "Object contents = " + rados_object.key
    except StopIteration :
        break
ioctx.close()

上传文件

# 连接到test池
ioctx = cluster.open_ioctx('test')
file_name = "yy.mp3"
f = open("yy.mp3", "r")
file_content = f.read()
f.close()
# 将文件写入池
ioctx.write_full(file_name, file_content)
ioctx.close()

下载文件

# 连接到test池
ioctx = cluster.open_ioctx('test')
f = open("yy.mp3", "w")
# 将文件下载(写入)到本地
f.write(ioctx.read("yy.mp3"))
f.close()
ioctx.close()

删除文件

ioctx = cluster.open_ioctx('test')
# 删除test池中的yy.mp3文件
ioctx.remove_object("yy.mp3")
ioctx.close()

断开ceph集群连接

cluster.shutdown()

centos重新安装,卸载python yum

公司测试机环境不知道给我卸了什么包,导致yum运行报错状况:

  • 系统版本:Red Hat Enterprise Linux Server release 6.2 (Santiago)

  • 内核版本:2.6.32-220.el6.x86_64

  • 报错情况:

There was a problem importing one of the Python modules
required to run yum. The error leading to this problem was:

No module named sqlite

Please install a package which provides this module, or
verify that the module is installed correctly.

It’s possible that the above module doesn’t match the
current version of Python, which is:

一、升级或卸载Python导致

1、查看已安装python的版本,可能是当前系统存在多个python导致

[root@test ~]# whereis python
python: /usr/bin/python2.6 /usr/bin/python /usr/bin/python2.6-config /usr/lib/python2.6 /usr/lib64/python2.6 /usr/include/python2.6 /usr/share/man/man1/python.1.gz
[root@test ~]# vi /usr/bin/yum

将 #!/usr/bin/python 修改为 #!/usr/bin/python2.6

如果是源代码安装的,默认路径是/usr/local/bin/python2.6,做个软链接即可

rm -rf /usr/bin/python
ln -s /usr/local/bin/python2.6 /usr/bin/python

二、完全重装python和yum

1、删除现有Python

[root@test ~]# rpm -qa|grep python|xargs rpm -ev --allmatches --nodeps ##强制删除已安装程序及其关联
[root@test ~]# whereis python |xargs rm -frv ##删除所有残余文件 ##xargs,允许你对输出执行其他某些命令
[root@test ~]# whereis python ##验证删除,返回无结果

2、删除现有的yum

[root@test ~]# rpm -qa|grep yum|xargs rpm -ev --allmatches --nodeps
[root@test ~]# whereis yum |xargs rm -frv

3、从http://mirrors.ustc.edu.cn/centos/6.4/os/x86_64/Packages/下载相应的包

python-2.6.6-36.el6.x86_64.rpm
python-devel-2.6.6-36.el6.x86_64.rpm
python-libs-2.6.6-36.el6.x86_64.rpm
python-pycurl-7.19.0-8.el6.x86_64.rpm
python-setuptools-0.6.10-3.el6.noarch.rpm
python-urlgrabber-3.9.1-8.el6.noarch.rpm  
python-iniparse-0.3.1-2.1.el6.noarch.rpm
rpm-python-4.8.0-32.el6.x86_64.rpm
yum-3.2.29-40.el6.centos.noarch.rpm
yum-metadata-parser-1.1.2-16.el6.x86_64.rpm
yum-utils-1.1.30-14.el6.noarch.rpm
yum-plugin-fastestmirror-1.1.30-14.el6.noarch.rpm     
yum-plugin-protectbase-1.1.30-14.el6.noarch.rpm
yum-plugin-aliases-1.1.30-14.el6.noarch.rpm
yum-plugin-downloadonly-1.1.30-14.el6.noarch.rpm

由于源中版本会更新,具体请查看URL中的版本再下载下来!

[root@test ~]# rpm -Uvh --replacepkgs python*.rpm
[root@test ~]# rpm -Uvh --replacepkgs rpm-python*.rpm yum*.rpm

可能之间还需要zlib和zlib-devel包,根据情况下载并安装!

三、运行python进行测试

[root@test ~]# python
Python 2.6.6 (r266:84292, Feb 22 2013, 00:00:18)
[GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import yum
>>>

如上,要是什么都没报,则说明OK啦~

zabbix自动截图留档_python版

一、背景

每个DB Server都有zabbix监控,除了异常情况的报警信息外,也会在日检、周检、月检等工作中用到zabbix的监控数据,对zabbix监控数据会做两种处理:1 数据分析(环比分析、最大值、最小值及平均值分析);2 主要检测项目折线图留档(为啥需要留档呢,因为zabbix监控过多服务器,监控数据仅保留半年到1年间)。

关于 数据分析类的,已嵌入 日检邮件报告跟 月度报告 中,而 zabbix 监控图留档 一直没实现自动化,每个月都是人工取截图。刚好最近遇到 国庆db报告跟9月数据库报告,需要各种截图留档,然后触发了写个小脚本来自动下载 zabbix的监控图。

二、写个小脚本

2.1 获取图片url

首先打开日常的zabbix监控图页面,点击 F12,然后点击,这个时候选中页面中的折线图,就可以看到 对应的HTML代码,最后点击对应的html代码右键 copy下图片的链接地址,即可知道 zabbix的监控图 的url。

未分类

根据获取的url如下:

http://company.moniter.com/chart.php?period=2592000&stime=20170901000000&itemids%5B0%5D=32571&type=0&updateProfile=1&profileIdx=web.item.graph&profileIdx2=32571&width=1778&sid=341eb79599119b85&screenid=&curtime=1508809467171

这里边有几个参数说明下

  • stime 是监控的开始时间按照 ‘%Y%m%d%H%M%S’ 的时间格式

  • period 是监控图的时长,从 stime开始要展示 多少秒 的监控数据

  • itemid[0] 是 监控项目在zabbix 数据库的 itemid 号

    • 这个如何查呢?首先根据 host表格,找到监控服务器的hostid,然后根据 items表格找到对应的监控id

    • select i.hostid,itemid,i.name,key_,i.description from items i join hosts h on i.hostid=h.hostid where h.name = ‘hostname’;

  • curtime这里可以不填写,但是注意 stime 加上 period秒数后,不要超过当前查询时间即可

  • width 为图片的长度

根据需要,仅保留4个参数,这里注意 stime 加上 period秒数后,不要超过当前查询时间 ,简化后的url如下(把zabbix部署的域名或者网址IP替换掉 company.moniter.com):

http://company.moniter.com/chart.php?period=2592000&stime=20170901000000&itemids[0]=32571&width=1778

2.2 脚步及测试

小脚本实现的功能是:根据批量的itemid,自动下载图片到本地目录,并且重命名图片名称。

代码实现如下:

# -*- coding: utf-8 -*-
__author__ = 'xinysu'
__date__ = '2017/10/12 14:38'
import sys
import datetime
import http.cookiejar, urllib.request, urllib
from lxml import etree
import requests
class ZabbixChart(object):
    def __init__(self, name, password):
        url="http://company.monitor.com/index.php";
        self.url = url
        self.name = name
        self.password = password
        cookiejar = http.cookiejar.CookieJar()
        urlOpener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar))
        values = {"name": self.name, 'password': self.password, 'autologin': 1, "enter": 'Sign in'}
        data = urllib.parse.urlencode(values).encode(encoding='UTF8')
        request = urllib.request.Request(url, data)
        try:
            urlOpener.open(request, timeout=10)
            self.urlOpener = urlOpener
        except urllib.request.HTTPError as e:
            print(e)
    def download_chart(self, image_dir,itemids,stime,etime):
        # 此url是获取图片是的,请注意饼图的URL 和此URL不一样,请仔细观察!
        url="http://company.monitor.com/chart.php";
        # 折线图的大小
        url_par={}
        url_par={"width":1778, "height":300,"itemids":itemids}
        # 开始日期、结束日期从str转换为datetime
        stime = datetime.datetime.strptime(stime, "%Y-%m-%d")
        etime=datetime.datetime.strptime(etime, "%Y-%m-%d")
        # 计算period
        diff_sec = etime - stime
        period = diff_sec.days*24*3600 + diff_sec.seconds
        url_par["period"] = period
        # stime转换str
        stime = stime.strftime('%Y%m%d%H%M%S')
        url_par["stime"] = stime
        key = url_par.keys()
        data = urllib.parse.urlencode(url_par).encode(encoding='UTF8')
        request = urllib.request.Request(url, data)
        url = self.urlOpener.open(request)
        image = url.read()
        html = requests.get('http://company.monitor.com/history.php?action=showgraph&itemids[]={}'.format(itemids)).text
        page = etree.HTML(html)
        hostname_itemname = page.xpath('//div[@class="header-title"]/h1/text()')[0].split(':')
        hostname = hostname_itemname[0]
        hostname_itemname.pop(0)
        itemname = '_'.join(hostname_itemname).replace('/','_')
        imagename = "{}{}_{}_{}_({}).png".format(image_dir,hostname,stime,etime.strftime('%Y%m%d%H%M%S'),itemname)
        f = open(imagename, 'wb')
        f.write(image)

根据写好的类,输入zabbix的登录帐号、监控图的起始跟结束时间、本地存放图片目录、itemid的list,运行后如下:

# 登陆URL
username = "xinysu"
password = "passwd"

# 图片的参数,该字典至少传入graphid
stime = "2017-09-01"
etime = "2017-10-01"

# 用于图片存放的目录
image_dir = "E:\03 WORK\03 work_sql\201709"

#运行
b = ZabbixChart(username, password)
item_list =(35295,35328,38080,37992,38102,38014,35059,35022,42765,35024,35028,35035,35036,35044,35045,35046,35047,38248,36369,36370,36371,36372)
for i in item_list:
    itemids = i
    b.download_chart(image_dir,itemids,stime,etime)

随便输入的itemid 测试下载,实际需要根据监控需要过滤itemid,下载后在文件夹中显示如下:

未分类

未分类