ubuntu系统安装virtualenv python版本管理工具

virtualenv的官网在http://www.virtualenv.org/en/latest/
如其官方所说,virtualenv 是一个创建独立python环境的工具。其要解决的最基本问题就是库的依赖和版本,以及间接权限(indirectly permisions,没太明白)。

安装virtualenv,在默认的python2下的pip就行:

sudo apt-get install python-virtualenv

创建虚拟环境:

virtualenv -p /usr/bin/python3 py3env

激活虚拟环境:

source py3env/bin/activate

你会注意到shell的提示符行前多了(py3env)字样,这样你就可以放心的使用python3做开发了。先下载个三方库试试吧

pip install httplib2

大功告成了!

如果要退出python3虚拟环境,输入命令

deactivate

python使用sqlalchemy连接mysql数据库

sqlalchemy是python当中比较出名的orm程序。

什么是orm?

orm英文全称object relational mapping,就是对象映射关系程序,简单来说我们类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的,为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系,这样我们在使用编程语言对数据库进行操作的时候可以直接使用编程语言的对象模型进行操作就可以了,而不用直接使用sql语言。

什么是sqlalchemy?

sqlalchemy是python的orm程序,在整个python界当中相当出名。

安装sqlalchemy

在使用sqlalchemy之前要先给python安装mysql驱动,由于我使用的是python3原来的mysqldb不可用,所以这里推荐使用pymysql。
我们通过pip进行安装,在windows下使用pip安装包的时候要记得使用管理员身份运行cmd不然有些操作是无法进行的。

pip install pymysql

安装完以后安装再安装sqlalchemy

pip install sqlalchemy

如何使用sqlalchemy连接mysql?

通过import导入必要的包

from sqlalchemy import create_engine,Table,Column,Integer,String,MetaData,ForeignKey

创建一个连接引擎

engine=create_engine("mysql+pymysql://root:a5230411@localhost:3306/test",echo=True)

