Yee's 部落格

Hadoop,hive,pig开发环境搭建

Hadoop的版本推荐选用cloudera的CDH系列,因为这个系列把hadoop,hive,pig等工具的版本已经匹配好了,并且有详细的安装说明文档,细节见http://www.cloudera.com/content/support/en/documentation.html

目前最新的发布版是CDH 5,支持的操作系统有CentOS6.5和Ubuntu12.04,搭建hadoop开发环境我更偏向centos6.5些。

首先安装JDK,官方推荐使用Oracle JDK,不建议使用OpenJDK。

1
2
3
wget http://download.oracle.com/otn-pub/java/jdk/8u11-b12/jdk-8u11-linux-x64.tar.gz
tar xvzf jdk-8u11-linux-x64.tar.gz
sudo mv jdk1.8.0_11/ /opt/

配置JAVA_HOME和PATH

1
2
3
4
5
6
7
8
#sudo vi /etc/environment

export JAVA_HOME=/opt/jdk1.8.0_11

#sudo vi /etc/profile

export JAVA_HOME=/opt/jdk1.8.0_11
export PATH=$JAVA_HOME/bin:$PATH

下载CDH5 1-click安装包

1
2
wget http://archive.cloudera.com/cdh5/one-click-install/redhat/6/x86_64/cloudera-cdh-5-0.x86_64.rpm
sudo yum --nogpgcheck localinstall cloudera-cdh-5-0.x86_64.rpm

安装上面的包会添加cloudera的仓库配置,查询包所安装的文件列表如下

1
2
3
4
5
6
rpm -lq cloudera-cdh-5-0.x86_64
/etc/pki/rpm-gpg
/etc/pki/rpm-gpg/RPM-GPG-KEY-cloudera
/etc/yum.repos.d/cloudera-cdh5.repo     #仓库配置文件
/usr/share/doc/cloudera-cdh-5
/usr/share/doc/cloudera-cdh-5/LICENSE

下面安装Hadoop, 使用第二代的yarn作为mapper/reducer调度器

1
sudo yum install hadoop-conf-pseudo  #这个是开发环境的配置文件,它的依赖里面有hadoop hdfs+yarn

把主机名加入hosts列表

1
127.0.0.1  vm4   #主机名是vm4

格式化NameNode

1
sudo -u hdfs hdfs namenode -format

给hadoop启动脚本添加JAVA_HOME环境变量

1
2
3
#sudo vi /etc/hadoop/conf/hadoop-env.sh

export JAVA_HOME=/opt/jdk1.8.0_11

启动hadoop namenode,datanode,secondarynamenode服务

1
for x in `cd /etc/init.d ; ls hadoop-hdfs-*` ; do sudo service $x stop ; done

创建hdfs相关的目录结构

1
2
3
4
5
6
7
sudo -u hdfs hadoop fs -rm -r /tmp  #确保/tmp目录不存在

sudo -u hdfs hadoop fs -mkdir -p /tmp/hadoop-yarn/staging/history/done_intermediate
sudo -u hdfs hadoop fs -chown -R mapred:mapred /tmp/hadoop-yarn/staging 
sudo -u hdfs hadoop fs -chmod -R 1777 /tmp 
sudo -u hdfs hadoop fs -mkdir -p /var/log/hadoop-yarn
sudo -u hdfs hadoop fs -chown yarn:mapred /var/log/hadoop-yarn

验证下创建过的目录结构

1
2
3
4
5
6
7
8
9
10
sudo -u hdfs hadoop fs -ls -R /

