0%

tcpdump

TcpDump可以将网络中传送的数据包完全截获下来提供分析。它支持针对网络层、协议、主机、网络或端口的过滤,并提供and、or、not等逻辑语句来帮助你去掉无用的信息。

用法

tcpdump <参数s> <包过滤表达式>

  • 参数
    详细请见man tcpdump
  • 包过滤表达式
    详细请见man pcap-filter

常用参数

  • -A 以ASCII格式打印出所有分组,并将链路层的头最小化。
  • -c 在收到指定的数量的分组后,tcpdump就会停止。
  • -C 在将一个原始分组写入文件之前,检查文件当前的大小是否超过了参数file_size 中指定的大小。如果超过了指定大小,则关闭当前文件,然后在打开一个新的文件。参数 file_size 的单位是兆字节(是1,000,000字节,而不是1,048,576字节)。
  • -d 将匹配信息包的代码以人们能够理解的汇编格式给出。
  • -dd 将匹配信息包的代码以C语言程序段的格式给出。
  • -ddd 将匹配信息包的代码以十进制的形式给出。
  • -D 打印出系统中所有可以用tcpdump截包的网络接口。
  • -e 在输出行打印出数据链路层的头部信息。
  • -E 用spi@ipaddr algo:secret解密那些以addr作为地址,并且包含了安全参数索引值spi的IPsec ESP分组。
  • -f 将外部的Internet地址以数字的形式打印出来。
  • -F 从指定的文件中读取表达式,忽略命令行中给出的表达式。
  • -i 指定监听的网络接口。
  • -l 使标准输出变为缓冲行形式,可以把数据导出到文件。
  • -L 列出网络接口的已知数据链路。
  • -m 从文件module中导入SMI MIB模块定义。该参数可以被使用多次,以导入多个MIB模块。
  • -M 如果tcp报文中存在TCP-MD5选项,则需要用secret作为共享的验证码用于验证TCP-MD5选选项摘要(详情可参考RFC 2385)。
  • -b 在数据-链路层上选择协议,包括ip、arp、rarp、ipx都是这一层的。
  • -n 不把网络地址转换成名字。
  • -nn 不进行端口名称的转换。
  • -N 不输出主机名中的域名部分。例如,‘nic.ddn.mil‘只输出’nic‘。
  • -t 在输出的每一行不打印时间戳。
  • -O 不运行分组分组匹配(packet-matching)代码优化程序。
  • -P 不将网络接口设置成混杂模式。
  • -q 快速输出。只输出较少的协议信息。
  • -r 从指定的文件中读取包(这些包一般通过-w选项产生)。
  • -S 将tcp的序列号以绝对值形式输出,而不是相对值。
  • -s 从每个分组中读取最开始的snaplen个字节,而不是默认的68个字节,一般设置为0,即65535字节。(抓包长度)
  • -T 将监听到的包直接解释为指定的类型的报文,常见的类型有rpc远程过程调用)和snmp(简单网络管理协议;)。
  • -t 不在每一行中输出时间戳。
  • -tt 在每一行中输出非格式化的时间戳。
  • -ttt 输出本行和前面一行之间的时间差。
  • -tttt 在每一行中输出由date处理的默认格式的时间戳。
  • -u 输出未解码的NFS句柄。
  • -v 输出一个稍微详细的信息,例如在ip包中可以包括ttl和服务类型的信息。
  • -vv 输出详细的报文信息。
  • -w 直接将分组写入文件中,而不是不分析并打印出来。

包过滤表达式

tcpdump利用它作为过滤报文的条件,如果一个报文满足表 达式的条件,则这个报文将会被捕获。如果没有给出任何条件,则网络上所有的信息包 将会被截获。

表达式类型关键字:

  • type
    主要包括host,net,port,例如 host 210.27.48.2, 指明 210.27.48.2是一台主机,net 202.0.0.0指明202.0.0.0是一个网络地址,port 23 指明端口号是23。如果没有指定类型,缺省的类型是host。
  • dir
    主要包括src,dst,dst or src,dst and src, 这些关键字指明了传输的方向。举例说明,src 210.27.48.2 ,指明ip包中源地址是 210.27.48.2 , dst net 202.0.0.0 指明目的网络地址是202.0.0.0。如果没有指明 方向关键字,则缺省是src or dst关键字。
  • proto
    主要包括fddi,ip,arp,rarp,tcp,udp等类型。Fddi指明是在FDDI (分布式光纤数据接口网络)上的特定的网络协议,实际上它是”ether”的别名,fddi和ether 具有类似的源地址和目的地址,所以可以将fddi协议包当作ether的包进行处理和分析。 其他的几个关键字就是指明了监听的包的协议内容。如果没有指定任何协议,则tcpdump 将会 监听所有协议的信息包。

除了这三种类型的关键字之外,其他重要的关键字如下:gateway, broadcast,less, greater, 还有三种逻辑运算,取非运算是not !,与运算是and&&,或运算是or,这些关键字可以组合起来构成强大的组合条件来满足人们的需要。

示例

查看HTTP请求响应头以及数据

sudo tcpdump -A -s 0 'tcp port 80 and (((ip[2:2] - ((ip[0]&0xf)<<2)) - ((tcp[12]&0xf0)>>2)) != 0)'

proto [ expr : size ]
Proto 是 ether, fddi, tr, ip, arp, rarp, tcp, udp, icmp or ip6中的一个,它为索引操作指明了协议层。注意,tcp,udp和其他较高层的协议类型只能应用于IPv4,而不能用于IPv6(这个问题可能在将来能得到解决)。被指定的协议层的字节偏移量由expr给出。Size是可选的,它指明了数据域中,我们所感兴趣的字节数。它可以是1,2,或4,默认为1。运算符的长度,由关键字len给出,指明了数据包的长度。
例如,ether[0] & 1 != 0会捕捉所有的多播数据流。表达式ip[0] & 0xf != 5能捕捉所有带可选域的IP数据包。表达式ip[6:2] & 0x1fff = 0仅捕捉未分段的数据报和段偏移量是0的数据报。这个检查隐含在tcp和udp的下标操作中。例如,tcp[0]通常指第一个字节的TCP首部,而不是指第一个字节的分段。
有些偏移量和域值可以以名字来表示,而不是数值。以下协议首部域的偏移量是正确的:icmptype (ICMP 类型域), icmpcode (ICMP 代码域), and tcpflags (TCP 标志域)。
ICMP 类型域有以下这些: icmp-echoreply, icmp-unreach, icmp-sourcequench, icmp-redirect, icmp-echo, icmp-routeradvert, icmp-routersolicit, icmp-timxceed, icmp-paramprob, icmp-tstamp, icmp-tstampreply, icmp-ireq, icmp-ireqreply, icmp-maskreq, icmp-maskreply.
TCP 标志域有以下这些: tcp-fin, tcp-syn, tcp-rst, tcp-push, tcp-push, tcp-ack, tcp-urg.

参考&鸣谢

** 纯转载 **

当我们用HBase 存储实时数据的时候, 如果要做一些数据分析方面的操作, 就比较困难了, 要写MapReduce Job。 Hive 主要是用来做数据分析的数据仓库,支持标准SQL 查询, 做数据分析很是方便,于是便很自然地想到用Hive来载入HBase的数据做分析, 但是很奇怪地是, 上网查了一下, 只看到以下两种情况:

  1. 如何用Hive 往HBase里面插入大量的数据。
  2. Hive 与HBase集成, 直接从Hive里面连HBase的数据库进行查询。参考链接: https://cwiki.apache.org/confluence/display/Hive/HBaseIntegration

选项1是我们需求的逆操作, 直接忽略, 选项2, 虽然没有做专门的Benchmark, 但总感觉直接对HBase进行查询操作不怎么靠谱, 如果我们要频繁做很多类型的数据分析, 那HBase的压力一定会倍增。
难道没有把HBase里面的数据直接导入到Hive当中的工具或者方法吗?
找了一会, 似乎没找到, 那么只好自己想一个解决方案了。

