ingress服务开发实践

Ingress简介

ingress 是除了 hostport nodeport clusterIP以及云环境专有的负载均衡器外的访问方式,通常情况下,service和pod的IP可以被集群网络访问。ingress是允许入站连接到达群集服务的规则集合。可以为外部提供可访问服务的URL,PATH路径,流量负载均衡,可被终止的ssl连接,以及基于配置的虚拟主机。

不同于k8s的ingress,我们开发的ingress服务支持rancher,并且定义了软件堆栈, 微服务概念。 可以使用NodeIP,暴露部分端口。通过反向代理,在云环境外访问云环境中的不同域名,不同的路径,不同网络协议的微服务,于是访问云内部的服务,有了一个统一的调用方式。 ingress服务通过接口更新,监听整个容器环境的变化,再配合接口下发转发规则来完成流量中转服务的配置更新。

核心组件,反向代理,负载均衡的选择

产品名 说明

F5 硬件负载性能高,有SDK

HAPROXY 软件性能相对高

NGINX 软件性能相对弱一些, 但功能更全,

配置更灵活, 用户量更大,

支持文档更多。

我们选择了NGINX

nginx升级版本有tingine, openresty

产品名 说明 比较

tingine nginx官方的分支版本 有部分配置

与官方版本不一样

openresty nginx官方的补丁包 拥有nginx官方版

的所有功能。可

以支持LUA+数

据库可实现高

性能路由功能。

我们选择了openresty,方便新增功能,不受限.只要nginx官方支持,我们都能集成enter code here

ingress设计架构

ingress设计图

ingress网络

技术要点

Ingress-Controller (中心处理节点)

▪ mysql 中心数据库

▪restful 提供对外的服务,接口。

1.下发ingress规则配置

2.蓝绿部署功能

3.部署状态....

▪web-socket

通讯的基础,异步的发送任务,同步+超时机制获得执行结果。

Ingress-Agent (监控中节点)

▪sqlite 本地数据库

▪docker-api

进行docker-event监听用户容器的事件。

▪ancher-metadata

获得metadata的容器详细信息。

▪nsenter

直接把网站相关的SSL相关的证书CRT,KEY,配置文件,nsenter --target {{}} --net curl 写到ingress-lb 的nginx.conf的目录中。

Ingress-lb (流量转发节点)

▪restful接口

设置新的配置文件,重新加载

查看当前配置文件

重新加载

▪template模板文件生成nginx配置文件

▪SSL安全隧道

resource manager 统一的管理域名对应的key,crt文件。在系统内部下载,并放到nginx需要的位置,完成SSL中转的功能了。

▪会话保持功能

在多台后端服务器情况下,为了让一个客户只和一台服务器通信的长连接。

IP_HASH nginx自带的方式,根据客户端公网IP不同,分布到后端服务器中去。如果一个局域网的客户同时访问服务器,有相同的公网IP,这时候IP_HASH就不能保证每次访问都能粘滞在同一台服务器。

Cookie Sticky 每台电脑都会有不同的cookie.。在保持长连接的同时,还能分布到不同的后端服务器。

▪流量限制

可以使用不同自定义的template生成扩展新的功能。

第一版本ingress通过 ingress-agent 感知云环境配置变化 + golang模板 + [nginx -s reload ]完成自动配置

nginx的配置文件示例

worker_processes 1;

events {

worker_connections 1024;

}

http {

upstream backend {

sticky;

server 192.168.0.2:80;

server 192.168.0.3:80;

# 每个5秒检测一次, 请求2次正常则标记realserver状态为up, 如果检测3次都失败,

# 则标记realserver的状态为down,超过时间为1秒.

check interval=5000 rise=2 fall=3 timeout=1000 type=http;

check_http_send "HEAD / HTTP/1.0\r\n\r\n";

check_http_expect_alive http_2xx http_3xx;

}

server {

listen 80;

server_name _;

index index.html;

location / {

# 设置主机名和客户端真实地址,以便服务器获取客户端真实IP

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_buffering off;

# 反向代理的地址

proxy_pass ;

}

location /status {

check_status;

access_log off;

allow 172.29.73.23;

deny all;

}

}

}

nginx的配置文件模板示例

daemon off;

worker_processes 1;

error_log logs/error.log;

events {

multi_accept on;

worker_connections 1024;

use epoll;

}

stream {

{{ range .Streams }}

upstream {{ .Upstream.Name }} {

{{ range .Upstream.EndPoints }} server {{ .Server }}:{{ .Port }} weight={{ .Weight }} max_fails={{ .MaxFails }} fail_timeout={{ .FailTimeout }}{{ if .Down }} down{{ end }};

{{ end }}}

server {

listen {{ .Server.Listen }}{{ if eq .Server.Protocol "udp" }} udp{{ end }};

proxy_pass {{ .Server.ProxyPass }};

}

{{ end }}

}

http {

{{ range .Https }}

upstream {{ .Upstream.Name }} {

{{ if ne .Upstream.SessionSticky.Name "" }} sticky{{ if ne .Upstream.SessionSticky.Name "" }} name={{ .Upstream.SessionSticky.Name }}{{ end }}{{ if ne .Upstream.SessionSticky.Domain "" }} domain={{ .Upstream.SessionSticky.Domain }}{{ end }}{{ if ne .Upstream.SessionSticky.Path "" }} path={{ .Upstream.SessionSticky.Path }}{{ end }}{{ if ne .Upstream.SessionSticky.Expires "" }} expires={{ .Upstream.SessionSticky.Expires }}{{ end }}{{ if ne .Upstream.SessionSticky.Hash "" }} hash={{ .Upstream.SessionSticky.Hash }}{{ end }}{{ if eq .Upstream.SessionSticky.NoFallback true }} no_fallback{{ end }};{{ end }}

{{ if eq .Upstream.RoutingMode "ip-hash" }} ip_hash; {{ end }}{{ $routing_mode := .Upstream.RoutingMode }}

{{ range .Upstream.EndPoints }} server {{ .Server }}:{{ .Port }} {{ if eq $routing_mode "round-robin" }} weight={{ .Weight }} {{ end }} max_fails={{ .MaxFails }} fail_timeout={{ .FailTimeout }}{{ if .Down }} down{{ end }};

{{ end }}}

server {

listen {{ .Server.Listen }};

server_name {{ .Server.ServerName }};

{{ if .Server.UseSSL }}

# for support ssl

ssl on;

ssl_certificate {{ .Server.SSLCertificate }};

ssl_certificate_key {{ .Server.SSLPrivateKey }};

{{ end }}

{{ range .Server.Locations }}

location {{ .Path }} {

{{ if .UseGzip }}

# for support data zip

gzip on;

gzip_comp_level 5;

gzip_http_version 1.1;

gzip_types text/plain text/css application/json application/x-javascript

text/xml application/xml application/xml+rss text/javascript;

gzip_proxied any;

{{ end }}

proxy_pass http://{{ .Host }}/;

# for support backend server.

# 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP

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_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;

}

{{ end }}

}

{{ end }}

}

测试配置文件是否能被使用

/usr/local/nginx-1.0.6/sbin/nginx -t

重新加载 nginx配置文件

/usr/local/nginx-1.0.6/sbin/nginx -s realod

虽然nginx -s reload 不中断业务,但当连接量很大的时候,可能出现部分访问失败的问题。接下来的工作,修改LUA+redis配置数据转发规则,只要修改nginx监听端口,nginx无需要重启,实现高性能动态配置的修改。