Big Little Ant

不被嘲笑的梦想,是不值得去实现的

实验环境介绍

实验环境规划

主机名 ip address 操作系统 职责
linux-node1 192.168.56.11 centos7 tomcat
1
2
3
4
5
6
[root@linux ~]# uname -r
3.10.0-229.el7.x86_64
[root@linux ~]# uname -m
x86_64
[root@linux ~]# cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

tomcat安装过程

先安装java环境

1
2
3
4
5
6
7
8
9
10
11
12
13
cd /usr/local/src/
tar -zxf jdk-8u65-linux-x64.tar.gz ##从官网下载好java包,上传到这个目录中。
mv jdk1.8.0_65/ /data/app/
ln -s /data/app/jdk1.8.0_65/ /data/app/java
vim /etc/profile
###setup java by biglittleant at 2015-08-28
export JAVA_HOME=/data/app/java
export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar

source /etc/profile##生效一下java版本

安装tomcat

1
2
3
4
5
6
7
8
9
10
11
cd /usr/local/src/
tar -zxf apache-tomcat-8.0.32.tar.gz
mv apache-tomcat-8.0.32 /data/app/
ln -s /data/app/apache-tomcat-8.0.32/ /data/app/tomcat
useradd -d /data/app/tomcat -u 505 tomcat
passwd tomcat
chown -R tomcat.tomcat /data/app/apache-tomcat-8.0.32/
cd /data/app/tomcat/
chmod 744 -R bin/*.sh
su - tomcat
pwd

手动编写tomcat启停脚本

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
#!/bin/bash

TOMCAT_PATH=/data/app/tomcat

usage(){
echo "Usage: $0 [start|stop|status|restart]"
}

status_tomcat(){

ps aux | grep java | grep tomcat | grep -v 'grep'

}

start_tomcat(){
/data/app/tomcat/bin/startup.sh
}

stop_tomcat(){

TPID=$(ps aux | grep java | grep tomcat | grep -v 'grep' | awk '{print $2}')
kill -9 $TPID
sleep 5;

TSTAT=$(ps aux | grep java | grep tomcat | grep -v 'grep' | awk '{print $2}')
if [ -z $TSTAT ];then
echo "tomcat stop"
else
kill -9 $TSTAT
fi

cd $TOMCAT_PATH

rm temp/* -rf
rm work/* -rf

}

main(){
case $1 in

start)
start_tomcat;;
stop)
stop_tomcat;;
status)
status_tomcat;;
restart)
stop_tomcat && start_tomcat;;
*)
usage;
esac

}

main $1

配置server.xml

tomcat的server.xml 配置文件一共分为五大部分:

  • server块
  • service块
  • connector块
  • engine块
  • host块
    下图是我看到比较好的一张解释server.xml配置文件的图片
    tomcat-配置文件结构图

看懂配置文件以后我们来说明一下tomcat处理客户端请求的过程

  1. 客户端访问URL:http://www.biglittleant.cn:8080/java/index.jsp 服务器端收到请求以后,开始解析URL。
  2. connector块创建8080端口,并接收客户端的请求地址,交给engine块。
  3. engine会根据域名(www.biglittleant.cn)读取相应的host块。
  4. host块接到请求后,分析URI(/java/index.jsp)匹配相应的context块。然后跳转到context段docBase的目录,并读取index.jsp,返回给engine。
  5. engine返回给connector。
  6. connector把结果返回给客户端。

server.xml 配置文件详细解释

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
<?xml version='1.0' encoding='utf-8'?>

<Server port="8888" shutdown="shutdowntomcat">
###开启8888管理端口,设定shutdowntomcat可以关闭tomcat服务器。
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JasperListener" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />


<GlobalNamingResources>

<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>

<Service name="Catalina">
##定义一个service

<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
##开启一个8080端口,来接收客户端请求,使用HTTP/1.1协议,超时时间为20000,redirectPort 是SSL的端口,也可以不配置。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
##同上。协议改变了。

<Engine name="Catalina" defaultHost="localhost">
#defaultHost 定义默认host主机,当所有host都匹配不了URL时,将转发给localhost虚拟主机。
<Realm className="org.apache.catalina.realm.LockOutRealm">

<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>

<Host name="localhost" appBase="webapps"
unpackWARs="false" autoDeploy="false">
##定义web应用程序的目录,关闭自动解压wAR包,关闭自动部署。生产上一定要关闭。否则会发生意想不到的问题。
<Context path="/java" docBase="/data/app/tomcat/webapps/java" debug="0" reloadable="false" crossContext="true"/>
##定义一个路径,当URI中包含/java时去,docbase路径下来查找相应的配置文件,reloadable=True时,会监控docbase路径下的文件是否发生改变,发生改变就自动重载配置,生产上这个也要禁止掉。

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t %r %s %b %{Referer}i %{User-Agent}i %D" resolveHosts="false" />
##定义本host的accesslog的文件名(localhost_access_log),后缀名(.txt)pattern 定义如何记录accesslog。

</Host>
</Engine>
</Service>
</Server>

配置web.xml

1
2
3
4
5
<init-param>
<param-name>listings</param-name>
<param-value>false</param-value>
</init-param>
#关闭服务器的list目录的文件内容。

删除tomcat的默认文件

1
2
3
4
rm -f tomcat/webapps/*
rm -f tomcat/conf/tomcat-user.xml
去除其他用户对tomcat 起停脚本的执行权限
chmod 744 /bin/*.sh

调优JAVA,开启JVM监控

1
2
3
4
5
6
7
8
9
10
vim tomcat/bin/catalina.sh
JAVA_OPTS="-XX:PermSize=64M -XX:MaxPermSize=128m -Xms512m -Xmx512m -Duser.timezone=Asia/Shanghai"
## 配置服务器的jvm参数调优
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=10053"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"
export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"
export CATALINA_OPTS="$CATALINA_OPTS -Djava.rmi.server.hostname=192.168.56.11"
##开启服务器的远程JVM端口
236 # ----- Execute The Requested Command -----------------------------------------

剩下的问题就是开启zabbix监控tomcat的JVM。

补充如何查看tomcat的jmx选项

JMX 有很多 Key 可以监控,具体的值,可以通过 jconsole 参看。如下图所示,如果要监控线程数,就可以写成 jmx[“java.lang:type=Threading”, “ThreadCount”]

Tomcat 日志配置

pattern属性值由字符串常量和pattern标识符加上前缀”%”组合而成。pattern标识符加上前缀”%”,用来代替当前请求/响应中的对应的变量值。目前支持如下的pattern:

  • %a - 远端IP地址
  • %A - 本地IP地址
  • %b - 发送的字节数,不包括HTTP头,如果为0,使用”-”
  • %B - 发送的字节数,不包括HTTP头
  • %h - 远端主机名(如果resolveHost=false,远端的IP地址)
  • %H - 请求协议
  • %l - 从identd返回的远端逻辑用户名(总是返回 ‘-‘)
  • %m - 请求的方法(GET,POST,等)
  • %p - 收到请求的本地端口号
  • %q - 查询字符串(如果存在,以 ‘?’开始)
  • %r - 请求的第一行,包含了请求的方法和URI
  • %s - 响应的状态码
  • %S - 用户的session ID
  • %t - 日志和时间,使用通常的Log格式
  • %u - 认证以后的远端用户(如果存在的话,否则为’-‘)
  • %U - 请求的URI路径
  • %v - 本地服务器的名称
  • %D - 处理请求的时间,以毫秒为单位
  • %T - 处理请求的时间,以秒为单位
    另外,Access Log中也支持cookie,请求header,响应headers,Session或者其他在ServletRequest中的对象的信息。格式遵循apache语法:
1
2
3
4
5
%{xxx}i 请求headers的信息
%{xxx}o 响应headers的信息
%{xxx}c 请求cookie的信息
%{xxx}r xxx是ServletRequest的一个属性
%{xxx}s xxx是HttpSession的一个属性

common模式的pattern(即默认pattern参数)的格式为’%h %l %u %t “%r” %s %b’。

combined模式的pattern可以增加Referer和User-Agent headers的参数形式,每个参数用双引号包起来,引号中的内容还是上面列举的参数。比如”%{User-Agent}i”使其为”%{User-Agent}i“,即请求的User-Agent(客户端,浏览器)。

关于Common Log Format参考:http://baike.baidu.com/view/2948003.htm

配置普通日志格式

1
2
3
4
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs" prefix="localhost_access_log." suffix=".txt"
pattern="%h %l %u %t %r %s %b %{Referer}i %{User-Agent}i %D"
resolveHosts="false" />

日志访问实例

1
2
192.168.0.113 - - [11/Jul/2016:16:25:53 +0800] PUT /fontgenerate/ HTTP/1.1 200 37 - Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like G
ecko) Chrome/45.0.2454.101 Safari/537.36 1

将日志格式输出为json格式

1
2
3
4
5
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="localhost_access_log." suffix=".json"
pattern="{&quot;client&quot;:&quot;%h&quot;, &quot;client user&quot;:&quot;%l&quot;, &quot;authenticated&quot;:&quot;%u&quot;, &quot;access time&quot;:&quot;%t&quot;, &quot;method&quot;:&quot;%r&quot;, &quot;status&quot;:&quot;%s&quot;, &quot;send bytes&quot;:&quot;%b&quot; , &quot;partner&quot;:&quot;%{Referer}i&quot;, &quot;Agent version&quot;:&quot;%{User-Agent}i&quot;, &quot;request_duration&quot;:&quot;%D&quot;}"
resolveHosts="false" />

访问日志结果:

1
2
3
4
5
6
7
8
9
10
11
12
{
"client": "192.168.0.13",
"client user": "-",
"authenticated": "-",
"access time": "[14/Sep/2016:11:03:33 +0800]",
"method": "GET /fontgenerate/?text=hello%E5%88%9D%E9%A1%B5&fontName=HYHLZTJ.ttf&type=Woff HTTP/1.1",
"status": "200",
"send bytes": "11572",
"partner": "http://192.168.0.226:8080/",
"Agent version": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.101 Safari/537.36",
"request_duration": "42"
}

sort

sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。
英文翻译:sort lines of text files .

格式:

1
2
Usage: sort [OPTION]... [FILE]...
or: sort [OPTION]... --files0-from=F

参数:

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
Ordering options:

-b, --ignore-leading-blanks 忽略每行前面开始出的空格字符。
-d, --dictionary-order 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
-f, --ignore-case 排序时,将小写字母视为大写字母。
-g, --general-numeric-sort 按照常规数值排序
-i, --ignore-nonprinting 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
-M, --month-sort 将前面3个字母依照月份的缩写进行排序。
-h, --human-numeric-sort 使用人类可读的数字(例如: 2K 1G)
-n, --numeric-sort 依照数值的大小排序。
-R, --random-sort 根据随机hash 排序
--random-source=FILE 从指定文件中获得随机字节
-r, --reverse 以相反的顺序来排序。
--sort=WORD 按照WORD 指定的格式排序:
一般数字-g,高可读性-h,月份-M,数字-n,
随机-R,版本-V
-V, --version-sort 按照常规数值排序

Other options:

--batch-size=NMERGE 一次最多合并NMERGE 个输入;如果输入更多则使用临时文件
-c, --check, --check=diagnose-first 检查输入是否已排序,若已有序则不进行操作
-C, --check=quiet, --check=silent 类似-c,但不报告第一个无序行
--compress-program=PROG 使用指定程序压缩临时文件;使用该程序
的-d 参数解压缩文件
--debug 为用于排序的行添加注释,并将有可能有问题的
用法输出到标准错误输出
--files0-from=F 从指定文件读取以NUL 终止的名称,如果该文件被
指定为"-"则从标准输入读文件名
-k, --key=KEYDEF 在位置1 开始一个key,在位置2 终止(默认为行尾)
-m, --merge 合并已排序的文件,不再进行排序
-o, --output=FILE 将排序后的结果存入指定的文件。
-s, --stable 禁用last-resort 比较以稳定比较算法
-S, --buffer-size=SIZE 禁用last-resort 比较以稳定比较算法
-t, --field-separator=SEP 使用SEP作为排序时所用的分隔符。
-T, --temporary-directory=DIR 使用指定目录而非$TMPDIR 或/tmp 作为
临时目录,可用多个选项指定多个目录
--parallel=N 将同时运行的排序数改变为N
-u, --unique 配合-c,严格校验排序;不配合-c,则只输出一次排序结果
-z, --zero-terminated 以0 字节而非新行作为行尾标志
--help 显示帮助
--version 显示版本信息

常用参数:

1
2
3
4
5
6
-n 按照数字排序。
-r 倒叙。
-t “.”表示按点号分隔域(awk -F ,cut -d 取段 -f)。
-u 相同的行,只输出一行。
-k 指定列进行排序。
-b会忽略每一行前面的所有空白部分,从第一个可见字符开始比较。

示例

按照数字正序排序

1
2
3
4
5
6
7
8
[root@MySQL /]# sort -n file1.txt
10.0.0.7 f
10.0.0.7 n
10.0.0.8 c
10.0.0.8 k
10.0.0.8 z
10.0.0.9 a
10.0.0.9 o

按照数字排序并倒叙

1
2
3
4
5
6
7
8
[root@MySQL /]# sort -nr file1.txt
10.0.0.9 o
10.0.0.9 a
10.0.0.8 z
10.0.0.8 k
10.0.0.8 c
10.0.0.7 n
10.0.0.7 f

按照第二列开始倒叙排序

-t 指定分隔符,-k2 表示按照第二列开始倒叙排序

1
2
3
4
5
6
7
8
[root@MySQL /]# sort -t" " -k2  -r file1.txt
10.0.0.8 z
10.0.0.9 o
10.0.0.7 n
10.0.0.8 k
10.0.0.7 f
10.0.0.8 c
10.0.0.9 a

-t 指定分隔符,-k2 表示按照第二列开始排序

1
2
3
4
5
6
7
8
[root@MySQL /]# sort -t" " -k2  file1.txt
10.0.0.9 a
10.0.0.8 c
10.0.0.7 f
10.0.0.8 k
10.0.0.7 n
10.0.0.9 o
10.0.0.8 z

先按照第一行排序,在按第三列排序并忽略空格 。

1
2
3
4
5
6
7
#sort -k 1 -n -k 3 emp.data
Beth 4.00 0
Dan 3.75 0
kathy 4.00 10
Susie 4.25 18
Mark 5.00 20
Mary 5.50 22

-n 参数讲解

测试文件内容

1
2
3
4
5
# cat info.txt
aa,201
zz,502
bb,1
ee,42

第一步 按照第二列倒叙排序

1
2
3
4
5
[root@linux-node2 111:33:23]#sort -t ',' -k2r info.txt
zz,502
ee,42
aa,201
bb,1

通过结果查看: 是按照第二列的首字母进行排序。

1
2
3
4
5
[root@linux-node2 111:33:30]#sort -t ',' -k2nr info.txt
zz,502
aa,201
ee,42
bb,1

加上 -n 后将第二列当成了一个整体进行排序。

结论:

  • 如果不加-n 默认按照列的第一个首字母排序,如果首字母相同排序第二列。
  • 如果加了-n,sort 会将值当成一个整数,而不是按照首字母排序。

uniq

uniq作用:只能对相邻的相同行去重。

格式

1
Usage: uniq [OPTION]... [INPUT [OUTPUT]]

参数

1
2
3
4
5
6
7
8
9
10
-c, --count:在行首显示该行重复出现的次数。
-d, --repeated:仅显示重复的列。
-D, --all-repeated[=METHOD] 仅显示重复行。
-f, --skip-fields=N 忽略比较指定的栏位
-i, --ignore-case 不区分大小写
-s, --skip-chars=N:忽略比较指定的字符
-u, --unique: 仅显示出一次的行列
-w, --check-chars=N:指定要比较的字符
--help:显示帮助文档并退出
--version:输出版本信息并退出

常用参数

1
-c, —count 打印每一重复行出现的次数。

示例

uniq 去重

第一步sort将相似的进行排序,uniq去掉重复行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@linux-node2 tmp16:03:32]#sort a.txt
10.10.0.1
10.10.0.1
10.10.0.2
10.10.0.3
10.10.0.3
10.10.0.4
10.10.0.4
10.10.0.5
10.10.0.8
[root@linux-node2 tmp16:03:51]#sort a.txt |uniq
10.10.0.1
10.10.0.2
10.10.0.3
10.10.0.4
10.10.0.5
10.10.0.8

uniq 统计出现的次数

uniq -c 去掉重复行,并统计出现次数

1
2
3
4
5
6
7
[root@linux-node2 tmp16:04:12]#sort a.txt |uniq -c
2 10.10.0.1
1 10.10.0.2
2 10.10.0.3
2 10.10.0.4
1 10.10.0.5
1 10.10.0.8

zookeeper工作原理

Zookeeper 的核心是广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播 模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后, 恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。为了保证事务的顺序一致性,zookeeper采用了递增的事务id号 (zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用 来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递 增计数。

每个Server在工作过程中有三种状态:

  • LOOKING:当前Server不知道leader是谁,正在搜寻。
  • LEADING:当前Server即为选举出来的leader。
  • FOLLOWING:leader已经选举出来,当前Server与之同步。

zookeeper快速安装

zookeeper配置文件解释

tickTime:CS通信心跳数
Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。

1
tickTime=2000

initLimit:LF初始通信时限
集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。

1
initLimit=5

syncLimit:LF同步通信时限
集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。

1
syncLimit=2

dataDir:数据文件目录
Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。

1
dataDir=/data/zk

dataLogDir:日志文件目录
Zookeeper保存日志文件的目录。

1
dataLogDir=/var/log/zookeeper/logs

clientPort:客户端连接端口
客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

1
clientPort=2181

服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
这个配置项的书写格式比较特殊,规则如下:

1
server.N=YYY:A:B

其中N表示服务器编号,YYY表示服务器的IP地址,A为LF通信端口,表示该服务器与集群中的leader交换的信息的端口。B为选举端口,表示选举新leader时服务器间相互通信的端口(当leader挂掉时,其余服务器会相互通信,选择出新的leader)。一般来说,集群中每个服务器的A端口都是一样,每个服务器的B端口也是一样。但是当所采用的为伪集群时,IP地址都一样,只能时A端口和B端口不一样。

正常集群的例子:

1
2
3
server.1=192.168.56.11:2181:2182
server.2=192.168.56.12:2181:2182
server.3=192.168.56.13:2181:2182

伪集群的例子:

1
2
3
server.1=192.168.56.11:2181:3181
server.2=192.168.56.11:2182:3182
server.3=192.168.56.11:2183:3183

单实例安装

安装zookeeper服务

1
2
3
4
5
6
7
cd /usr/local/src/
tar -zxf zookeeper-3.4.7.tar.gz
mv zookeeper-3.4.7 /usr/local/
ln -s /usr/loacl/zookeeper-3.4.7 /usr/loca/zookeeper
cd /usr/loca/zookeeper
cd conf/
cp zoo_sample.cfg zoo.cfg

编辑配置文件

1
2
3
4
vim zoo.cfg
tickTime=2000
dataDir=/data/zk
clientPort=2181

启动zookeeper服务

1
/usr/loca/zookeeper/bin/zkServer.sh start

检查服务是否正常启动

1
bin/zkCli.sh -server 127.0.0.1:2181

伪集群配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
cd /usr/local/src
wget http://mirrors.cnnic.cn/apache/zookeeper/stable/zookeeper-3.4.6.tar.gz
tar zxf zookeeper-3.4.6.tar.gz
mv zookeeper-3.4.6 /usr/local/
ln -s /usr/local/zookeeper-3.4.6/ /usr/local/zookeeper
cd /usr/local/zookeeper/conf/
mv zoo_sample.cfg zoo.cfg
vim zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/data/zk1
clientPort=2181
server.1=192.168.56.11:3181:4181
server.2=192.168.56.11:3182:4182
server.3=192.168.56.11:3183:4183

创建三个目录用来存放zookeeper数据

1
2
3
4
mkdir /data/{zk1,zk2,zk3} -p
echo "1" >/data/zk1/myid
echo "2" >/data/zk2/myid
echo "3" >/data/zk3/myid

生成三份zookeeper配置文件

1
2
3
cp zoo.cfg zk1.cfg
cp zoo.cfg zk2.cfg
cp zoo.cfg zk3.cfg

修改zk2和zk3的配置,使用对应的数据目录和端口。

1
2
3
4
sed -i 's/zk1/zk2/g' zk2.cfg
sed -i 's/2181/2182/g' zk2.cfg
sed -i 's/zk1/zk3/g' zk3.cfg
sed -i 's/2181/2183/g' zk3.cfg

启动Zookeeper

1
2
3
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk1.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk2.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk3.cfg

查看Zookeeper角色

1
2
3
4
5
6
7
8
9
10
11
12
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk1.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk1.cfg
#Mode: follower
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk2.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk2.cfg
#Mode: `leader`
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk3.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk3.cfg
#Mode: follower

连接Zookeeper

1
/usr/local/zookeeper/bin/zkCli.sh -server192.168.56.11:2181

通过上面的例子可以看到,目前zk2是leader,其它两个节点是follower。
本文由于实验环境局限使用的是伪分布式。
生产环境不建议使用。

集群模式

集群模式的配置和伪集群基本一致.
由于集群模式下, 各server部署在不同的机器上, 因此各server的conf/zoo.cfg文件可以完全一样.

下面是一个示例:

1
2
3
4
5
6
7
8
9
tickTime=2000 
initLimit=5 
syncLimit=2 
dataDir=/home/zookeeper/data 
dataLogDir=/home/zookeeper/logs 
clientPort=4180 
server.1=192.168.56.11:3181:4182
server.2=192.168.56.12:3181:4182
server.3=192.168.56.13:3181:4182

示例中部署了3台zookeeper server, 分别部署在192.168.56.11, 192.168.56.12, 1192.168.56.13上. 需要注意的是, 各server的dataDir目录下的myid文件中的数字必须不同,192.168.56.11 server的myid为1, 192.168.56.12 server的myid为2, 192.168.56.13server的myid为3。

zookeeper常用四字命令:

  • echo stat|nc 127.0.0.1 2181 来查看哪个节点被选择作为follower或者leader
  • echo ruok|nc 127.0.0.1 2181 测试是否启动了该Server,若回复imok表示已经启动
  • echo dump| nc 127.0.0.1 2181 ,列出未经处理的会话和临时节点。
  • echo kill | nc 127.0.0.1 2181 ,关掉server
  • echo conf | nc 127.0.0.1 2181 ,输出相关服务配置的详细信息。
  • echo cons | nc 127.0.0.1 2181 ,列出所有连接到服务器的客户端的完全的连接 / 会话的详细信息。
  • echo envi |nc 127.0.0.1 2181 ,输出关于服务环境的详细信息(区别于 conf 命令)。
  • echo reqs | nc 127.0.0.1 2181 ,列出未经处理的请求。
  • echo wchs | nc 127.0.0.1 2181 ,列出服务器 watch 的详细信息。
  • echo wchc | nc 127.0.0.1 2181 ,通过 session 列出服务器 watch 的详细信息,它的输出是一个与 watch 相关的会话的列表。
  • echo wchp | nc 127.0.0.1 2181 ,通过路径列出服务器 watch 的详细信息。它输出一个与 session 相关的路径。

zookeeper监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
`vim bin/zkServer.sh`

#修改前
#ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=$JMXLOCALONLY org.apache.zookeeper.server.quorum.QuorumPeerMa
in"

#修改后
ZOOMAIN="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false
-Djava.rmi.server.hostname=192.168.56.22
-Dcom.sun.management.jmxremote.port=9991
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false
-Dzookeeper.jmx.log4j.disable=true
org.apache.zookeeper.server.quorum.QuorumPeerMain"

更改完以后重启zookeeper服务器,使用JMX客户端连接服务器:

原理

日志轮询实际是基于logrotate命令对日志进行切割。
也可以通过修改配置文件,logrotate自动将要执行的命令,添加到crontab中。

1
2
3
4
5
6
7
8
9
10
11
12
13
logrotate --help
Usage: logrotate [OPTION...] <configfile>
-d, --debug Don't do anything, just test (implies -v)
-f, --force Force file rotation
-m, --mail=command Command to send mail (instead of `/bin/mail')
-s, --state=statefile Path of state file
-v, --verbose Display messages during rotation
--version Display version information

Help options:
-?, --help Show this help message
--usage Display brief usage message

中文翻译

1
2
3
4
5
6
7
8
9
10
11
12
13

Usage: logrotate [OPTION...] <configfile>
-d, --debug 测试文件是否正常,不执行。
-f, --force 强制转储文件。
-m, --mail=command 发送邮件(instead of `/bin/mail')
-s, --state=statefile 指定状态文件
-v, --verbose 显示转储过程
--version 显示版本信息

Help options:
-?, --help 显示帮助信息
--usage 显示简短的用法消息

配置文件解释

logrotate 默认配置文件/etc/logrotate.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
weekly   ## 所有的日志文件每周转储一次。
rotate 4 ## 转储的文件分为4份。
create ## logrotate自动创建新的日志文件。
dateext ## 轮询文件中包含日期信息
#compress :## 压缩日志文件。默认是注释掉的。
include /etc/logrotate.d ## 将/etc/logrotate.d/ 目录中的文件include 进来。
/var/log/wtmp { ## 指定日志的路径,支持通配符
monthly ## 按月切割
create 0664 root utmp ##切割文件的权限
minsize 1M ## 文件最小大小
rotate 1 ## 保留一个文件
}
/var/log/btmp {
missingok ## 如果日志不存在则忽略改日志的警告信息。
daily ## 按天切割
create 0600 root utmp
rotate 1
## 补充配置
postrotate
### sendall
echo "backup log OK"
endscript
## postrotate/endscript: 在所有其它指令完成后,postrotate和endscript里面指定的命令将被执行。在这种情况下,rsyslogd 进程将立即再次读取其配置并继续运行。
}

实战

配置logstash的日志切割

执行命令 vim /etc/logrotate.d/logstash

1
2
3
4
5
6
7
8
9
/var/log/logstash/*.log /var/log/logstash/*.err /var/log/logstash/*.stdout {    ###配置要压缩的日志。
daily ### 按天切割。
rotate 7 ## 保留七天。
copytruncate ## 先copy running.log内容至历史文件,然后清空running.log的内容。
compress ## 对轮询出来的文件用gzip压缩。
delaycompress ## 与compress成对出现,不要将最近的归档压缩,压缩将在下一次轮循周期进行。这在你或任何软件仍然需要读取最新归档时很有用。
missingok ## 在日志轮循期间,忽略所有错误。
notifempty ## 如果日志文件为空,轮循不会进行。
}

测试配置文件是否写正确

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>  logrotate -d /etc/logrotate.d/logstash
reading config file /etc/logrotate.d/logstash

Handling 1 logs

rotating pattern: /data/logs/logstash/*.log /data/logs/logstash/*.err /data/logs/logstash/*.stdout after 1 days (7 rotations)
empty log files are not rotated, old logs are removed
considering log /data/logs/logstash/logstash.log
log does not need rotating
considering log /data/logs/logstash/*.err
log /data/logs/logstash/*.err does not exist -- skipping
considering log /data/logs/logstash/*.stdout
log /data/logs/logstash/*.stdout does not exist -- skipping
[root@10.10.235.228 logrotate.d]#

脚本简介

这是一个用来生成用户名密码的软件

脚本演示

1
2
3
4
5
6
7
8
9
#sh adduser.sh
usage: adduser.sh [add | del ] username
## 添加用户
#sh adduser.sh add niu1
USERNAME : niu1
PASSWORD : kvgSOxUMJQb6k69M
## 删除用户
#sh adduser.sh del niu1
delete niu1 successful ....

脚本具体内容

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
#!/bin/bash

USERNAME="$2"
RETVAL="0"

color_shell(){

RED_COLOR='\E[1;31m'
GREEN_COLOR='\E[1;32m'
YELLOW_COLOR='\E[1;33m'
BLUE_COLOR='\E[1;34m'
RES='\E[0m'

}

usage(){
echo $"usage: $0 [add | del ] username "

}

create_passwd(){

GENPASSWD=`strings /dev/urandom | grep -o '[[:alnum:]]' | head -n 16 | tr -d '\n'; echo`

}

create_username(){

id $USERNAME &>/dev/null
RETVAL="$?"
if [[ $RETVAL -eq 0 ]]; then
echo "$USERNAME cunzai"
else
useradd $USERNAME
echo $GENPASSWD | passwd $USERNAME --stdin &>/dev/null
echo -e "$GREEN_COLOR USERNAME : $USERNAME $RES"
echo -e "$GREEN_COLOR PASSWORD : $GENPASSWD $RES"
fi
mkdir /home/$USERNAME/tools -p

}

delete_username(){

userdel -r $USERNAME
RETVAL=$?
if [[ $RETVAL -eq 0 ]]; then
echo -e "$GREEN_COLOR delete $USERNAME successful .... $RES"
else
echo -e "$RED_COLOR $USERNAME not delete ..... $RES"
fi
}

color_shell

case $1 in
add )
create_passwd
create_username
;;
del )
delete_username
;;
* )
usage
;;
esac

需求

今天测试了一下centos7,发现centos7的网卡名的后缀变成随机的了。
以前写的基于eth0和eth1的脚本已经不能用了,为了我的脚本,我只能把centos7的网卡命名规则改回来了。

实战过程

1
2
3
cd /etc/sysconfig/network-scripts/
mv ifcfg-eno1* ifcfg-eth0
mv ifcfg-eno3* ifcfg-eth1

重写网卡的配置文件

快速修改etho0网卡配置文件

1
2
3
4
5
6
cat >ifcfg-eth0<<EOF
DEVICE=eth0
ONBOOT=yes
BOOTPROTO=dhcp
DNS=8.8.8.8
EOF

快速修改etho1网卡配置文件

1
2
3
4
5
6
7
cat >ifcfg-eth1<<EOF
DEVICE=eth1
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.0.2.192
NETWORK=255.255.255.0
EOF

备份grub配置文件,方便回滚

1
2
3
cp /etc/default/grub /etc/default/grub_`date +%F`
vim /etc/sysconfig/grub
GRUB_CMDLINE_LINUX="net.ifnames=0 biosdevname=0 rhgb quiet"

生成新的配置文件

1
grub2-mkconfig -o /boot/grub2/grub.cfg

关闭多余的开机启动项

1
systemctl list-unit-files |grep enabled |awk '{print $1}' |egrep -v "sshd.service|rsyslog.service|crond.service"| sed -rn 's#(.*)#systemctl disable \1 #gp' |bash

重启系统

1
reboot

重启后登录系统查看IP地址已经修改成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

ip addr

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:50:56:39:b1:45 brd ff:ff:ff:ff:ff:ff
inet 192.168.0.128/24 brd 192.168.0.255 scope global dynamic eth0
valid_lft 1122sec preferred_lft 1122sec
inet6 fe80::250:56ff:fe39:b145/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:50:56:36:b7:0a brd ff:ff:ff:ff:ff:ff
inet 192.168.2.169/24 brd 192.168.2.255 scope global dynamic eth1
valid_lft 1721sec preferred_lft 1721sec
inet6 fe80::250:56ff:fe36:b70a/64 scope link
valid_lft forever preferred_lft forever

需求:日常工作中需要同时操作多台服务器,如果不注意会导致将命令执行在错误的服务器上。

解决办法

1
2
3
4
vim /etc/profile
### echo IP in bash
IP=`awk -F"=" '/IPADDR/{print $2}' /etc/sysconfig/network-scripts/ifcfg-eth0`
PS1='[\u@$IP \W]\$ '

备注

好多文章写PS1后面接的参数用双引号,但是实际测试中发现使用双引号登录到root环境下,会有问题。

演示如下

1
[root@linux-node1 ~]# IP=`awk -F”=” ‘/IPADDR/{print $2}’ /etc/sysconfig/network-scripts/ifcfg-eth0`

单引号

1
2
[root@linux-node1 ~]# PS1='[\u@$IP \W]\$ ‘
[root@10.0.0.7 ~]#

双引号

1
2
[root@10.0.0.7 ~]# PS1=”[\u@$IP \W]\$ ”
[root@10.0.0.7 ~]$

Mesos+marathon+Docker实战

1
2
**本篇博文参考赵班长发布在unixhot上的一篇文章**
[Mesos + marathon + Docker实战](http://www.unixhot.com/article/32)

环境架构图

上图显示了 Mesos 的主要组成部分。 Mesos 由一个 master daemon 来管理 slave daemon 在每个集群节点上的运行, mesos applications ( 也称为 frameworks )在这些 slaves 上运行 tasks。
Master 使用 Resource Offers 实现跨应用细粒度资源共享,如 cpu、内存、磁盘、网络等。 master 根据指定的策略来决定分配多少资源给 framework ,如公平共享策略,或优先级策略。 master 采用热插拔的方式实现了模块,为了以后更好的扩展。
在 Mesos 上运行的 framework 由两部分组成:一个是 scheduler ,通过注册到 master 来获取集群资源。另一个是在 slave 节点上运行的 executor 进程,它可以执行 framework 的 task 。 Master 决定为每个 framework 提供多少资源, framework 的 scheduler 来选择其中提供的资源。当 framework 同意了提供的资源,它通过 master 将 task发送到提供资源的 slaves 上运行。

实验环境准备

主机名 IP地址规划 主机描述
linux-node1 IP:192.168.56.22 Mesos Master、Mesos Slave、Marathon、Zookeeper
linux-node2 IP:192.168.56.23 Mesos Slave

基础环境准备

linux-node1

1
2
3
4
5
6
echo "linux-node1" > /etc/hostname
hostname linux-node1
cat >>/etc/hosts<<EOF
192.168.56.22 linux-node1
192.168.56.23 linux-node2
EOF

linux-node2

1
2
3
4
5
6
echo "linux-node2" > /etc/hostname
hostname linux-node2
cat >>/etc/hosts<<EOF
192.168.56.22 linux-node1
192.168.56.23 linux-node2
EOF

系统版本信息

1
2
3
4
5
6
uname  -r
3.10.0-229.el7.x86_64
uname -m
x86_64
cat /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

Zookeeper伪集群部署

安装java环境

1
2
3
4
5
6
7
8
9
10
cd /usr/local/src/
tar -zxf jdk-8u65-linux-x64.tar.gz
mv jdk1.8.0_65/ ../java-1.8.65
cd ../
ln -s java-1.8.65/ java
vim /etc/profile
export JAVA_HOME=/usr/local/java
export PATH=$JAVA_HOME/bin:$JAVA_HOME/ jre/bin:$PATH
export JRE_HOME=$JAVA_HOME/jre
export CLASSPATH=.$CLASSPATH: $JAVA_HOME/lib:$JAVA_HOME/jre/lib: $JAVA_HOME/lib/tools.jar

linux-node1 安装zookeeper

1
2
3
4
5
6
7
cd /usr/local/src
wget http://mirrors.cnnic.cn/apache/zookeeper/stable/zookeeper-3.4.6.tar.gz
tar zxf zookeeper-3.4.6.tar.gz
mv zookeeper-3.4.6 /usr/local/
ln -s /usr/local/zookeeper-3.4.6/ /usr/local/zookeeper
cd /usr/local/zookeeper/conf/
mv zoo_sample.cfg zoo.cfg

创建三个目录用来存放zookeeper数据

1
2
3
4
mkdir /data/{zk1,zk2,zk3} -p
echo "1" >/data/zk1/myid
echo "2" >/data/zk2/myid
echo "3" >/data/zk3/myid

生成三份zookeeper配置文件

1
2
3
cp zoo.cfg zk1.cfg
cp zoo.cfg zk2.cfg
cp zoo.cfg zk3.cfg

修改zk2和zk3的配置,使用对应的数据目录和端口。

1
2
3
4
sed -i 's/zk1/zk2/g' zk2.cfg
sed -i 's/2181/2182/g' zk2.cfg
sed -i 's/zk1/zk3/g' zk3.cfg
sed -i 's/2181/2183/g' zk3.cfg

启动Zookeeper

1
2
3
4
5
6
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk1.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk2.cfg
/usr/local/zookeeper/bin/zkServer.sh start /usr/local/zookeeper/conf/zk3.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk3.cfg
#Starting zookeeper ... STARTED

查看Zookeeper角色

1
2
3
4
5
6
7
8
9
10
11
12
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk1.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk1.cfg
#Mode: follower
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk2.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk2.cfg
#Mode: leader
/usr/local/zookeeper/bin/zkServer.sh status /usr/local/zookeeper/conf/zk3.cfg
#JMX enabled by default
#Using config: /usr/local/zookeeper/conf/zk3.cfg
#Mode: follower

连接Zookeeper

1
2
/usr/local/zookeeper/bin/zkCli.sh -server192.168.56.22:2181

通过上面的例子可以看到,目前zk2是leader,其它两个节点是follower。
本文由于实验环境局限使用的是伪分布式,注意生产环境不建议使用。

Mesos 集群部署

Mesos集群有MesosMaster和Mesos Slave两个角色。

安装mesosphere仓库

需要在Mesos Master和MesosSlave节点均安装

1
rpm -Uvh http://repos.mesosphere.com/el/7/noarch/RPMS/mesosphere-el-repo-7-1.noarch.rpm

Mesos Master部署(node1)

1
2
3
4
5
6
yum -y install mesos marathon
安装完毕后,增加zookeeper配置
[root@linux-node1 ~]# vim /etc/mesos/zk
zk://192.168.56.22:2181,192.168.56.22:2182,192.168.56.22:2183/mesos
systemctl start mesos-master mesos-slave
systemctl start marathon

Mesos Slave部署(node2)

1
2
3
4
yum -y install mesos marathon
[root@linux-node1 ~]# vim /etc/mesos/zk
zk://192.168.56.22:2181,192.168.56.22:2182,192.168.56.22:2183/mesos
systemctl start mesos-slave

Mesos的Web管理界面

Mesos安装完毕后,Mesos Master会启动一个Web服务,监听在5050端口。
http://192.168.56.22:5050/
这时候你将得到一个像这样的页面但可能在’Tasks’表格没有任何的条目。

下面我们来运行第一mesos任务,注意刷新查看Mesos的Web界面,你会在Active Tasks看到我们测试的任务。

1
2
MASTER=$(mesos-resolve `cat /etc/mesos/zk`)
mesos-execute --master=$MASTER --name="cluster-test" --command="sleep 60"

使用Marathon调用Mesos 运行Docker容器

配置Mesos运行Docker容器(node1)

1
2
3
[root@linux-node1 ~]# yum install -y docker
[root@linux-node1 ~]# systemctl start docker
[root@linux-node1 ~]# docker pull nginx

首先先测试下,保证手动创建Docker容器没问题。

所有mesos-slave上增加配置参数,并重启

linux-node1:

1
2
3
echo 'docker,mesos' | tee /etc/mesos-slave/containerizers
#docker,mesos
systemctl restart mesos-slave

linux-node2:

1
2
3
echo 'docker,mesos' | tee /etc/mesos-slave/containerizers
#docker,mesos
systemctl restart mesos-slave

接下来,我们要使用我们marathon来创建一个nginx的Docker容器,通过Mesos进行调度。 我们上面安装mesos-master的时候,已经安装了marathon。默认监听在8080端口,通过使用 http://192.168.56.22:8080/来打开marathon。如下图所示:

marathon启动的时候会读取/etc/mesos/zk配置文件,通过Zookeeper来找到Mesos Master。
marathon有自己的REST API,我们通过API的方式来创建一个nginx的docker容器:
首先创建如下的配置文件nginx.json:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@localhost ~10:57:59]#cat nginx.json
{
"id":"nginx",
"cpus":0.2,
"mem":20.0,
"instances": 1,
"constraints": [["hostname", "UNIQUE",""]],
"container": {
"type":"DOCKER",
"docker": {
"image": "nginx",
"network": "BRIDGE",
"portMappings": [
{"containerPort": 80, "hostPort": 0,"servicePort": 0, "protocol": "tcp" }
]
}
}
}

然后调用

1
2
curl -X POST http://192.168.56.22:8080/v2/apps -d @nginx.json \
-H "Content-type: application/json"

现在你就可以通过31984来访问到nginx了。当然了,你也可以在mesos-slave上来寻找一下这个容器:
linux-node1

1
2
3
docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5cc8d207d2b2 nginx "nginx -g 'daemon off" About a minute ago Up About a minute 443/tcp, 0.0.0.0:31610->80/tcp mesos-b5254dbf-0b69-4c0e-b9b6-cd271f73265c-S0.2d202e6a-fb23-41b9-93b6-2b3b1cbfcf30

如果你想创建同样的容器,可以点击上图中的Scale Application来体验一下。同样的,你也可以通过marathon的Web界面来进行容器的创建、扩展和销毁。

创建10台nginx虚拟机

Grains数据系统

Grains(鼓励):静态数据,存储客户端的信息。

1
salt '*' grains.items ###列出服务器的详细参数

只查看OS的信息:

1
2
3
4
5
6
7
8
9
[root@centos6 ~]# salt '*' grains.item os
minion.saltstack.com:
----------
os:
CentOS
[root@centos6 ~]# salt '*' grains.get os
minion.saltstack.com:
CentOS

1
2
3
4
5
6
7
8
[root@linux-node1 salt]# salt '*' grains.get ip_interfaces:eth0
linux-node2:
- 10.0.0.8
- fe80::20c:29ff:fea4:91c7
linux-node1:
- 10.0.0.7
- fe80::20c:29ff:fe6a:d896
[root@linux-node1 salt]#

列出所有信息的名称:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@centos6 ~]# salt '*' grains.ls
minion.saltstack.com:
- SSDs
- biosreleasedate
- biosversion
- cpu_flags
- cpu_model
- cpuarch
- domain
- fqdn
- fqdn_ip4
- fqdn_ip6
省略部分内容。。。。。。。。

在服务端测试:-G 表示匹配grains :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@centos6 ~]# salt -G 'env:prod' test.ping
minion.saltstack.com:
True

[root@linux-node1 salt]# salt -G 'os:CentOS' cmd.run 'w'
linux-node2:
03:35:48 up 9:50, 2 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
niu pts/0 10.0.2.1 02:02 1:10m 0.00s 0.00s -bash
niu pts/1 10.0.2.1 02:14 1:21m 0.00s 0.00s -bash
linux-node1:
03:35:46 up 19:30, 2 users, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
niu pts/0 10.0.2.1 02:02 1.00s 0.41s 0.00s sshd: niu [priv
niu pts/1 10.0.2.1 02:14 1:07m 0.02s 0.00s sshd: niu [priv
[root@linux-node1 salt]#

在客户端自定义grains:

1
2
3
4
5
6
7
[root@centos6 ~]# vim /etc/salt/minion
grains:
roles: nginx
env: prod

"/etc/salt/minion" 627L, 25173C written

使用命令行设置minion端的grains。

1
2
3
4
5
6
7
8
## 给logstash4服务器设置一个elastic_url的grains值
salt 'chuye.logstash4.service' grains.setval elastic_url 'http://10.10.196.24:9200'
## 查看elastic_url的值
salt 'chuye.logstash4.service' grains.item elastic_url
## 重新给elastic_url赋值
salt 'chuye.logstash5.service' grains.setval elastic_url '"http://10.10.160.129:9200"'
## 查看新赋值是否生效
salt 'chuye.logstash5.service' grains.item elastic_url

设置成功后,minion会在 /etc/minion/grains 增加一行配置文件

1
2
vim /etc/salt/grains
elastic_url: http://10.10.196.24:9200

也可以在客户端这样定义:
客户端编写: grains配置文件中,不能和minion的参数冲突。

1
2
3
4
5
6
[root@centos6 ~]# vim /etc/salt/grains
cloud: openstack
[root@centos6 ~]# /etc/init.d/salt-minion restart
Stopping salt-minion daemon: [ OK ]
Starting salt-minion daemon: [ OK ]
[root@centos6 ~]#

在top.sls中调用grains的方法:

1
2
3
4
5
6
[root@linux-node1 salt]# vim top.sls
base:
'web:nginx':
- match: grain
- apache

在服务器端测试:
[root@centos6 ~]# salt -G ‘cloud:openstack’ test.ping
minion.saltstack.com:
True

在服务端输入如下命令可以刷新:(客户端更改后不用重启)

1
2
[root@centos6 ~]# salt '*' saltutil.sync_grains

在配置文件中调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
nginx:
pkg:
- installed
file.managed:
- source: salt://nginx/nginx.conf
- name: /etc/nginx/nginx.conf
- user: root
- group: root
- mode: 644
- template: jinja

service.running:
- enable: True
- reload: True
- watch:
- file: /etc/nginx/nginx.conf
- pkg: nginx

Pillar(柱子)数据系统:
启动pillar功能

1
2
3
vim /etc/salt/master
pillar_opts: True
##piller 默认参数的开启。

作用:

  • 处理敏感数据。
  • 处理差异性的文件。

第二步:在master文件中配置pillar文件存放的位置

1
2
3
4
vim /etc/salt/master
pillar_roots:
base:
- /etc/salt/pillar

第三步:开始编写pillar文件

1
2
3
4
5
6
7
8
# mkdir /etc/salt/pillar
# cd /etc/salt/pillar/
# vim top.sls
base:
'*':
- init.rsyslog
~
"top.sls" [New] 3L, 33C written
1
2
3
4
5
6
7
8
# mkdir init
# cd init/
# vim rsyslog.sls
{% if grains['osfinger'] == 'CentOS-6' %}
syslog: rsyslog
{% elif grains['osfinger'] == 'CentOS-5' %}
syslog: syslog
{% endif %}

刷新一下配置:

1
2
3
4
[root@centos6 init]# salt '*' saltutil.refresh_pillar
minion.saltstack.com:
True
[root@linux-node1 pillar]# salt '*' pillar.items

第四步使用pillar
pillar跟grains的使用方法一样
可以用索引(pillar[‘pkgs’][‘apache’])或get方法(pillar.get(‘users’, {}))。

索引的方式:

1
2
3
4
5
6
/srv/salt/apache/init.sls:

apache:
pkg.installed:
- name: {{ pillar['pkgs']['apache'] }}

get的方式

1
2
3
4
5
还可以在state file中设置默认值: srv/salt/apache/init.sls:

apache:
pkg.installed:
- name: {{ salt['pillar.get']('pkgs:apache', 'httpd') }}

实例二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{% if grains['os'] == 'CentOS' %}
apache:httpd
{% elif grains['os'] == 'Debian' %}
apache:apche2
{% endif %}

[root@linux-node1 pillar]# cat /srv/pillar/top.sls
base:
'*':
- apache

[root@linux-node1 pillar]# ls
apache.sls top.sls
[root@linux-node1 pillar]# pwd
/srv/pillar
[root@linux-node1 pillar]#

grains和pillar对比:

使用salt进行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
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
# For more information on configuration, see:
user nginx;
worker_processes {{ grains['num_cpus'] }};
{% if grains['num_cpus'] == 2 %}
worker_cpu_affinity 01 10;
{% elif grains['num_cpus'] == 4 %}
worker_cpu_affinity 1000 0100 0010 0001;
{% elif grains['num_cpus'] >= 8 %}
worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;
{% else %}
worker_cpu_affinity 1000 0100 0010 0001;
{% endif %}
worker_rlimit_nofile {{ grains['max_open_file'] }};

error_log /var/log/nginx/error.log;
#error_log /var/log/nginx/error.log notice;
#error_log /var/log/nginx/error.log info;

pid /var/run/nginx.pid;

events {
worker_connections {{ grains['max_open_file'] }};
}


http {
include /etc/nginx/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 /var/log/nginx/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;

# Load config files from the /etc/nginx/conf.d directory
# The default server is in conf.d/default.conf
#include /etc/nginx/conf.d/*.conf;
server {
listen 80 default_server;
server_name _;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root {{ pillar['nginx']['root'] }};
index index.html index.htm;
}

error_page 404 /404.html;
location = /404.html {
root /usr/share/nginx/html;
}

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

}

}
0%