思路:
利用选项2, 先打通Hive对HBase指定表的全表访问, 再建立一个新的空表, 把查询出来的数据全部导入到新表当中, 以后的所有数据分析操作在新表中完成。
说干就干, 让我们试一个简单的例子。

  • 首先在HBase里面建一个表, 名为 student, 包含 id 和 name 两个column
    1
    2
    hbase shell
    create 'student', 'id', 'name'
  • 向表中插入两行数据
    1
    2
    3
    4
    put 'student', 'row1', 'id:val', '1'
    put 'student', 'row1', 'name:val', 'Tony'
    put 'student', 'row2', 'id:val', '2'
    put 'student', 'row2', 'name:val', 'Mike'
    注意:在插入数据的时候一定要指定column (如id:val, name:val) 直接使用column family (如 id, name) 去存数据会导致后面Hive 建表的时候有问题。
  • 扫描此表, 确定数据已经插入
    1
    2
    3
    4
    5
    6
    scan 'student'
    ROW COLUMN+CELL
    row1 column=id:val, timestamp=1384939342989, value=1
    row1 column=name:val, timestamp=1384939365511, value=Tony
    row2 column=id:val, timestamp=1384939351444, value=2
    row2 column=name:val, timestamp=1384939379245, value=Mike
  • 从Hive建立可以访问HBase的外部表
    1
    2
    3
    4
    CREATE EXTERNAL TABLE student(key string, id int, name string) 
    STORED BY 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
    WITH SERDEPROPERTIES ("hbase.columns.mapping" = "id:val,name:val")
    TBLPROPERTIES("hbase.table.name" = "student");
  • Hive中建立一个新的空表
    1
    2
    3
    4
    hive> select * from student;
    OK
    row1 1 Tony
    row2 2 Mike
    但是此时这个表实际上是一个虚拟表, 实际的数据还在HBase中。 下面需要在Hive中另建一个结构一样的空表, 再把数据导出来。
  • Hive中建立一个新的空表
    1
    2
    3
    4
    5
    6
    7
    CREATE TABLE new_student (
    key string,
    id INT,
    name STRING)
    ROW FORMAT DELIMITED
    FIELDS TERMINATED BY '\t'
    STORED AS TEXTFILE;
  • 将数据从HBase中导入到新的Hive表中
    1
    2
    3
    4
    5
    hive> INSERT OVERWRITE TABLE new_student SELECT * FROM student;
    hive> select * from new_student;
    OK
    row1 1 Tony
    row2 2 Mike
    至此大功告成!
    以后所有复杂的数据查询和数据分析都可以在new_student表中完成。

参考&鸣谢

xhyve_logo

FreeBSD 下的虚拟技术 bhyve (The BSD Hypervisor) 是去年1月份正式发布的,包含在了 FreeBSD 10.0 发行版中。今天要玩的这个 xhyve 是基于 bhyve 的 Mac OS X 移植版本,也就是说我们想在 Mac 上运行 Linux 的话除了 VirtualBox, VMware Fusion 外,现在有了第三种选择。

xhyve is a lightweight virtualization solution for OS X that is capable of running Linux. It is a port of FreeBSD’s bhyve, a KVM+QEMU alternative written by Peter Grehan and Neel Natu.

特点:

  • super lightweight, only 230 KB in size
  • completely standalone, no dependencies
  • the only BSD-licensed virtualizer on OS X
  • does not require a kernel extension (bhyve’s kernel code was ported to user mode code calling into Hypervisor.framework)
  • multi-CPU support
  • networking support
  • can run off-the-shelf Linux distributions (and could be extended to run other operating systems)

xhyve may make a good solution for running Docker on your Mac, for instance.

install

search xhyver:

1
2
3
4
5
6
7
8
9
$ brew info xhyve
xhyve: stable 0.2.0 (bottled), HEAD
xhyve, lightweight macOS virtualization solution based on FreeBSD's bhyve
https://github.com/mist64/xhyve
/usr/local/Cellar/xhyve/HEAD-1f1dbe3 (11 files, 11.2MB) *
Built from source on 2017-08-24 at 12:12:21
From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/xhyve.rb
==> Requirements
Required: macOS >= 10.10 ✔

install:

1
$ brew install xhyve

Ubuntu 16.04 VM

下载ubuntu-16.04.1-server-amd64.iso,装载该iso,然后将其中的vmlinuzinitrd.gz复制出来,以供xhyve使用。

在mac系统下直接装载ubuntu的iso会出错

1
2
$ hdiutil attach ./ubuntu-16.04.1-server-amd64.iso
hdiutil: attach failed - 无可装载的文件系统

所以需要制作一个新的iso,新的iso文件前预留2KB的空间

1
2
3
4
5
6
$ dd if=/dev/zero bs=2k count=1 of=./tmp.iso
$ dd if=./ubuntu-16.04.1-server-amd64.iso bs=2k skip=1 >> ./tmp.iso
$ hdiutil attach ./tmp.iso

$ cp /Volumes/Ubuntu-Server\ 16/install/vmlinuz .
$ cp /Volumes/Ubuntu-Server\ 16/install/initrd.gz .

创建一个磁盘映像文件hdd.img,当作虚拟机的虚拟硬盘

1
$ dd if=/dev/zero of=hdd.img bs=1g count=8

编写VM创建脚本mk_xhyve.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

KERNEL="vmlinuz"
INITRD="initrd.gz"
CMDLINE="earlyprintk=serial console=ttyS0 acpi=off"

MEM="-m 1G"
#SMP="-c 2"
NET="-s 2:0,virtio-net"
IMG_CD="-s 3,ahci-cd,./ubuntu-16.04.1-server-amd64.iso"
IMG_HDD="-s 4,virtio-blk,./hdd.img"
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
LPC_DEV="-l com1,stdio"

xhyve $MEM $SMP $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD -f kexec,$KERNEL,$INITRD,"$CMDLINE"

运行VM创建脚本sudo sh ./mk_xhyve.sh创建ubuntu虚拟机

xhyve_vm_run

按正常系统安装方法安装。。。
待成功安装完成后选择<Go Back> => Execute a shell,进入iso的shell界面,然后需要将已经安装好的hdd.img也就是系统中的/dev/vda中的boot目录copy出来,因为要用里面的vmlinuz-4.4.0-31-genericinitrd.img-4.4.0-31-generic

进入shell后先查看一下ip地址

1
2
3
4
5
6
7
8
9
BusyBox v1.22.1 (Ubuntu 1:1.22.0-15ubuntu1) built-in shell (ash)
Enter 'help' for a list of built-in commands.

~ # ip a
1: lo: <LOOPBACK> mtu 65536 qdisc noop qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop qlen 1000
link/ether 82:62:9e:40:cf:32 brd ff:ff:ff:ff:ff:ff
~ #

发现没有获取到ip地址,此时shell用的是busybox,是没有dhclient的,不过busybox提供udhcpc -i <interface>
获取到ip地址后,vm可以通过tar c ./boot | nc -l -p 1234将boot目录发送给宿主机,宿主机用nc <vm ip> 1234 | tar x接受boot目录。

获得到boot目录后取出其中的vmlinuz-4.4.0-31-genericinitrd.img-4.4.0-31-generic,然后修改VM创建脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash

KERNEL="vmlinuz-4.4.0-31-generic"
INITRD="initrd.img-4.4.0-31-generic"
CMDLINE="earlyprintk=serial console=ttyS0 acpi=off root=/dev/vda1"

MEM="-m 1G"
#SMP="-c 2"
NET="-s 2:0,virtio-net"
IMG_CD="-s 3,ahci-cd,./ubuntu-16.04.1-server-amd64.iso"
IMG_HDD="-s 4,virtio-blk,./hdd.img"
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
LPC_DEV="-l com1,stdio"

