容器:向死而生的一生

“重启”是一个具有哲学意义的话题,比如《黑客帝国》中特工史密斯可以随时在一个身体上重启自己;《明日边缘》中阿汤哥饰演的男主角在一次次的重启中不断进步,最终战胜了大 Boss;程序员的段子中,“你重启下试试”非常经典。虽然重启不能解决所有的问题,但还是能解决大部分问题的,因为重启能清除应用的当前状态,包括任何不在正常状态的代码。对于 Docker,我们可以将 restart 作为一种自我修复的机制。

如果把 Docker 容器看做生命,那必然是“向死而生”的一生:它们可能会随时被停止或删除。默认情况下,所有运行过程中产生的数据也将被清除。但就像《黑客帝国》中的特工史密斯一样,容器也可以立马以初始的状态被重启。无疑从这个角度来讲,暂时的任务是容器最常用的场景。但实际上,容器也可以完美运行 web 服务,还可以通过 volume 实现数据库和持久化数据存储。MongoDB,MySQL 和 Postgres 都是 Docker Hub 上最流行的 Docker 镜像。

一个容器的“传记”Containers Life Story

都有哪些因素影响了容器的平均寿命呢?我们可以通过容器的整个存在过程进行深入研究。在 Docker Engine 记录了容器整个生命周期的事件,还有其它的重要信息,都保存在了 /var/log/docker.log 中。我们也可以通过 docker events 命令行大体看下某个容器。这个命令会向 Docker Engine 查询某个时间段内容器内发生的重要事件。比如我们先启动一个容器:

然后,运行 docker events 看看哪些事件会被记录下来:

哇!能在命令行看到容器启动过程幕后发生了什么!

  • 首先,由于在本地未能找到镜像,Docker client 通过 Remote API 从 Docker Hub pull 下镜像;
  • 接下来,创建容器,添加 stdout/stderr 到终端;
  • 然后,新容器被加入到默认的 bridge 网络,被 engine 启动;
  • 最终,容器完成自己的使命后,就会被删除。在此之前,Docker engine 会将其移出默认的 bridge 网络中。

容器已死,容器万岁!The container is dead, long live the container!

虽然这个容器已经“死了”,我们还是能用 docker ps -a 命令捕捉到它生前的“音容笑貌”。

看起来这个容器去得很平静,因为 Exit(0) 并不是每个容器都能达到的境界。

而且虽然容器停止了,我们还是能找到它的“遗产”,因为所有容器的数据存储只有在 docker rm 执行后才会被正式销毁。 docker export 命令可以将容器的文件系统存储到一个 tar 包中。然后可以用 docker import 将其导入到同主机上的另一个容器中,或一个新的容器中。

请注意 docker export 导出的数据中不包含容器的历史。实际上,当 tar 包被导入到一个镜像中,结果镜像会被压缩为一层。

如果你在运行短期的前台操作容器,这些数据堆积会额外占用很多空间。docker run -rm 可以在容器停止后自动清理容器状态数据和镜像层。

重生?Is there life after death?

研究发现动物的基因并不会在其身体死亡立即消失,而是会存活长达四天,甚至有一些基因会在死后变得更加活跃。对于容器的“基因”当然可以保持更长的时间,而且还可以随时“复活”。

 

昨日重现Containers entire life flashes in front of your eyes the second before they die

docker event 不但让我们看到 Docker Engine 内部的工作,还能帮我们自动应对一些容器的事件。比如,类似 “Registrator” 的工具会在服务上线和下线时,使用这种机制向 Consul 自动发送注册和注销请求,可以告诉负载均衡器有新的实例进来,或有实例不能提供服务了。

生命本该如此This is your life

来自 GliderLabs 的 Matt Good 曾用一张图描述过 Docker 容器整个生命周期的事件,和引发这些事件的命令。

熟悉 Linux 信号的人都会发现这很像 Linux 中进程的生命周期,因为容器本质上就是 Linux 进程。只是 Docker Engine 利用了 Linux 内核的特性,将容器隔离起来,但容器内的进程可以和文件系统或网络交互,就好像自己是系统内唯一的进程。信号提供了一种处理异步事件的方式,可以用在 Docker 容器的进程上。 

不能承受的容器之轻The unbearable lightness of being a container

就像 Linux 一样,可以用 kill 命令停止一个不正常或空闲的容器,并且无需注销或重启底层的服务器。Kill 命令会向容器中的主进程发送一个 SIGKILL 的 Linux 信号,同样 stop 命令会发送 SIGSTOP 的Linux 信号。这些在 Brian DeHamer 的文章中有详细的描述,本文将重点分析上图中其它的命令和事件:pause,OOM 和 destroy。 

暂停Making a pause

