一.问题描述
近期遇到k8s环境中一个pod无法正常启动,启动报错,[PM2][ERROR] Process failed to launch spawn E2BIG
。
二.问题分析
2.1.了解报错相关知识
查阅资料发现,上面的问题,是因为环境变量过多引起的。K8S启动时会给容器注入环境变量,K8S集群中的项目数越多,环境变量也就越多。而pm2在启动时会导入系统中的环境变量,当环境变量数量过多时,就会报错[PM2][ERROR] Process failed to launch spawn E2BIG。
2.2.确定变量数量阈值
使用env或者printenv命令查看容器中的变量,果然环境变量特别多有。
但为何内部环境未复现,然后对比客户和内部环境:
客户环境故障pod中:env |wc输出有2111个;
内部环境正常pod中:env |wc输出有1853个;
然后尝试给内部环境正常pod对应values.yaml注入自定义随机环境变量用于增加pod环境变量数目,发现当此pod中环境变量为 2050左右 会出现[PM2][ERROR] Process failed to launch spawn E2BIG异常。
2.3.确定具体原因
1.将客户故障pod的env打印到error.txt后取出;
2.将内部正常pod的env打印后info.txt后取出;
3.对比环境变量;
对比error.txt和info.txt两个文件内容中环境变量的key,发现error.txt中多了506个GET_JS*服务相关变量相关变量:
4.确定GET_NODEJS* 环境变量来源
既然pod环境变量是在同一namespace中是叠加的,那他应该属于某个pod,进行pod过滤后过果然发现大量get_js的pod服务,
5.确定get_nodejs服务有效性
和业务咨询此问题后了解到此服务在客户正常使用的版本中已经废弃。
三.解决方案
3.1.方案1-清理无效pod
在第二章中提到了找到了引起环境变量增加500多个的服务,然后删掉此服务的相关资源:
#kubectl get svc |grep get_js |awk '{print $1}' |xargs kubectl delete svc #kubectl get deployment |grep get_js |awk '{print $1}' |xargs kubectl delete deployment
3.2.方案2-修改pm2源码
修改pm2源码,过滤掉环境变量。
编辑/usr/local/lib/node_modules/pm2/lib/Common.js,修改process.env部分。
function filterDockerEnv(envObj){ let keys = Object.keys(envObj); let new_env = {}; let allowKeys = keys.filter(item => !item.startsWith("ENV_HOST_")); allowKeys.forEach(key => { new_env[key] = envObj[key]; }); return new_env; } var newEnv = filterDockerEnv(env); // Change to double check (dropped , {pm_cwd: cwd}) app.env = [{}, newEnv, app.env || {}].reduce(function(e1, e2){ return util._extend(e1, e2); });
3.3.方案3-清除环境变量
清除环境变量
第三个方案是在pm2启动前清除系统中的环境变量。
正常启动命令前,先执行一段清除系统变量的脚本。
for i in `env | grep -E -i 'SERVICE|HOST|ADDR|PORT' | sed 's/=.*//'` ; do unset $i;done
3.4.方案4-修改k8s资源
在报错服务的deployment.spec.template.spec模块下添加如下内容,其中enableServiceLinks 表示是否将 Service 的相关信息注入到 Pod 的环境变量中,默认是 true:
enableServiceLinks: false