xhyve $MEM $SMP $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD -f kexec,$KERNEL,$INITRD,"$CMDLINE"

并执行sudo sh ./mk_xhyve.sh

xhyve_vm_run2

ubuntu 16.04 正常启动了,over!

参考&鸣谢

zeppelin_logo

Apache Zeppelin是一个让交互式数据分析变得可行的基于网页的开源框架。Zeppelin提供了数据分析、数据可视化等功能。Zeppelin 是一个提供交互数据分析且基于Web的笔记本。方便你做出可数据驱动的、可交互且可协作的精美文档,并且支持多种语言,包括 Scala(使用 Apache Spark)、Python(Apache Spark)、SparkSQL、 Hive、 Markdown、Shell等等。

环境

采用docker环境部署zeppelin

OS:CentOS 7.3.1611
JAVA:OpenJDK 1.8
zeppelin: 0.7.2

dockerfile:

1
2
3
4
5
6
7
8
FROM centos:7.3.1611

MAINTAINER zhoub

RUN yum update -y
RUN yum install -y java-1.8.0-openjdk.x86_64
RUN echo "JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.141-1.b16.el7_3.x86_64/jre" | tee -a /etc/bashrc
RUN echo "export JAVA_HOME" | tee -a /etc/bashrc

下载安装

zeppelin官网或github上下载,推荐下载最新版。解压tar包,然后在准备好的环境中运行zeppelin/bin/zeppelin-daemon.sh start

docker:

1
2
3
4
5
6
7
#!/bin/sh

cmd="/root/run/entry.sh"
image="centos7.3:java1.8"
net="hadoop_net"

docker run -d --rm -w /root/ -v ${PWD}/run:/root/run -v ${PWD}/zeppelin:/root/zeppelin -v ${PWD}/hbase:/root/hbase -p 8080 --network ${net} -h zeppelin --name zeppelin ${image} ${cmd}

entry.sh:

1
2
3
4
5
6
7
8
#!/bin/sh

/root/zeppelin/bin/zeppelin-daemon.sh start

while true
do
sleep 10s
done

架构

zeppelin_arch
Zeppelin具有客户端/服务器架构,客户端一般就是指浏览器。服务器接收客户端的请求,并将请求通过Thrift协议发送给翻译器组。翻译器组物理表现为JVM进程,负责实际处理客户端的请求并与服务器进行通信。

zeppelin_interpreter_arch
翻译器是一个插件式的体系结构,允许任何语言/后端数据处理程序以插件的形式添加到Zeppelin中。当前的Zeppelin已经支持很多翻译器。插件式架构允许用户在Zeppelin中使用自己熟悉的特定程序语言或数据处理方式。例如,通过使用%spark翻译器,可以在Zeppelin中使用Scala语言代码。

配置

zeppelin的配置主要指interpreter的设置,然后note通过配置好的interpreter进行解释执行。

JDBC-hive配置

zeppelin想要通过jdbc连接hive需要对hive、hdfs、zeppelin三者进行配置

hive

需要在hive节点上启动hiveserver2服务nohup /shared-disk/apache-hive-2.1.1-bin/bin/hive --service hiveserver2&

zeepelin

拷贝连接hive-jdbc需要用到的jar包

将包hive-jdbc-1.1.0+cdh5.9.1+795-1.cdh5.9.1.p0.4.el7.noarch.rpm解开后的jar文件拷贝到zeppelin/lib/interpreter/目录下
hive-jdbc-1.1.0+cdh5.9.1+795-1.cdh5.9.1.p0.4.el7.noarch.rpm包内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
total 51448
-rw-r--r-- 1 root root 62050 Aug 25 10:18 commons-logging-1.1.3.jar
-rw-r--r-- 1 root root 19386631 Aug 25 10:18 hive-exec-1.1.0-cdh5.9.1.jar
lrwxrwxrwx 1 root root 28 Aug 25 10:18 hive-exec.jar -> hive-exec-1.1.0-cdh5.9.1.jar
-rw-r--r-- 1 root root 96598 Aug 25 10:19 hive-jdbc-1.1.0-cdh5.9.1.jar
-rw-r--r-- 1 root root 23635048 Aug 25 10:19 hive-jdbc-1.1.0-cdh5.9.1-standalone.jar
lrwxrwxrwx 1 root root 28 Aug 25 10:19 hive-jdbc.jar -> hive-jdbc-1.1.0-cdh5.9.1.jar
lrwxrwxrwx 1 root root 39 Aug 25 10:19 hive-jdbc-standalone.jar -> hive-jdbc-1.1.0-cdh5.9.1-standalone.jar
-rw-r--r-- 1 root root 5558969 Aug 25 10:19 hive-metastore-1.1.0-cdh5.9.1.jar
lrwxrwxrwx 1 root root 33 Aug 25 10:19 hive-metastore.jar -> hive-metastore-1.1.0-cdh5.9.1.jar
-rw-r--r-- 1 root root 827980 Aug 25 10:19 hive-serde-1.1.0-cdh5.9.1.jar
lrwxrwxrwx 1 root root 29 Aug 25 10:19 hive-serde.jar -> hive-serde-1.1.0-cdh5.9.1.jar
-rw-r--r-- 1 root root 2058121 Aug 25 10:19 hive-service-1.1.0-cdh5.9.1.jar
lrwxrwxrwx 1 root root 31 Aug 25 10:19 hive-service.jar -> hive-service-1.1.0-cdh5.9.1.jar
-rw-r--r-- 1 root root 313702 Aug 25 10:19 libfb303-0.9.3.jar
-rw-r--r-- 1 root root 234201 Aug 25 10:19 libthrift-0.9.3.jar
-rw-r--r-- 1 root root 481535 Aug 25 10:19 log4j-1.2.16.jar

配置jdbc interpreter

  • default.driver: org.apache.hive.jdbc.HiveDriver
  • default.url: jdbc:hive2://172.26.1.177:10000/default
    hiveserver2的默认端口为10000
  • default.user: root
    此处我使用root用户,后文中的hdfs的proxy设置也要用root

zeppelin_hive_jdbc_setting

hdfs