drwxrwxrwt   - hdfs supergroup          0 2014-07-31 16:18 /tmp
drwxrwxrwt   - hdfs supergroup          0 2014-07-31 16:18 /tmp/hadoop-yarn
drwxrwxrwt   - mapred mapred              0 2014-07-31 16:18 /tmp/hadoop-yarn/staging
drwxrwxrwt   - mapred mapred              0 2014-07-31 16:18 /tmp/hadoop-yarn/staging/history
drwxrwxrwt   - mapred mapred              0 2014-07-31 16:18 /tmp/hadoop-yarn/staging/history/done_intermediate
drwxr-xr-x   - hdfs   supergroup          0 2014-07-31 16:18 /var
drwxr-xr-x   - hdfs   supergroup          0 2014-07-31 16:18 /var/log
drwxr-xr-x   - yarn   mapred              0 2014-07-31 16:18 /var/log/hadoop-yarn

启动map/reduce相关服务

1
2
3
sudo service hadoop-yarn-resourcemanager start 
sudo service hadoop-yarn-nodemanager start 
sudo service hadoop-mapreduce-historyserver start

产生用户目录,在hdfs下,每个用户有自己的home目录,我的测试机的用户名叫jojo,因此

1
2
sudo -u hdfs hadoop fs -mkdir -p /user/jojo
sudo -u hdfs hadoop fs -chown jojo /user/jojo

到目前为止hadoop hdfs+yarn map/reduce调度器安装完成了,下面测试下:

