学无止尽

Docker 学习的道路真的是学无止尽,以下笔者列出三十天里没有提到的东西,有兴趣的读者可以用关键字查询。

最後,来个小测验考考大家是不是对 Docker 更了解:

本测试有参考 Best practices for writing Dockerfiles

  1. Docker image 与 container 之间的关系,下列哪种描述「错误」?
    • (A) Container 必须基於 image 产生;但相对地,image 无法藉由 container 产生。
    • (B) 同个 image ID 内容是不可变的(immutable),而 container 内容是可变的(mutable)。
    • (C) 若使用某个 image 运行一个 container,则想移除 image 前,必须先移除 container 才能移除 image。
    • (D) 上述 ABC 都正确。
    • (E) 上述 ABC 都「错误」。
  2. 考虑部署「线上环境」,VM 与 container 的选择与比较,下列哪种描述「错误」?
    • (A) Container 启动速度比 VM 快。
    • (B) Container 记忆体使用量比 VM 小。
    • (C) 若过去是使用 VM,想改用 Container 就必须使用与 VM 一样的作业系统建置,才能确保系统运作正常。
    • (D) 上述 ABC 都正确。
    • (E) 上述 ABC 都「错误」。
  3. 在符合 Docker 官方的最佳实践(Docker best practices)与 12 Factor 原则的前提下,有一个 load balance 後面接多个 container 部署在「线上环境」,平常好好的,今天发现某一个 container 程序运作异常(如:即将 OOM),但後端服务(backing service)没异状。此时最「不」应该采取下列哪种做法?
    • (A) 启动一个新的 container 接到 LB,然後中断有问题的 container 流量。
    • (B) 透过 rolling update 机制,将该 container 砍掉重练。
    • (C) 尝试进入有问题的 container,利用工具 debug。
    • (D) 上述 ABC 做法都符合。
    • (E) 上述 ABC 做法都「不」符合。
  4. 下列都是两个 container 组合的架构,皆可正常运行。以单一 container 作为一个 SaaS 来看,哪一种「比较不」符合 Docker 官方的最佳实践(Docker best practices)?
    • (A) Nginx container + Apache with PHP-FPM(FastCGI)container。
    • (B) Apache container + Tomcat container。
    • (C) Nginx container + Node container。
    • (D) 以上 ABC 皆符合。
    • (E) 以上 ABC 皆「不」符合。
  5. 考虑部署「线上环境」,下列建置 Docker image 与运行 container 的描述,何种做法「不」符合 Docker 官方的最佳实践(Docker best practices)?
    • (A) 持续整合(Continuous Integration)有提到要经常做验证,因此部署上线後的第一件事是在 container 上先跑单元测试,再启动应用程序。
    • (B) 利用 Docker VOLUME 参数设定,可以直接进上线用的 container,到共用 volume 目录里更新程序。
    • (C) 使用 ARG 参数,在建置 image 阶段过程才能机敏资讯加入 image 里,如此一来,机敏资讯就可以不用放原始码里了。
    • (D) 上述 ABC 做法都符合。
    • (E) 上述 ABC 做法都「不」符合。

Image 与 Container 之间的关系

第一题的答案是 (A)

A 描述错误:docker run 可以基於 image 产生 container,所以第一句话是正确的;相对地,docker commit 可以藉由 container 产生 image,所以第二句话是错误的。

B 描述正确:docker run <IMAGE ID> 指令中, 为 SHA256 digest,同个 digest 的内容无法改变。而 container 内容则是可变的,比方说进入 Nginx container 新增 HTML 档,即可立刻使用浏览器看到内容。

C 描述正确:Image 上 run 一个 container 时,可以使用 docker rmi -f <IMAGE ID> 强制把 image 移除。虽然无法再使用该 Digest 再次启动 container,但实际上 image 内容依然是存在的,因为重新 pull image 会发现 Already exists 的关键字。实际测试指令如下:

$ docker run php:7.4 php -v
Unable to find image 'php:7.4' locally
7.4: Pulling from library/php
...
$ docker rmi -f php:7.4
Untagged: php:7.4
Untagged: php@sha256:...
Deleted: sha256:...
$ docker pull php:7.4
7.4: Pulling from library/php
xxxxxxxxxxxx: Already exists
xxxxxxxxxxxx: Already exists
...

了解 image 与 container 的关系後,才能进一步了解 Docker 是如何建置、如何加速建置、启动 container 等。

VM 与 Container 的比较与选择

第二题的答案是:(C)

此题目要考虑下列两件事:

  1. 「考虑部署线上环境」,因此没有环境一致的问题,只要考虑 VM 或 container 放到线上的选择或比较即可。
  2. 因情境是「考虑部署」与「VM 与 container 的选择与比较」,因此是在讨论 guest 而不是 host。

