1. 程式人生 > 其它 >使用docker快速部署一個consul叢集

使用docker快速部署一個consul叢集

  作為一個開發者,有時候需要一個叢集環境,之前的做法要麼就是使用多個虛擬機器,要麼就是採用不同的埠來模擬,但是虛擬機器比較佔記憶體,而且啟動慢,採用不同的埠來模擬,管理起來比較麻煩一些,程式隔離性差一些。

  docker的出現讓我們可以在一臺虛擬機器上模擬構建出來一個幾乎完全隔離的叢集,本文提供一種快速構建consul叢集的方法。

  首先我們需要consul的映象,這個可以從dockerhub上獲取:

  

  上面第一個就是consul官方的映象  

    # 搜尋映象
    sudo docker search consul
    # 拉取映象
    sudo docker pull consul

  獲取到映象之後,可以使用docker run執行,consul映象執行的相關引數可以參考官方的文件

  consul映象官方說明:https://registry.hub.docker.com/_/consul

  consul的官方文件:https://www.consul.io/docs

  直接使用docker run來啟動一個consul節點的叢集,如:

    # 不啟用acl時,可直接執行下面的命令,建立一個只有一個節點的consul叢集
    sudo docker run -id -expose=[8300,8301,8302,8500,8600] --restart always -p 18300:8300 -p 18301:8301 -p 18302:8302 -p 18500:8500 -p 18600:8600 --name server1 -e 'CONSUL_LOCAL_CONFIG={"
skip_leave_on_interrupt": true}' consul agent -server -bootstrap-expect=1 -node=server1 -bind=0.0.0.0 -client=0.0.0.0 -ui -datacenter dc1 # 啟用acl是,只需要修改上面-e引數,如下面的命令,其中token_value可自行設定 sudo docker run -id -expose=[8300,8301,8302,8500,8600] --restart always -p 18300:8300 -p 18301:8301 -p 18302:8302 -p 18500:8500 -p 18600:8600 --name server1 -e 'CONSUL_LOCAL_CONFIG={"
skip_leave_on_interrupt": true,"acl": {"enabled": true,"default_policy": "deny","down_policy": "extend-cache","tokens": {"master": "token_value"}}}' consul agent -server -bootstrap-expect=1 -node=server1 -bind=0.0.0.0 -client=0.0.0.0 -ui -datacenter dc1 各引數說明: -expose:暴露出出來的埠,即consul啟動所需的埠:8300,8301,8302,8500,8600 --restart:always表示容器掛了就自動重啟 -p:建立宿主機與容器的埠對映 --name:容器名稱 -e:環境變數,這裡用於對consul進行配置 consul:這是consul映象名,不是consul命令 agent:容器中執行的命令,各引數含義: -server:表示節點是server型別 -bootstrap-expect:表示叢集中有幾個server節點後開始選舉leader,既然是單節點叢集,那自然就是1了 -node:節點名稱 -bind:叢集內部通訊地址,預設是0.0.0.0 -client:客戶端地址,預設是127.0.0.1 -ui:啟用consul的web頁面管理 -datacenter:資料中心 更多配置參考:https://www.consul.io/docs/agent/options

  命令執行後,可以在瀏覽器上訪問宿主機上的18500埠(對映到容器的8500),就可以訪問到consul的web管理頁面了,如果啟動了acl,那麼需要點選右上角的登入進行授權,授權值即上面自己設定的token_value,之後頁面大概是這樣子的:

  

  如果是啟動一個多節點的consul叢集,docker run管理起來就會非常繁瑣,所以分享兩種簡單的管理方式:

  使用shell命令來管理

  自己可以寫一個shell檔案來時間叢集的管理,比如:  

  
#!/bin/bash

