在 TKE 中开启 CPU 静态管理策略

背景

默认情况下,节点上的 Pod 默认共享节点 CPU 池中所有的 CPU核数, 当节点上运行了很多 CPU 密集的 Pod 时,工作负载可能会切换调度到不同的 CPU 核, 这样就导致有些工作负载的性能明显地受到 CPU 缓存亲和性以及调度延迟的影响。 对此,kubelet 提供了可选的 CPU 管理策略,可以实现某些关键 Pod 的静态绑核,避免 CPU 抢占和切换对业务带来的性能损耗。详情参考:https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/

TKE 如何开启配置

下面介绍在 TKE 中开启 CPU 静态管理策略的两种方式。

一、存量节点开启

1. 静态 CPU 策略配置

在 K8S 1.17 版本之前,可供 Pod 独占 CPU 资源数量等于节点的 CPU 总量减去通过 --kube-reserved--system-reserved 参数保留的 CPU,从 1.17 版本开始,CPU保留列表可以通过 kublet 的 '--reserved-cpus' 参数显式地设置。由于 TKE 的 GA 版本 一般为偶数,所以:

  • 当 TKE 集群版本小于 1.18 时:

    在节点 /etc/kubernetes/kubelet 文件中添加如下配置:

    ...
    CPU_MANAGER_POLICY="--cpu-manager-policy=static"
    KUBE_RESERVED="--kube-reserved=cpu=xxx,memory=xxx"
    SYSTEM_RESERVED="--system-reserved=cpu=xxx,memory=xxx"
    ...

    其中, 给 Pods 独占 CPU 可用的资源数量等于节点的 CPU 总量减去通过 --kube-reserved--system-reserved 参数保留的 CPU,如果保留 CPU 数量设置非整数则向上取整,比如 250m,向上取整就是保留 1 核。

    由于 TKE 的 systemd 启动参数环境变量是硬编码,所以这里需要再添加下 kubelet 的启动参数环境变量 CPU_MANAGER_POLICYSYSTEM_RESERVEDKUBE_RESERVED 变量默认已经存在了):

    修改 kubelet 的 systemd 启动文件 /usr/lib/systemd/system/kubelet.service, 启动参数添加如下环境变量:

    ...
    ExecStart=/usr/bin/kubelet ... ${CPU_MANAGER_POLICY} ${KUBE_RESERVED} ${SYSTEM_RESERVED} ...
    ...
  • 当TKE 集群版本大于等于1.18 :

    在节点 /etc/kubernetes/kubelet 文件中添加如下配置:

    ...
    CPU_MANAGER_POLICY="--cpu-manager-policy=static"
    RESERVED_CPUS="--reserved-cpus=xxx"
    ...

    同样修改 kubelet 的 systemd 启动文件 /usr/lib/systemd/system/kubelet.service, 启动参数添加如下环境变量:

    ...
    ExecStart=/usr/bin/kubelet ... ${CPU_MANAGER_POLICY} ${RESERVED_CPUS} ...
    ...

    --reserved-cpus 参数值为显式指定的用逗号分隔的一组 CPU,如"--reserved-cpus=0,1,2,3",或 CPU 范围列表 "--reserved-cpus=0-3" 都是可以的。

2. 策略配置生效

接下来驱逐节点上的 Pods,并通过删除 kubelet 根目录中的状态文件 cpu_manager_state 来手动重置 CPU 管理器:

  1. 在 TKE 控制台 【节点列表】-> 【更多】 点【驱逐】选项或手动执行驱逐命令。

  2. 在TKE 节点中执行删除 cpu_manager_state 文件:

    rm /var/lib/kubelet/cpu_manager_state 
  3. 重启 kubelet 服务:

    systemctl  daemon-reload
    systemctl  restart kubelet

二、新加节点开启(推荐)

通过自定义kubelet 参数的方式完成上述的参数添加,配置的逻辑和上述存量节点一致,目前自定义参数需要开白支持,可联系售后同学帮忙开启即可。

总结

上述内容仅描述了如何在 TKE 中开启静态CPU 管理策略, 关于 工作负载的 CPU 静态绑核如何配置和注意事项,请参阅 static 策略

