EMQ X 在支持客戶的過(guò)程中,了解到有客戶使用 Nginx 做負(fù)載均衡,Docker 容器手動(dòng)加入集群的方式運(yùn)行 EMQ 集群,現(xiàn)將主要過(guò)程記錄下來(lái)。
成都創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),昆玉企業(yè)網(wǎng)站建設(shè),昆玉品牌網(wǎng)站建設(shè),網(wǎng)站定制,昆玉網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,昆玉網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
$ cat /etc/nginx/tcpstream.conf## tcp LB and SSL passthrough for backend ##stream {
upstream mqtt_broker {
server 127.0.0.1:21871; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21872; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21873; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21874; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21875; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21881; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21891; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21882; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21892; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21883; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21893; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21884; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21894; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21885; #max_fails=5 fail_timeout=30s;
server 127.0.0.1:21895; #max_fails=5 fail_timeout=30s;
}
log_format basic '$proxy_protocol_addr - $remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/access.log basic;
error_log /var/log/nginx/error.log;
server {
listen 8884 ssl; # proxy_protocol;
proxy_next_upstream on;
#proxy_bind $remote_addr transparent;
proxy_ssl off;
proxy_pass mqtt_broker;
proxy_protocol on;
#ssl_on;
# adding some extra proxy settings
proxy_timeout 350s;
#proxy_buffer_size 128k;
#ssl_certificate /etc/nginx/certs/solace.pem;
#ssl_certificate_key /etc/nginx/certs/solace.pem;
ssl_certificate /etc/nginx/certs/cert.pem;
ssl_certificate_key /etc/nginx/certs/key.pem;
#ssl_verify_client off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers HIGH:!aNULL:!MD5;
}
}
客戶自行編譯的 Docker image,并非使用 EMQ 提供的官方鏡像。
Dockerfile 目錄如下:
$ ll /opt/Docker/總用量 28
-rw-r--r-- 1 alexeyp emq 620 10月 22 17:26 Dockerfile
lrwxrwxrwx 1 alexeyp emq 13 10月 24 13:59 emqttd -> emqttd.2.3.11
drwxr-xr-x 10 alexeyp emq 110 10月 24 14:27 emqttd.2.3.11
-rwxr-xr-x 1 alexeyp emq 3463 10月 26 05:03 StartEmqInstance.sh
-rwxr-xr-x 1 alexeyp alexeyp 270 10月 25 10:46 status.sh
Dockerfile:
$ cat DockerfileFROM centos:latest
RUN yum -y update
EXPOSE 60000-65000
WORKDIR /opt/emqttd
ADD ./emqttd /opt/emqttd
ADD ./vsparc.rpm /tmp/vsparc.rpm
ADD ./StartEmqInstance.sh /opt/emqttd/StartEmqInstance.sh
RUN yum install -y epel-release
RUN yum install -y which less sed net-tools telnet gtest /tmp/vsparc.rpm
ENV TZ Australia/Melbourne
CMD bash /opt/emqttd/StartEmqInstance.sh && bash
可以看到 Docker 容器啟動(dòng)后會(huì)執(zhí)行一個(gè) StartEmqInstance.sh 的腳本,查看該腳本:
$ cat StartEmqInstance.sh#!/bin/bashDIR=$(dirname $0)
HOSTNAME=$(hostname -s)
function adjust_instance()
{
local INST=$1
local INST_ROOT=$2
cat $INST_ROOT/etc/emq.conf | \
sed -re "s/^node\.name\s*=.*$/node.name = emq$INST@127.0.0.1/" | \
#sed -re "s/^cluster\.name\s*=.*$/cluster.name = $HOSTNAME/" | \
sed -re "s/^listener\.tcp\.external\s*=.*$/listener.tcp.external = 0.0.0.0:6188$INST/" | \
sed -re "s/^listener\.tcp\.external1\s*=.*$/listener.tcp.external1 = 0.0.0.0:6189$INST/" | \
sed -re "s/^listener\.tcp\.external2\s*=.*$/listener.tcp.external2 = 0.0.0.0:6187$INST/" | \
sed -re "s/^listener\.tcp\.internal\s*=.*$/listener.tcp.internal = 127.0.0.1:6298$INST/" | \
sed -re "s/^listener\.ssl\.external\s*=.*$/listener.ssl.external = 6288$INST/" | \
sed -re "s/^listener\.ws\.external\s*=.*$/listener.ws.external = 6208$INST/" | \
sed -re "s/^listener\.wss\.external\s*=.*$/listener.ws.external = 6308$INST/" | \
sed -re "s/^listener\.api\.mgmt\s*=.*$/listener.api.mgmt = 6408$INST/" | \
sed -re "s/^(##\s)?listener\.tcp\.external\.proxy_protocol\s=.*$/listener.tcp.external.proxy_protocol = on/" | \
sed -re "s/^(##\s)?listener\.tcp\.external1\.proxy_protocol\s=.*$/listener.tcp.external1.proxy_protocol = on/" | \
sed -re "s/^(##\s)?listener\.tcp\.external2\.proxy_protocol\s=.*$/listener.tcp.external2.proxy_protocol = on/" | \
sed -re "s/^(##\s)?listener\.tcp\.external\.proxy_protocol_timeout\s=.*$/listener.tcp.external.proxy_protocol_timeout = 30s/" | \
sed -re "s/^(##\s)?listener\.tcp\.external1\.proxy_protocol_timeout\s=.*$/listener.tcp.external1.proxy_protocol_timeout = 30s/" | \
sed -re "s/^(##\s)?listener\.tcp\.external2\.proxy_protocol_timeout\s=.*$/listener.tcp.external2.proxy_protocol_timeout = 30s/" | \
sed -re "s/^(##\s)?node.dist_listen_min\s*=.*$/node.dist_listen_min = 6000$INST/" | \
sed -re "s/^(##\s)?node.dist_listen_max\s*=.*$/node.dist_listen_max = 6000$INST/" | \
cat - > $INST_ROOT/etc/emq.conf.new
mv $INST_ROOT/etc/emq.conf.new $INST_ROOT/etc/emq.conf
}
function cluster_instance()
{
local INST=$1
for DEST in 1 2 3 4 5; do
if [ $DEST == $INST ]; then
continue;
fi
DEST_NODE="emq$DEST@127.0.0.1"
RESULT=$(/opt/emqttd/bin/emqttd_ctl cluster join $DEST_NODE 2>&1)
echo "$RESULT"
echo "$RESULT" | grep -E 'successfully|already' > /dev/null
RC=$?
[ $RC == 0 ] && break
done
}
cd "$DIR"
if [ "$EMQ_INSTANCE_NUMBER" == "" ]; then
echo "Environment variable EMQ_INSTANCE_NUMBER(1..10) is not set."
echo "eMQ instance name is not configured."
exit 1
else
adjust_instance $EMQ_INSTANCE_NUMBER $DIR
fi
function run_application()
{
local CMD="$1"
local RC=1
while [ $RC != 0 ]; do
$CMD
RC=$?
echo "### Exited: $CMD"
echo "### rc = $RC"
#[ $RC != 0 ] && sleep 3
RC=1
done
echo "### Done: $CMD"
}
function start_node()
{
bin/emqttd start
STARTED=0
while [ $STARTED == 0 ]; do
sleep 1
/opt/emqttd/bin/emqttd_ctl status | grep "is running"
[ $? == 0 ] && break
done
cluster_instance $EMQ_INSTANCE_NUMBER > /tmp/cluster_instance.log
}
start_node
sleep 5
run_application "/usr/local/bin/emqtt-stats-collector" &#waitIDLE_TIME=0
while [[ $IDLE_TIME -lt 5 ]]
do
IDLE_TIME=$((IDLE_TIME+1))
if [[ ! -z "$( /opt/emqttd/bin/emqttd_ctl status|grep 'is running'|awk '{print $1}')" ]]; then
IDLE_TIME=0
else
echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqttd not running, waiting for recovery in $((60-IDLE_TIME*5)) seconds"
fi
sleep 5
done
echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqttd exit abnormally"
exit 1
腳本內(nèi)容稍多而且有些復(fù)雜,需要結(jié)合
start.sh
腳本和
etc/emq.conf
一起看
$ cat start.sh#!/bin/bashfor INST in 1 2 3 4 5
do
docker ps | grep -E "\sinstance_$INST$"
if [ $? != 0 ]; then
#docker run -itd ---ulimit nofile=1048576 -restart=always -v /opt/Docker/emqtt/emq$INST/data/mnesia:/opt/emqttd/data/mnesia -e EMQ_INSTANCE_NUMBER=$INST --name=instance_$INST --network host emq:test &
docker run -itd --ulimit nofile=1048576 -e EMQ_INSTANCE_NUMBER=$INST --name=instance_$INST --network host emq:latest &
fi
done
wait
etc/emq.conf`的全文就不貼出來(lái)了,主要是增加了兩個(gè) tcp 監(jiān)聽(tīng)端口,并且關(guān)閉了`listener.tcp.external.tune_buffer
$ cat etc/emq.conf......
##--------------------------------------------------------------------
listener.tcp.external = 0.0.0.0:21881
listener.tcp.external.acceptors = 16
listener.tcp.external.max_clients = 512000
listener.tcp.external.access.1 = allow all
listener.tcp.external.proxy_protocol = on
listener.tcp.external.proxy_protocol_timeout = 30s
listener.tcp.external.backlog = 1024
listener.tcp.external.send_timeout = 15s
listener.tcp.external.send_timeout_close = on
## listener.tcp.external.tune_buffer = on
listener.tcp.external.nodelay = true
listener.tcp.external.reuseaddr = true
##--------------------------------------------------------------------
listener.tcp.external1 = 0.0.0.0:21891
listener.tcp.external1.acceptors = 16
listener.tcp.external1.max_clients = 512000
listener.tcp.external1.access.1 = allow all
listener.tcp.external1.proxy_protocol = on
listener.tcp.external1.proxy_protocol_timeout = 30s
listener.tcp.external1.backlog = 1024
listener.tcp.external1.send_timeout = 15s
listener.tcp.external1.send_timeout_close = on
## listener.tcp.external1.tune_buffer = on
listener.tcp.external1.nodelay = true
listener.tcp.external1.reuseaddr = true
##--------------------------------------------------------------------
listener.tcp.external2 = 0.0.0.0:21871
listener.tcp.external2.acceptors = 16
listener.tcp.external2.max_clients = 512000
listener.tcp.external2.access.1 = allow all
listener.tcp.external2.proxy_protocol = on
listener.tcp.external2.proxy_protocol_timeout = 30s
listener.tcp.external2.backlog = 1024
listener.tcp.external2.send_timeout = 15s
listener.tcp.external2.send_timeout_close = on
## listener.tcp.external2.tune_buffer = on
listener.tcp.external2.nodelay = true
listener.tcp.external2.reuseaddr = true
......
Docker 容器創(chuàng)建之后,
StartEmqInstance.sh
執(zhí)行
adjust_instance()
將
etc/emq.conf
中監(jiān)聽(tīng)的端口修改為Nginx 的代理 server
sed -re "s/^node\.name\s*=.*$/node.name = emq$INST@127.0.0.1/" | \
sed -re "s/^listener\.tcp\.external\s*=.*$/listener.tcp.external = 0.0.0.0:6188$INST/"
sed -re "s/^listener\.tcp\.external1\s*=.*$/listener.tcp.external1 = 0.0.0.0:6189$INST/"
sed -re "s/^listener\.tcp\.external2\s*=.*$/listener.tcp.external2 = 0.0.0.0:6187$INST/"
sed -re "s/^listener\.tcp\.internal\s*=.*$/listener.tcp.internal = 127.0.0.1:6298$INST/"
并通過(guò)
join
命令來(lái)實(shí)現(xiàn)集群功能
function cluster_instance()
{
local INST=$1
for DEST in 1 2 3 4 5; do
if [ $DEST == $INST ]; then
continue;
fi
DEST_NODE="emq$DEST@127.0.0.1"
RESULT=$(/opt/emqttd/bin/emqttd_ctl cluster join $DEST_NODE 2>&1)
echo "$RESULT"
echo "$RESULT" | grep -E 'successfully|already' > /dev/null
RC=$?
[ $RC == 0 ] && break
done
}
循環(huán)檢查 EMQ 的狀態(tài),當(dāng) EMQ 停止了之后退出容器
IDLE_TIME=0
while [[ $IDLE_TIME -lt 5 ]]
do
IDLE_TIME=$((IDLE_TIME+1))
if [[ ! -z "$( /opt/emqttd/bin/emqttd_ctl status|grep 'is running'|awk '{print $1}')" ]]; then
IDLE_TIME=0
else
echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqttd not running, waiting for recovery in $((60-IDLE_TIME*5)) seconds"
fi
sleep 5
done
echo "['$(date -u +"%Y-%m-%dT%H:%M:%SZ")']:emqttd exit abnormally"
exit 1
客戶端通過(guò) SSL 方式連接
PS:關(guān)于 Nginx 如何反向代理 tcp 和 ssl 的設(shè)置,可以參考 EMQ X 消息服務(wù)器 Nginx 反向代理
容器啟動(dòng)后通過(guò)
StartEmqInstance.sh
腳本查詢 EMQ 的狀態(tài),當(dāng) EMQ 停止時(shí)退出容器,配合
--restart=always
來(lái)達(dá)到重啟容器的目的。
EMQ 將集群信息儲(chǔ)存在
data/mnesia
中,將容器的中的目錄映射到宿主機(jī),當(dāng)容器重啟之后會(huì)讀取宿主機(jī)映射的相關(guān)目錄,實(shí)現(xiàn)重啟后自動(dòng)集群。
/proc/sys/net/ipv4/ip_local_port_range
指定系統(tǒng)分配的端口為
1024 60000
,然后將 EMQ 的業(yè)務(wù)端口分配為 60000 之后的端口建議使用 kubernetes 來(lái)編排 docker 容器:
kube-apiserver
來(lái)實(shí)現(xiàn)自動(dòng)集群的功能。deployment
可以監(jiān)控
emqx pod
的狀態(tài),實(shí)現(xiàn)自動(dòng)重啟、彈性擴(kuò)容等功能。emqx pod
都有獨(dú)立的虛擬 IP,不會(huì)出現(xiàn)端口沖突的問(wèn)題。Service
可以實(shí)現(xiàn)固定 IP 和負(fù)載均衡的需求,在
Service
創(chuàng)建的請(qǐng)求中,可以通過(guò)設(shè)置
spec.clusterIP
字段來(lái)指定自己的集群 IP 地址,將 Nginx 的代理 server 設(shè)置成
clusterIP
即可,
Service
可自行實(shí)現(xiàn)負(fù)載均衡。
當(dāng)前題目:Nginx+Docker手動(dòng)集群方式運(yùn)行EMQ
網(wǎng)站路徑:http://www.rwnh.cn/article6/jipdig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、營(yíng)銷型網(wǎng)站建設(shè)、品牌網(wǎng)站建設(shè)、、云服務(wù)器、定制開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)