登录
  • 人们都希望被别人需要 却往往事与愿违
  • 企业最大的资产是人[email protected]松下幸之助 (号称日本经营之神)

没事别在容器里装openssh-server,真的

编程 Benny小土豆 715次浏览 1971字 6个评论
文章目录[显示]

几天前,跑的好好的CI突然fail,报错信息看起来很奇怪,像是使用上的问题。

没事别在容器里装openssh-server,真的

本地跑了一下这两个测试用例,并没有复现。以为是CI偶尔抽风了,就没管。

后来发现有点不对,怎么都跑不过。甚至直接在develop上跑CI都跑不过。这和GraphQL有什么关系啊?明明都能用的啊。让写这部分代码的同事帮忙看了下,发现他也能跑过。奇怪。

由于整套CI是跑在concourse上的,于是通过fly hijack进去,在对应失败的step中成功复现了这个问题。

再后来同事发现出问题的是urllib3/util/retry.py的Retry

max_retries = Retry(
    total=1,
    backoff_factor=0.1,
    status_forcelist=[500, 502, 503, 504],
    allowed_methods=None,
)

去比对了下,fly进去的容器中的urllib3版本和我测试的版本确实不一样。把fly进去的容器中的urllib3升级了之后,test case就可以过了。

啥?这啥情况?先在requirements.txt中写上urllib3==1.26.7临时解决一下这个问题。至少别耽误大家跑CI啊。

差异

fly进去的容器是用名为builder/Dockerfile构建的,我测试的是websvc是websvc/Dockerfile构建的,两者基本没什么差别。

我自己跑测试用例是用的websvc,而跑CI用的是builder。

可是问题来了,二者明明用了一样的requirements.txt,怎么会安装出来不一样的library?pip install -r requirements.txt 之后也没有安装别的,怎么就版本不一致了?

后来经过一步一步测试,最终发现了这背后的原因。

没事别在容器里装openssh-server,真的

根本原因

builder/Dockerfile中,我们安装了openssh-server,先别管为啥……

openssh-server有非常多的依赖,如下图中选中的地方,就有python3-urllib3

没事别在容器里装openssh-server,真的

apt中的python package的版本是相对而言比较老的,经过查看这种方式安装的urllib3的版本是1.22

没事别在容器里装openssh-server,真的

requirements.txt 中,我们安装的是requests==2.25.1gql==3.0.0b0。这两个package对urllib3的版本要求比较宽泛,通过apt 安装的这个版本恰巧能够满足。

没事别在容器里装openssh-server,真的

websvc这个image由于没有通过apt安装openssh-server,所以也没有python3-urllib3。在 pip install -r requirements.txt时,requests 2.25.1的要求是urllib3>=1.21.1,<1.27,也就安装了1.26.7(可用的版本)

综上所述,在构建之后,builder这个image中 urllib3的版本就是1.22;而websvc是1.26.7。这也就是为什么本机永远无法复现而只有在fly hijack之后才可以复现的原因

所以root cause是,在 builder中安装了openssh-server(容器里安装openssh-server干嘛🤣)

直接原因

direct cause是 gql==3.0.0b0 install_requires 没有要求urllib3的版本,也可能是graphql-core,或者说requiremens.txt应该写gql[all]==3.0.0.b0,但是很少有人这么写啊,真的是醉了。

间接原因

那为啥之前都一直没问题怎么突然就挂了?

一番实验之后也发现了原因。之前Base image升级到了Ubuntu 18.04,16.04的时候Ubuntu自带的python版本是3.5,所以哪怕安装了openssh-server,那也是py3.5的,而我们用的是从ppa安装的3.6所以无关联。

升级之后,18.04自带的Python是3.6,即使通过ppa安装其实也是“共享”的,因此…

修复方法

修复的办法包括

  1. patch掉graphql的调用
  2. requirements.txt中强制安装新版本urllib3
  3. builder/Dockerfileopenssh-server改成wget(安装openssh-server时会附带wget,后续我们需要wget

总结

  1. 升级升级到Ubuntu 18.04是我搞的,我背锅。境外势力已经够忙了,请不要诬陷境外势力。
  2. Dockerfile可以再更新一下了,把PPA去掉,一些重复的安装(指apt和pip)可以只保留pip了。openssh-server 也可以去掉,历史遗留问题。
  3. 为啥不用multi-stage build?估计也是历史遗留原因。
  4. 没事别在容器里安装openssh-server,真的。除非你知道你在干嘛。或者装降低熊。

没事别在容器里装openssh-server,真的


文章版权归原作者所有丨本站默认采用CC-BY-NC-SA 4.0协议进行授权|
转载必须包含本声明,并以超链接形式注明原作者和本文原始地址:
https://dmesg.app/no-openssh-server-container.html
喜欢 (27)
分享:-)
Benny小土豆
关于作者:
If you have any further questions, feel free to contact me in English or Chinese.
发表我的评论(代码和日志请使用Pastebin或Gist)
取消评论

                     

去你妹的实名制!

  • 昵称 (必填)
  • 邮箱 (必填,不要邮件提醒可以随便写)
  • 网址 (选填)
(6)个小伙伴在吐槽
  1. 看了一下 gql 的文档,感觉至少应该写gql[requests]就能避免这个问题。 个人感觉根本原因还是 Python Packaging & Dependency Management 拉垮,就算在容器里面也不能觉得全剧环境很干净就掉以轻心,还是得开 venv(或者等 PEP 582) 谢谢小土豆,学到很多~
    Queensferry2022-01-19 18:58 回复
    • Benny小土豆
      这样binding其实就足够了,gql要背锅。
      Benny小土豆2022-02-02 17:24 回复
  2. 手边只有Ubuntu 20.02:依赖关系应该是这样"openssh-server" -> "ssh-import-id" -> "python3-requests" -> "python3-urllib3" 而"ssh-import-id"是"openssh-server"推荐,不是必须。理论上"apt install"的时候带上"--no-install-recommends"参数可以关掉
    Kane2022-01-18 11:16 回复
    • Benny小土豆
      差不多是这样(还是别装了,挺大一坨东西的
      --本评论由Telegram Bot回复~❤️
      Benny小土豆2022-01-18 11:17 回复
  3. :mrgreen: 不错不错,学习了
    zhangsan2022-01-17 20:59 回复
    • Benny小土豆

      --本评论由Telegram Bot回复~❤️
      Benny小土豆2022-01-17 20:59 回复