<audio id="audio" title="用户故事 | 莫名：相信坚持的力量，终会厚积薄发" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/90/85/90b5359yy1f17b63f9bed65f0a733f85.mp3"></audio>

你好，我是莫名同学，坐标杭州。

我已经工作六年多了，曾经参与过对象存储、大数据等产品的开发。最近两年，我开始接触容器云平台系统开发与性能优化方向的工作。

最初是偶然的一次机会，我关注了eBay技术荟公众号，认真拜读过作者的eBay云计算网事系列文章，受益匪浅，从中汲取了不少排查网络疑难杂症的新思路。但意犹未尽，一直期待有机会看到作者更多的分享。

后来，又看到极客时间**《容器实战高手课》**的课程预告，作者正是程远老师，而且课程内容也和我现在做的工作不谋而合。我满怀期待地翻了一遍开篇词，激起了不少共鸣，于是毫不犹豫地购买了该专栏。

我比较赞同作者“一个态度，两个步骤”的方法论。可以说，近年来我也是这个方法论的忠实践行者。正如作者所言，**容器的大多数问题，最终都可以映射到Linux操作系统相应模块上。**因此，想要在容器方面技高一筹，意味着需要苦练内功，深入了解隐藏在容器背后的Linux操作系统知识原理。

记得我刚参加工作的前几年，我没有直接接触过容器技术，对Linux了解也不多，仅仅停留在使用层面，遇到问题经常一头雾水。

庆幸的是，从2017年末起，我开始沉下心来学习Linux相关技术，从基础知识到内核源码，一步一步地向前进。这个过程中，也逐渐养成了遇到问题刨根问底的思维习惯，而这种态度，也正是这个专栏里一直倡导的。

2019年初，我开始真正接触容器技术，凭借平时积累了比较扎实的Linux知识功底，遇到的多数容器问题都能够迎刃而解，“两个步骤”在平时的系统性能分析与优化工作中得以体现。

## 我为什么要学习专栏？

选择学习专栏的主要原因有两个，一方面是完善知识体系，另一方面是拓宽自己的技术思路。

经过前期了解，我认为作者技术经验丰富。他经历了Kubernetes容器云平台在eBay的具体落地过程，解决过大大小小的各类问题，是货真价实的容器实战高手。在学习专栏之前，我自己简单整理过一套容器知识结构体系。不过相比之下，作者列出的容器知识结构体系更加完备。

所以，我期待借鉴作者的思路重新审视自己的理解，查漏补缺、温故知新，并在专栏更新过程中通过留言和作者进一步交流心得体会。相信经过系统的学习，我也能更好地建立自己的知识架构。

另外，既然这门课是实战课，自然少不了动手实战，我期待可以在案例中，借鉴老师解决问题的思路。

作者在eBay云计算网事系列文章中曾提过，Kubernetes容器云平台在大规模应用场景下的偶发性问题十分棘手，如果手忙脚乱地进行各种尝试，可能会事倍功半、越理越乱。事实的确如此，在复杂的Linux环境下，传统的性能分析工具应对这些偶发性问题，已经略显捉襟见肘了。

过去一年里，我也曾使用perf、ftrace、BCC/bpftrace等Linux性能分析工具解决过网络抖动、存储写入延迟等偶发性问题。但是仍然担心自己的思路存在局限性，所以很期待作者专题加餐的分享，看看这些工具在容器网络不稳定的真实案例中要怎么综合运用，拓宽自己定位、解决类似问题的思路。

## 我是怎么学习专栏的

我应该是订阅比较早的同学了，现在想想，能够坚持学完整个专栏，而且在更新期间跟老师做了积极互动，主要有这样三个方法。

<img src="https://static001.geekbang.org/resource/image/d1/29/d16e5761504a9cc4dff7ed5382db9329.png" alt="">

### 1.坚持学习，用好碎片时间

专栏的首刷，我基本上是利用碎片化的时间完成的。每周一、三、五专栏更新时，我会在早上通勤路上先把内容过一遍，从整体上把握文章思路。

由于碎片时间很难保持较高专注度，我倾向于选择轻松一些的阅读方式，不刻意做过多的深度思考，但是会把自己比较赞同或疑惑的知识点先标记下来，以便后续重点学习。

专栏内容结构简练、清晰，一共二十多篇，其实我觉得坚持下来并不难。专栏更新过程中，我利用工作闲暇时，针对最有收获的几篇文章反复刷了若干次，结合文章示例动手实践，并翻阅相关的Linux、Docker源码，将首刷时留下的疑点逐一击破。

两个月下来，这样的学习让我受益匪浅，进一步拓宽了自己的容器知识结构体系，也学到了分析常见容器性能问题的新思路。

**我相信，当一个人开始把坚持学习当作一种习惯，并且善于合理利用碎片时间提升自我的时候，他已经走在超越大多数人的道路上。**

### 2.知行合一，善于思考总结

每个专栏作者几乎都会反复强调：学习专栏时，请动手实践文章中提到的示例以及课后思考题。所以，学习中思考与实践的重要性不言而喻。

数学家华罗庚说过，他的学习方法很简单，就是“读书要从薄到厚，再从厚到薄”。其实专栏的学习也是同样的道理。在我看来，专栏每篇文章都浓缩着作者历经磨砺后的思考与总结，有些很难一次性消化，所以需要我们在不断实践与思考中领悟。