我们将连接引擎放到engine里面方便后面使用。
create_engine(“数据库类型+数据库驱动://数据库用户名:数据库密码@IP地址:端口/数据库”,其他参数)
上文当中echo=True是开启调试,这样当我们执行文件的时候会提示相应的文字。

创建元数据

什么是元数据?元数据就是描述数据的数据,举个简单的例子,小明身高170cm,体重50kg,性别男。其中身高,体重,性别就是元数据。当我们创建好连接引擎以后可以通过这个引擎抓取元数据。

metadata=MetaData(engine)

通过MetaData()方法创建了metadata实例,在这个方法里面带上engine的目的是绑定要连接引擎,当我们对这个metadata实例进行操作的时候就会直接连接到数据库。

添加表结构

设定好连接引擎和元数据,让我们向mysql里面创建表结构来进行测试。

user=Table('user',metadata,
    Column('id',Integer,primary_key=True),
    Column('name',String(20)),
    Column('fullname',String(40)),
    )
address_table = Table('address', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_id', None, ForeignKey('user.id')),
    Column('email', String(128), nullable=False)
    )

其中Table()方法用来创建表,第一个参数为表明,第二是存入元数据,后面的参数使用Column()方法将数据库当中每一个字段的数据参数设置好。

执行创建

metadata.create_all()

因为已将将表结构存到了metadata里面,然后让metadata执行create_all()方法,这样就向数据库里创建了user和address表。

完成代码

from sqlalchemy import create_engine,Table,Column,Integer,String,MetaData,ForeignKey
engine=create_engine("mysql+pymysql://root:a5230411@localhost:3306/test",echo=True)
metadata=MetaData(engine)

user=Table('user',metadata,
    Column('id',Integer,primary_key=True),
    Column('name',String(20)),
    Column('fullname',String(40)),
    )
address_table = Table('address', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_id', None, ForeignKey('user.id')),
    Column('email', String(128), nullable=False)
    )

metadata.create_all()

Ubuntu系统使用Nginx uWSGI部署Flask应用

我职业生涯的大部分都在使用微软的架构,最近我决定走出技术的舒适区,步入开源软件世界。我现在日常工作的项目是一个RESTful服务,这个服务需要在主流硬件上运行,且能够按照需要进行水平拓展。为完成这项工作我决定使用Flask和Nginx。Flask是一个轻量级的Python Web框架,Nginx是一个非常稳定的Web服务器,它们在廉价硬件平台上工作良好。

在这篇文章中我将指导你完成使用Nginx服务器托管Flask应用的安装、配置过程。我所使用的操作系统是Ubuntu 13.04。

前提条件

在我们开始安装Nginx及其他所需软件之前先安装一些前提软件。首先,我们需要PIP与virtualenv:

sudo apt-get install python-setuptools
sudo easy_install pip
sudo pip install virtualenv

使用apt-get安装Nginx的话,我们需要添加Nginx库到apt-get source中:

sudo add-apt-repository ppa:nginx/stable

注意:如果“add-apt-repository”命令在你的Ubuntu版本中不存在的话,你需要安装“software-properties-common”包,使用命令:sudo apt-get software-properties-common(感谢get_with_it在评论中提到)

升级已有的包,确保系统上有uWSGI所需的编译器和工具:

sudo apt-get update && sudo apt-get upgrade
sudo apt-get install build-essential python python-dev

Nginx

安装并运行Nginx:

sudo apt-get install nginx
sudo /etc/init.d/nginx start

Nginx是一个提供静态文件访问的web服务,然而,它不能直接执行托管Python应用程序,而uWSGI解决了这个问题。让我们先安装uWSGI,稍候再配置Nginx和uWSGI之间的交互。

sudo pip install uwsgi

里程碑 #1

打开浏览器访问你的服务器,你应该能看到Nginx欢迎页:

示例应用

我们将托管的应用是经典的“Hello, world!”。这个应用只有一个页面,已经猜到页面上将有什么内容了吧。将所有应用相关的文件存放在/var/www/demoapp文件夹中。下面创建这个文件夹并在其中初始化一个虚拟环境:

sudo mkdir /var/www
sudo mkdir /var/www/demoapp

由于我们使用root权限创建了这个文件夹,它目前归root用户所有,让我们更改它的所有权给你登录的用户(我的例子中是ubuntu)

sudo chown -R ubuntu:ubuntu /var/www/demoapp/

创建并激活一个虚拟环境,在其中安装Flask:

cd /var/www/demoapp
virtualenv venv
. venv/bin/activate
pip install flask

使用下面的代码创建hello.py文件:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(host='0.0.0.0', port=8080)

里程碑 #2

让我们执行我们刚创建的脚本:

python hello.py

现在你可以通过浏览器访问你服务器的8080端口,看,应用生效了:

注意:因为80端口已被Nginx使用,这里我使用8080端口。

现在应用是由Flask内置的web服务托管的,对于开发和调试这确实是个不错的工具,但不推荐在生产环境中使用。让我们配置Nginx来挑起这个重担吧。

配置Nginx

首先删除掉Nginx的默认配置文件:

sudo rm /etc/nginx/sites-enabled/default

注意:如果你安装了其他版本的Nginx,默认配置文件可能在/etc/nginx/conf.d文件夹下。

创建一个我们应用使用的新配置文件/var/www/demoapp/demoapp_nginx.conf:

server {
    listen      80;
    server_name localhost;
    charset     utf-8;
    client_max_body_size 75M;

    location / { try_files $uri @yourapplication; }
    location @yourapplication {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/demoapp/demoapp_uwsgi.sock;
    }
}

将刚建立的配置文件使用符号链接到Nginx配置文件文件夹中,重启Nginx:

sudo ln -s /var/www/demoapp/demoapp_nginx.conf /etc/nginx/conf.d/
sudo /etc/init.d/nginx restart

里程碑 #3

访问服务器的公共ip地址,你会看到一个错误:

别担心,这个错误是正常的,它代表Nginx已经使用了我们新创建的配置文件,但在链接到我们的Python应用网关uWSGI时遇到了问题。到uWSGI的链接在Nginx配置文件的第10行定义:

uwsgi_pass unix:/var/www/demoapp/demoapp_uwsgi.sock;

这代表Nginx和uWSGI之间的链接是通过一个socket文件,这个文件位于/var/www/demoapp/demoapp_uwsgi.sock。因为我们还没有配置uWSGI,所以这个文件还不存在,因此Nginx返回“bad gateway”错误,让我们马上修正它吧。

配置uWSGI

创建一个新的uWSGI配置文件/var/www/demoapp/demoapp_uwsgi.ini:

[uwsgi]
#application's base folder
base = /var/www/demoapp

#python module to import
app = hello
module = %(app)

home = %(base)/venv
pythonpath = %(base)

#socket file's location
socket = /var/www/demoapp/%n.sock

#permissions for the socket file
chmod-socket    = 666

#the variable that holds a flask application inside the module imported at line #6
callable = app

#location of log files
logto = /var/log/uwsgi/%n.log

创建一个新文件夹存放uWSGI日志,更改文件夹的所有权:

sudo mkdir -p /var/log/uwsgi
sudo chown -R ubuntu:ubuntu /var/log/uwsgi

里程碑 #4

执行uWSGI,用新创建的配置文件作为参数:

uwsgi --ini /var/www/demoapp/demoapp_uwsgi.ini

接下来访问你的服务器,现在Nginx可以连接到uWSGI进程了:

我们现在基本完成了,唯一剩下的事情是配置uWSGI在后台运行,这是uWSGI Emperor的职责。

uWSGI Emperor

uWSGI Emperor (很拉风的名字,是不?) 负责读取配置文件并且生成uWSGI进程来执行它们。创建一个初始配置来运行emperor – /etc/init/uwsgi.conf:

description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn

env UWSGI=/usr/local/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log

exec $UWSGI --master --emperor /etc/uwsgi/vassals --die-on-term --uid www-data --gid www-data --logto $LOGTO

最后一行运行uWSGI守护进程并让它到/etc/uwsgi/vassals文件夹查找配置文件。创建这个文件夹,在其中建立一个到链到我们刚创建配置文件的符号链接。

sudo mkdir /etc/uwsgi && sudo mkdir /etc/uwsgi/vassals
sudo ln -s /var/www/demoapp/demoapp_uwsgi.ini /etc/uwsgi/vassals

同时,最后一行说明用来运行守护进程的用户是www-data。为简单起见,将这个用户设置成应用和日志文件夹的所有者。

sudo chown -R www-data:www-data /var/www/demoapp/
sudo chown -R www-data:www-data /var/log/uwsgi/

注意:我们先前安装的Nginx版本使用“www-data”这个用户来运行Nginx,其他Nginx版本的可能使用“Nginx”这个替代用户。

由于Nginx和uWSGI都由同一个用户运行,我们可以在uWSGI配置中添加一个安全提升项。打开uWSGI配置文件,将chmod-socket值由666更改为644:

...
#permissions for the socket file
chmod-socket    = 644

现在我们可以运行uWSGI了:

sudo start uwsgi

最后,Nginx和uWSGI被配置成启动后立即对外提供我们的应用服务。

问题解决

如果出现错误的话,第一个检查的地方是日志文件。Nginx默认将错误信息写到/var/log/nginx/errors.log文件。

我们已经配置了uWSGI emperor将日志写到/var/log/uwsgi/emperor.log。这个文件夹还包含着每个配置应用的单独日志。我们的例子是 – /var/log/uwsgi/demoapp_uwsgi.log。

静态文件

如果你的应用提供静态文件的话,将下面的规则添加到demoapp_nginx.conf文件:

location /static {
    root /var/www/demoapp/;
}

上面配置的结果就是所有在/var/www/demoapp/static文件夹中的文件将由提供Nginx对外服务(谢谢Bastianh指出)

托管多个应用

如果你想在一台服务器上托管多个Flask应用,为每个应用创建一个单独的文件夹,像我们前面所做的一样,创建Nginx及uWSGI配置文件到应用文件夹的符号链接。

使用Distribute部署应用

使用distribute部署Flask应用的话,首先,按照Flask文档里的步骤将应用转化成package,然后复制distribute通用安装包到服务器上,使用虚拟环境中的Python来安装它。如下:

python setup.py install

最后且同样重要的是,uwsgi配置里应用属性的值要设置成包含Flask应用的包的名称。

supervisor的安装配置及常用命令介绍

前言

在 web 应用部署到线上后,需要保证应用一直处于运行状态,在遇到程序异常、报错等情况,导致 web 应用终止时,需要保证程序可以立刻重启,继续提供服务。

所以,就需要一个工具,时刻监控 web 应用的运行情况,管理该进程。

Supervisor 就是解决这种需求的工具,可以保证程序崩溃后,重新把程序启动起来等功能。

简介

Supervisor 是一个用 Python 写的进程管理工具,可以很方便的用来在 UNIX-like 系统(不支持 Windows)下启动、重启(自动重启程序)、关闭进程(不仅仅是 Python 进程)。

安装

  1. Ubuntu系统下:apt-get install supervisor,通过这种方式安装后,自动设置为开机启动
  2. 也可以通过 pip install supervisor 进行安装,但是需要手动启动,然后设置为开机启动(不推荐这种安装方式)

Supervisor 配置

Supervisor 是一个 C/S 模型的程序,supervisord 是 server 端,supervisorctl 是 client 端。

supervisord

下面介绍 supervisord 配置方法。supervisord 的配置文件默认位于 /etc/supervisord.conf,内容如下(;后面为注释):

; supervisor config file

[unix_http_server]
file=/var/run/supervisor.sock   ; (the path to the socket file) UNIX socket 文件,supervisorctl 会使用
chmod=0700                       ; sockef file mode (default 0700) socket 文件的 mode,默认是 0700

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; (main log file;default $CWD/supervisord.log) 日志文件,默认是 $CWD/supervisord.log
pidfile=/var/run/supervisord.pid ; (supervisord pidfile;default supervisord.pid) pid 文件
childlogdir=/var/log/supervisor            ; ('AUTO' child log dir, default $TEMP)

; the below 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: sections
[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///var/run/supervisor.sock ; use a unix:// URL  for a unix socket 通过 UNIX socket 连接 supervisord,路径与 unix_http_server 部分的 file 一致

; 在增添需要管理的进程的配置文件时,推荐写到 `/etc/supervisor/conf.d/` 目录下,所以 `include` 项,就需要像如下配置。
; 包含其他的配置文件
[include]
files = /etc/supervisor/conf.d/*.conf ; 引入 `/etc/supervisor/conf.d/` 下的 `.conf` 文件

program 配置

program 的配置文件就写在,supervisord 配置中 include 项的路径下:/etc/supervisor/conf.d/,然后 program 的配置文件命名规则推荐:app_name.conf

[program:app] ; 程序名称,在 supervisorctl 中通过这个值来对程序进行一系列的操作
autorestart=True      ; 程序异常退出后自动重启
autostart=True        ; 在 supervisord 启动的时候也自动启动
redirect_stderr=True  ; 把 stderr 重定向到 stdout,默认 false
environment=PATH="/home/app_env/bin"  ; 可以通过 environment 来添加需要的环境变量,一种常见的用法是使用指定的 virtualenv 环境
command=python server.py  ; 启动命令,与手动在命令行启动的命令是一样的
user=ubuntu           ; 用哪个用户启动
directory=/home/app/  ; 程序的启动目录

需要注意:

  • 用 supervisord 管理时,gunicorn 的 daemon 选项需要设置为 False
  • 如果启动命令需要包含workon,修改environment参数:environment=PATH=”/home/username/.virtualenvs/myproject/bin”

supervisorctl 操作

supervisorctl 是 supervisord 的命令行客户端工具,使用的配置和 supervisord 一样,这里就不再说了。下面,主要介绍 supervisorctl 操作的常用命令:

输入命令 supervisorctl 进入 supervisorctl 的 shell 交互界面(还是纯命令行)

Linux上的后台进程管理工具Supervisor

当你的系统上有许多工作进程在跑,你想要一个统一的入口来管理这些进程,包括状态检查,启动和关闭,出错时警告,及自动重启等。那你就需要一个进程管理工具来帮助你。Supervisor就是其中一个简单而又强大的工具。虽说标题写了Linux,其实它可以用在大部分Unix衍生出来的系统,比如Linux, Mac OS X, Solaris和FreeBSD。

一. Supervisor组件

Supervisor有四个组件:

1. supervisord

运行Supervisor的后台服务,它用来启动和管理那些你需要Supervisor管理的子进程,响应客户端发来的请求,重启意外退出的子进程,将子进程的stdout和stderr写入日志,响应事件等。它是Supervisor最核心的部分。

2. supervisorctl

相当于supervisord的客户端,它是一个命令行工具,用户可以通过它向supervisord服务发指令,比如查看子进程状态,启动或关闭子进程。它可以连接不同的supervisord服务,包括远程机上的服务。

3. Web服务器

这是supervisord的Web客户端,用户可以在Web页面上完成类似于supervisorctl的功能。

4. XML-RPC接口

这是留给第三方集成的接口,你的服务可以在远程调用这些XML-RPC接口来控制supervisord管理的子进程。上面的Web服务器其实也是通过这个XML-RPC接口实现的。

二. 安装

Supervisor是由Python写的,源码托管在Github仓库里。如果你机上有Python环境,你可以clone一份源码,然后通过setup.py来安装:

$ python setup.py install

也可以通过PyPI安装,这样方便许多:

$ pip install supervisor

另外,Supervisor在Ubuntu和CentOS上都有分发包,比如在Ubuntu上,你就可以用”apt-get”来安装:

$ apt-get install supervisor

注意,根据你系统权限的情况,以上这些命令可能会需要root权限来执行。

三. 配置

安装完毕后,你可以执行下命令”echo_supervisord_conf”,它会将一个配置样例打印在控制台上,如果你看到配置信息了,说明安装成功。现在让我们将配置样例保存在本地:

$ echo_supervisord_conf > supervisord.conf

官网上建议直接保存在”/etc/supervisord.conf”文件中,可是大部分情况下我们是没有权限写etc目录的,所以要先保存下来,再通过root拷贝过去。Supervisor启动时会自动加载该配置文件。

让我们打开配置文件看看,这就是一个INI格式的配置文件啊,参数好多,而且大部分都注视掉了。这里就不一一介绍了,官方文档里有详细的。我们就介绍下最重要的部分,就是”[program:theprogramname]”。

这个”[program:xxx]”块定义了你要Supervisor管理的子进程,冒号后面是你可以起的名字。建议采用比较有意义的名字,因为”[program:xxx]”块可以有多个,这样可以同时管理多个不同的子进程,名字起的好方便区分。让我们了解下这个配置块下几个主要的配置参数吧:

  • command
    子进程的运行命令,比如你要监控一个Python程序”app.py”的运行,你可以设置”command=python /home/bjhee/myapp/app.py”。当supervisord服务启动时,该程序也会被自动启动,并作为子进程由supervisord管理。

  • numprocs
    同时启动的进程个数,用来实现并发,默认是1。注意如果该参数大于1的话,你必须同时配置”process_name”参数,并且将”%(process_num)s”变量放入”process_name”中,防止多个进程同名导致启动出错。

  • directory
    如果配置了这个目录,那子进程运行前,会先切换到这个目录。

  • user
    运行该子进程的用户,默认同supervisord服务的启动用户。如果supervisord由root启动,而你又不想给子进程root,你可以配置这个参数。

  • priority
    该子进程优先级,决定了启动和关闭子进程的顺序,默认是最大值999。

  • autostart
    启动supervisord时,子进程是否自动启动,默认是true。

  • autorestart
    当子进程出错退出时,supervisord是否自动将其重启,默认是unexpected,也就是不自动重启,你可以设为true。

  • stdout-logfile
    由于子进程由supervisord启动,所以其stdout将无法输出到系统的标准输出上,所以你要将子进程的stdout写入到日志文件中。这个参数指定了该日志文件的位置。

  • stderr-logfile
    同上面的stdout-logfile,这里指定了stderr写入的日志文件位置。

四. 启动Supervisor

我们就写个最简单的Web应用吧,可以从我的这篇文章里拷一个Flask的Hello World程序,假设保存在”/home/billy/myapp/app.py”文件中。现在让我们在配置文件中,加入配置项:

[program:app]
command=python /home/billy/myapp/app.py

就这一个配置够了,然后让我们启动supervisord:

$ supervisord

注意,你可能要root来运行supervisord命令。运行该命令时,supervisord会自动在以下几个位置寻找配置文件:

  • 当前目录下的supervisord.conf
  • 当前目录下的etc/supervisord.conf
  • /etc/supervisord.conf
  • /etc/supervisor/supervisord.conf

当你的配置文件不在上述位置时,那就必须指定配置文件的位置,这时启动命令应改为:

$ supervisord -c /home/billy/supervisor/hello.conf

如果你的确想把配置文件放在自己的工作目录下,一个推荐的方式,是依然创建”/etc/supervisord.conf”文件,并在该文件的最后加上”[include]”配置块:

[include]
files = /home/billy/supervisor/*.conf

运行完supervisord命令后,你可以打开supervisord的日志文件,默认是”/tmp/supervisord.log”,你也可以通过”[supervisord]”配置块下的参数”logfile”来指定。如果在日志文件中看到下面的信息,就说明Supervisor启动成功了。

2016-11-27 15:03:06,830 INFO RPC interface 'supervisor' initialized
2016-11-27 15:03:06,830 CRIT Server 'unix_http_server' running without any HTTP     authentication checking
2016-11-27 15:03:06,832 INFO daemonizing the supervisord process
2016-11-27 15:03:06,833 INFO supervisord started with pid 73469

五. 命令行客户端

让我们再打开一个控制台窗口,运行supervisorctl命令,supervisorctl同supervisord一样会自动寻找”supervisord.conf”配置文件,如果不在默认位置的话,启动时须用参数”-c”指定。

supervisorctl启动后,你将会看到一个类似Shell的交互窗口。在这个窗口中,你可以输入”status”命令查看所有子进程的状态;可以输入”stop app”或”start app”命令来关闭或启动名称为”app”的子进程;如果此时你修改了配置文件,你可以输入”reload”命令让supervisord服务重新加载配置文件。

supervisor> status
app                              RUNNING   pid 74652, uptime 0:00:34
supervisor> stop app
app: stopped
supervisor> status app
app                              STOPPED   Nov 27 10:35 PM

当你不清楚命令怎么用时,可以输入”help”查看帮助,或者类似于”help start”来查看”start”命令的帮助。

supervisor> help start
start <name>        Start a process
start <gname>:*     Start all processes in a group
start <name> <name> Start multiple processes or groups
start all       Start all processes

六. Web客户端

使用Web客户端前,你先要在配置文件中启用它,方法是添加下列配置项:

[inet_http_server]
port=*:9001
;username=user
;password=123

用户名密码是用于安全验证,不设的话任何人都可以访问。配置完毕启动supervisord服务,你就可以通过”http://localhost:9001″来访问Web客户端了。下面是页面的示例,可以看到这里允许你从Web页面上查看/启动/关闭子进程。

未分类

七. 进程组

当你要管理的子进程非常多时,Supervisor允许你将子进程分组,也就是多个子进程可以在同一组内统一管理。你只需要配置”[group:thegroupname]”块就行了。

我们可以试下,再配置一个”[program:hello]”子程序,然后加上”[group:xxx]”配置:

[program:hello]
command=python /home/billy/myapp/hello.py

[group:appgroup]
programs=app,hello

现在我们将子进程”app”和”hello”都配置在进程组”appgroup”中,启动supervisord,让我们在supervisorctl客户端下试一试:

supervisor> status appgroup:*
appgroup:app                     RUNNING   pid 75042, uptime 0:03:12
appgroup:hello                   RUNNING   pid 75043, uptime 0:03:12
supervisor> stop appgroup:*
appgroup:app: stopped
appgroup:hello: stopped
supervisor> status appgroup:*
appgroup:app                     STOPPED   Nov 27 11:05 PM
appgroup:hello                   STOPPED   Nov 27 11:05 PM

子进程名前都加了前缀”appgroup:”,这样我们使用通配符”appgroup:*”来执行的命令就对进程组内所有的子进程起效了,果然很方便。

修改PostgreSQL数据库的默认用户postgres的密码

有时候,忘记了postgresql 安装时默认用户postgres 的密码,怎么办呢?

linux shell命令下面输入: sudo -u postgres psql (这样就可以直接登录进postgres 了, 然后在里面可以进行添加用户,修改密码之类的,都不是问题了!!)


修改PostgreSQL数据库的默认用户postgres的密码(注意不是linux系统帐号)

第一步:

1. PostgreSQL登录(使用psql客户端登录)

# sudo -u postgres psql        
  • //其中,sudo -u postgres 是使用postgres 用户登录的意思
  • //PostgreSQL数据默认会创建一个postgres的数据库用户作为数据库的管理员,密码是随机的,所以这里
  • //设定为’postgres’

2. 修改PostgreSQL登录密码:

postgres=# ALTER USER postgres WITH PASSWORD 'postgres';
  • //postgres=#为PostgreSQL下的命令提示符

3. 退出PostgreSQL psql客户端

postgres=# q

[代码说明]

‘#’和’#’之前的字符是系统提示符,’postgres=#’是psql客户端的提示符,红色字符为输入命令(本文其它部分亦如此);

[功能说明]

PostgreSQL数据默认会创建一个postgres的数据库用户作为数据库的管理员,密码是随机的,我人需要修改为指定的密码,这里设定为’postgres’

第二步:

修改linux系统的postgres用户的密码(密码与数据库用户postgres的密码相同)

1. 删除PostgreSQL用户密码

# sudo passwd -d postgres
  • passwd: password expiry information changed.
  • //passwd -d 是清空指定用户密码的意思

2. 设置PostgreSQL用户密码

PostgreSQL数据默认会创建一个linux用户postgres,通过上面的代码修改密码为’postgres’(这取决于
第二步中的密码,只要与其相同即可)。

现在,我们就可以在数据库服务器上用 postgres帐号通过psql或者pgAdmin等等客户端操作数据库了。

#sudo -u postgres passwd
  • 输入新的 UNIX 密码:
  • 重新输入新的 UNIX 密码:
  • passwd:已成功更新密码

—————————————————————-分割线———————————————————————-

有时候,发现同一台ubuntu 上面有两个postgres server 的实例

未分类

要修改其中一个实例的postgres (9.5)的密码。

sudo -u postgres psql -p 5433

这样,如下图所示,就登录进9.5这个实例了,这样就可以修改这个实例的postgres 的密码了。!

未分类

查看这个postgres实例的用户列表。只有一个安装的时候默认的用户。

未分类

查看这个postgres 实例的数据库列表, 只有安装的时候默认的数据库。

未分类

CentOS7安装配置PostgreSQL数据库服务器

步骤摘要

    yum install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm
    yum install postgresql96-server postgresql96-contrib
    /usr/pgsql-9.6/bin/postgresql96-setup initdb
    systemctl start postgresql-9.6
    systemctl enable postgresql-9.6
    firewall-cmd --add-service=postgresql --permanent
    firewall-cmd --reload
    su - postgres
    psql -U postgres
    ALTER USER postgres with encrypted password 'abc123';
    q
    exit
    vi /var/lib/pgsql/9.6/data/postgresql.conf
    vi /var/lib/pgsql/9.6/data/pg_hba.conf
    systemctl restart postgresql-9.6.service

步骤详情

安装yum源

打开https://yum.postgresql.org/repopackages.php ,找到自己需要的版本。

未分类

本文撰写时,PostgreSQL 10还是测试版,因此在此演示9.6版。
右键复制链接地址。

未分类

不放心是否复制成功的话可以粘贴出来看看。

未分类

以root模式进入CentOS7,输入“yum install ”后面加上刚刚复制的链接,回车。

未分类

输入“y”,回车。

未分类

安装PostgreSQL

输入“yum install postgresql96-server postgresql96-contrib”并回车。
(如果使用其他版本的PostgreSQL则需要把其中的两个“96”换成对应的数字)

未分类

输入“y”并回车。

未分类

安装后,可执行文件在“/usr/pgsql-9.5/bin/”, 数据和配置文件在“/var/lib/pgsql/9.6/data/”。因此输入“/usr/pgsql-9.6/bin/postgresql96-setup initdb”并回车,初始化数据库。

未分类

输入“systemctl start postgresql-9.6”并回车,启动服务。
输入“systemctl enable postgresql-9.6”并回车,设为开机自启。
(如果使用其他版本的PostgreSQL则需要把其中的两个“9.6”换成对应的版本)

未分类

输入“firewall-cmd –add-service=postgresql –permanent”并回车,开放防火墙。
输入“firewall-cmd –reload”并回车,重启防火墙。

修改默认PostgreSQL用户密码

  • PostgreSQL的默认用户为“postgres”。
  • 输入“su – postgres”并回车,切换至用户。
  • 输入“psql -U postgres”并回车,登录数据库。
  • 输入“ALTER USER postgres with encrypted password ‘abc123’;”(不要漏了“;”)并回车,设置默认用户postgre的密码,此处密码为“abc123”,可自行修改。
  • 输入“q”并回车, 退出数据库。
  • 输入“exit”并回车,退出用户。

未分类

配置远程访问

输入“vi /var/lib/pgsql/9.6/data/postgresql.conf”并回车。
(如果使用其他版本的PostgreSQL则需要把其中的“9.6”换成对应的版本)
光标下翻,找到“listen_addresses”。

未分类

按“i”键进入插入编辑模式,如果想对所有IP开放,则将“localhost”改为“*”即可,如果想仅对部分IP开放,多个IP之间用“, ”(逗号+空格)隔开。

改完之后去掉“listen_address”前面的“#”。

未分类

编辑完成后,按“Esc”键,输入“:wq”并回车。
输入“vi /var/lib/pgsql/9.6/data/pg_hba.conf”并回车,将光标移至底部。
(如果使用其他版本的PostgreSQL则需要把其中的“9.6”换成对应的版本)

未分类

按“i”键进入插入编辑模式,在“IPv4 local connections”下方添加允许连接的IP。
如果想允许所有IPv4地址,则加入一行“host all all 0.0.0.0/0 md5”。IPv6方法类似。

未分类

编辑完成后,按“Esc”键,输入“:wq”并回车。
输入“systemctl restart postgresql-9.6.service”并回车,重启服务。
(如果使用其他版本的PostgreSQL则需要把其中的“9.6”换成对应的版本)

从ceph对象中提取RBD中的指定文件

1. 前言

之前有个想法,是不是有办法找到rbd中的文件与对象的关系,想了很久但是一直觉得文件系统比较复杂,在fs 层的东西对ceph来说是透明的,并且对象大小是4M,而文件很小,可能在fs层进行了合并,应该很难找到对应关系,最近看到小胖有提出这个问题,那么就再次尝试了,现在就是把这个实现方法记录下来

这个提取的作用个人觉得最大的好处就是一个rbd设备,在文件系统层被破坏以后,还能够从rbd提取出文件,我们知道很多情况下设备的文件系统一旦破坏,无法挂载,数据也就无法读取,而如果能从rbd中提取出文件,这就是保证了即使文件系统损坏的情况下,数据至少不丢失

本篇是基于xfs文件系统情况下的提取,其他文件系统有时间再看看,因为目前使用的比较多的就是xfs文件系统

本篇也回答了一个可能会经常被问起的问题,能告诉我虚拟机里面的文件在后台存储在哪里么,看完本篇就知道存储在哪里了

2. XFS文件系统介绍

[root@lab8106 ~]# mkfs.xfs -f /dev/rbd0p1 
warning: device is not properly aligned /dev/rbd0p1
meta-data=/dev/rbd0p1            isize=256    agcount=9, agsize=162816 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=1310475, imaxpct=25
         =                       sunit=1024   swidth=1024 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal log           bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=8 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0

XFS文件系统采取是AG管理的,每个AG维护自己的inode和数据,所以XFS文件系统是一种很容易扩展的文件系统,本篇里面主要用到的命令是xfs_bmap这个命令

[root@lab8106 ~]# xfs_bmap -lvp /etc/fstab
/etc/fstab:
 EXT: FILE-OFFSET      BLOCK-RANGE        AG AG-OFFSET        TOTAL FLAGS
   0: [0..7]:          26645424..26645431  1 (431024..431031)     8 00000

一个文件最小就是8个block(512b),也就是4k,这个因为上面默认的xfs的格式化就是data bsize=4K,这个值可以自行调整的,本篇尽量用默认常规的参数来讲例子

查看man xfs_bmap这个命令可以看到:

Holes are marked by replacing the startblock..endblock with hole. All the file offsets and disk blocks are in units of 512-byte blocks, no matter what the filesystem’s block size is.

意思是这个查询到的里面的计数单位都是512-byte,不管上层设置的block大小是多少,我们知道文件系统底层的sector就是512-byte,所以这个查询到的结果就可以跟当前的文件系统的sector的偏移量联系起来,这里强调一下,这个偏移量的起始位子为当前文件系统所在分区的偏移量,如果是多分区的情况,在计算整个偏移量的时候就要考虑分区的偏移量了,这个会在后面用实例进行讲解的

rbd的对象是不清楚内部分区的偏移量,所以在rbd层进行提取的时候是需要得到的是分区当中的文件相对整个磁盘的一个sector的偏移量

3. rbd的对象结构

[root@lab8106 ~]# rados -p rbd ls|grep data
rbd_data.25a636b8b4567.00000000000009ff
rbd_data.25a636b8b4567.00000000000001dd
rbd_data.25a636b8b4567.0000000000000000
rbd_data.25a636b8b4567.000000000000009f
rbd_data.25a636b8b4567.0000000000000459
rbd_data.25a636b8b4567.000000000000027e
rbd_data.25a636b8b4567.00000000000004ff
rbd_data.25a636b8b4567.000000000000027c
rbd_data.25a636b8b4567.000000000000027d
rbd_data.25a636b8b4567.0000000000000001
rbd_data.25a636b8b4567.000000000000013e
rbd_data.25a636b8b4567.00000000000003ba
rbd_data.25a636b8b4567.000000000000031b
rbd_data.25a636b8b4567.00000000000004f8

rbd被xfs格式化以后会产生一些对象,这些对象是以16进制名称的方式存储在后台的,也就是rbd大小一定的情况下对象数目是一定的,也就是名称也是一定的

[root@lab8106 ~]# parted -s /dev/rbd0 unit s print
Model: Unknown (unknown)
Disk /dev/rbd0: 20971520s
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start      End        Size       File system  Name     Flags
 1      1953s      10485759s  10483807s  xfs          primari
 2      10485760s  20963327s  10477568s               primari

上面可以看到rbd0的sector个数为20971520s
20971520s*512byte=10737418240byte=10485760KB=10240MB
sector的大小一定,总rbd大小一定的情况下sector的数目也是一定的,本篇实例的rbd大小

[root@lab8106 ~]# rbd info zp
rbd image 'zp':
    size 10000 MB in 2500 objects
    order 22 (4096 kB objects)
    block_name_prefix: rbd_data.25a776b8b4567
    format: 2
    features: layering
    flags: 
    create_timestamp: Sat Jul 22 18:04:12 2017

4. sector和ceph object的对应关系的查询

这个就像个map一样,需要把这个关系给找到,一个sector的区间对应到object的map,这里我用python写个简单的方法来做查询,也可以自己用其他语言来实现

首先查询到rbd的对象数目

[root@lab8106 ~]# rbd info zp
rbd image 'zp':
    size 10000 MB in 2500 objects
    order 22 (4096 kB objects)
    block_name_prefix: rbd_data.25a776b8b4567
    format: 2
    features: layering
    flags: 
    create_timestamp: Sat Jul 22 18:04:12 2017

处理脚本如下:

vim getsecob.py

添加下面内容

#! /bin/python
# *-* conding=UTF-8 *-*

import commands

def main():
    getmap(2500)


def getmap(object):
    sector=int(object)*4096*1024/512
    print "object:"+str(object)
    print "sector:"+str(sector)
    incre=sector/object
    for item in range(int(object)):
        a=int(item*8192)
        b=int((item+1)*8192-1)
        print str([a,b])+"  --&gt;  "+"%016x" %item

if __name__ == '__main__':
    main()

其中getmap后面为对象数目

输出是这个形式的:

[root@lab8106 ~]# python getsecob.py
object:2500
sector:20480000
[0, 8191]  --&gt;  0000000000000000
[8192, 16383]  --&gt;  0000000000000001
[16384, 24575]  --&gt;  0000000000000002
[24576, 32767]  --&gt;  0000000000000003
[32768, 40959]  --&gt;  0000000000000004
[40960, 49151]  --&gt;  0000000000000005
···

对rbd0进行分区,分区后的结果如下

[root@lab8106 ~]# parted -s /dev/rbd0 unit s print
Model: Unknown (unknown)
Disk /dev/rbd0: 20480000s
Sector size (logical/physical): 512B/512B
Partition Table: gpt
Disk Flags: 

Number  Start      End        Size       File system  Name     Flags
 1      1953s      10240000s  10238048s               primari
 2      10248192s  20471807s  10223616s               primari

这个是个测试用的image,大小为10G分成两个5G的分区,现在我们在两个分区里面分别写入两个测试文件,然后经过计算后,从后台的对象中把文件读出

mount /dev/rbd0p1 /mnt1
mount /dev/rbd0p2 /mnt2
cp /etc/fstab /mnt1
cp /etc/hostname /mnt2

首先获取文件在分区上的sector的偏移量

[root@lab8106 ~]# xfs_bmap -lvp /mnt1/fstab 
/mnt1/fstab:
 EXT: FILE-OFFSET      BLOCK-RANGE      AG AG-OFFSET        TOTAL FLAGS
   0: [0..7]:          8224..8231        0 (8224..8231)         8 01111

可以得到是(8224..8231)共8个sector
从上面的分区1的start的sector可以知道起始位置是1953,那么相对于磁盘的偏移量就变成了

(8224+1953..8231+1953) = (10177..10184)

这里说下,这个地方拿到偏移量后,直接通过对rbd设备进行dd读取也可以把这个文件读取出来,这个顺带讲下,本文主要是从对象提取:

dd if=/dev/rbd0 of=a bs=512 count=8 skip=10177

bs取512是因为sector的单位就是512b
这样就把刚刚的fstab文件读取出来了,skip就是文件的sector相对磁盘的起始位置,count就是文件所占的block数目

继续我们的对象提取方式,上面的(10177..10184)这个我们根据上面那个脚本输出的对象列表来找到对象

[8192, 16383] —&gt; 0000000000000001
获取名称,这个因为我的是测试环境,就只有一个匹配,多个image的时候要过滤出对用的rbd的对象,用prifix过滤即可
[root@lab8106 ~]# rados -p rbd ls|grep 0000000000000001
rbd_data.25a776b8b4567.0000000000000001

下载对象

[root@lab8106 ~]# rados -p rbd get rbd_data.25a776b8b4567.0000000000000001 rbd_data.25a776b8b4567.0000000000000001

根据偏移量计算对象中的偏移量

(10177..10184)
[8192, 16383]  --&gt;  0000000000000001

得到

10177-8192=1985

dd if=rbd_data.25a776b8b4567.0000000000000001 of=a bs=512 count=8 skip=1985

得到的文件a的内容即为之前文件的内容

准备取第二个分区的文件

[root@lab8106 ~]# xfs_bmap -lvp /mnt2/hostname 
/mnt2/hostname:
 EXT: FILE-OFFSET      BLOCK-RANGE      AG AG-OFFSET        TOTAL FLAGS
   0: [0..7]:          8224..8231        0 (8224..8231)         8 01111

8224+10248192..8231+10248192=10256416..10256423

从磁盘方式

[root@lab8106 ~]# dd if=/dev/rbd0 of=a bs=512 count=8 skip=10256416

从对象方式
10256416..10256423 对应
[10256384, 10264575] —> 00000000000004e4
对象偏移量

10256416-10256384=32
rados -p rbd get 
[root@lab8106 ~]# rados -p rbd get rbd_data.25a776b8b4567.00000000000004e4 rbd_data.25a776b8b4567.00000000000004e4

获取文件

[root@lab8106 ~]# dd if=rbd_data.25a776b8b4567.00000000000004e4 of=a bs=512 count=8 skip=32

如果文件比较大的情况,可能出现就是文件是跨对象的,那么还是跟上面的提取方法一样,然后进行提取后的文件进行合并即可

5. 总结

在存储系统上面存储的文件必然会对应到底层磁盘的sector,而sector也是会一一对应到后台的对象的,这个在本文当中得到了验证,所以整个逻辑就是,在文件系统层找到文件对应的sector位置,然后再在底层把sector和对象关系找好,就能从找到文件在对象当中的具体的位置,也就能定位并且能提取了,本篇是基于xfs的,其他文件系统只要能定位文件的sector,就可以在底层找到文件,这个以后会补充其他文件系统进来。

使用HAProxy Keepalived实现主备及负载均衡

HAProxy提供高可用性负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。根据官方数据,其最高极限支持10G的并发。

HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。其支持从4层至7层的网络交换,即覆盖所有的TCP协议。就是说,Haproxy甚至还支持Mysql的负载均衡。如果说在功能上,能以proxy反向代理方式实现WEB均衡负载,这样的产品有很多。包括Nginx,ApacheProxy,lighttpd,Cheroke等。但要明确一点的,Haproxy并不是Http服务器。以上提到所有带反向代理均衡负载的产品,都清一色是WEB服务器。简单说,就是他们能自个儿提供静态(html,jpg,gif..)或动态(php,cgi..)文件的传输以及处理。而Haproxy仅仅,而且专门是一款的用于均衡负载的应用代理。其自身并不能提供http服务。开始Haproxy主备高可用测试

未分类

测试系统:

  • CentOS6.7/Ubuntu15.04

IP信息:

  • 主Haproxy:192.168.15.132

  • 备Haproxy:192.168.15.133

  • VIP:192.168.15.135(www.test.com/img.test.com)

  • Real1:192.168.15.128

  • Real2:192.168.15.130

  • Real3:192.168.15.140

主LB与备LB均配置

echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf         #开启数据包转发

echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf   #允许监听非本地地址

sysctl -p

安装haproxy

cd /usr/local/src

CentOS系统:

yum install wget gcc gcc-c++ autoconf automake make

Ubuntu系统:

sudo apt-get install build-essential  libtool

wget http://pkgs.fedoraproject.org/repo/pkgs/haproxy/haproxy-1.4.24.tar.gz/86422620faa9759907563d5e0524b98c/haproxy-1.4.24.tar.gz

tar -xvzf haproxy-1.4.24.tar.gz

cd haproxy-1.4.24

make TARGET=linux2628 && make install  

#kernel版本大于2.6.28的,使用"TARGET=linux2628",否则使用"TARGET=linux26"。

添加haproxy用户:

useradd -d /var/lib/haproxy -s /bin/false haproxy

创建配置文件

mkdir -p /etc/haproxy 

cp -r  /usr/local/src/haproxy-1.4.24/examples/errorfiles  /etc/haproxy/errorfiles

cp /usr/src/haproxy-1.4.24/examples/haproxy.cfg /etc/haproxy  #拷贝示例文件

cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak      #备份示例文件

负载均衡①:

vi /etc/haproxy/haproxy.cfg
global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http          #所处理的类别 (#7层 http;4层tcp  )
        option  httplog
        option  httpclose
        option  dontlognull   #不记录健康检查的日志信息
        option  forwardfor    #后端服务器需要获得客户端真实ip时配置的参数,可以从Http Header中获得客户端ip
        option  redispatch    #serverId对应的服务器挂掉后,强制定向到其他健康的服务器
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen Web_LB  
      bind *:80
      mode http   #7层:http;4层:tcp
      cookie Web_LB  insert
      balance roundrobin
      option httpclose
      option forwardfor
      #option httpchk GET /index.html #心跳检测的文件
      server Real1 192.168.15.128:80 cookie Real1 check inter 1500 rise 3 fall 3 weight 1
      server Real2 192.168.15.130:80 cookie Real2 check inter 1500 rise 3 fall 3 weight 1
      server Real3 192.168.15.140:80 cookie Real3 check inter 1500 rise 3 fall 3 weight 1
      #服务器定义,"cookie Real1"表示serverid为Real1,"check inter 1500"是检测心跳频率,"rise 3"是3次正确认为服务器可用,"fall 3"是3次失败认为服务器不可用,weight代表权重
      srvtimeout 30000 
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics #监控页面提示信息
    stats uri /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE  #手动启用/禁用后端服务器(haproxy-1.4.9以后版本)
    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

负载均衡②:

vi /etc/haproxy/haproxy.cfg
global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http 
        option  httplog
        option  httpclose
        option  dontlognull  
        option  forwardfor   
        option  redispatch   
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics 
    stats uri  /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE
frontend www
    bind *:80
    acl web hdr_reg(host) -i ^(www.test.com|test.com)$
    #acl后面是规则名称。如果请求的域名满足正则表达式中的2个域名返回true(-i是忽略大小写),则分发请求至webserver的作用域。
    acl img hdr(host) -i img.test.com
    #如果访问img.test.com就分发到imgserver这个作用域。
    use_backend webserver if web
    use_backend imgserver if img
    default_backend webserver

backend webserver
    mode http
    balance roundrobin               #默认的负载均衡方式
    #balance source                  #类似Nginx的ip_hash,balance source 保存session值
    #balance leastconn               #最小连接
    cookie  SERVERID insert indirect
    option  httpchk /index.php   
    server Real1 192.168.15.128:80 cookie Real1 check inter 1500 rise 3 fall 3 weight 1
    server Real2 192.168.15.130:80 cookie Real2 check inter 1500 rise 3 fall 3 weight 1
    server Real3 192.168.15.140:80 cookie Real3 check inter 1500 rise 3 fall 3 weight 1
    #服务器定义,"cookie Real1"表示serverid为Real1,"check inter 1500"是检测心跳频率,"rise 3"是3次正确认为服务器可用,"fall 3"是3次失败认为服务器不可用,weight代表权重

backend imgserver
    mode http
    balance  roundrobin  
    option  httpchk /index.php
    server Real1 192.168.15.128:80 check inter 1500 rise 3 fall 3 weight 1
    server Real2 192.168.15.130:80 check inter 1500 rise 3 fall 3 weight 1
    server Real3 192.168.15.140:80 check inter 1500 rise 3 fall 3 weight 1

    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

动静分离:

global
        log 127.0.0.1   local0
        log 127.0.0.1   local1 notice
        maxconn 5000
        chroot /var/lib/haproxy
        user haproxy
        group haproxy
        daemon
defaults
        log     global
        mode    http 
        option  httplog
        option  httpclose
        option  dontlognull  
        option  forwardfor   
        option  redispatch   
        retries 3
        maxconn 4000
        contimeout      8000
        clitimeout      80000
        srvtimeout      80000
listen stats  192.168.15.135:9999
    mode http
    stats enable
    stats refresh 5s
    stats hide-version
    stats realm Haproxy Statistics 
    stats uri  /haproxy-status
    stats auth test:123456
    acl allow src 192.168.15.0/16
    stats admin if TRUE
frontend  main *:80       #前端代理
    acl url_static     path_beg   -i  /static /images /javascript /stylesheets
    acl url_static     path_end   -i  .jpg .gif .png .css .js
    acl url_dynamic    path_end   -i  .php
    use_backend static_servers    if url_static
    default_backend           dynamic_servers 
backend static_servers   #后端的静态请求响应
    balance     roundrobin
    server      static 192.168.15.128:80 inter 3000 rise 2 fall 3 check maxconn 5000
backend dynamic_servers  #后端的动态请求响应
    balance     roundrobin
    server  dynamic1 192.168.15.130:80 inter 3000 rise 2 fall 3 check maxconn 5000
    server  dynamic2 192.168.15.140:80 inter 3000 rise 2 fall 3 check maxconn 5000

    errorfile 403 /etc/haproxy/errorfiles/403.http
    errorfile 500 /etc/haproxy/errorfiles/500.http
    errorfile 502 /etc/haproxy/errorfiles/502.http
    errorfile 503 /etc/haproxy/errorfiles/503.http
    errorfile 504 /etc/haproxy/errorfiles/504.http

启动haproxy

cp /usr/local/src/haproxy-1.4.24/examples/haproxy.init  /etc/rc.d/init.d/haproxy

chmod +x  /etc/rc.d/init.d/haproxy

chkconfig haproxy on

cp /usr/local/src/haproxy-1.4.24/haproxy /usr/sbin/haproxy

/etc/init.d/haproxy start

设置HAProxy日志

“/etc/rsyslog.d”目录下创建haproxy日志配置文件

local0.=info -/var/log/haproxy.log         #haproxy.log保存http日志

local0.notice -/var/log/haproxy-status.log #haproxy-status.log记录haproxy状态变更

vi /etc/rsyslog.d/haproxy.conf

$ModLoad imudp       #imudp是模块名,支持UDP协议
$UDPServerRun 514   #允许514端口接收使用UDP和TCP协议转发过来的日志,rsyslog在默认情况下在514端口监听UDP
$template Haproxy,"%msg%n"
local0.=info -/var/log/haproxy.log;Haproxy
local0.notice -/var/log/haproxy-status.log;Haproxy
### keep logs in localhost ##
local0.* ~

vim /etc/sysconfig/rsyslog

SYSLOGD_OPTIONS="-c 2 -r -m 0"
#各参数作用:
#-c 指定运行兼容模式。
#-r 接收远程日志
#-x 在接收客户端消息时,禁用DNS查找。需和-r参数配合使用。
#-m 标记时间戳。单位是分钟,为0时,表示禁用该功能。

重启rsyslog服务

service rsyslog restart

日志轮转配置

vim /etc/logrotate.d/haproxy

/var/log/haproxy.log {
    missingok
    notifempty
    sharedscripts
    rotate 5
    daily
    compress
    postrotate
        reload rsyslog &gt;/dev/null 2&gt;&amp;1 ||truep;true
    endscript
}

创建定时任务:

59 23 * * * root /usr/sbin/logrotate -f /etc/logrotate.conf &gt;/dev/null 2&gt;&amp;1
service crond restart

配置keepalived

wget http://www.keepalived.org/software/keepalived-1.2.15.tar.gz

tar -zxvf keepalived-1.2.15.tar.gz

cd keepalived-1.2.15

./configure --sysconf=/etc/  --with-kernel-dir=/usr/src/kernels/2.6.32-573.8.1.el6.x86_64

make &amp;&amp; make install

ln -s /usr/local/sbin/keepalived  /sbin/  

配置keepalived.conf:

主:

! Configuration File for keepalived
global_defs {
   notification_email {
    [email protected]
   }
   notification_email_from keepalived@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Haprxoy_Master    
}
vrrp_script check_haproxy {
  script "/usr/local/src/check_haproxy.sh"
  interval 4
  weight 2
}
vrrp_instance VI_1 {
 #state MASTER
  state BAKCUP
  nopreempt 
  interface bond0
  smtp_alert
  virtual_router_id 66
  priority 100
  advert_int 1
  authentication {
  auth_type PASS
  auth_pass 1111
 }
 track_script {
  check_haproxy
 }
 virtual_ipaddress {
  192.168.15.135/24 broadcast 192.168.15.255 dev bond0 label bond0:1
 }
}

备:

! Configuration File for keepalived
global_defs {
   notification_email {
     [email protected]
   }
   notification_email_from keepalived@localhost
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id Haprxoy_BACKUP   
}
vrrp_script check_haproxy {
 script "/usr/local/src/check_haproxy.sh"
 interval 4
 weight 2
}
vrrp_instance VI_1 {
  state BACKUP
  interface bond0
  smtp_alert
  virtual_router_id 66
  priority 88
  advert_int 1
  authentication {
  auth_type PASS
  auth_pass 1111
 }
 track_script {
  check_haproxy
 }
 virtual_ipaddress {
  192.168.15.135/24 broadcast 192.168.15.255 dev bond0 label bond0:1
 }
}

为防止haproxy异常关闭导致keepalived不自动切换

#!/bin/bash
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
     /etc/init.d/haproxy  start
fi
sleep 3
if [ $(ps -C haproxy --no-header | wc -l) -eq 0 ]; then
       /etc/init.d/keepalived stop
fi

chmod +x /usr/local/src/check_haproxy.sh

Keepalived.conf配置完毕,启动keepalived服务:/etc/init.d/keepalived start

关闭其中任何一个服务,访问正常,测试OK。

未分类

未分类

未分类

遇到的问题:

备机启动报错“Starting proxy LOADBAL: cannot bind socket”,原因为nginx进程占用80端口造成,停止nginx后正常。如果“ip_nonlocal_bind”未设置为1(启动haproxy的时候,允许忽视VIP的存在)也会造成相同问题

启动keepalived后日志出现“didn’t respond to SIGTERM”,需将“interval”时间设置相对较长(同时检查iptables状态)

配置HAproxy实现动静态请求分离

一. 简述

在现实的应用环境中,往往根据业务请求的不同将相关的请求指定到不同的后端服务器中,例如客户是静态资源的请求,haproxy就将请求转发给静态服务器,如果是动态的请求就转发给静态服务器,haproxy实现动静分离是通过acl匹配规则来实现这一目的。

未分类

未分类

二. 具体的步骤:

(1)在192.168.180.4上配置static服务器

[root@Monitor conf]# vim /data/index.html 
<h1>192.168.180.4---static</h1>

[root@Monitor conf]# vim /usr/local/nginx/conf/nginx.conf       
worker_processes  1;
user appuser appuser;
error_log  /data/nginx/error.log;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
   sendfile        on;
    access_log      /data/nginx/access.log;
    keepalive_timeout  65;
    gzip  on;
    server_tokens off;

 server {
         listen    80;
         server_name  192.168.180.4;
         access_log  /data/nginx/nginx.access.log;
         index   index.php  index.html index.htm;
       # root       /data/www/;
         root      /data/;
         }
     }
[root@Monitor conf]# /usr/local/nginx/sbin/nginx -s reload

保存后直接加载nginx ,在浏览器上查看该页面

未分类

(2)在192.168.180.9安装配置php服务器。

[root@localhost www]# vim /www/html/www/index.php 
<h1>this is 192.168.180.9---dynamic for php page</h1>

[root@localhost www]# cat  /usr/local/nginx/conf/nginx.conf
worker_processes  1;
#error_log  logs/error.log  info;
#pid        logs/nginx.pid;
events {
    worker_connections  1024;
}
http {
    include       mime.types;
    default_type  application/octet-stream;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
    access_log  logs/access.log  main;
    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
    gzip  on;
   server {
       listen 80;
       location ~ .php$ {
                   root /www/html/www;
                   fastcgi_pass 127.0.0.1:9000;
                   fastcgi_index index.php;
                   fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    include fastcgi_params;
                 }
     }
 }

重新加载nginx ,在浏览器中查看如下界面:

未分类

(3)在192.168.180.2服务器中安装配置jsp测试界面

[root@ittestserver1 m]# vim 1.jsp
this is test jsp page
[root@ittestserver1 conf]# /usr/local/tomcat/bin/startup.sh 
Using CATALINA_BASE:   /usr/local/tomcat
Using CATALINA_HOME:   /usr/local/tomcat
Using CATALINA_TMPDIR: /usr/local/tomcat/temp
Using JRE_HOME:        /usr/java/jdk1.7.0_79
Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar
Tomcat started.

查看测试界面

未分类

(4)接下来是最重要的配置haproxy服务器

[root@localhost haproxy]# vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
 log 127.0.0.1 local2 info  ###[err warning info debug] 
 chroot /usr/local/haproxy
 pidfile /var/run/haproxy.pid ###haproxy的pid存放路径,启动进程的用户必须有权限访问此文件 
 maxconn 4000     ###最大连接数,默认4000
 user haproxy
 group haproxy
 daemon       ###创建1个进程进入deamon模式运行。此参数要求将运行模式设置为"daemon"

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will 
# use if not designated in their block
#---------------------------------------------------------------------
defaults
 mode http    ###默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK
 log global   ###采用全局定义的日志
 option dontlognull  ###不记录健康检查的日志信息
 option httpclose  ###每次请求完毕后主动关闭http通道 
 option httplog   ###日志类别http日志格式 
 option forwardfor  ###如果后端服务器需要获得客户端真实ip需要配置的参数,可以从Http Header中获得客户端ip 
 option redispatch  ###serverId对应的服务器挂掉后,强制定向到其他健康的服务器
 timeout connect 10000 #default 10 second timeout if a backend is not found
 timeout client 300000 ###客户端连接超时
 timeout server 300000 ###服务器连接超时
 maxconn  60000  ###最大连接数
 retries  3   ###3次连接失败就认为服务不可用,也可以通过后面设置 
####################################################################
listen stats
  bind 0.0.0.0:1080   #监听端口 
  stats refresh 30s   #统计页面自动刷新时间 
  stats uri /stats   #统计页面url 
  stats realm Haproxy Manager #统计页面密码框上提示文本 
  stats auth admin:admin  #统计页面用户名和密码设置 
  stats hide-version   #隐藏统计页面上HAProxy的版本信息
  stats enable         ###启用管理界面
  stats admin if TRUE  ##如果登录成功就可以管理在线服务器
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend main
#frontend   www    # *表示haproxy监听所有地址,监听的端口为80
 bind 0.0.0.0:80
# bind *:8080
#######定义访问控制,表示url以.css .js .html .php结尾的分别调度到哪台服务器上访问
# acl  url_static    path_beg  -i   /static /images /javascript /stylesheets
 acl  url_static    path_end  -i   .jpg .gif .png .css .js .html
 acl  url_dynamic_php   path_end  -i   .php
 acl  url_dynamic_jsp   path_end  -i   .jsp
#######usr_backend表示使用backend服务,if表示如果满足url_static这个条件就调度到这台服务器上
 use_backend         static          if url_static  ###满足策略要求,则响应策略定义的backend静态页面
 use_backend         dynamic_php     if url_dynamic_php   ###满足策略要求,则响应策略定义的backend静态页面
  se_backend         dynamic_jsp     if url_dynamic_jsp  ###满足策略要求,则响应策略定义的backend静态页面
# default_backend     dynamic                  ###不满足则响应backend的默认动态页面
# default_backend     dynamic                  ###不满足则响应backend的默认动态页面

#---------------------------------------------------------------------
# static backend for serving up images, stylesheets and such
#---------------------------------------------------------------------

backend static           ###定义后端静态请求响应
 balance  roundrobin     ###负载均衡模式轮询
 server  static 192.168.180.4:80 check ###后端服务器定义
#server  static 192.168.180.9:80 check ###后端服务器定义

backend dynamic_php           #####定义后端动态请求响应
 balance roundrobin
 server   phpsrv1 192.168.180.9:80 check maxconn 2000
# server   websrv1 dd192.168.180.9:80 check maxconn 2000
#server   websrv2 192.168.180.4:80 check maxconn 2000
# server   websrv2 192.168.180.2:443 check maxconn 2000
backend dynamic_jsp           #####定义后端动态请求响应                                                           
 balance roundrobin                                                                                               
 server   jspsrv1 192.168.180.2:8081 check maxconn 2000   

#---------------------------------------------------------------------
# round robin balancing between the various backends
#---------------------------------------------------------------------


errorfile 403 /etc/haproxy/errorfiles/403.http

errorfile 500 /etc/haproxy/errorfiles/500.http

errorfile 502 /etc/haproxy/errorfiles/502.http

errorfile 503 /etc/haproxy/errorfiles/503.http
[root@localhost haproxy]# systemctl restart haproxy.service

三. 测试

(1)测试static页面并查看haproxy的访问日志;

未分类

[root@localhost ~]# tail -f /var/log/haproxy.log 
Jul 20 18:07:22 localhost haproxy[6436]: 192.168.181.231:53672 [20/Jul/2017:18:07:22.371] main static/static 0/0/0/1/1 304 167 - - ---- 0/0/0/0/0 0/0 "GET /index.html HTTP/1.1"

(2)访问php页面

未分类

[root@localhost ~]# tail -f /var/log/haproxy.log 
Jul 20 18:08:36 localhost haproxy[6436]: 192.168.181.231:53834 [20/Jul/2017:18:08:36.261] main dynamic_php/phpsrv1 0/0/1/0/2 200 2332 - - ---- 0/0/0/0/0 0/0 "GET /index.php?=PHPE9568F35-D428-11d2-A769-00AA001ACF42 HTTP/1.1"

(3)访问jsp页面

未分类

[root@localhost ~]# tail -f /var/log/haproxy.log 
Jul 20 18:09:58 localhost haproxy[6436]: 192.168.181.231:54015 [20/Jul/2017:18:09:57.999] main dynamic_jsp/jspsrv1 0/0/1/2/3 200 188 - - ---- 0/0/0/0/0 0/0 "GET /1.jsp HTTP/1.1"

(4)查看haproxy监控页面

未分类

总之:haproxy可以利用acl规则匹配url做相应的请求跳转,比如动静分离,域名跳转等等应用需求,haproxy是一款性能很强大的四层以及七层代理server。HAProxy运行在 当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。