Nginx利用Consul实现动态负载均衡
首先,说声抱歉哈~~,最近更新的比较慢,不是工作比较忙,而是自己变懒了,对不住各位了
一. 前言
由于最近手中的项目在不断更新迭代,经常对服务做些调整,一调整就需要改配置文件,真是烦死了,这里先简单说下我司架构, openresty 当前端网关,利用nginx反向代理多应用服务器,提供服务(不重要的服务省略了),通过查资料发现,利用consul 可以和nginx配合,实现动态修改nginx配置的需求
二. 资源说明
10.10.100.4
- centos 系统
- nginx服务
- consul template服务
10.10.100.3
- centos 系统
- consul服务
- web1服务
- web2服务
由于资源有限,就开了2台虚拟机来模拟一下,当然可以用docker实现,这里就不演示了,consul服务也不开集群模式了,同时 consul服务与web服务就放在同一个服务器上了,看懂意思就可以了,多个web服务,就以不同的端口来区分
三. 安装过程
3.1 在10.10.100.4安装openresty
# add the yum repo:
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/
# 更新
sudo yum check-update
#安装
sudo yum install openresty
#启动
systemctl start openresty.service
#开机自启动
systemctl enable openresty.service
验证安装成功
- 浏览器访问 10.10.100.4
- 在10.10.100.4服务器上的命令行中执行curl 127.0.0.1
3.2 在10.10.100.4安装 consul-template
consul-template是基于consul自动替换配置文件的应用。在Consul-Template没出现之前,大家构建服务发现系统大多采用的是Zookeeper、Etcd+Confd这样类似的系统。
Consul官方推出了自己的模板系统Consul-Template后,动态的配置系统可以分化为Etcd+Confd和Consul+Consul-Template两大阵营。Consul-Template的定位和Confd差不多,Confd的后端可以是Etcd或者Consul。
Consul-Template提供了一个便捷的方式从Consul中获取存储的值,Consul-Template守护进程会查询Consul实例来更新系统上指定的任何模板。当更新完成后,模板还可以选择运行一些任意的命令。
#下载
wget https://releases.hashicorp.com/consul-template/0.29.2/consul-template_0.29.2_linux_amd64.zip
#解压
unzip consul-template_0.29.2_linux_amd64.zip
#添加到环境变量中,这里直接复制到里面
mv consul-template /usr/local/bin/
#查看版本
consul-template -v
3.3 在10.10.100.3安装 consul
sudo yum install -y yum-utils
#配置源
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
#安装consul
sudo yum -y install consul
#查看版本
consul -v
#测试环境这里使用单机 dev模式了,这种模式只能使用127.0.0.1 的ip访问
consul agent -dev
#客户端ip访问 可以指定client参数 就可以访问了http://10.10.100.3:8500/ui/dc1/services
consul agent -dev -ui -client 10.10.100.3
3.4 在10.10.100.3安装 web应用服务
这里的web服务,我使用go语言实现了,源码在后面,这里通过不同的端口,来对应多个不同的服务,go程序编译后就是一个二进制文件,直接上传到服务器,运行即可!
上传web服务到10.10.100.3,并启动
#go程序编译命令
go build -o web01 main.go
#修改端口号,重新编译
go build -o web02 main.go
#修改端口号,重新编译
go build -o web03 main.go
#上传到10.10.100.3服务器的/web目录
#启动命令
cd /web
nohup ./web01 >/dev/null 2>&1 &
nohup ./web02 >/dev/null 2>&1 &
nohup ./web03 >/dev/null 2>&1 &
web服务源码如下:
package main
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
"net/http"
)
const (
CONSULURL = "10.10.100.3"
CONSULPORT = 8500
SERVERADDR = "10.10.100.3"
SERVERPORT = 8081 //端口需要修改,8081, 8082 ,8083
SERVERNAME = "go-server"
SERVERID = "100" //需要修改 100 ,200 ,300
checkAddr = "10.10.100.3"
checkPort = 8081 //端口需要修改 8081, 8082 ,8083
)
func consulRegister() {
//链接到consul
config := consulapi.DefaultConfig()
config.Address = fmt.Sprintf("%s:%d", CONSULURL, CONSULPORT)
client, err := consulapi.NewClient(config)
if err != nil {
fmt.Println("consul client err ", err)
return
}
//注册服务到consul
registion := new(consulapi.AgentServiceRegistration)
registion.ID = SERVERID
registion.Name = SERVERNAME
registion.Port = SERVERPORT
registion.Address = SERVERADDR
registion.Tags = []string{"web03", "go-web03"}
//增加consul健康检查回调函数
check := new(consulapi.AgentServiceCheck)
check.HTTP = fmt.Sprintf("http://%s:%d%s", checkAddr, checkPort, "/check")
check.Timeout = "5s"
check.Interval = "5s"
check.DeregisterCriticalServiceAfter = "30s" //故障检查失败30s后,自动删除删除
registion.Check = check
//注册服务
err = client.Agent().ServiceRegister(registion)
if err != nil {
fmt.Println("注册服务失败", err)
return
}
}
func main() {
consulRegister()
http.HandleFunc("/check", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("我是check "))
})
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("我是8081 端口服务返回的 "))
})
fmt.Println("启动....")
err := http.ListenAndServe(fmt.Sprintf("%s:%d", "", SERVERPORT), nil)
if err != nil {
fmt.Println("启动 http 失败", err)
}
}
3.5 在10.10.100.4配置consul-template文件
consul-template的常用参数
-consul-auth=<username[:password]> 设置基本的认证用户名和密码。
-consul-addr=<address> 设置Consul实例的地址。
-max-stale=<duration> 查询过期的最大频率,默认是1s。
-dedup 启用重复数据删除,当许多consul template实例渲染一个模板的时候可以降低consul的负载。
-consul-ssl 使用https连接Consul。
-consul-ssl-verify 通过SSL连接的时候检查证书。
-consul-ssl-cert SSL客户端证书发送给服务器。
-consul-ssl-key 客户端认证时使用的SSL/TLS私钥。
-consul-ssl-ca-cert 验证服务器的CA证书列表。
-consul-token=<token> 设置Consul API的token。
-syslog 把标准输出和标准错误重定向到syslog,syslog的默认级别是local0。
-syslog-facility=<facility> 设置syslog级别,默认是local0,必须和-syslog配合使用。
-template=<template> 增加一个需要监控的模板,格式是:'templatePath:outputPath(:command)',多个模板则可以设置多次。
-wait=<duration> 当呈现一个新的模板到系统和触发一个命令的时候,等待的最大最小时间。如果最大值被忽略,默认是最小值的4倍。
-retry=<duration> 当在和consul api交互的返回值是error的时候,等待的时间,默认是5s。
-config=<path> 配置文件或者配置目录的路径。
-pid-file=<path> PID文件的路径。
-log-level=<level> 设置日志级别,可以是"debug","info", "warn" (default), and "err"。
-dry Dump生成的模板到标准输出,不会生成到磁盘。
-once 运行consul-template一次后退出,不以守护进程运行。
新建nginx配置的模板文件
注意如果要生成nginx的配置文件,则要一定要与nginx安装到同一台服务器上
upstream go-server {
{{range service "go-server" }} {{$name := .Name}}
##upstream {{$name}}
##zone upstream-{{$name}} 64k;
server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502
{{end}}
}
server {
listen 8000;
server_name localhost;
location / {
add_header 'Access-Control-Allow-Origin' '*';
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://go-server/;
#Proxy Settings
proxy_set_header Host $host;
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
}
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
执行命令生成nginx.conf配置文件
consul-template -consul-addr 10.10.100.3:8500 -template "nginx.ctmpl:/usr/local/openresty/nginx/conf/conf.d/consul.conf:/usr/local/openresty/bin/openresty -s reload"
当然可以使用配置文件生成了
vim /usr/local/openresty/nginx/conf/consul-nginx-template/nginx.hcl
配置文件如下:
wait {
min="3s"
max="10s"
}
consul {
address="10.10.100.3:8500"
}
template {
source ="/usr/local/openresty/nginx/conf/consul-nginx-template/nginx.ctmpl"
destination="/usr/local/openresty/nginx/conf/conf.d/consul.conf"
command="/usr/local/openresty/bin/openresty -s reload"
}
运行配置文件
consul-template -config /usr/local/openresty/nginx/conf/consul-nginx-template/nginx.hcl
浏览器测试
我这里绑定了8000端口,所以访问 10.10.100.4:8000,就可以发现后端3个go服务开始提供服务了,关闭一个服务,nginx的配置文件也会动态的做出改变
结尾:
这种解决方案是可以解决我们遇到的问题, 但是最终开会后确没有使用这种方法来解决,还是使用原始 方法手动改,我是无语了,可能是怕麻烦吧