HashiCorp 公司推出的Consul是一款分布式高可用服务治理与服务配置的工具。关于其配置与使用可以参考这篇文章 consul 简介与配置说明

一般,我们会在多台主机上安装并启动 consul,在开发时这可能会比较不方便,所以这里介绍如何使用 vagrant 和 docker 来简化开发环境的搭建。

利用 vagrant 创建虚拟机


Vagrant 是 HashiCorp 公司的产品, 用于创建和部署虚拟化开发环境,支持常见的操作系统。由于其安装比较简单,参照官方文档即可,此处不再赘述。

安装完成后,我们创建文件夹consul,在consul文件夹下创建一个文件Vagrantfile,内如如下:

# -*- 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

这里我们创建了三个虚拟机,hostname为 n1,n2,n3;ip分别为 172.20.20.10,172.20.20.11,172.20.20.10,使用镜像 ubuntu/xenial64,并且将镜像更新为了阿里云,安装了一些必须的软件。

编辑好该文件,在命令行运行 vagrant up,出去喝杯咖啡,你的机器上就会启动三台对应的虚拟机了。如果你不想使用ubuntu 16.04,还可以更换其他的操作系统。

在 consul 文件夹下使用 vagrant ssh命令,就可以登录到对应的虚拟机了:

➜  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:~$

配置运行consul的docker容器


docker的安装请参照这里docker安装。需要注意,鉴于 dockerhub 在国内丧心病狂的访问速度,我们一般会选择使用国内的镜像,如阿里云、网易蜂巢等。

安装好了docker后,我们以 n1 虚拟机为例,说明如何在虚拟机上使用docker容器来运行consul。

首先,创建一个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为基础构建docker容器。然后设置使用阿里云镜像,安装各种工具,下载 consul 并创建 consul 使用的 ui 文件夹。然后声明暴露8个 consul 需要使用的 tcp 或 udp 端口,并将 /data 设置为一个 VOLUME (通过--volumes-from可以在容器之间共享数据)。 最后,注意 ENTRYPOINT 声明了容器启动时执行的命令,而在启动容器时加上的命令会被添加在 ENTRYPOINT 指定的命令后,比如ENTRYPOINT为 [ "/usr/sbin/consul", "agent", "-config-dir=/config" ],启动镜像时的命令为 sudo docker run <镜像名称> XXXX,则容器启动时执行的命令为 /usr/sbin/consul agent -config-dir=/config XXXX

另外,为了使用 consul,我们也需要编辑其配置文件 consul.json。这里我们使用一个比较简单的配置,有特殊需要的请参阅 consul 官方文档的配置说明。

{
"data_dir": "/data",
"ui_dir": "/webui",
"client_addr": "0.0.0.0",
"ports": {
"dns": 53
},
"recursor": "8.8.8.8"
}

编辑好这2个文件后,在consul文件夹下执行命令 sudo docker build -t millions/consul . 即可创建镜像 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

而后在其他虚拟机使用同样方法创建镜像。为了方便启动 docker 镜像,我们再在每台虚拟机上创建以下环境变量:

# 在 Vagrantfile 中指定的ip,对于n1为172.20.20.10
export PUBLIC_IP="$(ifconfig enp0s8 | awk -F ' *|:' '/inet addr/{print $4}')"

而后,由于我们打算用n1做 bootstrap 时的leader,所以在 n2、n3 上创建环境变量:

export JOIN_IP=172.20.20.10

接下来,我们就可以准备启动 consul 实例们啦~

启动 consul 实例

注意启动时需要使用 -h $HOSTNAME 指定容器的hostname。首先我们启动 n1,由于用其做 bootstrap, 所以我们使用了 -bootstrap-expect 3。其他相关启动参数如果不熟悉的话可以查看 consul 的文档,这里不做详细解释。比较重要的是需要额外设置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 的输出发现其已经启动,但是还无法组成集群:

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 参数):

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参数而不是 bootstrap-expect。都完成启动后在物理机上访问 http://172.20.20.10:8500 即可看到熟悉的consul web-ui 界面。至此,我们的 consul 集群开发环境就搭建完成了,我们可以使用其他各种程序将自己作为服务注册到 consul 集群中,并且访问集群获取其他服务地址。

测试


为了测试集群是否可以正常工作,我们再创建其他2个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 的内容为:

require 'rubygems'
require 'sinatra' get '/' do
"Hello World!"
end run Sinatra::Application

uwsgi-consul.ini 的内容为:

