总结

  • multiprocessing.cpu_count() 获取 CPU 核数不准确
  • 在 docker 上使用 docker 而不是 supervisor 来监控程序.
  • 屏幕输出日志就可以.

正文

首先开宗明义,定义先行,我自己的态度很明确 不推荐在必要的场合以外使用 Docker 或者说更明确的是 不推荐初学者或中小公司在生产环境中使用 Docker

大家现在对于 Docker 其实有一种错觉,凡事涉及到隔离,跨平台,就第一反应想到 Docker。但是实际上 Docker 的使用或者说容器化的使用其实是一件很有挑战的事情,所以我来聊聊。

  1. 已有经验的迁移并不是一件代价很低事

举个例子,大家使用 Gunicorn 的时候,习惯使用 multiprocessing.cpu_count() 来获取 CPU 数量,并以此作为基准来设计 Worker 的数量。但是实际上,如果容器限制了对应的 CPU 资源,multiprocessing.cpu_count() 并不能有效的获取 CPU 数量,从而造成进一步的资源浪费。再比如,大家在物理机上,习惯使用 Supervisor 来作为进程管理的工具,但是在 Docker 上利用 Supervisor 可能就是一件不太合适的事。这样的例子还有很多,将已有的经验进行迁移是一个代价不小的事情

  1. 容器化是非常依赖于基础设施的一件事
    这里的基础设施包含两个维度,一个是治理设施的配套。一个是 Docker 本身的调优
    治理设施的配套其实包含很多东西,比如监控系统的建立,trace 系统的建立,包括服务注册中心的建立,调度设施,Gateway 等等。虽然说目前 K8S 和周边社区给予了一套开箱即用的方案,但是基本上还是需要开发和公司拥有对应的技术储备以及拥有一部分进行定制的能力。讲道理,去熟悉 K8S 这一套还是挺难的(比如我就不会)
    而 Docker 本身的调优也不是一个轻松的活。怎么样去压缩镜像大小,怎么样去优化 Docker 网络性能,怎么样去排查一些疑难问题。举个例子,17年的时候,我遇到过一个问题,当时我自己的一个服务(规模不大),频繁出现 (Connection aborted.’,RemoteDisconnected….) 的异常。后续排查问题是我日志输出(直接输出到 stdout)的姿势有问题,打了太多不该打的日志,而 Docker daemon 日志性能搜集出现了问题,导致 Work 频繁超时,从而被 Gunicorn 杀掉,造成生产异常。虽然说这些问题,都有很好的解决方案,比如通过 1.8 之后的 plugin 机制,用高性能的网络和 volumn 组件进行替换等等,但是无一例外,这些都依赖于基础设施的完备性,以及定位问题时需要依赖与公司 SOP的完备性。

  2. 容器化对于本地开发和调试都是不友好的
    其实很简单,因为为了缩减镜像的大小,我们很多镜像都基于 slim 这样的微镜像进行构建,在这种情况下,很多调试工具,比如 gdb 等会受到一定程度的限制(调试的时候堪称吃屎(