HashiCorp 公司推出的Consul是一款分布式高可用服務(wù)治理與服務(wù)配置的工具兆旬。關(guān)于其配置與使用可以參考這篇文章 consul 簡介與配置說明抄瓦。
一般彼妻,我們會在多臺主機(jī)上安裝并啟動 consul其爵,在開發(fā)時(shí)這可能會比較不方便咖耘,所以這里介紹如何使用 vagrant 和 docker 來簡化開發(fā)環(huán)境的搭建。
利用 vagrant 創(chuàng)建虛擬機(jī)
Vagrant 是 HashiCorp 公司的產(chǎn)品蜀踏, 用于創(chuàng)建和部署虛擬化開發(fā)環(huán)境维蒙,支持常見的操作系統(tǒng)。由于其安裝比較簡單果覆,參照官方文檔即可颅痊,此處不再贅述。
安裝完成后局待,我們創(chuàng)建文件夾consul八千,在consul文件夾下創(chuàng)建一個(gè)文件Vagrantfile,內(nèi)如如下:
# -*- mode: ruby -*-
# vi: set ft=ruby :
$script = <<SCRIPT
echo "Installing dependencies ..."
# 使用阿里云鏡像
sudo sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
sudo apt-get update
sudo apt-get install -y unzip curl jq
SCRIPT
# Specify a custom Vagrant box for the demo
DEMO_BOX_NAME = "ubuntu/xenial64"
# Vagrantfile API/syntax version.
# NB: Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = "2"
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.box = DEMO_BOX_NAME
config.vm.provision "shell",
inline: $script
config.vm.define "n1" do |n1|
n1.vm.hostname = "n1"
n1.vm.network "private_network", ip: "172.20.20.10"
end
config.vm.define "n2" do |n2|
n2.vm.hostname = "n2"
n2.vm.network "private_network", ip: "172.20.20.11"
end
config.vm.define "n3" do |n3|
n3.vm.hostname = "n3"
n3.vm.network "private_network", ip: "172.20.20.12"
end
end
這里我們創(chuàng)建了三個(gè)虛擬機(jī)燎猛,hostname為 n1恋捆,n2,n3重绷;ip分別為 172.20.20.10沸停,172.20.20.11,172.20.20.10昭卓,使用鏡像 ubuntu/xenial64愤钾,并且將鏡像更新為了阿里云瘟滨,安裝了一些必須的軟件。
編輯好該文件能颁,在命令行運(yùn)行 vagrant up
杂瘸,出去喝杯咖啡,你的機(jī)器上就會啟動三臺對應(yīng)的虛擬機(jī)了伙菊。如果你不想使用ubuntu 16.04败玉,還可以更換其他的操作系統(tǒng)。
在 consul 文件夾下使用 vagrant ssh命令镜硕,就可以登錄到對應(yīng)的虛擬機(jī)了:
? consul vagrant ssh n2
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.4.0-66-generic x86_64)
0 packages can be updated.
0 updates are security updates.
Last login: Tue Mar 28 04:13:00 2017 from 10.0.2.2
ubuntu@n2:~$
配置運(yùn)行consul的docker容器
docker的安裝請參照這里docker安裝运翼。需要注意,鑒于 dockerhub 在國內(nèi)喪心病狂的訪問速度兴枯,我們一般會選擇使用國內(nèi)的鏡像血淌,如阿里云、網(wǎng)易蜂巢等财剖。
安裝好了docker后悠夯,我們以 n1 虛擬機(jī)為例,說明如何在虛擬機(jī)上使用docker容器來運(yùn)行consul躺坟。
首先疗疟,創(chuàng)建一個(gè)consul文件夾,然后編輯 Dockerfile:
FROM phusion/baseimage:latest
MAINTAINER millions <chenzhesp@gmail.com>
RUN DEBIAN_FRONTEND=noninteractive
RUN locale-gen en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENV LC_CTYPE=UTF-8
ENV LANG=en_US.UTF-8
ENV TERM xterm
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get -qq install curl unzip
ADD https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip /tmp/consul.zip
RUN cd /usr/sbin && unzip /tmp/consul.zip && chmod +x /usr/sbin/consul && rm /tmp/consul.zip
ADD consul.json /config/
ADD https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_web_ui.zip /tmp/webui.zip
RUN mkdir /webui && unzip /tmp/webui.zip -d /webui/ && rm /tmp/webui.zip
EXPOSE 8300 8301 8301/udp 8302 8302/udp 8400 8500 53/udp
VOLUME ["/data"]
ENTRYPOINT [ "/usr/sbin/consul", "agent", "-config-dir=/config" ]
CMD []
大約解釋一下上面的Dockerfile。首先,我們選擇phusion/baseimage為基礎(chǔ)構(gòu)建docker容器褪贵。然后設(shè)置使用阿里云鏡像亏吝,安裝各種工具,下載 consul 并創(chuàng)建 consul 使用的 ui 文件夾裹刮。然后聲明暴露8個(gè) consul 需要使用的 tcp 或 udp 端口音榜,并將 /data 設(shè)置為一個(gè) VOLUME (通過--volumes-from可以在容器之間共享數(shù)據(jù))。 最后捧弃,注意 ENTRYPOINT 聲明了容器啟動時(shí)執(zhí)行的命令赠叼,而在啟動容器時(shí)加上的命令會被添加在 ENTRYPOINT 指定的命令后,比如ENTRYPOINT為 [ "/usr/sbin/consul", "agent", "-config-dir=/config" ]
违霞,啟動鏡像時(shí)的命令為 sudo docker run <鏡像名稱> XXXX
嘴办,則容器啟動時(shí)執(zhí)行的命令為 /usr/sbin/consul agent -config-dir=/config XXXX
。
另外买鸽,為了使用 consul涧郊,我們也需要編輯其配置文件 consul.json。這里我們使用一個(gè)比較簡單的配置眼五,有特殊需要的請參閱 consul 官方文檔的配置說明妆艘。
{
"data_dir": "/data",
"ui_dir": "/webui",
"client_addr": "0.0.0.0",
"ports": {
"dns": 53
},
"recursor": "8.8.8.8"
}
編輯好這2個(gè)文件后彤灶,在consul文件夾下執(zhí)行命令 sudo docker build -t millions/consul .
即可創(chuàng)建鏡像 millions/consul,通過 docker images
命令可以查看批旺。
ubuntu@n1:~/consul$ sudo docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
millions/consul latest 5fc1597b91cf 23 hours ago 372 MB
phusion/baseimage latest b6b482650b50 7 days ago 247 MB
而后在其他虛擬機(jī)使用同樣方法創(chuàng)建鏡像幌陕。為了方便啟動 docker 鏡像,我們再在每臺虛擬機(jī)上創(chuàng)建以下環(huán)境變量:
# 在 Vagrantfile 中指定的ip汽煮,對于n1為172.20.20.10
export PUBLIC_IP="$(ifconfig enp0s8 | awk -F ' *|:' '/inet addr/{print $4}')"
而后搏熄,由于我們打算用n1做 bootstrap 時(shí)的leader,所以在 n2逗物、n3 上創(chuàng)建環(huán)境變量:
export JOIN_IP=172.20.20.10
接下來搬卒,我們就可以準(zhǔn)備啟動 consul 實(shí)例們啦~
啟動 consul 實(shí)例
注意啟動時(shí)需要使用 -h $HOSTNAME
指定容器的hostname。首先我們啟動 n1翎卓,由于用其做 bootstrap契邀, 所以我們使用了 -bootstrap-expect 3
。其他相關(guān)啟動參數(shù)如果不熟悉的話可以查看 consul 的文檔失暴,這里不做詳細(xì)解釋坯门。比較重要的是需要額外設(shè)置dns,首先使用本地 docker0 來使用 consul 解析 DNS逗扒,然后使用 8.8.8.8解析其他請求的dns,最后為 consul 的查詢指定搜索域矩肩。
sudo docker run -d -h $HOSTNAME -p 8300:8300 \
-p 8301:8301 -p 8301:8301/udp -p 8302:8302 \
-p 8302:8302/udp -p 8400:8400 -p 8500:8500 \
-p 53:53/udp --name n1 \
--dns 172.17.0.1 --dns 8.8.8.8 \
--dns-search 'service.consul' millions/consul \
-server -advertise $PUBLIC_IP -bootstrap-expect 3
這是查看 n1 的輸出發(fā)現(xiàn)其已經(jīng)啟動黍檩,但是還無法組成集群:
ubuntu@n1:~/consul$ sudo docker logs n1
==> WARNING: Expect Mode enabled, expecting 3 servers
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
Version: 'v0.7.5'
Node ID: 'cedd93d8-4ff4-4bde-8bb4-391f5a129ed4'
Node name: 'n1'
Datacenter: 'dc1'
Server: true (bootstrap: false)
Client Addr: 0.0.0.0 (HTTP: 8500, HTTPS: -1, DNS: 53, RPC: 8400)
Cluster Addr: 172.20.20.10 (LAN: 8301, WAN: 8302)
Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false
Atlas: <disabled>
接下來喳逛,我們來啟動 n2 還有 n3(注意修改 --name 參數(shù)):
sudo docker run -d -h $HOSTNAME \
-p 8300:8300 -p 8301:8301 -p 8301:8301/udp \
-p 8302:8302 -p 8302:8302/udp -p 8400:8400 \
-p 8500:8500 -p 53:53/udp --name n2 \
-dns 172.17.0.1 --dns 8.8.8.8 \
--dns-search 'service.consul' millions/consul \
-server -advertise $PUBLIC_IP -join $JOIN_IP
這里作為后來加入者我們使用 -join參數(shù)而不是 bootstrap-expect润文。都完成啟動后在物理機(jī)上訪問 http://172.20.20.10:8500 即可看到熟悉的consul web-ui 界面典蝌。至此赠法,我們的 consul 集群開發(fā)環(huán)境就搭建完成了砖织,我們可以使用其他各種程序?qū)⒆约鹤鳛榉?wù)注冊到 consul 集群中,并且訪問集群獲取其他服務(wù)地址新锈。
測試
為了測試集群是否可以正常工作妹笆,我們再創(chuàng)建其他2個(gè)docker 鏡像拳缠。
distributed_app
Dockerfile為:
ROM phusion/baseimage:latest
MAINTAINER millions <chenzhesp@gmail.com>
RUN DEBIAN_FRONTEND=noninteractive
RUN locale-gen en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENV LC_CTYPE=UTF-8
ENV LANG=en_US.UTF-8
ENV TERM xterm
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get -qq install ruby-dev git libcurl4-openssl-dev curl build-essential python
RUN gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
RUN gem install --no-ri --no-rdoc uwsgi sinatra
RUN mkdir -p /opt/distributed_app
WORKDIR /opt/distributed_app
RUN uwsgi --build-plugin https://github.com/unbit/uwsgi-consul
ADD uwsgi-consul.ini /opt/distributed_app/
ADD config.ru /opt/distributed_app/
ENTRYPOINT [ "uwsgi", "--ini", "uwsgi-consul.ini", "--ini", "uwsgi-consul.ini:server1", "--ini", "uwsgi-consul.ini:server2" ]
CMD []
config.ru 的內(nèi)容為:
require 'rubygems'
require 'sinatra'
get '/' do
"Hello World!"
end
run Sinatra::Application
uwsgi-consul.ini 的內(nèi)容為:
[uwsgi]
plugins = consul
socket = 127.0.0.1:9999
master = true
enable-threads = true
[server1]
consul-register = url=http://%h.node.consul:8500,name=distributed_app,id=server1,port=2001
mule = config.ru
[server2]
consul-register = url=http://%h.node.consul:8500,name=distributed_app,id=server2,port=2002
mule = config.ru
而后創(chuàng)建鏡像:
sudo docker build -t millions/distributed_app .
我們創(chuàng)建好鏡像后绵疲,在 n1 和 n2 上分別啟動該容器:
sudo docker run -h $HOSTNAME -d --name n1-distributed \
--dns 172.17.0.1 --dns 8.8.8.8 \
--dns-search 'service.consul' millions/distributed_app
完成之后可以在 web-ui 上看到 n1 和 n2 上各有2個(gè)名為distributed_app的服務(wù)盔憨。
我們使用一個(gè)腳本來進(jìn)行測試郁岩,為了再溫習(xí)一下 docker问慎,我們還是將其放在一個(gè) docker 容器中運(yùn)行蝴乔,Dockerfile 如下薇正,注意我們替換了使用了淘寶的 ruby source 來加速:
FROM phusion/baseimage:latest
MAINTAINER millions <chenzhesp@gmail.com>
RUN DEBIAN_FRONTEND=noninteractive
RUN locale-gen en_US.UTF-8
ENV LANGUAGE=en_US.UTF-8
ENV LC_ALL=en_US.UTF-8
ENV LC_CTYPE=UTF-8
ENV LANG=en_US.UTF-8
ENV TERM xterm
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
RUN apt-get update -y
RUN apt-get upgrade -y
RUN apt-get -qq install ruby ruby-dev build-essential
RUN gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
RUN gem install --no-ri --no-rdoc json
RUN mkdir -p /opt/distributed_client
ADD client.rb /opt/distributed_client/
WORKDIR /opt/distributed_client
ENTRYPOINT [ "ruby", "/opt/distributed_client/client.rb" ]
CMD []
ruby 腳本如下,分別使用了http和dns兩種方式來獲取服務(wù):
require "rubygems"
require "json"
require "net/http"
require "uri"
require "resolv"
empty = "There are no distributed applications registered in Consul"
uri = URI.parse("http://consul.service.consul:8500/v1/catalog/service/distributed_app")
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Get.new(uri.request_uri)
while true
response = http.request(request)
if response.body == "{}"
puts empty
sleep(1)
elsif
result = JSON.parse(response.body)
result.each do |service|
puts "Application #{service['ServiceName']} with element #{service["ServiceID"]} on port #{service["ServicePort"]} found on node #{service["Node"]} (#{service["Address"]})."
sleep(1)
end
end
end
創(chuàng)建好鏡像:
sudo docker build -t millions/distributed_client .
運(yùn)行之:
sudo docker run -h $HOSTNAME -d --name n3-distributed \
--dns 172.17.0.1 --dns 8.8.8.8 \
--dns-search 'service.consul' millions/distributed_client
使用 sudo docker logs n3-distributed
命令,可以查看到:
ubuntu@n3:~$ sudo docker logs n3-distributed
Application distributed_app with element server1 on port 2001 found on node n1 (172.20.20.10).
Application distributed_app with element server2 on port 2002 found on node n1 (172.20.20.10).
Application distributed_app with element server1 on port 2001 found on node n2 (172.20.20.11).
Application distributed_app with element server2 on port 2002 found on node n2 (172.20.20.11).
或者可以使用 dns 來向 consul 查詢 ip 以及 port疾渣,我們利用 dig 命令查看 dns 的結(jié)果榴捡,可以看到獲取了 port 以及 n1 和 n2 的 ip:
ubuntu@n3:~$ dig @172.17.0.1 distributed_app.service.consul SRV
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @172.17.0.1 distributed_app.service.consul SRV
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30551
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 2
;; QUESTION SECTION:
;distributed_app.service.consul. IN SRV
;; ANSWER SECTION:
distributed_app.service.consul. 0 IN SRV 1 1 2001 n2.node.dc1.consul.
distributed_app.service.consul. 0 IN SRV 1 1 2001 n1.node.dc1.consul.
distributed_app.service.consul. 0 IN SRV 1 1 2002 n1.node.dc1.consul.
;; ADDITIONAL SECTION:
n2.node.dc1.consul. 0 IN A 172.20.20.11
n1.node.dc1.consul. 0 IN A 172.20.20.10
;; Query time: 0 msec
;; SERVER: 172.17.0.1#53(172.17.0.1)
;; WHEN: Tue Mar 28 14:41:34 UTC 2017
;; MSG SIZE rcvd: 155
總結(jié)
至此吊圾,我們的consul 集群開發(fā)環(huán)境就搭建好了项乒。關(guān)機(jī)前不要忘記用 vagrant halt
或者 vagrant suspend
關(guān)閉或暫停你的虛擬機(jī)哦~