1
2
3
4
5
6
7
8
9
hadoop fs -mkdir input #创建一个input目录
hadoop fs -put /etc/hadoop/conf/*.xml input  #把hadoop的配置文件copy到input目录
hadoop fs -ls input   #列出input目录下的文件

Found 4 items
-rw-r--r--   1 jojo supergroup       2133 2014-07-31 16:28 input/core-site.xml
-rw-r--r--   1 jojo supergroup       2324 2014-07-31 16:28 input/hdfs-site.xml
-rw-r--r--   1 jojo supergroup       1549 2014-07-31 16:28 input/mapred-site.xml
-rw-r--r--   1 jojo supergroup       2375 2014-07-31 16:28 input/yarn-site.xml

编辑.bashrc设置HADOOP_MAPRED_HOME, 这个变量在运行map/reduce程序的时候需要用到

1
2
3
4
5
#vi ~/.bashrc

export HADOOP_MAPRED_HOME=/usr/lib/hadoop-mapreduce  #加入这行

source ~/.bashrc  #source下,让export立即生效

运行例子程序

1
2
#把input下符合'dfs[a-z.]+'的项输出到output23目录下
hadoop jar /usr/lib/hadoop-mapreduce/hadoop-mapreduce-examples.jar grep input output23 'dfs[a-z.]+'

列出 output23目录看看

1
2
3
4
5
hadoop fs -ls output23 

Found 2 items
-rw-r--r--   1 jojo supergroup          0 2014-07-31 16:35 output23/_SUCCESS
-rw-r--r--   1 jojo supergroup        244 2014-07-31 16:35 output23/part-r-00000

看下输出文件的内容

1
2
3
4
5
6
7
8
9
10
11
12
hadoop fs -cat output23/part-r-00000 | head

1       dfs.safemode.min.datanodes
1       dfs.safemode.extension
1       dfs.replication
1       dfs.namenode.name.dir
1       dfs.namenode.checkpoint.dir
1       dfs.domain.socket.path
1       dfs.datanode.hdfs
1       dfs.datanode.data.dir
1       dfs.client.read.shortcircuit
1       dfs.client.file

到这里hadoop已经安装成功了,下面安装hive

1
sudo yum install hive hive-metastore hive-server2

hive的metastore是用来存储hive的表结构的,习惯的做法是把metastore存放到mysql里面,hive-server2是hive-server的改良版,增强了并发性。

首先安装mysql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
sudo yum install mysql-server

sudo service mysqld start #启动mysql服务

#安装mysql jdbc驱动
sudo yum install mysql-connector-java
sudo ln -s /usr/share/java/mysql-connector-java.jar /usr/lib/hive/lib/mysql-connector-java.jar

#设置mysql root用户的密码
sudo /usr/bin/mysql_secure_installation

#确保mysql开机启动
sudo /sbin/chkconfig mysqld on
sudo /sbin/chkconfig --list mysqld

下面产生metastore需要用的schema和用户

1
2
3
4
5
6
7
8
9
10
11
12
mysql -u root -p
Enter password:
mysql> CREATE DATABASE metastore;
mysql> USE metastore;
mysql> SOURCE /usr/lib/hive/scripts/metastore/upgrade/mysql/hive-schema-0.12.0.mysql.sql;  #导入schema

#添加hive用户
mysql> CREATE USER 'hive'@'localhost' IDENTIFIED BY 'passwd1234';  #密码passwd1234
mysql> REVOKE ALL PRIVILEGES, GRANT OPTION FROM 'hive'@'localhost';
mysql> GRANT SELECT,INSERT,UPDATE,DELETE,LOCK TABLES,EXECUTE ON metastore.* TO 'hive'@'localhost';
mysql> FLUSH PRIVILEGES;
mysql> quit;

编辑hive配置文件,加入如下配置

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
#sudo vi /etc/hive/conf/hive-site.xml

<property>
	<name>javax.jdo.option.ConnectionURL</name>
	<value>jdbc:mysql://localhost/metastore</value>
	<description>the URL of the MySQL database</description>
</property>

<property>
	<name>javax.jdo.option.ConnectionDriverName</name>
	<value>com.mysql.jdbc.Driver</value>
</property>

<property>
	<name>javax.jdo.option.ConnectionUserName</name>
	<value>hive</value>
</property>

<property>
	<name>javax.jdo.option.ConnectionPassword</name>
	<value>passwd1234</value>
</property>

<property>
	<name>datanucleus.autoCreateSchema</name>
	<value>false</value>
</property>

<property>
	<name>datanucleus.fixedDatastore</name>
	<value>true</value>
</property>

<property>
	<name>datanucleus.autoStartMechanism</name>
	<value>SchemaTable</value>
</property>

<property>
	<name>hive.metastore.uris</name>
	<value>thrift://localhost:9083</value>
	<description>IP address (or fully-qualified domain name) and port of the metastore host</description>
</property>

启动metastore服务

1
2
sudo service hive-metastore start
sudo service hive-metastore status #检查下状态,因为配置项比较多,容易出错,出错后检查/var/log/hive/hive-metastore.out对照日志排错

测试下hive是否能连接到metastore

1
2
3
4
5
hive -e 'show tables;'

#没表输出,因为还没创建过
OK
Time taken: 2.836 seconds

下面配置hive-server2, 这个服务依赖zookeeper,因此先在本机部署一个zookeeper测试实例

1
2
3
4
5
6
7
8
sudo yum install zookeeper zookeeper-server

#产生zookeeper的数据目录
sudo mkdir -p /var/lib/zookeeper
sudo chown -R zookeeper /var/lib/zookeeper/

sudo service zookeeper-server init #初始化zookeeper
sudo service zookeeper-server start #启动zookeeper服务

编辑hive配置文件,增加如下配置

1
2
3
4
5
6
7
8
9
10
11
12
#sudo vi /etc/hive/conf/hive-site.xml
<property>
	<name>hive.support.concurrency</name>
	<description>Enable Hive's Table Lock Manager Service</description>
	<value>true</value>
</property>

<property>
	<name>hive.zookeeper.quorum</name>
	<description>Zookeeper quorum used by Hive's Table Lock Manager</description>
	<value>localhost</value>
</property>

启动hive-server2服务

1
sudo service hive-server2 start

连接上hive-server2看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[jojo@vm4 ~]$ beeline
Beeline version 0.12.0-cdh5.1.0 by Apache Hive
beeline> !connect jdbc:hive2://localhost:10000 username password org.apache.hive.jdbc.HiveDriver
Connecting to jdbc:hive2://localhost:10000
Connected to: Apache Hive (version 0.12.0-cdh5.1.0)
Driver: Hive JDBC (version 0.12.0-cdh5.1.0)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://localhost:10000> SHOW TABLES;
+-----------+
| tab_name  |
+-----------+
+-----------+
No rows selected (2.547 seconds)
0: jdbc:hive2://localhost:10000> !quit
Closing: org.apache.hive.jdbc.HiveConnection

可以看到现在还没hive的数据表,在产生hive数据表之前,先要生成hive的数据目录

1
2
sudo -u hdfs hadoop fs -mkdir -p /user/hive/warehouse
sudo -u hdfs hadoop fs -chmod -R 1777 /user/hive/warehouse  #让任何用户都能操作hive的数据

下面来测试下hive

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0: jdbc:hive2://localhost:10000> CREATE TABLE pokes (foo INT, bar STRING);  #产生一张表
No rows affected (1.166 seconds)
0: jdbc:hive2://localhost:10000> show tables;
+-----------+
| tab_name  |
+-----------+
| pokes     |
+-----------+
1 row selected (0.589 seconds)
0: jdbc:hive2://localhost:10000> SELECT COUNT(*) FROM pokes;  #count下
+------+
| _c0  |
+------+
| 0    |
+------+
1 row selected (56.58 seconds)

#检查下hdfs下刚才产生的表
[jojo@vm4 ~]$ sudo -u hdfs hadoop fs -ls -R /user/hive
drwxrwxrwt   - hdfs supergroup          0 2014-07-31 17:53 /user/hive/warehouse
drwxrwxrwt   - hive supergroup          0 2014-07-31 17:53 /user/hive/warehouse/pokes

到这里hive已经安装完成了,下面安装pig

1
sudo yum install pig

pig安装完成啦~ 下面来测试下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
pig 
grunt> ls  #列出当前用户目录下的文件

grunt> A = LOAD 'input';  #input目录下有hadoop的配置文件
grunt> B = FILTER A BY $0 MATCHES '.*dfs[a-z.]+.*';   #匹配dfs的项
grunt> DUMP B;  #查看B的内容

#输出如下
(    <name>dfs.replication</name>)
(    <name>dfs.safemode.extension</name>)
(     <name>dfs.safemode.min.datanodes</name>)
(     <name>dfs.namenode.name.dir</name>)
(     <name>dfs.namenode.checkpoint.dir</name>)
(     <name>dfs.datanode.data.dir</name>)
(    <name>dfs.client.read.shortcircuit</name>)
(    <name>dfs.client.file-block-storage-locations.timeout.millis</name>)
(    <name>dfs.domain.socket.path</name>)
(    <name>dfs.datanode.hdfs-blocks-metadata.enabled</name>)

pig测试完成,到这里hadoop+hive+pig的开发环境配置完成。

配置Virtualbox虚拟机网卡,支持内外网访问

使用Virtualbox新建完成虚拟机后,打开设置->网络,第一块网卡选择”网络地址转换(NAT)”,用来共享上网;第二块网卡选择”桥接网卡”,在网卡列表里面选择内网所连的那块网卡,这个虚拟网卡用来支持内网访问。

接下来启动虚拟机配置网卡:

CentOS系列:

配置第一块网卡,因为是NAT网络,直接使用dhcp服务自动配置

1
2
3
4
5
6
7
8
9
10
11
#sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth0
TYPE=Ethernet
UUID=ccd8c9e7-f8a8-413d-a2eb-6c343f540ab1
#开机启用
ONBOOT=yes
NM_CONTROLLED=yes
#使用dhcp自动配置
BOOTPROTO=dhcp
HWADDR=08:00:27:D9:32:00
NAME="System eth0"

配置第二块网卡,桥接网络,需要手工配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#sudo vi /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE=eth1
TYPE=Ethernet
UUID=741f9e69-c4f0-4321-a0ea-427611f53f8f
#开机启用
ONBOOT=yes
NM_CONTROLLED=yes
#手工配置
BOOTPROTO=static
HWADDR=08:00:27:78:C1:DF
#内网IP地址
IPADDR=192.168.1.101
#子网掩码,相当于255.255.255.0
PREFIX=24
#这里忽略了网关的配置
#GATEWAY=x.x.x.x
NAME="System eth1"

检查/etc/sysconfig/network,确保里面没有网关的配置

1
2
3
NETWORKING=yes
HOSTNAME=vm3
#GATEWAY=x.x.x.x

sudo service network restart, ifconfig信息如下

1
2
eth0   inet addr:10.0.2.15  
eth1   inet addr:192.168.1.101

route下确保缺省网关使用的是eth0(网络地址转换, aka NAT)的网关

1
default         10.0.2.2        0.0.0.0         UG    0      0        0 eth0

这样配置后就既能通过eth0共享上网,又能通过eth1跟内网主机通信了。

Ubuntu系统配置如下:

1
2
3
4
5
6
7
8
9
10
#sudo vi /etc/network/interfaces

auto eth0
iface eth0 inet dhcp

auto eth1
iface eth1 inet static
address 192.168.1.102
netmask 255.255.255.0
#gateway x.x.x.x

sudo ifup eth0 eth1,就可以了,如果上网有问题请检查下缺省网关,确保使用的是eth0所在网段的网关。

使用logstash, elasticsearch, kibana做日志分析系统

一般情况下,一个站点会由多台server构成, 每台server每天会产生多种不同的日志,为了方面分析线上日志,常用做法是把线上日志集中存储到一个地方,然后按照日期,日志类型,日志内关键字等条件查询。而logstash, elasticsearch, 和kibana就是用来做这件事的开源解决方案。

Logstash 运行于Jruby上的日志收集和分析系统,支持多种后端存储,包括elasticsearch, s3, riak, mongodb, redis等
Elasticsearch Java写的搜索引擎,简单好用,很适合日志的存储和查询, 简称ES
Kibana Elasticsearch的查询前端,最早用PHP写的,后来用Ruby重新实现了一遍,最新版本是纯Javascript的,直接在浏览器端运行。

架构上,在服务器不多的情况下,可以使用Logstash分析日志后,直接存储到ES里面,然后调用Kibana做日志查询。

如果服务器很多,或者是需要跨网络,那么可以使用前向代理,做成树状结构,树叶是Logstash,分析完成后传给树枝logstash-forwarder, 然后传给树干Logstash, 最终输出汇总给ES

树枝的角色一般叫做shipper,有很多方案可以代替logstash-forwarder, 比如redis, zeromq, rabbitmq等

Logstash, elasticsearch, kibana的安装都很简单,这里直接略过,下面说下logstash是如何完成日志收集工作的。

Logstash日志收集可以分成3大块,input, filter和output, 可以通过启动时指定配置文件来配置。

1
./bin/logstash -f config_file

Input是配置日志源的,这里使用文件做例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
input {
  file {
    #日志存储格式 /web/mywebsite/logs/201407/login_errr_10.log
    path => "/web/mywebsite/logs/*/*"  
    type => "web_log"
  }

  file {
    #日志存储格式 /web/mywebsite/logs/apache_access.log
    path => "/web/mywebsite/logs/*"
    type => "access_log"
  }
}