A 与 B 很明显正确,container 因为少了 OS 层,当然启动速度与记忆体使用量,都相较 VM 来的有优势。

C 假设过去 VM 习惯使用 Ubuntu 或是任一种 OS,现在 container 是否必须要用相同的 OS 才能正常运行(VM 跟 Container 也可以交换反过来看)?答案当然是「非必要」的,如官方 Redis image 就提供了 Debian 和 Alpine 等选择,即使作业系统不一样,只要把程序或设定做好,系统一样能正常运作。

Container 用起来跟 VM 很类似,但要记得它们本质是不同的。而不管 VM 或 container 都得经过调校才能发挥最大的优势。

Container 是一次性的(disposable)

第三题的答案是:(C)

A 与 B 其实是差不多的,差别是 B 会把 container 砍掉。

C 很明显是不能做的。进去安装 Vim 或相关除错工具明显错误就不提了,如果是为了看 log,参考 12 Factor Logs,它应该能在其他地方查得到,而不是进 container 查;如果是进去调整参数等行为,则会不符合 12 Factor Build, release, run 严格分离的原则。

现在 container 都是交由 Kubernetes 等 container orchestration 系统负责这些维运任务,但开发者也有必要了解这类问题的处理方法,才有办法写出符合 container 架构的程序。

一次性的特色可以参考 Create ephemeral containers

Container 尽可能只做一件事

第四题的答案是:(A)

参考 Decouple applications,Docker 官方是这麽说的:

Limiting each container to one process is a good rule of thumb, but it is not a hard and fast rule.

上面五种 container,唯独 Apache with PHP-FPM(FastCGI)container 是比较不符合的,因为它必须启动做两件不同任务的 process。可以注意到在 DockerHub 找到类似的 image 的 CMD,都必须要使用 Supervisor 或类似的工具来管理 process。

顺带一提,官方也没有提供 Apache + PHP-FPM 或 Nginx + PHP-FPM 的 image,而是提供只有 PHP-FPM 的 image,或是 Apache + PHP-CGI 的 image。

这概念与 SOLID 里 SRP 的优点一样:只做一件事,架构不会复杂,除错会更容易。

Container 应该怎麽应用?

第四题的答案是:(E)

A 的问题:部署上线後居然可以跑单元测试?这代表测试程序码和单元测试套件也一并被部署上线,这不符合 Don’t install unnecessary packages

正确的做法:在建置 image 前或是 Use multi-stage builds 在一开始的阶段做单元测试,最终仅部署做完单元测试後的程序码。

相对地,部署上线後,可以做冒烟测试(smoke testing)。

B 的问题:VOLUME 官方不建议用来放程序,而是放额外要保存的资料,如 MySQL 的 Dockerfile 就有设定 VOLUME /var/lib/mysql 是存放资料库档案。

正确的做法:程序上线应该透过建置新的 image,跑新的 container 来取代旧的。

可以试着反过来思考,为何我们会觉得 Docker 上跑 MySQL / Redis / Apache 很快速方便?因为它们把程序都包在 image 里了。

C 的问题:「把机敏资讯加入 image 里」这句话的意思就是,只要有办法下载 image 就能得到机敏资讯。当然可以限制下载 image 的权限,但还是有另一个问题是难以做到环境同步,因为线上环境跟测试环境会是不同的 image--因为机敏资讯设定通常是不一样的。

正确的做法:使用 ENV 环境参数(参考 12 Factor Config),把机敏资讯存在环境。

写在最後

Docker 真的是学无止尽,虽然笔者跟他相处了很久,但要写的时候,还是得东查西查。

希望这次的铁人赛能帮助到大家,感谢收看。


<<:  [Day29] 建立购物车系统 - 12

>>:  Day30 - 逆向 WannaCry 病毒,想哭病毒?

[2021铁人赛 Day12] General Skills 09

引言 昨天的题目学习到进位制以及「 ASCII code <-> 字元」转换, 关於 ...

k8s开的kubectl logs路径修改

【YC的迷路青春】 如果不要用预设的路径,例如专案是用tomcat起的,我们不想看tomcat的lo...

云端资安之AWS篇

今天要谈的是AWS(Amazon Web Services)云端服务, 这个也是众多云端服务当中,我...

JavaScript Day16 - 箭头函式

函式陈述式与函式表达式 函式陈述式:之前直接定义 function 的方式 会被提升到最上面,所以可...

EP22 - 持续部署使用 Octopus Deploy 二部曲,安装 Octopus Deploy

昨天我们耗尽洪荒之力, 终於用 terraform 配置好整个基础设施, 今天我们将继续环境操作, ...