servers=3                     #server節點數
prefix_server="server"        #server節點名稱字首
clients=3                     #client節點數
prefix_client="client"        #client節點名稱字首
datacenter="dc1"              #資料中心
port_rpc=18100                #rpc埠(起始)(不包含)
port_lan=18200                #lan埠(起始)(不包含)
port_wan=18300                #wan埠(起始)(不包含)
port_http=18400               #http埠(起始)(不包含)
port_dns=18500                #dns埠(起始)(不包含)
network_name="net-consul"     #docker網路名稱
token=                        #認證token,可以使用guid,之後連線需要攜帶token

# 檢查網路是否存在
network_create(){
  if [ -z "$network_name" ];then
    echo network not exists
    exit 1
  fi
  
  if [ $(sudo docker network ls | grep -c "$network_name") -gt 0 ];then
    echo network [$network_name] exists
    return
  fi

  echo create network [$network_name]
  sudo docker network create --driver bridge $network_name > /dev/null
}

# 停止並刪除docker容器
node_down(){
  for i in $(seq 1 $2); do
    node_name="$1$i"
    sudo docker stop $node_name > /dev/null && sudo docker rm $node_name > /dev/null
    echo node [$node_name] removed
  done
}

# 停止執行docker容器
node_stop(){
  for i in $(seq 1 $2); do
    node_name="$1$i"
    sudo docker stop $node_name > /dev/null
    echo node [$node_name] stoped
  done
}

# 生成一組可用的埠
generate_ports(){
  port_rpc=`expr 1 + $port_rpc`
  port_lan=`expr 1 + $port_lan`
  port_wan=`expr 1 + $port_wan`
  port_http=`expr 1 + $port_http`
  port_dns=`expr 1 + $port_dns`
  
  p_rpc="$port_rpc:8300"
  p_lan="$port_lan:8301"
  p_wan="$port_wan:8302"
  p_http="$port_http:8500"
  p_dns="$port_dns:8600"
  
  bind_ports="-p $p_rpc -p $p_lan -p $p_wan -p $p_http -p $p_dns"
}

# 建立並執行叢集
consul_run(){  
  network_create
 
  if [ $servers -eq 0 ];then
    echo no servers
    exit 0
  fi
   
  common_agent="-bind=0.0.0.0 -client=0.0.0.0"
  common_docker="--network $network_name -expose=[8300,8301,8302,8500,8600] --restart always"
  
  #設定通用的環境變數
  if [ -z "$token" ];then
    e_server='CONSUL_LOCAL_CONFIG={"skip_leave_on_interrupt": true}'     # 不使用token 
  else 
    e_server='CONSUL_LOCAL_CONFIG=
    {
      "skip_leave_on_interrupt": true,
      "acl": {
        "enabled": true,
        "default_policy": "deny",
        "down_policy": "extend-cache",
        "tokens": {
          "master": "'$token'"
        }
      }
    }'
    echo server token:$token
  fi
  e_client='CONSUL_LOCAL_CONFIG={"leave_on_terminate": true}'
  
  # 建立並啟動server節點  
  for i in $(seq 1 $servers); do
    node_name="$prefix_server$i"  #節點名稱    

    generate_ports
    
    if [ $(sudo docker ps -a | grep -c "$node_name") -gt 0 ];then
      echo node [$node_name] exists
      continue
    fi

    node_join= 
    if [ $i -ne 1 ];then
      node_join="-join ${prefix_server}1"
    fi    
      
    sudo docker run -d $common_docker -e "$e_server" $bind_ports --name $node_name consul \
    agent -server -bootstrap-expect=$servers -node=$node_name $common_agent -ui -datacenter $datacenter $node_join > /dev/null
      
    echo "server node:[$node_name] is running => $p_rpc  $p_lan  $p_wan  $p_http  $p_dns"    
  done
  
  if [ $clients -gt 0 ];then
    sleep 3
  fi
  
  # 建立並啟動client節點
  for i in $(seq 0 `expr $clients - 1`); do
    node_name="$prefix_client`expr $i + 1`"
    
    if [ $(sudo docker ps -a | grep -c "$node_name") -gt 0 ];then
      echo node [$node_name] exists
      continue
    fi
    
    generate_ports    
    server_node="$prefix_server`expr $i % $servers + 1`"
    
    sudo docker run -d $common_docker -e "$e_client" $bind_ports --name $node_name consul \
    agent -node=$node_name $common_agent -retry-join=$server_node > /dev/null
    
    echo "client node:[$node_name] is running => $p_rpc  $p_lan  $p_wan  $p_http  $p_dns"
  done
}