可以看到指定输入的时候可以使用通配符监视多个文件。

Filter用来对日志做过滤,比较常用的filter有

grok 通过正则表达式把每一行的日志做匹配,把非结构化的信息变成结构化的
date 可以用指定字段的值作为当前log的时间戳,而不是使用导入log时的系统时间。
multiline 可以把多行日志合并成一个logstash事件

解释起来比较拗口,看实际的配置例子更容易理解。

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
filter {
  #可以使用条件语句的, 中括号里面的[type]代表引用type这个字段的值
  if [type] == "access_log" {
    grok {
      #COMBINEDAPACHELOG, 预定义的一组正则
      match => { "message" => "%{COMBINEDAPACHELOG}" }
    }

    #这里把[timestamp]这个字段的值按照"dd/MMM/yyyy:HH:mm:ss Z"的格式解析成日期,作为本条log的产生日期。
    date {
      match => [ "timestamp" , "dd/MMM/yyyy:HH:mm:ss Z" ]
    }
  } else {

    #匹配这样的消息:  2014-07-14T22:10:51-07:00 INFO (6): log body
    grok {
      match => {"message"  => "%{TIMESTAMP_ISO8601:timestamp} %{DATA:data}"}
    }

    #这里把[timestamp]这个字段的值按照iso8601的格式解析
    date {
      match => [ "timestamp" , "ISO8601" ]
    }

    #增加[site], [log]字段,比如/web/mywebsite/logs/login_error_10.log
    #匹配到的[site] == 'mywebsite', [log] = 'login_error_'
    ruby {
        code => "
           site = 'null'
           log = 'null'
           m = /(.*)\/(.*)\/logs(.*)\/([a-zA-Z\-_]+)(.*)\.(.*)/.match(event['path'])
           site = m[2]; log=m[4] if m
           event['site'] = site
           event['log'] = log
        "
    }
  }
}