为什么要 pause 一个容器?好吧,你可能需要暂停一个拖慢进度的容器,或者想对这个容器做一下备份。 

有人预测 docker pause 未来可以用在容器的热迁移上。理论上,容器的热迁移是没有意义的,因为它们是无状态的,一次性的,还可以随时重启,但是…… 

避免“拥堵”Defending yourself from being choked

默认情况下,所有的容器都是平等的:它们享有同样的 CPU 周期和 IO,还能自由地使用内存。但某些情况下,我们需要用一些限制参数打破这种平等的待遇。比如,为了防止某些容器一直占用内存,造成 OOM(Out Of Memory)事件,“堵塞”服务器。但是,需要先去设置内存的限制。

首先我们来模拟下 OOM 的情景,来看下如果设置了内存限制,Docker Engine 是如何发挥作用的:


这个例子基于《Docker in Practice》一书中 301 的一个实例,在第一种情况下,被杀死的是进程(非主进程),而第二种情况下才是容器,为什么? 

健康检查Health checks that could save your container

要注意 Linux 内核在异常情况(比如资源不足)下只会 kill 一个进程,可能这样做已经太迟了。为什么不在应用出现问题前,提前检查呢?

在 Docker 1.12 中,不但可以在运行时进行限制,还能在启动容器时添加用户自定义的健康检查探针。比如,我们可以周期性地验证一个 web 服务是否在正常工作,而不仅仅是避免紊乱情况或内存溢出。

可以将健康检查作为 docker run 的选项,或写在 Dockerfile 中,docker ps 命令除了容器的常规状态,也会显示其“健康状况”。如下所示,第一次 docker ps 执行时,监控探针还是 starting 的状态,当第一个探针通过后变成 healthy 的状态。接下来我们用 docker inspect 查看容器的健康状况。我们通过删除一个配置文件制造不健康的假象,在一系列的探针失败后,最终容器被加上了 unhealthy 的标志。 

在当前的 Docker Engine 版本(1.12r3)中,容器不会在 unhealthy 的状态下重启,所以要检测容器的状态,手动地重启容器。

重启Reboot your life or your container

在程序员的段子中,“你重启下试试”是很经典的一个,虽然重启不能解决所有的问题,但还是能解决大部分问题的,因为重启能清除应用的当前状态,包括任何不在正常状态的代码。

对于 Docker,我们可以用 restart 作为一种自我修复的机制(就像《明日边缘》中汤姆克鲁斯饰演的男主角)。但是,需要注意的是,默认情况下容器不会在主进程存在的情况下重新启动。我们可以强制 Docker Engine 在任何情况下都重新发布这个容器,或者只在主进程错误退出时重启这个容器: 

重置We should just reset

小故障可能会引起整个应用的崩溃,on-failure 重启的政策可以帮助我们在容器返回非 0 退出时就重新发布。

注意上面 Docker Engine 是如何提高再启动延时的,直到其达到最大的 on-failure 重启数。

不被打扰的容器Untroubled containers

在 Docker 1.12 中,又可以运行 daemonless 的容器啦!这意味着你可以在不影响或重启容器的情况下,停止、升级、重启Docker Engine,期间服务不会受到任何影响。这个特性之前被取消过,因为会给 Docker 初学者造成困惑。

为了能使用这个功能,要在启动 Docker Engine 时添加 live-restore 的 选项,保证 Docker 在关闭和重启的过程中,不会 kill 运行中的容器。如下,使用 docker-machine 传递 live-restore 的选项:

颂词A eulogy

容器确实随时都面临着“死亡”,但是有了重启,健康检查探针和热修复机制,没有必要担心。套用马克·吐温的一句话:“对死亡的恐惧源于对生活的恐惧。完全活过的容器,随时都准备着死。”

原文发布时间为:2016-07-20

时间: 2024-11-01 21:17:43

容器:向死而生的一生的相关文章

说到容器的安全性,我觉得它就像三明治

本文讲的是说到容器的安全性,我觉得它就像三明治,[编者的话]作者Josh Bressers用生动的比喻把容器比做一个三明治,而容器安全则是隐藏在三明治里面不为人知的成分.选择一个安全可用的容器,就如同选择一个放心可吃的三明治一样. 在RSA会议上,当我正在谈论容器时忽然想到,我们可以认为容器就像一个三明治,不是说他们有多"好吃",而是关注于你的容器是从哪里来的.我感到高兴的是,几乎所有我与之交谈的安全人员,他们都了解当前的容器安全噩梦,当然,挑战在于我们如何把当前的状况解释给其他人.安

Integration Services:容器