若zeppelin使用jdbc连接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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
Could not establish connection to jdbc:hive2://192.168.0.51:10000: Required field 'serverProtocolVersion' is unset! Struct:TOpenSessionResp(status:TStatus(statusCode:ERROR_STATUS, infoMessages:[*org.apache.hive.service.cli.HiveSQLException:Failed to open new session: java.lang.RuntimeException:
java.lang.RuntimeException:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate hive:13:12,
org.apache.hive.service.cli.session.SessionManager:openSession:SessionManager.java:266,
org.apache.hive.service.cli.CLIService:openSessionWithImpersonation:CLIService.java:202,
org.apache.hive.service.cli.thrift.ThriftCLIService:getSessionHandle:ThriftCLIService.java:402,
org.apache.hive.service.cli.thrift.ThriftCLIService:OpenSession:ThriftCLIService.java:297,
org.apache.hive.service.cli.thrift.TCLIService$Processor$OpenSession:getResult:TCLIService.java:1253,
org.apache.hive.service.cli.thrift.TCLIService$Processor$OpenSession:getResult:TCLIService.java:1238,
org.apache.thrift.ProcessFunction:process:ProcessFunction.java:39,
org.apache.thrift.TBaseProcessor:process:TBaseProcessor.java:39,
org.apache.hive.service.auth.TSetIpAddressProcessor:process:TSetIpAddressProcessor.java:56,
org.apache.thrift.server.TThreadPoolServer$WorkerProcess:run:TThreadPoolServer.java:285,
java.util.concurrent.ThreadPoolExecutor:runWorker:ThreadPoolExecutor.java:1145,
java.util.concurrent.ThreadPoolExecutor$Worker:run:ThreadPoolExecutor.java:615,
java.lang.Thread:run:Thread.java:745,
*java.lang.RuntimeException:java.lang.RuntimeException:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate hive:21:8,
org.apache.hive.service.cli.session.HiveSessionProxy:invoke:HiveSessionProxy.java:83,
org.apache.hive.service.cli.session.HiveSessionProxy:access$000:HiveSessionProxy.java:36,
org.apache.hive.service.cli.session.HiveSessionProxy$1:run:HiveSessionProxy.java:63,
java.security.AccessController:doPrivileged:AccessController.java:-2,
javax.security.auth.Subject:doAs:Subject.java:415,
org.apache.hadoop.security.UserGroupInformation:doAs:UserGroupInformation.java:1657,
org.apache.hive.service.cli.session.HiveSessionProxy:invoke:HiveSessionProxy.java:59,
com.sun.proxy.$Proxy19:open::-1,
org.apache.hive.service.cli.session.SessionManager:openSession:SessionManager.java:258,
*java.lang.RuntimeException:
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate hive:26:5,
org.apache.hadoop.hive.ql.session.SessionState:start:SessionState.java:494,
org.apache.hive.service.cli.session.HiveSessionImpl:open:HiveSessionImpl.java:137,
sun.reflect.GeneratedMethodAccessor11:invoke::-1,
sun.reflect.DelegatingMethodAccessorImpl:invoke:DelegatingMethodAccessorImpl.java:43,
java.lang.reflect.Method:invoke:Method.java:606,
org.apache.hive.service.cli.session.HiveSessionProxy:invoke:HiveSessionProxy.java:78,
*org.apache.hadoop.ipc.RemoteException:User: hive is not allowed to impersonate hive:45:19,
org.apache.hadoop.ipc.Client:call:Client.java:1427,
org.apache.hadoop.ipc.Client:call:Client.java:1358,
org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker:invoke:ProtobufRpcEngine.java:229,
com.sun.proxy.$Proxy14:getFileInfo::-1,
org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB:getFileInfo:ClientNamenodeProtocolTranslatorPB.java:771,
sun.reflect.GeneratedMethodAccessor7:invoke::-1,
sun.reflect.DelegatingMethodAccessorImpl:invoke:DelegatingMethodAccessorImpl.java:43,
java.lang.reflect.Method:invoke:Method.java:606,
org.apache.hadoop.io.retry.RetryInvocationHandler:invokeMethod:RetryInvocationHandler.java:252,
org.apache.hadoop.io.retry.RetryInvocationHandler:invoke:RetryInvocationHandler.java:104,
com.sun.proxy.$Proxy15:getFileInfo::-1,
org.apache.hadoop.hdfs.DFSClient:getFileInfo:DFSClient.java:2116,
org.apache.hadoop.hdfs.DistributedFileSystem$22:doCall:DistributedFileSystem.java:1315,
org.apache.hadoop.hdfs.DistributedFileSystem$22:doCall:DistributedFileSystem.java:1311,
org.apache.hadoop.fs.FileSystemLinkResolver:resolve:FileSystemLinkResolver.java:81,
org.apache.hadoop.hdfs.DistributedFileSystem:getFileStatus:DistributedFileSystem.java:1311,
org.apache.hadoop.fs.FileSystem:exists:FileSystem.java:1424,
org.apache.hadoop.hive.ql.session.SessionState:createRootHDFSDir:SessionState.java:568,
org.apache.hadoop.hive.ql.session.SessionState:createSessionDirs:SessionState.java:526,
org.apache.hadoop.hive.ql.session.SessionState:start:SessionState.java:480],
errorCode:0, errorMessage:Failed to open new session: java.lang.RuntimeException: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate hive), serverProtocolVersion:null)

需要在hdfs core-site.xml中增加配置

1
2
3
4
5
6
7
8
9
10
11
...
<property>
<name>hadoop.proxyuser.hive.groups</name>
<value>*</value>
</property>

<property>
<name>hadoop.proxyuser.hive.hosts</name>
<value>*</value>
</property>
...

然后重启hdfs namenode

使用

zeppelin_main_ui

参考&鸣谢

ubuntu

Xenial Xerus (好客的非洲地松鼠)

Ubuntu 16.04 的发布代号,简称XX。Canonical和Ubuntu的创始人马克·沙特尔沃思(Mark Shuttleworth) 在他的个人博文中写道:“这是如此的巧合幸运,我们的下个LTS应该为X,因为‘xenial’代表着主人和客人之间融洽的友好关系,而且对于推进Ubuntu OpenStack的LXD和KVM工作起到了非常积极的作用。Xerus则是非洲地松鼠,是我的祖国最为常见的动物。他们在沙漠环境中繁殖,并且以小型团体的方式生活,能够和邻居和谐生活的社会群体。”

glusterfs-antmascot

概述

GlusterFS (Gluster File System) 是一个开源的分布式文件系统,主要由 Z RESEARCH 公司负责开发。GlusterFS 是 Scale-Out 存储解决方案 Gluster 的核心,具有强大的横向扩展能力,通过扩展能够支持数PB存储容量和处理数千客户端。GlusterFS 借助 TCP/IP 或 InfiniBand RDMA 网络将物理分布的存储资源聚集在一起,使用单一全局命名空间来管理数据。GlusterFS 基于可堆叠的用户空间设计,可为各种不同的数据负载提供优异的性能。

glusterfs-frame

GlusterFS 总体架构与组成,它主要由存储服务器(Brick Server)、客户端以及 NFS/Samba 存储网关组成。不难发现,GlusterFS 架构中没有元数据服务器组件,这是其最大的设计这点,对于提升整个系统的性能、可靠性和稳定性都有着决定性的意义。

  • GlusterFS 支持 TCP/IP 和 InfiniBand RDMA 高速网络互联。
  • 客户端可通过原生 GlusterFS 协议访问数据,其他没有运行 GlusterFS 客户端的终端可通过 NFS/CIFS 标准协议通过存储网关访问数据(存储网关提供弹性卷管理和访问代理功能)。
  • 存储服务器主要提供基本的数据存储功能,客户端弥补了没有元数据服务器的问题,承担了更多的功能,包括数据卷管理、I/O 调度、文件定位、数据缓存等功能,利用 FUSE(File system in User Space)模块将 GlusterFS 挂载到本地文件系统之上,实现 POSIX 兼容的方式来访问系统数据。

卷类型

Distribute卷

分布式卷,基于 Hash 算法将文件分布到所有 brick server,只是扩大了磁盘空间,不具备容错能力。由于distribute volume 使用本地文件系统,因此存取效率并没有提高,相反会因为网络通信的原因使用效率有所降低,另外本地存储设备的容量有限制,因此支持超大型文件会有一定难度。

glusterfs-volume-distribute

Stripe卷

条带卷,类似 RAID0,文件分成数据块以 Round Robin 方式分布到 brick server 上,并发粒度是数据块,支持超大文件,大文件的读写性能高。

glusterfs-volume-stripe

Replica卷

复制卷,文件同步复制到多个 brick 上,文件级 RAID1,具有容错能力,写性能下降,读性能提升。Replicated 模式,也称作 AFR(Auto File Replication),相当于 RAID1,即同一文件在多个镜像存储节点上保存多份,每个 replicated 子节点有着相同的目录结构和文件,replica volume 也是在容器存储中较为推崇的一种。

glusterfs-volume-replica

Distribute Stripe卷

分布式条带卷,Brick server 数量是条带数的倍数,兼具 distribute 和 stripe 卷的特点。分布式的条带卷,volume 中 brick 所包含的存储服务器数必须是 stripe 的倍数(>=2倍),兼顾分布式和条带式的功能。每个文件分布在四台共享服务器上,通常用于大文件访问处理,最少需要 4 台服务器才能创建分布条带卷。

glusterfs-volume-distribute-stripe

Distribute Replica卷

分布式复制卷,Brick server 数量是镜像数的倍数,兼具 distribute 和 replica 卷的特点,可以在 2 个或多个节点之间复制数据。分布式的复制卷,volume 中 brick 所包含的存储服务器数必须是 replica 的倍数(>=2倍),兼顾分布式和复制式的功能。