上面的COMBINEDAPACHELOG是一组预定义的正则,https://github.com/logstash/logstash/tree/v1.4.2/patterns这里能看到更多的。

使用上面配置解析出的log如下

1
2
3
4
5
6
7
8
9
10
11
{
  "message" => "2014-07-14T22:12:26-07:00 INFO (6): Log detail",
  "@version" => "1",
  "@timestamp" => "2014-07-15T05:12:26.000Z",
  "type" => "web_log",
  "host" => "myserver.local",
  "path" => "/web/mywebsite/logs/201407/login_error_14.txt",
  "timestamp" => "2014-07-14T22:12:26-07:00"
  "site" => "mywebsite",
  "log" => "login_error_"  
}

##在使用Filter转换好格式后,就可以配置output输出了

1
2
3
4
output {
  stdout { codec => rubydebug }
  elasticsearch_http { host => localhost port => 9200}
}

可以看到,我配置了2个输出,一个使用rubydebug的格式打印到console上,一个使用elasticsearch_http输出到ES。

以上就是logstash的配置过程,最重点的部分在filter上。数据到了ES之后,使用kibana查询可以参考这里的介绍


补充: 如果不想处理多行消息,可以使用\v\r,代替\r\n,可以在写入log前统一处理, php代码如下:

1
2
$message = str_replace(array("\r\n","\n","\r"), "\v", $message);
$message = str_replace("\v", "\v\r", $message);

