假设我们写的代码会调用 REST API 或者 Thrift API 的服务。为了完成一次请求,代码需要知道服务实例的网络位置(IP 地址和端口)。
运行在物理硬件上的传统应用中,服务实例的网络位置是相对固定的,代码能从一个偶尔更新的配置文件中读取网络位置。
对于基于云端的、现代化的微服务应用而言,这却是一大难题。将容器应用部署到集群时,其服务地址是由集群系统动态分配的。那么,当我们需要访问这个服务时,如何确定它的地址呢?这时就需要服务发现(Service Discovery)了。
Docker+Consul+registrator实现服务发现
实验环境
Docker01 192.168.2.10
Docker02 192.168.2.20
Docker03 192.168.2.30
关闭防火墙和selinux。consul_1.5.1_linux_amd64.zip
[root@docker01 ~]# unzip consul_1.5.1_linux_amd64.zip
[root@docker01 ~]# mv consul /usr/local/bin/
[root@docker01 ~]# chmod +x /usr/local/bin/consul
[root@docker01 ~]# consul --help ##确认命令可用
1)在docker01上启动consul服务
//启动consul
[root@docker01 ~]# consul agent -server -bootstrap \
-ui -data-dir=/var/lib/consul-data \
-bind=192.168.2.10 \
-client=0.0.0.0 \
-node=master
后台运行
[root@docker01 ~]# nohup consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=192.168.2.10 -client=0.0.0.0 -node=master &
[1] 17633
[root@docker01 ~]# nohup: 忽略输入并把输出追加到"nohup.out
PS://-bootstrap:加入这个选项时,一般都在server单节点的时候用,自选举为leader。
-ui:开启内部的web页面 -data-dir:key/volum数据存储位置
-bind:指定开启服务的IP
-client:指定访问的客户端
-node:指定集群内通信使用的名称。默认是主机名
PS:开启的端口
8300 集群节点
8301 集群内部的访问
8302 跨数据中心的通信
8500 web ui 界面
8600 使用dns协议查看节点信息的端口
//查看consul的信息
[root@docker01 ~]# consul info
leader_addr = 192.168.2.10:8300
//查看集群内成员的信息
[root@docker01 ~]# consul members
Node Address Status Type Build Protocol DC Segment
master 192.168.2.10:8301 alive server 1.5.1 2 dc1 <all>
2)docker02、docker03,加入consul集群
这里我们采用容器的方式去运行consul服务。myprogrium-consul.tar
docker load < myprogrium-consul.tar
报错重启docker:
Systemctl restart docker
[root@docker02 ~]# docker run -d --name consul -p 8301:8301 -p 8301:8301/udp -p 8500:8500 -p 8600:8600/udp --restart always progrium/consul:latest -join 192.168.2.10 -advertise 192.168.2.20 -client 0.0.0.0 -node=node01
[root@docker03 ~]# docker run -d --name consul -p 8301:8301 -p 8301:8301/udp -p 8500:8500 -p 8600:8600/udp --restart always progrium/consul:latest -join 192.168.2.10 -advertise 192.168.2.30 -client 0.0.0.0 -node=node02
[root@docker01 ~]# consul members ##可查询到3台主机
浏览器访问本机的8500端口
3)下载部署consul-template
consul-template_0.19.5_linux_amd64.zip
[root@docker01 ~]# unzip consul-template_0.19.5_linux_amd64.zip
[root@docker01 ~]# mv consul-template /usr/local/bin/
[root@docker01 ~]# chmod +x /usr/local/bin/consul-template
4)docker02、docker03上部署registrator服务
registrator是一个能自动发现docker container提供的服务,并在后端服务注册中心注册服务或取消服务的工具,后端注册中心支持conusl、etcd、skydns2、zookeeper等。
myregistrator.tar
[root@docker02 ~]# docker load < myregistrator.tar
[root@docker02 ~]# docker run -d \
--name registrator \
-v /var/run/docker.sock:/tmp/docker.sock \
--restart always \
gliderlabs/registrator \
consul://192.168.2.20:8500
[root@docker03 ~]# docker load < myregistrator.tar
[root@docker03 ~]# docker run -d \
--name registrator \
-v /var/run/docker.sock:/tmp/docker.sock \
--restart always \
gliderlabs/registrator \
consul://192.168.2.30:8500
Docker2上创建一个nginx容器
[root@docker02 ~]# docker run -d -P --name test nginx
验证conusl上的nginx服务
5)docker01部署一个ngixn服务
[root@docker01 ~]# yum -y install gcc openssl openssl-devel zlib zlib-devel pcre pcre-devel
[root@docker01 ~]# useradd -M -s /sbin/nologin nginx
[root@docker01 ~]# tar zxf nginx-1.14.0.tar.gz
[root@docker01 ~]# cd nginx-1.14.0/
nginx-1.14.0.tar.gz
[root@docker01 nginx-1.14.0]# ./configure --user=nginx --group=nginx \
--with-http_stub_status_module --with-http_realip_module --with-pcre --with-http_ssl_module
[root@docker01 nginx-1.14.0]# make && make install
[root@docker01 nginx-1.14.0]# ln -s /usr/local/nginx/sbin/* /usr/local/bin/
[root@docker01 nginx-1.14.0]# nginx -t
[root@docker01 nginx-1.14.0]# nginx
PS:这里nginx作为反向代理,代理后端docker02、docker03上nginx的容器服务,所以我们先去docker02、docker03上部署一些服务,为了方便等会回看到负载的效果,所以,我们运行完成容器之后,做一个主界面内容的区分
Docker02:web01 web02
[root@docker02 ~]# docker run -itd --name web01 -P nginx:latest
[root@docker02 ~]# docker exec -it web01 /bin/bash
root@b47619f3f7ae:/# echo The web container in docker02-web01 > /usr/share/nginx/html/index.html
[root@docker02 ~]# docker run -itd --name web02 -P nginx:latest
[root@docker02 ~]# docker exec -it web02 /bin/bash
root@89cc41040e33:/# echo The web container in docker02-web02 > /usr/share/nginx/html/index.html
Docker03:web03 web04
[root@docker03 ~]# docker run -itd --name web03 -P nginx:latest
[root@docker03 ~]# docker exec -it web03 /bin/bash
root@3f0d20853b0b:/# echo The web container in docker03-web03 > /usr/share/nginx/html/index.html
[root@docker03 ~]# docker run -itd --name web04 -P nginx:latest
[root@docker03 ~]# docker exec -it web04 /bin/bash
root@79168d0aa77f:/# echo The web container in docker03-web04 > /usr/share/nginx/html/index.html
更改nginx服务的配置文件
[root@docker01 ~]# cd /usr/local/nginx/
[root@docker01 nginx]# mkdir consul
[root@docker01 nginx]# cd consul/
[root@docker01 consul]# vim nginx.ctmpl
upstream http_backend {
{{range service "nginx"}}
server {{ .Address }}:{{ .Port }};
{{ end }}
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
[root@docker01 nginx]# cd ../conf/
[root@docker01 conf]# vim nginx.conf
include /usr/local/nginx/consul/*.conf;
//是nginx的主配置文件能够识别到新的
[root@docker01 conf]# consul-template -consul-addr 192.168.2.10:8500 -template "/usr/local/nginx/consul/nginx.ctmpl:/usr/local/nginx/consul/vhost.conf:/usr/local/bin/nginx -s reload"
后台运行
[root@docker01 conf]# nohup consul-template -consul-addr 192.168.2.10:8500 -template "/usr/local/nginx/consul/nginx.ctmpl:/usr/local/nginx/consul/vhost.conf:/usr/local/bin/nginx -s reload" &
[root@docker01 conf]# nohup: 忽略输入并把输出追加到"nohup.out"
[root@docker01 consul]# pwd
/usr/local/nginx/consul
[root@docker01 consul]# ls ##生成一个vhost.conf文件
nginx.ctmpl vhost.conf
[root@docker01 consul]# cat vhost.conf
查看8000端口是否起来
[root@docker01 consul]# ss -lnt
没起来,重启nginx
[root@docker01 consul]# nginx -s reload
访问本机的8000端口
[root@docker01 ~]# curl 127.0.0.1:8000
当然:这时不管后端是新添加nginx的web容器,或是删除,新生产的配置文件都会实时的更新,这是我们在运行consul-template这条命令添加的模板。