[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

而后创建镜像:

sudo docker build -t millions/distributed_app .

我们创建好镜像后,在 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个名为distributed_app的服务。

web-ui

我们使用一个脚本来进行测试,为了再温习一下 docker,我们还是将其放在一个 docker 容器中运行,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两种方式来获取服务:

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

创建好镜像:

sudo docker build -t millions/distributed_client .

运行之:

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 的结果,可以看到获取了 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

总结


至此,我们的consul 集群开发环境就搭建好了。关机前不要忘记用 vagrant halt 或者 vagrant suspend 关闭或暂停你的虚拟机哦~

作者:millions_chan
链接:https://www.jianshu.com/p/52f4ea31aa1b
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

vagrant+docker搭建consul集群开发环境的更多相关文章

  1. 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介      在第七篇文章<庐山真面目之七微服务架构Consul ...

  2. 如何基于Jupyter notebook搭建Spark集群开发环境

    摘要:本文介绍如何基于Jupyter notebook搭建Spark集群开发环境. 本文分享自华为云社区<基于Jupyter Notebook 搭建Spark集群开发环境>,作者:apr鹏 ...

  3. Docker学习-Docker搭建Consul集群

    1.环境准备 Linux机器三台 网络互通配置可以参考 https://www.cnblogs.com/woxpp/p/11858257.html 192.168.50.21 192.168.50.2 ...

  4. 使用Docker搭建consul集群+registrator实现服务自动注册。

    准备工作:10.173.16.83 master10.172.178.76 node110.171.19.139 node210.162.204.252 node3 一.安装consul-cluste ...

  5. docker搭建etcd集群环境

    其实关于集群网上说的方案已经很多了,尤其是官网,只是这里我个人只有一个虚拟机,在开发环境下建议用docker-compose来搭建etcd集群. 1.拉取etcd镜像 docker pull quay ...

  6. Docker 搭建 etcd 集群

    阅读目录: 主机安装 集群搭建 API 操作 API 说明和 etcdctl 命令说明 etcd 是 CoreOS 团队发起的一个开源项目(Go 语言,其实很多这类项目都是 Go 语言实现的,只能说很 ...

  7. Docker搭建RabbitMQ集群

    Docker搭建RabbitMQ集群 Docker安装 见官网 RabbitMQ镜像下载及配置 见此博文 集群搭建 首先,我们需要启动运行RabbitMQ docker run -d --hostna ...

  8. hadoop-2.6.0集群开发环境配置

    hadoop-2.6.0集群开发环境配置 一.环境说明 1.1安装环境说明 本例中,操作系统为CentOS 6.6, JDK版本号为JDK 1.7,Hadoop版本号为Apache Hadoop 2. ...

  9. Docker安装Consul集群

    Docker 安装Consul集群 使用windows 环境,Docker desktop community 构建consul集群. 1.docker 容器网络 docker安装后,默认会创建三种网 ...

随机推荐

  1. Base64编码的 换行 转义

    用Base64编码的时候如果出现\n 之类的字符,java中转义. 当字符串过长(一般超过76)时会自动在中间加一个换行符,字符串最后也会加一个换行符.导致和其他模块对接时结果不一致. 解决方法:将  ...

  2. hihoCoder1599 bfs

    特殊的剪枝,整体上和辗转相除法有点像 #1599 : 逃离迷宫4 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi被坏女巫抓进一座由无限多个格子组成的矩阵迷宫. 小 ...

  3. BZOJ2753 SCOI2012 滑雪与时间胶囊 【最小生成树】*

    BZOJ2753 SCOI2012 滑雪与时间胶囊 Description a180285非常喜欢滑雪.他来到一座雪山,这里分布着M条供滑行的轨道和N个轨道之间的交点(同时也是景点),而且每个景点都有 ...

  4. Working out

    Summer is coming! It's time for Iahub and Iahubina to work out, as they both want to look hot at the ...

  5. idea Java spring 入门 demo

    根据这个 来实现 理解 https://www.cnblogs.com/xing901022/p/3963962.html 这里没有说如何导入包,现在我们用 idea 来实现 新建项目结构后 RUN ...

  6. [LeetCode系列]N皇后问题递归解法 -- 位操作方式

    N皇后问题: 给定8*8棋盘, 放置n个皇后, 使其互相不能攻击(即2个皇后不能放在同一行/列/正反对角线上), 求解共有多少种放置方式? 这个问题的解答网上有不少, 但是位操作解法的我看到的不多. ...

  7. Linux之 手动释放内存

    我们在进程中要怎样去描述一个文件呢?我们用目录项(dentry)和索引节点(inode).它们的定义如下: 所谓"文件", 就是按一定的形式存储在介质上的信息,所以一个文件其实包含 ...

  8. js前台调用lodop打印

    lodop简单介绍 lodop的打印功能已经非常强大,也在带web端的图形界面,可以供用户使用.使用js在前台调用lodop打印,一般分为两种方法: 1:特殊的指令打印,这种打印方式,是采用的与js无 ...

  9. vuejs2.0的生命周期解读

    每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer).编译模版.挂载实例到 DOM ,然后在数据变化时更新 DOM .下图展示的就是一个v ...

  10. Extjs tree1

    1.代码如下: 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...