consul_down(){
  node_down $prefix_client $clients   
  node_down $prefix_server $servers   
}

consul_start(){
  if [ $servers -le 0 ];then
    echo invalid servers
    exit 2
  fi

  for i in $(seq 1 $servers); do
    node_name="$prefix_server$i"
    sudo docker start $node_name > /dev/null 
    echo node [$node_name] started
  done
  
  if [ $clients -gt 0 ];then
    sleep 3
  fi

  for i in $(seq 1 $clients); do
    node_name="$prefix_client$i"
    server_node_name="$prefix_server`expr $i % $servers + 1`"
    sudo docker start $node_name > /dev/null
    echo node [$node_name] started
  done
}

consul_stop(){
  node_stop $prefix_client $clients   
  node_stop $prefix_server $servers   
}

consul_up(){
  consul_run
  sleep 3
  consul_status
}

consul_restart(){
  consul_stop
  sleep 3
  consul_start
}

consul_logs(){
  sudo docker logs $1
}

consul_status(){
  para_token=
  if [ -n "$token" ];then
    para_token="-token $token"
  fi
  # 檢測並等待leader選舉
  consul_exec consul operator raft list-peers $para_token > /dev/null
  consul_exec consul members $para_token
}

consul_exec(){
    sudo docker exec -i ${prefix_server}1 $@
}


if [ ! -z "$1" ];then
  _args=$@
  _index=`expr index "$_args" " "`
  _args=`echo ${_args:$_index}`
  consul_$1 $_args
  exit 0
fi

echo "
Usage:    $0 COMMAND

可用命令:
start    啟動叢集
stop     停止叢集服務
up       建立並啟動叢集
run      建立並啟動叢集
down     停止並刪除叢集
status   檢視叢集容器節點資訊
logs     輸出指定節點的日誌
exec     在叢集中的首個節點執行指定的命令
restart  重新啟動叢集"
consul.sh

  賦值上面的程式碼到一個sh檔案,比如叫consul.sh,其中,檔案開頭是幾個配置,可以修改:  

    servers=3                     #server節點數
    prefix_server="server"        #server節點名稱字首
    clients=3                     #client節點數
    prefix_client="client"        #client節點名稱字首
    datacenter="dc1"              #資料中心
    port_rpc=18100                #rpc埠(起始)(不包含)
    port_lan=18200                #lan埠(起始)(不包含)
    port_wan=18300                #wan埠(起始)(不包含)
    port_http=18400               #http埠(起始)(不包含)
    port_dns=18500                #dns埠(起始)(不包含)
    network_name="net-consul"     #docker網路名稱
    token=                        #認證token,可以使用guid,之後連線需要攜帶token

  然後進行下面的操作:  

    # 賦予可執行的許可權,指令碼需要使用/bin/bash來執行,如果使用sh執行可能會報錯,sh預設使用/bin/dash執行
    sudo chmod +x consul.sh 
    # 啟動
    ./consul.sh up
    # 檢視狀態
    ./consul.sh status
    # 停止並刪除
    ./consul.sh down

  如,啟動後:

  

  然後可以在瀏覽器上訪問陣列機上對應server節點的8500埠的埠,比如這裡的18401,18402,18403,就是開啟consul的web管理頁面了,如果需要token,就是檔案中配置的token引數

  使用docker-compose來管理

  使用shell命令來管理可以很靈活的拓展,以及實現自己的需求,但是需要自行編碼比較繁瑣,如果需要拓展自己的一些功能,可以使用docker-compose來管理,如下面的內容複製到一個docker-compose.yml檔案中:  

  
