感谢腾讯刘天斯带来HECD架构的理念。
约定由Haproxy+etcd+confd+Docker构建的基础服务平台简称“HECD”架构。Haproxy+etcd+confd,采用松散式的组织结构,但各个组件之间的通信是非常严密的,且扩展性更强,定制也更加灵活。HECD架构具有一下优势:
1、自动、实时发现及无感知服务刷新;
2、支持任意多台Docker宿主机;
3、支持多种APP接入,且打散至不分宿主机;
4、采用Etcd存储信息,集群支持可靠性高;
5、采用Confd配置引擎,支持各类接入层,如Nginx;
6、支持负载均衡、故障迁移;
7、具备资源弹性,伸缩自如;
一、架构说明:
在HECD架构中,首先管理员操作Docker Client,除了提交容器(Container)启动与停止指令外,还通过REST-API方式向Etcd(K/V)存储组件注册容器信息,包括容器名称、主宿机IP、映射端口等。Confd配置组件会定时查询Etcd组件获取最新的容器信息,根据定义好的配置模板生成Haproxy配置文件Haproxy.cfg,并且自动reload haproxy服务。用户在访问业务服务时,完全没有感知后端APP的上线、下线、切换及迁移,达到了自动发现、高可用的目的。详细架构图见图1-1。
为了方便大家理解各组件间的关系,通过图1-2进行架构流程梳理,首先管理员通过Shell或api操作容器,下一步将容器信息注册到Etcd组件,Confd组件会定时查询Etcd,获取已经注册到Etcd中容器信息,最后通过Confd的模板引擎生成Haproxy配置,整个流程结束。
了解架构流程后,我们逐一对流程中各组件进行详细介绍。
1、Etcd介绍
Etcd是一个高可用的 Key/Value 存储系统,主要用于分享配置和服务发现。
简单:支持 curl 方式的用户 API (HTTP+JSON)
安全:可选 SSL 客户端证书认证
快速:单实例可达每秒 1000 次写操作
可靠:使用 Raft 实现分布式
2、Confd介绍
Confd是一个轻量级的配置管理工具。通过查询Etcd,结合配置模板引擎,保持本地配置最新,同时具备定期探测机制,配置变更自动reload。
3、Haproxy介绍
HAProxy是提供高可用性、负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。(来源百科)
二、架构部署
0、集群IP
HECD1: 192.168.200.83
HECD2: 192.168.200.84
HECD3: 192.168.200.85
1、安装环境(haproxy+etcd+confd+docker)
1.docker(HECD3)
将所需包复制到/root/Downloads目录下
安装libcgroup,命令:rpm -ivh libcgroup-*
安装docker,命令:rpm -ivh docker-engine-1.7.1-1.el6.x86_64.rpm
启动docker,设置开机自启动,命令:
service docker start
chkconfig --add docker
2.安装haproxy(HECD1)
安装popt,命令:rpm -ivh popt-devel-1.13-7.el6.x86_64.rpm
安装haproxy,命令:rpm -ivh haproxy-1.5.4-3.el6.x86_64.rpm
3.安装confd(HECD1)
将所需文件复制到/root/Downloads目录下
安装confd,
命令:mv confd-0.6.3-linux-amd64 /usr/local/bin/confd
chmod +x /usr/local/bin/confd
查看安装是否完成,命令:/usr/local/bin/confd -version
4.安装etcd(HECD2)
将所需文件复制到/root/Downloads目录下
解压,命令:tar -zxvf etcd-v0.4.6-linux-amd64.tar.gz
安装etcd,命令:
cd etcd-v0.4.6-linux-amd64
cp etcd* /bin/
查看是否安装完成,命令:/bin/etcd -version
2、配置环境
1.Etcd配置(HECD2)
创建/data/etcd目录,命令:mkdir /data mkdir /data/etcd
由于etcd是一个轻量级的K/V存储平台,启动时指定相关参数即可,无需配置。
命令:
/bin/etcd -name etcdserver -peer-addr 192.168.200.83:7001 -addr 192.168.200.83:4001 -data-dir /data/etcd -peer-bind-addr 0.0.0.0:7001 -bind-addr 0.0.0.0:4001 > /var/log/etcd.log &
记下进程号,以便kill
2.Confd+Haproxy配置(HECD1)
创建配置文件目录,命令:mkdir -p /etc/confd/{conf.d,templates}
(1)配置资源文件
【/etc/confd/conf.d/haproxy.toml】
[template]
src = "haproxy.cfg.tmpl"
dest = "/etc/haproxy/haproxy.cfg"
keys = ["/app/servers"]
reload_cmd = "/etc/init.d/haproxy reload"
其中“src”为指定模板文件名称(默认到路径/etc/confd/templates中查找);“dest”指定生成的Haproxy配置文件路径;“keys”指定关联Etcd中key的URI列表;“reload_cmd”指定服务重载的命令,本例中配置成haproxy的reload命令。
(2)配置模板文
【/etc/confd/templates/haproxy.cfg.tmpl】
global
log 127.0.0.1 local3
maxconn 5000
uid 99
gid 99
daemon
defaults
log 127.0.0.1 local3
mode http
option dontlognull
retries 3
option redispatch
maxconn 2000
contimeout 5000
clitimeout 50000
srvtimeout 50000
listen frontend 0.0.0.0:14569
mode http
balance roundrobin
maxconn 2000
option forwardfor
{{range gets "/app/servers/*"}}
server {{base .Key}} {{.Value}} check inter 5000 fall 1 rise 2
{{end}}
stats enable
stats uri /admin-status
stats auth admin:123456
stats admin if TRUE
测试用例:(在HECD2上执行)
curl -XPUT http://192.168.200.83:4001/v2/keys/app/servers/backstabbing_rosalind -d value="192.168.200.84:49156"
(3)启动confd及haproxy服务(HECD1)
启动confd,命令:
/usr/local/bin/confd -verbose -interval 10 -node '192.168.200.83:4001' -confdir /etc/confd > /var/log/confd.log &
启动haproxy,命令:
/etc/init.d/haproxy start
浏览器访问:http://192.168.200.83:14569/admin-status 用户名:admin 密码:123456
【docker.sh】
#!/bin/bash
if [ -z $1 ]; then
echo "Usage: c run <image name>:<version>"
echo " c stop <container name>"
echo " c start <container name>"
exit 1
fi
if [ -z $ETCD_HOST ]; then
ETCD_HOST="192.168.200.83:4001"
fi
if [ -z $ETCD_PREFIX ]; then
ETCD_PREFIX="app/servers"
fi
if [ -z $CPORT ]; then
CPORT="7001"
fi
if [ -z $FORREST_IP ]; then
FORREST_IP=`ifconfig eth0| grep "inet addr" | head -1 | cut -d : -f2 | awk '{print $1}'`
fi
function launch_container {
echo "Launching $1 on $FORREST_IP ..."
CONTAINER_ID=`docker run -d -P -v ~/exchange_files:/u01/oracle/weblogic/user_projects/domains/base_domain/servers/AdminServer/upload -v ~/weblogiclogs:/u01/oracle/weblogic/user_projects/domains/base_domain/servers/AdminServer/logs $1 startWebLogic.sh`
PORT=`docker inspect $CONTAINER_ID|grep "\"Ports\"" -A 50|grep "\"$CPORT/tcp\"" -A 3| grep HostPort|cut -d '"' -f4|head -1`
NAME=`docker inspect $CONTAINER_ID | grep Name | cut -d '"' -f4 | sed "s/\///g"|sed -n 1p`
echo "Announcing to $ETCD_HOST..."
curl -XPUT "http://$ETCD_HOST/v2/keys/$ETCD_PREFIX/$NAME" -d value="$FORREST_IP:$PORT"
echo "$1 running on Port $PORT with name $NAME"
}
function stop_container {
echo "Stopping $1..."
CONTAINER_ID=`docker ps -a| grep $1 | awk '{print $1}'`
echo "Found container $CONTAINER_ID"
docker stop $CONTAINER_ID
echo http://$ETCD_HOST/v2/keys/$ETCD_PREFIX/$1
curl -XDELETE http://$ETCD_HOST/v2/keys/$ETCD_PREFIX/$1 &> /dev/null
echo "Stopped."
}
function start_container {
echo "Starting $1..."
CONTAINER_ID=`docker ps -a| grep $1 | awk '{print $1}'`
echo "Found container $CONTAINER_ID"
docker start $CONTAINER_ID
echo http://$ETCD_HOST/v2/keys/$ETCD_PREFIX/$1
PORT=`docker inspect $CONTAINER_ID|grep "\"Ports\"" -A 50|grep "\"$CPORT/tcp\"" -A 3| grep HostPort|cut -d '"' -f4|head -1`
curl -XPUT "http://$ETCD_HOST/v2/keys/$ETCD_PREFIX/$1" -d value="$FORREST_IP:$PORT"
echo "Started."
echo "$1 running on Port $PORT with name $1"
}
if [ $1 = "run" ]; then
launch_container $2
fi
if [ $1 = "start" ]; then
start_container $2
fi
if [ $1 = "stop" ]; then
stop_container $2
fi
运行容器:
./docker.sh run <name>:<tag>
停止容器:
./docker.sh stop <name>
停止后重新运行容器:
./docker.sh start <name>
注意:
1. 在宿主机(HECD3)上,~/目录下要存在~/exchange_files、和weblogiclogs目录,而且weblogiclogs目录要有读写权限(chmod -R 777 ~/weblogiclogs)
2. 三台设备的防火墙必须关闭,或者打开相应端口。