背景
最近一直在准备k8s 发布20000 ops吞吐量图片识别服务。服务外部Nginx入口部署在多台腾讯云虚拟机器上,后端计算服务部署在机房k8s实例上,入口虚拟和公司机房通过专线和腾讯云虚拟打通。
K8 Ingress nginx 转发
腾讯云虚拟机器也可以作为k8s节点,但是这个比较绕, 为了安装ingres nginx,虚拟机上部署kubelet, 而且夸网络。开始可以通过比较简单方法,把nginx upsream 指向私有云机房的k8s ingress nginx, 如图:<br /> <br /> ![Nginx-old.png](https://cdn.nlark.com/yuque/0/2020/png/614455/1607567641822-5cfd4827-da91-457e-bad9-a5eede3ee192.png#align=left&display=inline&height=515&margin=%5Bobject%20Object%5D&name=Nginx-old.png&originHeight=515&originWidth=592&size=22069&status=done&style=none&width=592)
Nginx 动态upstream server
这架构并发当吞吐量上5000 ops的时候,k8s ingress nginx 不定时出现 connect reset。为了不影响当前其他应用使用ingress nginx 转发。打算打通腾讯云虚拟机器和pod网段。 `打通外部机器和pod网段通信后面在分享` 但是服务发现怎么做呢,想到借助了nginx-upstream-dynamic-server模块。外面nginx可以通过域名解析解析 headless service 所用 pod 地址, 采用了在外部部署nginx来实现负载均衡的方法,由于upstream里的pod ip会动态变化,所以我们不能直接在upstream里写死pod的ip地址,而只能用service的域名来替代,并让nginx自己去解析这个域名,我们知道headless service的域名由于没有内部的service ip。架构简化如下:<br /> ![Nginx-2.png](https://cdn.nlark.com/yuque/0/2020/png/614455/1607568958496-44f7ef01-dfcf-45e7-ae70-615341db34a3.png#align=left&display=inline&height=453&margin=%5Bobject%20Object%5D&name=Nginx-2.png&originHeight=453&originWidth=547&size=20951&status=done&style=none&width=547)
部署和配置
编译
nginx-upstream-dynamic-server是不提供动态加载, 需要重新编译nginx,可以通过线上版本rpm 安装nginx v1.16.0,重新编译. 获取线上版本编译参数
$ nginx -V
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
下载nginx-upstream-dynamic-server
git clone https://github.com/GUI/nginx-upstream-dynamic-servers.git
下载对应版本nginx然后编译
$ ./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock --http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http-scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --add-module=/path/to/nginx-upstream-dynamic-servers/ --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -fPIC' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -pie'
$ make -j4
安装
编译以后,在objs文件有nginx可执行文件,可以把他覆盖 /usr/sbin/nginx
可以了。
配置
k8s dns cache
k8s headless服务都是通过k8s-coredns解析到所有pod ip地址,可以和nginx-upstream-dynamic-server完美组合。但是测试发送,启动nginx服务以后,nginx直接占用了100% cpu, 发现一个不是bug的bug。打开debug日志发现,upstream-dynamic-server模块发送dns解析动态server,导致cpu占用很多。
模块nginx-upstream-dynamic-server根据dns 返回 ttl 间隔定时发送dns请求更新updstream,我们可用dig工具获取k8s dns返回ttl是多少, 下图
默认是5ttl, 有时候返回小于5,每次访问都比较耗时,所有不能偷懒,再得部署一个dns cache,上游可以解析k8s 域名dns地址,并且覆盖5ttl。coredns 1.4 以上的可以使用proxy插件,同时也有cache minttl支持。配置如下:
cat /usr/local/coredns/Corefile
.:53 {
errors
whoami
log
# 遇到后缀 cluster.local 指向k8s dns
proxy cluster.local <ip for k8s dns>
# 腾讯云内部dns
proxy . 183.60.83.19 183.60.83.98
cache 30 {
# 如果成功缓存多少个, ttl, minttl
success 5000 30 30
}
}
启动core-dns以后在虚拟机器解析k8s 服务域名,ttl覆盖为30, 如图
Nginx 配置修改
nginx 如果在 upstream 配置域名,nginx启动解析以后就不去更新,以后k8s pod 滚动更新以后,nginx不能转发pod上。需要按照动态upstream插件。需要配置下面文件:
/etc/nginx/nginx.conf
...
# dns cache ip 可以多个空格分隔
resolver <dns-cache-ip> valid=30s;
...
/etc/nginx/conf.d/your-service.conf
upstream cg-lobby {
server <your-k8s-service-name>.<your-service-namespace>.svc.cluster.local:51020 max_fails=2 resolve;
keepalive 100; # 如果太大压力测试反而发现连接不能改变,不是长连接了
}
server {
listen 80;
server_name ;
location / {
client_body_buffer_size 1m; # max requst body size 1m
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP Sremote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://cg-lobby;
}
}
资源消耗
腾讯云 Nginx 可以根据带宽进行添加,一般可以下面配置。这个压力其实5台VM就差不多了
CPU: 4 core
内存:8G
网络:2Gb/s 网卡