我觉得，专栏起到的是一个**领航**的作用，想要相关的知识点我们可以根据自己的需要继续做功课，这样才能不断精进。遇到有疑问的地方，我会通过官方文档、源码等方式深挖这些知识点背后原理，希望可以由点及面，直达问题本质。

有了这样的问题导向，我才会进行更多深度思考，在研究、解决问题的过程中，也加深了自己对知识的理解。下面举几个我曾经思考并想办法弄清楚的问题：

- 什么是容器绑定挂载？容器创建过程中涉及哪些挂载行为和传播方式？
- 为什么说虚拟网络设备veth的行为像一根网线？
- 如何使用strace追踪容器创建的大致过程？
- 拥有独立Network Namespace的容器如何反过来操控宿主机的防火墙、路由表等？
- 为什么Pid Namespace可以使得容器的init进程的PID总是为1？
- ...

### 3.敢于怀疑，拒绝教条主义

延续刚才说的知行合一。其实我们学习的时候，对有疑问的内容拒绝教条主义，这也很重要，我举个例子吧。

第12讲学习容器Quota技术的时候，文章里用到的例子是xfs quota。但我认为，目前容器quota技术存在以下局限性：容器通常采用overlay存储驱动，仅支持在宿主文件系统xfs上开启quota功能，这意味着overlay over ext4不支持project quota功能。

虽然ext4自身支持project quota功能（Linux4.5版本之后）。但是，overlay over ext4却不支持project quota功能。

经过我的尝试，采用overlay over ext4启动容器，会报以下错误：

Docker:Error response from daemon: --storage-opt is supported only for overlay over xfs with 'pquota' mount option.

[官方文档](https://docs.docker.com/engine/reference/commandline/run/#set-storage-driver-options-per-container)里也有提到：For the overlay2 storage driver, the size option is only available if the backing fs is xfs and mounted with the pquota mount option（大意是overlay存储驱动仅支持基于xfs开启project quota功能）。

## 专栏中最有收获的文章是哪几篇？

首先是[第2讲](https://time.geekbang.org/column/article/309423)，我印象最深的是这篇文章最后的总结了，提到容器里1号进程对信号处理的两个要点：

1.在容器中，1号进程永远不会响应SIGKILL和SIGSTOP这两个特权信号；<br>
2.对于其他的信号，如果用户自己注册了handler，1号进程可以响应。

其中，要点2打破了我的固有认知。我原先一直认为在容器中1号进程无法被杀死，而这一讲结合相关内核源码与若干示例充分证明了这一要点，思路清晰，令人受益良多。

在[第9讲](https://time.geekbang.org/column/article/316436)学习Memory Cgroup的时候，课程里提到，每个容器的Memory Cgroup在统计每个控制组的内存使用时包含了两部分，RSS和Page Cache。

不过我认为，Momory Cgroup除了包括RSS 和Page Cache，还包括了对内核内存的限制，作者给出的例子情况比较简单，基本没有使用slab，倘若在容器中打开海量小文件，内核内存inode、dentry等会被计算在内。

内存使用量计算公式（memory.kmem.usage_in_bytes表示该memcg内核内存使用量）：

memory.usage_in_bytes = memory.stat[rss] + memory.stat[cache] + memory.kmem.usage_in_bytes

另外，Memory Cgroup OOM不是真正依据内存使用量memory.usage_in_bytes，而是依据working set（使用量减去非活跃 file-backed 内存），working set计算公式是：

working_set=memory.usage_in_bytes-total_inactive_file。

接下来要说说[第14讲](https://time.geekbang.org/column/article/321330)，文章首先抛出一个引人关注的现象：应用程序从虚拟机迁移到容器并施加Memory Cgroup 限制时，文件写入出现较大的延时波动。

我印象最深的是，这一讲通过程序复现、理论分析、工具追踪等一系列手段，最终得出一个令我深有同感的结论：在对容器做Memory Cgroup限制内存大小的时候，不仅要考虑容器中进程实际使用的内存量，还要考虑容器中程序I/O的量，合理预留足够的内存作为Buffered I/O的Page Cache。

其实学习容器技术没不久，我就已经了解到，容器网络延迟相比宿主机高出10%左右，但并未深入思考过网络延迟变高的具体原因。

而专栏[第17讲](https://time.geekbang.org/column/article/324122)内容讲网络延时的时候，从veth driver的内核源码入手，合理解释了容器网络性能损失的来龙去脉，感觉收获很大，可以说是透过现象挖到了本质。受到这一讲的启发，对排查网络延迟问题，我又多了新的思路。

## 总结

在这个专栏学习结束后，我回过头来看，很高兴已经达到当初选择学习专栏的目的。

阅读过程整体比较顺畅，尤其觉得作者列出的Linux源码恰到好处，产生不少共鸣，因为在探究容器问题过程中，我也曾经阅读过这些代码。

感谢极客时间为我们提供了如此优秀的学习平台，也感谢作者为我们带来了非常精彩的容器实战课程。希望订阅这门课程的同学，也能有所收获，把学到的知识用到工作里。

**我觉得，无论是学习容器，还是学习其他技术知识，就好像升级打怪一样，苦练基本功，手感和意识才会逐渐提升。最后，希望我们都能成为容器高手，让我们相信坚持的力量，终会厚积薄发！**