用hexo在github上搭建个人博客

幻灯片看这里

Ubuntu下samba共享服务设置

Samba实现了windows共享服务,配置完成后可以通过windows网上邻居交换文件。

首先安装samba软件包

1
sudo apt-get install samba

安装完成后,打开/etc/samba/smb.conf,配置共享目录,个人习惯配置home目录跟/web目录

1
2
3
4
5
6
7
8
9
10
11
12
13
[homes]
   comment = Home Directories
   browseable = no
   #允许向home目录写入文件
   read only = no

[web]
   path = /web
   guest ok = no
   browseable = yes
   create mask = 0644
   directory mask = 0755
   read only = no

配置完成后重启samba服务,使配置文件生效。

1
sudo service smbd restart

samba有自己的用户授权体系,每个linux系统中原有的用户,都需要重新加入samba的用户库,并且重新设置密码,这样才能访问共享服务。
这里假设加入rose这个用户

1
sudo smbpasswd -a rose

之后绑定域名dev.example.com到开发机,打开资源管理器,地址栏输入\\dev.example.com就可以访问共享的资源了。

Mercurial仓库架设

Mercurial是使用python编写的,因此需要安装python包管理器,常见的包管理器有easy install和pip。个人推荐使用pip,因为pip比easy install更成熟,不会出现某个python模块安装不完整,导致无法卸载也无法重新安装的问题。