容器是Integration Services 包中非常重要的一部分功能,它可以对控制流中的任务进行直观的划分与组织,使包的结构简明扼要.易于管理.易于维护. 在Integration Services 中,主要有以下三种类型的容器: 序列容器(SequenceContainers).For 循环.Foreach 循环.下面我们将一一介绍这三种容器的使用方法. (一).序列容器(SequenceContainers). 序列容器是一种十分简单,但使用非常广泛的容器,它可以对控制流的任务流组件进行

专访阿里云易立:从实践积累到需求沉淀,容器技术必将引领主流

2017杭州云栖大会详情请戳这里! 容器技术是目前云计算领域最受关注的方向之一.阿里云在2015年底推出了容器服务,之后在2016年云栖大会上宣布和Docker建立合作关系,今年阿里云和Docker公司的合作全面开花结果.易立作为阿里云资深技术专家,目前在阿里云负责云应用服务,并主要关注容器技术.开发者工具和开源生态领域的产品和技术.随着容器.集群调度.微服务等开源技术的发展,在本次访谈中,易立详细介绍了阿里云在容器技术和Cloud Native生态建设上思考与探索. 阿里云资深技术专家易立 容

将Node.js项目docker容器化并纳入kubernetes调度编排的实践

  简述 此文档以XXXLogApi-nj项目为例,讲解了将基于Node.js+Express开发的javascript项目容器化的过程.希望以后类似的项目可以以此为参照进行扩展. XXXLogApi-nj本身是一个微服务化的项目,其作用是为系统单纯的收集相关发布日志,以便能及时的展示给用户. ***这份文档的操作,开始于编码完成之后流程.不涉及GIT和JENKINS的等的操作. ***为保持职业操作,涉及公司信息的地方作了敏感化处理. ***在这个系列中,我同时作了spring boot, b

2016美国QCon观察:容器与调度这么热,未来会是怎样的一个趋势?

编者按:今年QCon容器/Docker和微服务几乎占据了会场的半壁江山,大家也都趋之若鹜场场爆满,而且作为一名云计算工程师,对容器/Docker也是格外关注,容器/Docker已经不仅仅是个技术,而是作为一个生态在深刻影响着每一个细分行业,对于每个行业既是机会也是挑战,稍有不慎可能就会被时代抛弃.作为与会者现场聆听大家对容器/Docker的思考和应用,并逐步廓清现状和未来,与大家共同学习.     容器(Container)是近些年迅速火热的一门技术和话题,容器技术本身和在容器之上衍生的资源编排

如何保证摘除公网EIP的容器服务VPC集群可以正常访问公网

在使用容器服务的过程中.出于业务的需要,用户需要创建VPC集群,但是又不希望每台ECS都绑定公网EIP,一方面是出于业务私密性的保护,另外一方面是出于节约成本的考虑. 基于以上场景,我们可以让集群内的机器,通过一台有EIP的机器来上网.在这个过程中主要使用到了SNAT相关的知识. 先找一台同Region内的VPC机器,为该机器配置EIP 登陆到配置了EIP的ECS,为机器开启IP转发功能,找到#net.ipv4.ip_forward=1行,去掉注释即可 执行以下命令,让IP转发生效 iptabl

Castle IOC容器内幕故事(上)

主要内容 1.WindsorContainer分析 2.MicroKernel分析 3.注册组件流程 一.WindsorContainer分析 WindsorContainer是Castle的IOC容器,也是它的一个核心,先来看一下WindsorContainer在Castle中所处的位置: 图1 WindsorContainer构建于MicroKernel之上,MicroKernel仅仅是提供了一个IOC的容器,非常的轻巧,它只依赖于Castle.Model一个程序集,但它的可扩展能力却很强,

javase-关于马士兵老师的坦克大战小程序为什么用了LIST容器来装炮弹还是只能一发一发的打

问题描述 关于马士兵老师的坦克大战小程序为什么用了LIST容器来装炮弹还是只能一发一发的打 主窗口TankClient.java代码如下:import java.awt.*;import java.awt.event.*;import java.util.List;import java.util.ArrayList; public class TankClient { public static void main(String[] args) { new MyFrame(""Tan

容器服务slack运维机器人

初识slack 几年前开始创业,组建团队的第一天,我们首先讨论和考虑的不是高屋建瓴的业务场景和目标,而是整个团队的协同和沟通的问题.选择使用什么作为团队的IM,选择什么作为BUG的记录,选择什么作为需求的跟踪,这些基础设施的存在无形中提高了整个团队的生产力,保证了协作的顺畅和流程.由于团队的成员有些是外国人,而在国外GEEK圈中风光无限的SLACK也就顺理成章的被老外们安利到了团队中. 那么slack是个什么东西呢. Slack 是聊天群组 + 大规模工具集成 + 文件整合 + 统一搜索.截至2