glusterfs-volume-distribute-replica

Stripe Replica卷

条带复制卷,类似 RAID 10,同时具有条带卷和复制卷的特点。

glusterfs-volume-stripe-replica

Distribute Stripe Replica卷

分布式条带复制卷,三种基本卷的复合卷,通常用于类 Map Reduce 应用。

glusterfs-volume-distribute-stripe-replica

环境

使用docker部署GlusterFS,dockerfile如下:

1
2
3
4
5
6
7
8
9
FROM centos:7.3.1611

MAINTAINER zhoub

RUN yum update -y
RUN yum install -y centos-release-gluster310.noarch
RUN yum update -y

RUN yum clean all

创建GlusterFS镜像

1
2
# docker build -t glusterfs:3.10 -f ./dockerfile .
...

创建docker容器脚本mkgfs.sh,创建两个容器,用来组件gluster集群

1
2
3
4
5
6
7
8
9
#!/bin/sh

count=2
image=glusterfs:3.10

for((i=1;i<=$count;i++))
do
docker run -d -e "container=docker" --privileged=true -v /sys/fs/cgroup:/sys/fs/cgroup -h glf-client-$i --name glf_client_$i ${image} /usr/sbin/init
done

部署&使用

部署

安装glusterfs-server

1
2
# yum install -y glusterfs-server
...

准备数据目录

1
# mkdir -p /brks/brk1/gv0

(此处不进行数据盘挂载,直接使用系统硬盘)

启动glusterd服务

1
2
3
4
5
# systemctl enable glusterd
...
# systemctl start glusterd
# systemctl status glusterd
...

在容器glf-client-1上添加glf-client-2

1
gluster peer probe glf-client-2

(此处省去向/etc/hosts增加ip、域名的映射修改)

在容器glf-client-2上添加glf-client-1

1
gluster peer probe glf-client-1

(此处省去向/etc/hosts增加ip、域名的映射修改)

在任意一个容器上创建、启动volume

1
2
# gluster volume create gv0 replica 2 glf-client-1:/brks/brk1/gv0 glf-client-2:/brks/brk1/gv0 force
# gluster volume start gv0

(由于gv0使用的是系统盘,所以在volume创建时,需要指定force参数)
创建、启动完volume后可通过gluster volume infogluster volume status gv0查看状态。

使用

1
mount -t glusterfs glf-client-1:gv0 /mnt/

参考&鸣谢

背景

OpenStack(以下简称OPS)是一个很庞大的系统,想要部署一个OPS需要部署很多组件。想必部署之路也是坑坑奇多。所以为了方便使用OPS,需要部署一个“all-in-one”环境的OPS

环境

  • CPU
    2U X86_64
  • Memory
    4G及以上,如果内存过小,会出现各种问题。(整个devstack-Openstack-Ocata + CentOS7.3 1611需要占用3.4G内存)
  • OS
    CentOS 7.3 1611
  • NET
    建议创建两个网络,一个用于连接外网用于做管理性工作;一个供neutron使用
  • OpenStack版本
    Ocata

部署

准备

关闭防火墙

关闭selinux

编辑/etc/selinux/configSELINUX=enforcing改为SELINUX=disabled

关闭iptables

执行命令sudo systemctl disable iptables,关闭iptables服务

上诉两处修改若想生效需要重启系统。

安装依赖软件

1
sudo yum install -y epel-release git net-tools

下载Devstack

从github上下载devstackgit clone https://github.com/openstack-dev/devstack.git,然后切换版本到Ocata git checkout stable/ocata,可使用git branch -av查看devstack所处分支

安装

创建stack用户

  1. 进入devstack目录
    1
    cd devstack
  2. 创建stack用户
    1
    sudo ./tools/create-stack-user.sh

切换用户

  1. 修改目录owner
    1
    sudo chown -R stack:stack ./devstack
  2. 修改/opt/stack目录访问权限
    1
    2
    sudo chmod 777 /opt/stack -R
    sudo mv ./devstack /opt/stack/
  3. 切换用户
    1
    sudo su - stack

撰写local.conf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
[[local|localrc]]

DEST=/opt/stack/ocata
# use TryStack git mirror
GIT_BASE=http://git.trystack.cn
NOVNC_REPO=http://git.trystack.cn/kanaka/noVNC.git
SPICE_REPO=http://git.trystack.cn/git/spice/spice-html5.git

#OFFLINE=True
RECLONE=False

# Define images to be automatically downloaded during the DevStack built process.
DOWNLOAD_DEFAULT_IMAGES=False
IMAGE_URLS=",https://launchpad.net/cirros/trunk/0.3.0/+download/cirros-0.3.0-x86_64-disk.img"

HOST_IP=127.0.0.1


# Credentials
DATABASE_PASSWORD=pass
ADMIN_PASSWORD=pass
SERVICE_PASSWORD=pass
SERVICE_TOKEN=pass
RABBIT_PASSWORD=pass

HORIZON_BRANCH=stable/ocata
KEYSTONE_BRANCH=stable/ocata
NOVA_BRANCH=stable/ocata
NEUTRON_BRANCH=stable/ocata
GLANCE_BRANCH=stable/ocata
CINDER_BRANCH=stable/ocata


#keystone
KEYSTONE_TOKEN_FORMAT=UUID

##Heat
HEAT_BRANCH=stable/ocata
enable_service h-eng h-api h-api-cfn h-api-cw


## Swift
SWIFT_BRANCH=stable/ocata
ENABLED_SERVICES+=,s-proxy,s-object,s-container,s-account
SWIFT_REPLICAS=1
SWIFT_HASH=011688b44136573e209e


# Enabling Neutron (network) Service
disable_service n-net
enable_service q-svc
enable_service q-agt
enable_service q-dhcp
enable_service q-l3
enable_service q-meta
enable_service q-metering
enable_service neutron

## Neutron options
Q_USE_SECGROUP=True
FLOATING_RANGE="192.168.36.0/24"
FIXED_RANGE="10.0.0.0/24"
Q_FLOATING_ALLOCATION_POOL=start=192.168.36.55,end=192.168.36.100
PUBLIC_NETWORK_GATEWAY="192.168.36.1"
Q_L3_ENABLED=True
PUBLIC_INTERFACE=eth1
Q_USE_PROVIDERNET_FOR_PUBLIC=True
OVS_PHYSICAL_BRIDGE=br-ex
PUBLIC_BRIDGE=br-ex
OVS_BRIDGE_MAPPINGS=public:br-ex

# #VLAN configuration.
Q_PLUGIN=ml2
ENABLE_TENANT_VLANS=True

# Logging
LOGFILE=/opt/stack/logs/stack.sh.log
VERBOSE=True
LOG_COLOR=True
SCREEN_LOGDIR=/opt/stack/logs

安装OPS(all-in-one)

安装使用stack.sh脚本,卸载使用unstack.sh脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ ./stack.sh
...

=========================
DevStack Component Timing
=========================
Total runtime 1254

run_process 83
test_with_retry 4
pip_install 127
restart_apache_server 29
wait_for_service 19
yum_install 50
=========================



This is your host IP address: 127.0.0.1
This is your host IPv6 address: ::1
Horizon is now available at http://127.0.0.1/dashboard
Keystone is serving at http://127.0.0.1/identity/
The default users are: admin and demo
The password: pass

安装时遇到问题可从两个角度考虑,一个网络不通,一个内存不足。这里再次重申,内存一定要>=4G,如果网络不通或延时太大,建议使用国内镜像。

例如/opt/stack/.pip/pip.conf:

1
2
3
4
5
[global]

timeout = 6000
index-url = http://pypi.douban.com/simple
trusted-host = pypi.douban.com

horizon

安装成功后,访问http://x.x.x.x/dashboard, 用户民密码见local.conf

horizon_login

参考&鸣谢

