共计 3299 个字符,预计需要花费 9 分钟才能阅读完成。
1、前言
最近在项目中用 Nginx 做反向代理,需要动态生成 Nginx 的配置。大概流程是用户在页面上新增域名、http 或 https 协议以及端口信息,后台会根据域名自动生成一个 Nginx 的 Server 配置,在 nginx.conf 配置文件中使用 include 将所有的 server 配置加载进来。遇到一个问题就是如何动态生成 nginx 的配置,以及配置更新。在此之前也接触过配置生成及更新,当时配置的格式都是基于 xml 的,使用 protobuf 与 xml 结合,先采用 protobuf 定义好配置的数据结构,然后将 protobuf 转换为 xml 配置文件。配置更新通过判断配置文件的 md5 是否发生变化进行。而如今接触的配置是 nginx 的配置,是一套自定义的配置。看了一眼 nginx 的配置源码,用一个 void**** conf 来表示,顿时吓死宝宝了,膜拜作者编程技能。nginx 配置代码内存组织是相当的牛逼,通用性非常强,有兴趣可以认真研究一下。我要自动生成的配置是如下所示:
upstream www_test {server 196.75.121.112:443; (动态生成)
}
server {listen 443 ssl; (动态生成)
server_name www.test.com; (动态生成)
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;;
ssl_certificate /home/build/openresty/nginx/cert/dealssl/www.bestenover.com.crt; (动态生成)
location / {proxy_pass https://www_test; (动态生成)
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
}
2、实现框架
看完 nginx 的配置不难发现,nginx 是一个典型的 key value 类型的,而且与文件系统的非常类似,一个目录下面可以包含其他配置,目录下还可以有目录,嵌套多层。如今 key value 类型的数据库非常多,redis、leveldb 等,最近新秀 etcd 也是 key-value 分布式数据库,提供类似文件系统操作,使用 raft 协议保持数据一致性,非常适合云计算分布式部署场景,将 confd 与 etcd 搭配,非常适合 nginx 这样的配置格式。
使用 etcd 新建与 nginx 配置对应的目录如下:
为了配合 webui 展示配置和后台生成 nginx 配置,总体的配置流程图如下所示:
3、生成配置
WEBUI 通过 API 将配置写入 mysql 和 etcd,confd 注册监控 etcd 的 key 为 /nginx/,只要发生变化就通知 confd 根据模板生成配置。confd 默认的配置路径为 /etc/confd/,创建 conf.d 和 template 两个目录,分别存放配置资源和配置模板。
nginx 的配置资源如下所示 :test.conf.toml
[template]
src = "test.conf.tmpl"
dest = "/tmp/test.conf"
keys = ["/nginx",
]
check_cmd = "/usr/sbin/nginx -t -c {{.src}}"
reload_cmd = "/usr/sbin/service nginx reload"
nginx 的配置模板如下所示 :test.conf.tmpl
upstream www_{{getv "/nginx/https/www/server/server_name"}} {{{range getvs "/nginx/https/www/upstream/*"}}server {{.}};{{end}}
}
server {server_name {{getv "/nginx/https/www/server/server_name"}}:443;
ssl on
ssl_certificate {{getv "/nginx/https/www/server/ssl_certificate"}};
ssl_certificate_key {{getv "/nginx/https/www/server/ssl_certificate_key"}};
location / {proxy_pass http://www_{{getv "/nginx/https/www/server/server_name"}};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
}
开启 confd,执行 ./confd -watch -backend etcd -node http://127.0.0.1:2379
使用 ectdctl 添加配置如下:
./etcdctl set /nginx/https/www/server/server_name test.com
./etcdctl set /nginx/https/www/server/ssl_certificate /home/waf/build/openresty/nginx/cert/client/client.crt
./etcdctl set /nginx/https/www/server/ssl_certificate_key /home/waf/build/openresty/nginx/cert/client/client.key;
/etcdctl set /nginx/https/www/upstream/server1 192.168.1.2:443
./etcdctl set /nginx/https/www/upstream/server2 192.168.4.2:443
confd 的执行结果如下所示:
生成位置文件如下所示:
upstream www_test.com {server 192.168.1.2:443;
server 192.168.4.2:443;
}
server {server_name test.com:443;
ssl on
ssl_certificate /home/waf/build/openresty/nginx/cert/client/client.crt;
ssl_certificate_key /home/waf/build/openresty/nginx/cert/client/client.key;
location / {proxy_pass http://www_test.com;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
}
}
与模板生成的保持一致。
4、参考资料
cond 的 github 上文档介绍
https://github.com/kelseyhightower/confd/blob/master/docs/template-resources.md
confd 和 etcd 实现配置管理及模板使用 http://www.linuxidc.com/Linux/2016-12/137934.htm
本文永久更新链接地址 :http://www.linuxidc.com/Linux/2016-12/137935.htm