安装easy install

1
sudo apt-get install python-setuptools

用easy install安装pip

1
sudo easy_install pip

在安装mercurial之前, 需要先安装gcc等编译工具,以及python的开发支持库

1
sudo apt-get install build-essential python-dev

安装mercurial

1
sudo pip install mercurial

到目前为止mercurial已经安装完成了,命令行下输入”hg”就可以看到mercurial的help信息了。接下来配置一个mercurial的公共仓库,方便代码共享。

平时我的开发网站放在/web目录下面,比如域名为demo.example.com的网站,物理路径是/web/demo.example.com

首先初始化一个mercurial的仓库

1
mkdir /web/demo.example.com && cd /web/demo.example.com && hg init

接下来使用hgweb的wsgi脚本配置一个服务,详细信息可以参考: http://mercurial.selenic.com/wiki/PublishingRepositories#hgweb

个人喜欢gunicorn作为python app的WSGI服务器,因此先安装gunicorn

1
sudo pip install gunicorn

/web/hgweb.py (wsgi脚本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# An example WSGI for use with mod_wsgi, edit as necessary
# See http://mercurial.selenic.com/wiki/modwsgi for more information

# Path to repo or hgweb config to serve (see 'hg help hgweb')
config = "/web/hgweb.config"

# Uncomment and adjust if Mercurial is not installed system-wide
# (consult "installed modules" path from 'hg debuginstall'):
#import sys; sys.path.insert(0, "/path/to/python/lib")

# Uncomment to send python tracebacks to the browser if an error occurs:
import cgitb; cgitb.enable()

# enable demandloading to reduce startup time
from mercurial import demandimport; demandimport.enable()

from mercurial.hgweb import hgweb
application = hgweb(config)

/web/hgweb.config 配置文件

1
2
3
4
5
6
7
[paths]
/ = /web/*

[web]
style = monoblue
push_ssl = false
allow_push = *

绑定hgrepos.example.com到开发环境IP
gunicorn —workers=2 hgweb:application —bind=0.0.0.0:8001 启动guincorn服务器看看

1
2
Name			Description		Contact		Last modified	 	 
demo.example.com	unknown			unknown		Fri, 04 Jul 2014 08:12:42 -0400

可以看到前面建立的仓库demo.example.com,成功的列出了。

下面使用apache代理gunicorn的请求,首先启用代理模块

1
2
LoadModule proxy_module /usr/lib/apache2/modules/mod_proxy.so
LoadModule proxy_http_module /usr/lib/apache2/modules/mod_proxy_http.so

配置apache虚拟主机 hgrepos.example.com.conf (apache2.4需要 “Require all granted”, 详细信息见http://httpd.apache.org/docs/2.4/upgrading.html)

1
2
3
4
5
6
7
8
9
10
11
<VirtualHost *:80>
ServerName hgrepos.example.com
ProxyRequests On
<Proxy *>
Order deny,allow
Allow from all
Require all granted
</Proxy>
ProxyPass / http://127.0.0.1:8001/
ProxyPassReverse / http://127.0.0.1:8001/
</VirtualHost>

如果用nginx,参考配置如下

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
server {
    listen          80;
    server_name     hgrepos.example.com;
    server_name_in_redirect off;

    access_log  /var/log/nginx/hg_access.log;
    error_log   /var/log/nginx/hg_error.log;
    send_timeout     3m;
    location / {
        proxy_pass http://127.0.0.1:8001;
        proxy_redirect off;
        proxy_connect_timeout 3000;
        proxy_read_timeout 3000;
        proxy_send_timeout 3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_body_buffer_size 128k;
        client_max_body_size 2000m;
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 4 32k;
        proxy_busy_buffers_size 64k;
        proxy_temp_file_write_size 64k;
    }
}