接上文基于Kubernetes的PaaS平台如何提供ssh服务(调研), 当我在我们的线上环境中实现了这一功能后, 有用户来反馈, 讲到自己登录到ssh后马上就会断开, 没有shell可用.

这篇文章就记录一下该情况出现的原因以及解决方案, 希望大家在Kubernetes环境中遇到了相关问题可以避免吧.

具体现象

表现为连接到服务器之后, 打印欢迎信息之后就退出了:

排查过程

起初我以为是用户的mac系统以及客户端ssh有问题, 后来用自己的电脑尝试了一下也会出现这样的现象, 初步确定是服务端的问题.

ssh -vvv只会显示这样的日志, 日志太普通了, 根本看不出来是什么错误.

1
2
3
4
5
6
7
8
9
10
11
12
13
debug3: send packet: type 97
debug2: channel 0: is dead
debug2: channel 0: garbage collecting
debug1: channel 0: free: client-session, nchannels 1
debug3: channel 0: status: The following connections are open:
#0 client-session (t4 r0 i3/0 o3/0 e[write]/0 fd -1/-1/7 sock -1 cc -1)

debug3: send packet: type 1
debug3: fd 1 is not O_NONBLOCK
Connection to 10.96.115.41 closed.
Transferred: sent 3912, received 3292 bytes, in 0.1 seconds
Bytes per second: sent 33161.8, received 27906.1
debug1: Exit status 255

找了一些帖子, 但其实基本没啥用:

https://stackoverflow.com/questions/23357926/ssh-closes-connection-immediately-after-login

https://unix.stackexchange.com/questions/148714/cant-ssh-connection-terminates-immediately-with-exit-status-254

最后我测试发现, 在测试环境中使用ssh可以连接, 但是在正式环境却怎么也连不上, 回想自己所做的操作, 里面有这么一句话

1
/usr/bin/env | grep _ >> /etc/environment

然后, 我发现测试环境中/etc/environment, 里面的文件大概700行, 正式环境就多了大约1400行, 我将正式环境中的文本直接删除了一半, 确认可以连接, 终于找到了问题, 是因为环境变量太多导致的, 气不气, 头一次知道ssh服务器的环境变量不能有太多.

在Kubernetes环境的容器中, 记录服务信息的环境变量特别的多, 几千个都是比较少的.

解决方案

最后我的解决方案是, /etc/environment中只保留重要的环境变量, Kubernetes的其他环境变量保存到一个特定文件中, 用户能找到即可, 上面的一句话被拆成了下面两句:

1
2
3
4
5
# grep -v 表示不取这些值, 也就是将类似这样的变量去掉
# STAGE_XXX_STATIC_PORT_80_TCP_PROTO=tcp
/usr/bin/env | grep -Ev "SERVICE_HOST|SERVICE_PORT|TCP_ADDR|TCP_PORT|tcp" >> /etc/environment
# 全部的环境变量保存到某个文件中
/usr/bin/env > $env_file

扩展

为啥会出现环境变量太多, 就直接退出的问题呢?

我简单找了一下OpenSSH的代码, 发现了这几行, 以下代码截取自OpenSSH项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static void
read_environment_file(char ***env, u_int *envsize,
const char *filename, const char *whitelist)
{
FILE *f;
u_int lineno = 0;

f = fopen(filename, "r");
while (getline(&line, &linesize, f) != -1) {
## 你就看这句就好了, 如果环境变量的长度太多, 就会直接退出 !!!
if (++lineno > 1000)
fatal("Too many lines in environment file %s", filename);
// ...
}
free(line);
fclose(f);
}

// 代码中也有这么一句话, 基本也就确定原因了.
read_environment_file(&env, &envsize, "/etc/environment",
options.permit_user_env_whitelist);

总结

这篇博客主要分享一下我在使用ssh服务器时遇到的一种特定问题, 如果有其他Kubernetes用户遇到了, 希望能帮上你, 遇到问题时别急, 慢慢找就好了. 因为是在容器中的ssh服务, 所以一开始没有打印日志, 其实好好打印一下日志, 这个问题应该能更快定位到的.

从我个人角度来看, 建立了连接马上断开, 一般是服务端的问题, 客户端如果有问题会在连接过程中就失败, 像是之前的调研报告中那种netcat将数据包拆分的问题.