1. 使用到的框架或者组件
- Consul:分布式的、高可用的、 可横向扩展的,用于实现分布式系统的服务发现与配置。
- Registrator:可以用来做服务发现。
- Consul Template:搭配Consul使用,支持多种接入层,如Nginx、Haproxy。可以动态添加和移除服务,不需要重写任何服务。
- Docker:利用容器化,简化部署,节省资源。
- Supervisor: 是基于Python 的进程管理工具,可以帮助我们更简单的启动、重启和停止服务器上的后台进程,是Linux 服务器管理的效率工具。
2. 架构设计
3. 环境说明
我们需要部署nginx、consul、consul-template、registrator、webservice1(nginx)/webservice2(nginx)等服务。
需要注意的是:consul-template必须和nginx部署在一台机器上(因为consul-template动态更新nginx的配置后,需要通过自动触发的方式,来reload nginx的配置信息,否则是没法自动生效。这个reload就需要保证consul-template和nginx处于同一机器才行)
我们测试机器有限,而且有Docker这么方便的容器化工具,所以我们打算把所有服务都通过docker容器来运行。这样的话,我们只要一台安装了docker的机器就行,这里使用一台安装了docker的centos机器。
但是我们刚才讲到了consul-template和nginx必须要在一台机器上,这个时候我们不得不要违背一个Docker容器运行一个服务的建议了。我们考虑使用Supervisor来让一个Docker容器同时运行consul-template和nginx服务。
服务器IP | 容器名 | 容器IP | 角色 |
---|---|---|---|
192.168.1.92 | consultemplate | 172.10.0.2 | 通过Supervisor运行consul-template,nginx服务 |
192.168.1.92 | consulserver | 172.10.0.3 | 运行consul服务 |
192.168.1.92 | registrator | -- | 运行registrator服务 |
192.168.1.92 | nginx_81 | -- | 运行webservice1(nginx,使用端口81)服务 |
192.168.1.92 | nginx_82 | -- | 运行webservice2(nginx,使用端口82)服务 |
4. 制作服务镜像
4.1 制作Nginx和Consul-template镜像
4.1.1 创建目录nginx-consultemplate
mkdir -p nginx-consultemplate
cd nginx-consultemplate
4.1.2 创建nginx.ctmpl模板文件
upstream http_backend {
{{range service "nginx"}}
server {{ .Address }}:{{ .Port }};
{{ end }}
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
第一段是定义了nginx upsteam的一个简单模板,第二段则是定义了一个server,监听8000端口,反向代理到upstream。
4.1.3 创建nginx.conf文件
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
#添加这一行
include /etc/nginx/consul/*.conf;
}
我们后面运行consul-template的时候,会使用nginx.ctmpl模板,解析之后生成.conf文件到/etc/nginx/consul目录下,所以nginx.conf文件的最后一条内容是include /etc/nginx/consul/*.conf;
4.1.4 创建supervisord.conf配置文件
[supervisord]
nodaemon=true
[program:consul-template]
command=consul-template -consul-addr 172.12.0.3:8500 -template "/etc/nginx/consul/nginx.ctmpl:/etc/nginx/consul/vhost.conf:nginx -s reload" -log-level=info
[program:nginx]
command=nginx
运行consul-template的时候,通过-consul-addr
参数来指定consul服务的IP和端口号,-template
参数来指定模板的解析,规则是:冒号第一段是模板文件路径,第二段是生成的配置文件路径,第三段是额外指令(这里特别重要:如果我们没有nginx -s reload这个,配置更新之后,无法自动生效。这个代表每次配置改变之后,都会自动执行此指令,用来reload nginx的配置,以便自动生效)
4.1.5 创建Dockerfile文件
# 基于nginx基础镜像创建
FROM nginx:1.12.1
# 设置作者信息
MAINTAINER zwffff "[email protected]"
# 设置环境变量,用于更新时,更改此信息来忽略缓存
ENV REFRESHED_AT 2019-05-26
# 安装net-tools(用于调试的时候,打印网络信息),supervisor(进程管理工具),wget,unzip
RUN apt-get update -yqq && apt-get install -yqq net-tools supervisor wget unzip
# 下载安装consul-template
RUN wget https://releases.hashicorp.com/consul-template/0.19.3/consul-template_0.19.3_linux_amd64.zip
RUN unzip consul-template_0.19.3_linux_amd64.zip
RUN mv consul-template /usr/bin/
RUN mkdir -p /etc/nginx/consul/
# 将模板文件nginx.ctmpl拷贝到/etc/nginx/consul目录下
ADD nginx.ctmpl /etc/nginx/consul/
# 将nginx.conf配置文件拷贝到/etc/nginx配置下进行覆盖
ADD nginx.conf /etc/nginx/
# 将supervisord.conf配置文件拷贝到/etc/supervisor/目录
ADD supervisord.conf /etc/supervisor/supervisord.conf
# 运行supervisord时,指定上一条语句的配置文件
ENTRYPOINT [ "/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf" ]
4.1.6 编辑好Dockerfile文件之后,我们可以通过以下命令来生成nginx-consultemplate镜像文件
docker build -t zwffff/nginx-consultemplate .
4.2 制作Consul镜像
4.2.1 创建目录consul
mkdir -p consul
cd consul
4.2.2 创建Dockerfile文件
FROM centos:7.4.1708
MAINTAINER zwffff "[email protected]"
#配置consul版本
ENV CONSUL_VERSION=1.0.6
ENV HASHICORP_RELEASES=https://releases.hashicorp.com
#创建用户
RUN groupadd consul && useradd -g consul consul
RUN yum upgrade -y
RUN yum install -y net-tools
#RUN yum install -y firewall firewalld-config
RUN yum install -y wget unzip
RUN wget ${HASHICORP_RELEASES}/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip && \
unzip consul_${CONSUL_VERSION}_linux_amd64.zip && \
rm -rf consul_${CONSUL_VERSION}_linux_amd64.zip && \
mv consul /usr/local/bin
#创建consul数据目录和配置目录
RUN mkdir -p /consul/data && \
mkdir -p /consul/config && \
chown -R consul:consul /consul
#设置匿名卷
VOLUME /consul/data
#开放端口
EXPOSE 8300
EXPOSE 8301 8301/udp 8302 8302/udp
EXPOSE 8500 8600 8600/udp
EXPOSE 80
4.2.3 生成镜像
docker build -t zwffff/consul .
我们只需要用到以上两个自定义镜像,至此镜像就都制作完成了。下面我们考虑把所有镜像通过docker-compose
进行编排到一起执行。
5. 利用Docker-Compose进行容器编排
docker-compose怎么使用,这里不做具体的介绍,它主要使用YAML文件进行配置。有version、services和networks三部分组成。特别留意的是:version版本为2和3的时候,有一些配置是有区分的,不一样的。 services就是我们需要定义的容器集合,networks则是我们需要定义的网络集合。
我们需要启动以下容器:
web:使用zwffff/nginx-consultemplate镜像启动,会运行consul-template和nginx服务,依赖consul服务
consul:使用zwffff/consul镜像启动,运行consul服务
registrator:使用docker hub上的gliderlabs/registrator镜像启动,运行registrator服务,依赖web服务
nginx1:使用nginx镜像启动,用来作为webservice1调用测试,依赖registrator服务
nginx2:使用nginx镜像启动,用来作为webservice2调用测试,作为webservice1服务的同级服务,用来进行负载均衡测试,依赖registrator服务
创建自定义网络
docker network create --subnet=172.12.0.0/16 consul_testconsul
创建 docker-compose.yml文件
version: "2"
services:
web:
image: zwffff/nginx-consultemplate # 指定容器所使用的镜像
container_name: consultemplate # 指定容器名称
networks: #指定容器所使用的网络
consul_testconsul: # 自定义网络的名称,这个与第一步创建的网络名称一致,同时下面的networks必须进行定义
ipv4_address: 172.12.0.2 #指定当前容器所使用的IP地址
depends_on: #指定该容器依赖的容器
- consul
ports: #指定容器绑定的端口号
- "8000:8000"
consul:
image: zwffff/consul
# -bind指定了当前consul服务所绑定的IP地址
command: consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=172.12.0.3 -client=0.0.0.0 -node=server01
networks:
consul_testconsul:
ipv4_address: 172.12.0.3
container_name: consulserver
ports:
- "8300"
- "8301"
- "8301/udp"
- "8302"
- "8302/udp"
- "8500"
- "8602"
- "8600/udp"
- "80"
registrator:
image: gliderlabs/registrator:latest
container_name: registrator
network_mode: host # 这里要把宿主机注册到consul上去,所以网络模式必须要使用host模式
command: --ip 192.168.1.92 consul://172.12.0.3:8500
depends_on:
- web
volumes:
- /var/run/docker.sock:/tmp/docker.sock
restart: always
nginx1:
image: nginx
container_name: nginx_81
depends_on:
- registrator
ports:
- "81:80"
nginx2:
image: nginx
container_name: nginx_82
depends_on:
- registrator
ports:
- "82:80"
networks:
consul_testconsul:
external: true #使用外部已创建的网络时,external属性必须设置为true
这样,我们五个容器都已经通过docker-compose编排好了。
通过执行docker-compose up
指令即可一键运行整个集群服务了。
参考文章:
基于Consul+Registrator+Nginx实现容器服务自动发现的集群框架: https://blog.51cto.com/ganbing/2086851
consul官网:https://www.consul.io
consul github:https://github.com/hashicorp/consul
consul-template:https://github.com/hashicorp/consul-template
registrator:https://github.com/gliderlabs/registrator