# yaml 配置
version: '2'
services:
    server1:
        image: consul
        restart: always
        container_name: server1
        ports:
            - 18101:8300
            - 18201:8301
            - 18301:8302
            - 18401:8500
            - 18501:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        command: agent -server -bootstrap-expect=3 -node=server1 -bind=0.0.0.0 -client=0.0.0.0 -ui -datacenter dc1 
        environment:
            # 不啟用acl
            #CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true}'
            # 啟用acl,下面的token_value是token值,可自行設定
            CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true,"acl": {"enabled": true,"default_policy": "deny","down_policy": "extend-cache","tokens": {"master": "token_value"}}}'        
    server2:
        image: consul
        restart: always
        container_name: server2
        ports:
            - 18102:8300
            - 18202:8301
            - 18302:8302
            - 18402:8500
            - 18502:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        depends_on:
            - server1
        command: agent -server -bootstrap-expect=3 -node=server2 -bind=0.0.0.0 -client=0.0.0.0 -ui -datacenter dc1 -join server1
        environment:
            # 不啟用acl
            #CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true}'
            # 啟用acl,下面的token_value是token值,可自行設定
            CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true,"acl": {"enabled": true,"default_policy": "deny","down_policy": "extend-cache","tokens": {"master": "token_value"}}}'    
    server3:
        image: consul
        restart: always
        container_name: server3
        ports:
            - 18103:8300
            - 18203:8301
            - 18303:8302
            - 18403:8500
            - 18503:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        depends_on:
            - server1
        command: agent -server -bootstrap-expect=3 -node=server3 -bind=0.0.0.0 -client=0.0.0.0 -ui -datacenter dc1 -join server1
        environment:
            # 不啟用acl
            #CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true}'
            # 啟用acl,下面的token_value是token值,可自行設定
            CONSUL_LOCAL_CONFIG: '{"skip_leave_on_interrupt": true,"acl": {"enabled": true,"default_policy": "deny","down_policy": "extend-cache","tokens": {"master": "token_value"}}}' 
    client1:
        image: consul
        restart: always
        container_name: client1
        ports:
            - 18104:8300
            - 18204:8301
            - 18304:8302
            - 18404:8500
            - 18504:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        depends_on:
            - server1
        command: agent -node=client1 -bind=0.0.0.0 -client=0.0.0.0 -retry-join=server1
        environment:
            CONSUL_LOCAL_CONFIG: '{"leave_on_terminate": true}'
    client2:
        image: consul
        restart: always
        container_name: client2
        ports:
            - 18105:8300
            - 18205:8301
            - 18305:8302
            - 18405:8500
            - 18505:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        depends_on:
            - server2
        command: agent -node=client2 -bind=0.0.0.0 -client=0.0.0.0 -retry-join=server2
        environment:
            CONSUL_LOCAL_CONFIG: '{"leave_on_terminate": true}'
    client3:
        image: consul
        restart: always
        container_name: client3
        ports:
            - 18106:8300
            - 18206:8301
            - 18306:8302
            - 18406:8500
            - 18506:8600
        expose:
            - 8300
            - 8301
            - 8302
            - 8500
            - 8600
        depends_on:
            - server3
        command: agent -node=client3 -bind=0.0.0.0 -client=0.0.0.0 -retry-join=server3
        environment:
            CONSUL_LOCAL_CONFIG: '{"leave_on_terminate": true}'      
docker-compose.yml

  然後可以使用docker-compose來啟動和停止

    # 啟動
    sudo docker-compose up -d
    # 停止
    sudo docker-compose down

  啟動後,如:

  

  同樣的,這時可以在瀏覽器上訪問陣列機上對應server節點的8500埠的埠,比如這裡的18401,18402,18403,就是開啟consul的web管理頁面了,如果需要token,就是檔案中配置的token引數

一個專注於.NetCore的技術小白