利用Github pages实现域名的cname功能

利用Github pages 做重定向背景:

由于在一台服务器上有个多站点服务,并且各站点服务是以域名区分的。在域名注册商使用CNAME解析时,发现CNAME仅能做到解析到CNAME的目标域名的ip地址,并不能做域名的重定向,这样的话,以域名区分服务的站点配置下依然没法正常访问想要CNAME的网站服务。

解决办法:

利用Github pages做页面重定向,从而实现到"服务的CNAME",具体做法如下:

1.在Github上新建一个项目,添加一个简单的名为index.html的html文件。

2.根据Github的自定义项目"custom domain"的的说明文档配置访问解析,例如我想在访问 http://www.nslover.com.cn 时重定向访问 http://nslover.com.cn 的服务时,先在项目的settings中开启自定义域名"www.nslover.com.cn"的设置,然后添加域名解析CNAME记录的"www"主机记录到GitHub的"nslover.github.io"(如果是主域名使用A记录,如果是子域名使用CNAME)。详见 https://help.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site .

3.编辑index.html,使用html和js双保险的方式做页面重定向,例如我想在访问 http://www.nslover.com.cn 时重定向访问 http://nslover.com.cn 的服务时,在index.html中修改添加如下代码:

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<!-- 注释原html meta标签设置 -->
<!--<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> --> 
<!-- 使用html meta标签重定向 -->
<meta http-equiv="refresh" content="0; url=http://nslover.com.cn/"/> 
...
<script type="text/javascript">
 
    window.location.href = "http://nslover.com.cn"  //使用js重定向
 
</script>
</head>
...

待解析生效后,借用这个机制就可以实现服务的重定向了。

 

Tornado web框架XSRF开启时使用JS不使用模板渲染表单进行POST请求的解决方法

Tornado 框架本身提供XSRF保护机制,开启方式详见官方文档https://tornado-zh.readthedocs.io/zh/latest/guide/security.html

官方文档中提供的使用turnado的template form表单方式的示例是可用的,但是在不使用form表单时,前后端分离场景下使用的介绍是很含糊的,网上搜索的资料也基本是官方文档说的,没有参考价值。经过阅读相关源码和实践,得出以下方案:

1.前端调用时先重定向至后端一个view函数(MainHandler),使用框架模板渲染的方式给浏览器写cookie,再在模板中使用js代码跳转到前端真正要访问的页面,之后在POST请求时带上cookie的参数“_xsrf”就可以正常请求了,示例代码如下:

后端view函数:

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        # self.set_secure_cookie("_xsrf", self.xsrf_token)  # 使用这种方式写的cookie,POST请求即使带”_xsrf“的参数,后端依然会报"XSRF cookie does not match POST argument"的403信息,无法正常请求。
        self.render("./test.html")

test.html内容:

<html>
<head>
<title></title><script
<script src="https://cdn.staticfile.org/jquery/3.4.0/jquery.min.js"></script>
<script src="https://cdn.staticfile.org/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// executes when HTML-Document is loaded and DOM is ready
location.href="/login"  // 重定向到真正想要访问的url
});
</script>
</head>
<body>
<form method="POST">
{% raw xsrf_form_html()%}  # 模板语法渲染页面的方式写”_xsrf“的cookie到浏览器
</form>
</body>
</html>

2.后来通过阅读源码发现xsrf_form_html()这个函数在后端有封装,view层函数可以直接调用,与第一种方法同样的效果,使用纯js进行POST等请求也没有问题,代码如下:

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.xsrf_form_html()  # 后端view接口调用此函数即可
        #self.set_secure_cookie("_xsrf", self.xsrf_token)  # 使用这种方式写的cookie,POST请求即使带”_xsrf“的参数,后端依然会报"XSRF cookie does not match POST argument"的403信息,无法正常请求。

实践发现,调用self.xsrf_form_html()函数是这样的,浏览器cookie的内容不会每次调用都更新,它会根据cookies的状态才更新,比如浏览器没有cookie,就会刷新一下,或者是浏览器的cookie过期了,才会重新刷新,所以可以将它放在Tornado的入口view中,可以重复调用,保证浏览器cookie始终有效。