cosbench-usage.png

COSBench是Intel团队基于java开发,对云存储的测试工具,全称是Cloud object Storage Bench。COSBench也分控制台和发起请求的driver,且driver可以分布式部署。可以支持swift、s3、Openstack等接口

获取

从github上下载release版本(https://github.com/intel-cloud/cosbench)。解压后可以获取COSBenchUserGuide.pdf(只有英文版)和workload配置文件(./conf/*.xml)。

部署&启动

COSBench的运行依赖于java和curl这两个包,并且调用linux的nc来做数据分析,如果没有安装nc,请手动安装。
本人将COSBench部署到docker中,为的是方便以后运行,不要将有限的生命耗费到无限的折腾当中。

docker镜像使用的是centos:7.3.1611,具体dockerfile如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM centos:7.3.1611

RUN yum update -y
RUN yum install -y java-1.8.0-openjdk

RUN yum clean all

EXPOSE 19088 18088

ADD ./cosbench.tar.gz /root/
ADD ./entry.sh /root/

ENTRYPOINT ["/root/entry.sh"]

entry.sh是容器的启动脚本,脚本中主要用于启动COSBench服务,具体实现如下:

1
2
3
4
5
6
7
#!/bin/sh

./start-all.sh

while true; do
sleep 10s
done

完成docker镜像的生成后,使用docker run -d -w /root/cosbench/ --rm -P s3test:performance命令运行容器。然后通过docker ps查看可访问的端口。

1
2
3
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ed37db78178a s3test:performance "/root/entry.sh" 19 hours ago Up 19 hours 0.0.0.0:32771->18088/tcp, 0.0.0.0:32770->19088/tcp unruffled_mahavira

在浏览器中输入http://x.x.x.x:32770/controller/index.html访问COSBench首页。COSBench是以”master-slave”模式运行的,19088端口对应的是master端口,18088对应的是driver端口,任务的运行是有master下发给driver,然后由driver执行的(driver可配置多个)。

关于workload配置文件的撰写请见COSBenchUserGuide.pdf,此处给出一个测试S3接口的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
<?xml version="1.0" encoding="UTF-8" ?>
<workload name="S3Test" description="Performance">
<storage type="s3" config="accesskey=Ltiakby8pAAbHMjpUr3L;secretkey=qMTe5ibLW49iFDEHNKqspdnJ8pwaawA9GYrBXUYc;endpoint=http://los-cn-north-2.lecloudapis.com" />
<workflow>

<workstage name="init">
<work type="init" workers="1" config="cprefix=testp;containers=r(1,4)" />
</workstage>

<workstage name="prepare">
<work type="prepare" workers="1" config="cprefix=testp;containers=r(1,2);objects=r(1,800);sizes=c(4)MB" />
</workstage>

<workstage name="sequential_RO_8W_4MB">
<work name="sequential_RO_8W_4MB" workers="8" totalOps="1600">
<operation type="read" ratio="100" config="cprefix=testp;containers=c(1);objects=s(1,800);size=c(4)MB" />
</work>
</workstage>

<workstage name="random_RO_8W_4MB">
<work name="random_RO_8W_4MB" workers="8" totalOps="1600">
<operation type="read" ratio="100" config="cprefix=testp;containers=c(2);objects=u(1,800);size=c(4)MB" />
</work>
</workstage>

<workstage name="sequential_WO_8W_4MB">
<work name="sequential_WO_8W_4MB" workers="8" totalOps="1600">
<operation type="write" ratio="100" config="cprefix=testp;containers=c(3);objects=s(1,800);sizes=c(4)MB" />
</work>
</workstage>

<workstage name="random_WO_8W_4MB">
<work name="random_WO_8W_4MB" workers="8" totalOps="1600">
<operation type="write" ratio="100" config="cprefix=testp;containers=c(4);objects=u(1,800);sizes=c(4)MB" />
</work>
</workstage>

<workstage name="cleanup">
<work type="cleanup" workers="1" config="cprefix=testp;containers=r(1,4);objects=r(1,800)" />
</workstage>

<workstage name="dispose">
<work type="dispose" workers="1" config="cprefix=testp;containers=r(1,4)" />
</workstage>

<workstage name="init">
<work type="init" workers="1" config="cprefix=testp;containers=r(1,4)" />
</workstage>

<workstage name="prepare">
<work type="prepare" workers="1" config="cprefix=testp;containers=r(1,2);objects=r(1,800);sizes=c(64)KB" />
</workstage>

<workstage name="sequential_RO_32W_64KB">
<work name="sequential_RO_32W_64KB" workers="32" totalOps="1600">
<operation type="read" ratio="100" config="cprefix=testp;containers=c(1);objects=s(1,800);size=c(64)KB" />
</work>
</workstage>

<workstage name="random_RO_32W_64KB">
<work name="random_RO_32W_64KB" workers="32" totalOps="1600">
<operation type="read" ratio="100" config="cprefix=testp;containers=c(2);objects=u(1,800);size=c(64)KB" />
</work>
</workstage>

<workstage name="sequential_WO_32w_64KB">
<work name="sequential_WO_32w_64KB" workers="32" totalOps="1600">
<operation type="write" ratio="100" config="cprefix=testp;containers=c(3);objects=s(1,800);sizes=c(64)KB" />
</work>
</workstage>

<workstage name="random_WO_32W_64KB">
<work name="random_WO_32W_64KB" workers="32" totalOps="1600">
<operation type="write" ratio="100" config="cprefix=testp;containers=c(4);objects=u(1,800);sizes=c(64)KB" />
</work>
</workstage>

<workstage name="cleanup">
<work type="cleanup" workers="1" config="cprefix=testp;containers=r(1,4);objects=r(1,800)" />
</workstage>

<workstage name="dispose">
<work type="dispose" workers="1" config="cprefix=testp;containers=r(1,4)" />
</workstage>

</workflow>
</workload>

问题及解决

  1. COSBench首页时间显示没有按东八区显示
    cosbench-start.sh中找到/usr/bin/nohup java这一行,增加-Duser.timezone=Asia/Shanghai参数
  2. COSBench在测试过程中MD5校验失败问题
    在测试过程中GET操作失败,而且错误日志如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    2017-07-11 07:26:42,297 [INFO] [Log4jLogManager] - will append log to file /root/cosbench/log/mission/MA308B012AE.log
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp2/myobjects38
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects43
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects43
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects31
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects7
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects26
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp1/myobjects34
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp2/myobjects25
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp2/myobjects45
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp1/myobjects7
    2017-07-11 07:26:42,574 [INFO] [NoneStorage] - performing GET at /testp2/myobjects43
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp2/myobjects16
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp2/myobjects23
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp1/myobjects15
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp1/myobjects36
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp2/myobjects34
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp1/myobjects34
    2017-07-11 07:26:42,576 [INFO] [NoneStorage] - performing GET at /testp2/myobjects27
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects49
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects27
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects24
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects35
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects2
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects47
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects39
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects50
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects8
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects21
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects24
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects15
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp1/myobjects4
    2017-07-11 07:26:42,575 [INFO] [NoneStorage] - performing GET at /testp2/myobjects1
    2017-07-11 07:26:45,476 [ERROR] [AbstractOperator] - worker 8 fail to perform operation testp1/myobjects7
    com.amazonaws.AmazonClientException: Unable to verify integrity of data download. Client calculated content hash didn't match hash calculated by Amazon S3. The data may be corrupt.
    at com.amazonaws.services.s3.internal.DigestValidationInputStream.validateMD5Digest(DigestValidationInputStream.java:79)
    at com.amazonaws.services.s3.internal.DigestValidationInputStream.read(DigestValidationInputStream.java:61)
    at com.amazonaws.internal.SdkFilterInputStream.read(SdkFilterInputStream.java:72)
    at com.amazonaws.services.s3.model.S3ObjectInputStream.read(S3ObjectInputStream.java:155)
    at com.amazonaws.services.s3.model.S3ObjectInputStream.read(S3ObjectInputStream.java:147)
    at com.intel.cosbench.driver.operator.Reader.copyLarge(Reader.java:120)
    at com.intel.cosbench.driver.operator.Reader.doRead(Reader.java:92)
    at com.intel.cosbench.driver.operator.Reader.operate(Reader.java:69)
    at com.intel.cosbench.driver.operator.AbstractOperator.operate(AbstractOperator.java:76)
    at com.intel.cosbench.driver.agent.WorkAgent.performOperation(WorkAgent.java:197)
    at com.intel.cosbench.driver.agent.WorkAgent.doWork(WorkAgent.java:177)
    at com.intel.cosbench.driver.agent.WorkAgent.execute(WorkAgent.java:134)
    at com.intel.cosbench.driver.agent.AbstractAgent.call(AbstractAgent.java:44)
    at com.intel.cosbench.driver.agent.AbstractAgent.call(AbstractAgent.java:1)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:748)
    2017-07-11 07:26:45,476 [INFO] [NoneStorage] - performing GET at /testp1/myobjects14
    2017-07-11 07:26:46,880 [INFO] [NoneStorage] - performing GET at /testp2/myobjects14
    2017-07-11 07:26:49,806 [INFO] [NoneStorage] - performing GET at /testp1/myobjects43
    2017-07-11 07:26:51,514 [INFO] [NoneStorage] - performing GET at /testp2/myobjects31
    2017-07-11 07:26:54,021 [INFO] [NoneStorage] - performing GET at /testp1/myobjects5
    你可以通过增加-Dcom.amazonaws.services.s3.disableGetObjectMD5Validation=true参数来关闭MD5校验,据说此bug只在0.4.3.c4版本出现,我没验证过其它版本。

参考&鸣谢

今天是2017年6月12日,在此之前Docker就已经更名为moby了,就moby的的编译与之前docker的编译无异,为什么呢,因为无论是docker还是moby,都将自己的编译放在了容器中,编译所依赖的包也在容器中完成安装,目前moby(以下都以此替代docker)能直接编译出rpm、deb两种安装包,具体支持哪些平台,哪些操作系统,请见./contrib/builder/

本文主要以编译centos7能用的rpm包为例,对moby的编译配置文件进行了修改,从而使moby快速完成编译。

编译原理

1
2
3
4
5
6
7
8
 Debian:jessie
+-------------+ golang 1.7.5-alpine
| | +------------------------+
| Moby | ----- docker run -----> | docker manpage compile |
| Compile | +------------------------+ centos:7
| Container | +--------------------+
| | -------------- docker run ----------------------------> | build centos rpm |
+-------------+ +--------------------+

Moby先创建一个Debian的容器,编译Moby,然后该容器根据用户输入的参数决定使用哪些容器编译哪些安装包,在编译目标安装包之前会使用golang容器编译manpage。总之moby的所有编译工作都是在容器中进行的。

编译方法

环境

  • 宿主机
    RHEL7.2
  • docker
    17.04.0-ce

RPM (Only CentOS)

  • 获取 moby 代码
    1
    2
    3
    4
    # clone moby
    git clone https://github.com/moby/moby.git
    # 切换到17.04.0-ce版本
    git checkout -b building_v17.04.0-ce v17.04.0-ce
  • 修改Dockerfile
    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
    diff --git a/Dockerfile b/Dockerfile
    index 8a361ce..3d6b0bb 100644
    --- a/Dockerfile
    +++ b/Dockerfile
    @@ -34,8 +34,12 @@ COPY keys/launchpad-ppa-zfs.asc /go/src/github.com/docker/docker/keys/
    RUN apt-key add /go/src/github.com/docker/docker/keys/launchpad-ppa-zfs.asc
    RUN echo deb http://ppa.launchpad.net/zfs-native/stable/ubuntu trusty main > /etc/apt/sources.list.d/zfs.list

    +RUN apt-get clean
    +RUN apt-get update -o Acquire::http::No-Cache=True
    +
    # Packaged dependencies
    -RUN apt-get update && apt-get install -y \
    +# RUN apt-get update && apt-get install -y \
    +RUN apt-get install -y \
    apparmor \
    apt-utils \
    aufs-tools \
    @@ -112,10 +116,12 @@ ENV PATH /osxcross/target/bin:$PATH
    ENV SECCOMP_VERSION 2.3.2
    RUN set -x \
    && export SECCOMP_PATH="$(mktemp -d)" \
    - && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
    + # && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
    + && curl -fsSL "https://github.com/seccomp/libseccomp/archive/v${SECCOMP_VERSION}.tar.gz" \
    | tar -xzC "$SECCOMP_PATH" --strip-components=1 \
    && ( \
    cd "$SECCOMP_PATH" \
    + && ./autogen.sh \
    && ./configure --prefix=/usr/local \
    && make \
    && make install \
  • 去掉DM(DeviceMapper)支持
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    diff --git a/hack/make/.integration-daemon-start b/hack/make/.integration-daemon-start
    index 0bc8b96..bea0d70 100644
    --- a/hack/make/.integration-daemon-start
    +++ b/hack/make/.integration-daemon-start
    @@ -71,7 +71,7 @@ if [ -z "$DOCKER_TEST_HOST" ]; then
    ( set -x; exec \
    dockerd --debug \
    --host "$DOCKER_HOST" \
    - --storage-driver "$DOCKER_GRAPHDRIVER" \
    + # --storage-driver "$DOCKER_GRAPHDRIVER" \
    --pidfile "$DEST/docker.pid" \
    --userland-proxy="$DOCKER_USERLANDPROXY" \
    $storage_params \
  • 由于GFW的原因,去掉manpage中关于golang.org/x/sys的安装
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    diff --git a/man/glide.lock b/man/glide.lock
    index 5ec765a..2ecad45 100644
    --- a/man/glide.lock
    +++ b/man/glide.lock
    @@ -38,10 +38,6 @@ imports:
    version: dabebe21bf790f782ea4c7bbd2efc430de182afd
    - name: github.com/spf13/viper
    version: c1ccc378a054ea8d4e38d8c67f6938d4760b53dd
    -- name: golang.org/x/sys
    - version: 62bee037599929a6e9146f29d10dd5208c43507d
    - subpackages:
    - - unix
    - name: gopkg.in/yaml.v2
    version: a83829b6f1293c91addabc89d0571c246397bbf4
    - name: github.com/spf13/cobra
  • 删除amd64平台下的与centos7无关的目录
    1
    2
    3
    4
    5
    6
    7
    rm -rvf contrib/builder/rpm/amd64/amazonlinux-latest/
    rm -rvf contrib/builder/rpm/amd64/fedora-24/
    rm -rvf contrib/builder/rpm/amd64/fedora-25/
    rm -rvf contrib/builder/rpm/amd64/opensuse-13.2/
    rm -rvf contrib/builder/rpm/amd64/oraclelinux-6/
    rm -rvf contrib/builder/rpm/amd64/oraclelinux-7/
    rm -rvf contrib/builder/rpm/amd64/photon-1.0/
  • 修改contrib/builder/rpm/amd64/centos-7/Dockerfile
    由于docker 17.04.0-ce这个版本是由golang1.7.5这个版本所编译的,所以在centos容器中需要安装golang1.7.5,而golangtc.com上没有1.7.5这个版本,所以只能通过vpn去golang.org上获取
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    diff --git a/contrib/builder/rpm/amd64/centos-7/Dockerfile b/contrib/builder/rpm/amd64/centos-7/Dockerfile
    index 5986dfd..b1f024d 100644
    --- a/contrib/builder/rpm/amd64/centos-7/Dockerfile
    +++ b/contrib/builder/rpm/amd64/centos-7/Dockerfile
    @@ -9,7 +9,9 @@ RUN yum -y swap -- remove systemd-container systemd-container-libs -- install sy
    RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel systemd-devel tar git cmake vim-common

    ENV GO_VERSION 1.7.5
    +ENV https_proxy 192.168.1.230:1080
    RUN curl -fSL "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
    +# RUN curl -fSL "https://www.golangtc.com/static/go/${GO_VERSION}/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
    ENV PATH $PATH:/usr/local/go/bin

    ENV AUTO_GOPATH 1
  • 使用Makefile编译Moby
    完成了上述Dockerfile的修改以后,可以使用make进行编译,由于我们需要编译的是rpm安装包,所以可直接使用make rpm进行。更多编译操作,可通过make help查看。

*** 目前,Moby的编译主要问题处在GFW对网络封锁上,如遇到其它问题,请第一时间确认该网络是否能访问,尤其是中国大陆地区。 ***

参考&鸣谢

nfs-ganesha.jpg

Ceph是统一存储,包括块、文件、对象。其中块存储必须映射给linux内核,然后才能用,而内核客户端代码的更新收到了linus的限制,已经好久没更新了。librbd又不能直接用,不过道是可以用nbd映射一下使用。cephfs目前还不太适合生产环境。目前*nix对nfs的支持还是很全面的,而对librbd、cephfs的支持就是大不一样了。so,使ceph支持nfs协议很有意义了,but!ceph是分布式存储,被ganesha一搞,出现了单节点问题,所以只能想办法从HA角度解决了,这也是一种无奈,唉。。。

(~~一丝光~~)从nfs v4.1开始支持并行存储,这或许是一缕新曙光。

NFS-Ganesha架构

ceph-nfs-service-by-rgw-with-nfs-ganesha.png

实施

RGW搭建

关于RGW的安装搭建请于Ceph官网查看

用户创建

创建一个S3用户专门服务于nfs-ganesha

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
$ sudo radosgw-admin --uid=nfs_ganesha_user --display="User for NFS-Ganesha"
{
"user_id": "nfs_ganesha_user",
"display_name": "User for NFS-Ganesha",
"email": "",
"suspended": 0,
"max_buckets": 1000,
"auid": 0,
"subusers": [],
"keys": [
{
"user": "nfs_ganesha_user",
"access_key": "xxxxxxxxxxxxxxxxxxxx",
"secret_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
],
"swift_keys": [],
"caps": [],
"op_mask": "read, write, delete",
"default_placement": "",
"placement_tags": [],
"bucket_quota": {
"enabled": false,
"max_size_kb": -1,
"max_objects": -1
},
"user_quota": {
"enabled": false,
"max_size_kb": -1,
"max_objects": -1
},
"temp_url_keys": []
}

useraccess_keysecret_key是后续nfs-ganesha配置是需要使用到的。

nfs-ganesha编译部署

获取Project

1
2
3
4
5
6
7
8
9
// clone nfs-ganesha project
$ git clone https://github.com/nfs-ganesha/nfs-ganesha.git
$ cd ./nfs-ganesha

// 切换到v2.4 stable版本
$ git checkout V2.4-stable

// 获取submodule libntirpc
$ git submodule update --init

在正式开始编译前,需要安装一些包,libntirpc强制使用了GSS,使用-DUSE_GSS=OFF是不能关闭GSS使用的。所以在编译nfs-ganesha时不需要关闭GSS。
本人编译使用的系统是rhel7.2,需要安装一些软件包krb5-libs-1.14.1-27.el7_3.x86_64krb5-devel-1.14.1-27.el7_3.x86_64libgssglue-0.4-2.el7.nux.x86_64libgssglue-devel-0.4-2.el7.nux.x86_64

编译安装

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
// libntirpc 编译 
$ cd ./nfs-ganesha/src/libntirpc
$ cmake ./
...
$ make
...

// nfs-ganesha 编译
$ cd ./nfs-ganesha
$ mkdir ./build
$ cd ./build
$ cmake -DUSE_NLM=OFF -DRGW_PREFIX=/usr -DUSE_FSAL_RGW=ON -DUSE_FSAL_CEPH=OFF -DCMAKE_INSTALL_PREFIX=/home/xxxxx/.local -DUSE_GSS=ON -DUSE_FSAL_ZFS=OFF -DUSE_NFSIDMAP=OFF -DUSE_FSAL_GLUSTER=OFF ../src
...
$ make
...
$ make install
...

// 为了能让ganesha正常运行,需要更新一下ld.cache,保证动态库可以正常加载
$ sudo echo "/home/xxxxx/.local/lib64/ganesha" >> /etc/ld.so.conf
$ sudo ldconfig -v

//生成RPM包
$ cpack -G RPM
...

配置启动

配置RGW的Keyring

librgw 访问ceph时会用到keyring,它回去/var/lib/ceph/radosgw/ceph-admin这个目录下去找keyring,这个目录需要用户自己创建并,copy一个keyring进去,这个keyring可以是admin,也可以是rgw实用的keyring,从权限管理角度建议使用rgw的keyring

撰写ganesha.conf.rgw

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
###################################################
#
# EXPORT
#
# To function, all that is required is an EXPORT
#
# Define the absolute minimal export
#
###################################################

EXPORT
{
# Export Id (mandatory, each EXPORT must have a unique Export_Id)
Export_Id = 1;

# Exported path (mandatory)
Path = "nfs_bucket";

# Pseudo Path (required for NFS v4)
Pseudo = "/nfs_bucket";

# Required for access (default is None)
# Could use CLIENT blocks instead
Access_Type = RW;
Protocols = 4;
Transports = TCP;

# Exporting FSAL
FSAL {
# Name = VFS;
Name = RGW;
User_Id = "xxxxxxxxxxx";
Access_Key_Id = "xxxxxxxxxxxxxxxxxxxx";
Secret_Access_Key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
}
}

RGW {
ceph_conf = "/etc/ceph/ceph.conf";
name = "client.admin";
cluster = "ceph";
}

运行ganesha进程

1
sudo ganesha.nfsd -f /home/xxxxx/.local/etc/ganesha/ganesha.conf.rgw -F -L /var/log/ganesha.log

客户端连接

1
sudo mount -t nfs4 192.168.1.82:/nfs_bucket /mnt

docker容器部署

镜像

ananace/nfs-ganesha-ceph

gannesha配置

配置上来讲与编译部署没有太大差别

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
# NFS protocol options
EXPORT
{
# Export Id (mandatory, each EXPORT must have a unique Export_Id)
Export_Id = 77;

# Exported path (mandatory)
Path = /;

# Pseudo Path (for NFS v4)
Pseudo = /;

# Access control options
Access_Type = RW;
Squash = No_Root_Squash;

# NFS protocol options
SecType = "sys";
Transports = TCP;
Protocols = 4;

# Exporting FSAL
FSAL {
Name = RGW;
User_Id = "admin";
Access_Key_Id = "8I4K2USDV5SK3UFLQUB0";
Secret_Access_Key = "A4JuvB468tmnDpmkZMfwesb2zmGZeSiCJlzJMALc";
}
}

RGW {
cluster = "ceph";
ceph_conf = "/etc/ceph/ceph.conf";
name = "client.rgw.host-10-100-13-111";
}

运行ganesha容器

由于Ganesha 的 FSAL 使用到了librgw,所以在镜像中会装好ceph-commonlibrgw2等。

1
docker run -d --net=host  -v /home/xxx/ceph/etc_ceph/:/etc/ceph:ro -v /home/xxx/ceph/ganesha/:/etc/ganesha:ro -v /home/xxx/ceph/var_lib_ceph/:/var/lib/ceph --name nfs -e GANESHA_BOOTSTRAP_CONFIG=no ananace/nfs-ganesha-ceph

docker 启动是需要设置环境变量GANESHA_BOOTSTRAP_CONFIG=no,默认配置为yes;若为yes的化,nfs-ganesha在启动的时候会重置/etc/ganesha/ganesha.conf配置文件。

参考&鸣谢