标签 容器 下的文章

容器构建有两大趋势:使用基本镜像和从头开始构建。每个都有工程上的权衡。

有人说 Linux 发行版不再与容器有关。像 distroless 和 scratch 容器等可替代的方法,似乎是风靡一时。看来,我们在考虑和做出技术决策时,更多的是基于时尚感和即时的情感满足,而不是考虑我们选择的次要影响。我们应该问这样的问题:这些选择将如何影响未来六个月的维护?工程权衡是什么?这种范式转换如何影响我们的大规模构建系统?

这真让人沮丧。如果我们忘记了工程是一个零和游戏,有可衡量的利弊权衡,有不同方法的成本和收益 —— 这样对我们自己不利,对雇主不利,对最终维护我们的代码的同事不利。最后,我们对所有的维护人员(向维护人员致敬! )都是一种伤害,因为我们不欣赏他们所做的工作。

理解问题所在

为了理解这个问题,我们必须首先研究为什么我们使用 Linux 发行版。我将把原因分为两大类:内核和其他包。编译内核实际上相当容易。Slackware 和 Gentoo( 我的小心脏还是有点害怕)教会了我们这一点。

另一方面,对于一个可用的 Linux 系统需要打包大量的开发软件和应用软件,这可能会让人望而生畏。此外,确保数百万个程序包可以一起安装和工作的唯一方法是使用旧的范例:即编译它并将它作为一个工件(即 Linux 发行版)一起发布。那么,为什么 Linux 发行版要将内核和所有包一起编译呢?很简单:确保事情协调一致。

首先,我们来谈谈内核。内核很特别。在没有编译好的内核的情况下引导 Linux 系统有点困难。它是 Linux 操作系统的核心,也是我们在系统启动时首先依赖的。内核在编译时有很多不同的配置选项,这些选项会对硬件和软件如何在一个内核上运行产生巨大影响。这方面中的第二个问题是,系统软件(如编译器 、C 库和解释器)必须针对内核中内置的选项进行调优。Gentoo 的维基以一种发自内心的方式教我们这一点,它把每个人都变成了一个微型的开发版维护者。

令人尴尬的是(因为我在过去五年里一直在使用容器),我必须承认我最近才编译过内核。我必须让嵌套的 KVM 在 RHEL7 上工作,这样我才能在笔记本电脑上的 KVM 虚拟机中运行 OpenShift on OpenStack 虚拟机,以及我的 Container Development Kit(CDK)。我只想说,当时我在一个全新的 4.X 内核上启动了 RHEL7。和任何优秀的系统管理员一样,我有点担心自己错过了一些重要的配置选项和补丁。当然,我也的确错过了一些东西。比如睡眠模式无法正常工作,我的扩展底座无法正常工作,还有许多其他小的随机错误。但它在我的笔记本电脑上的一个 KVM 虚拟机上,对于 OpenStack 上的 OpenShift 的实时演示来说已经足够好了。来吧,这很有趣,对吧?但我离题了……

现在,我们来谈谈其他的软件包。虽然内核和相关的系统软件可能很难编译,但从工作负载的角度来看,更大的问题是编译成千上万的包,以提供一个可用的 Linux 系统。每个软件包都需要专业知识。有些软件只需要运行三个命令:./configuremakemake install。另一些则需要大量的专业知识,从在 etc 中添加用户和配置特定的默认值到运行安装后脚本和添加 systemd 单元文件。对于任何一个人来说,调试好你可能用得到的成千上万种不同软件所需要的一套技能都是令人望而生畏的。但是,如果你想要一个可以随时尝试新软件的可用系统,你必须学会如何编译和安装新软件,然后才能开始学习使用它。这就是没有 Linux 发行版的 Linux。当你放弃使用 Linux 发行版时,那么你就得自己编译软件。

关键是,你必须将所有内容构建在一起,以确保它能够以任何合理的可靠性级别协同工作,而且构建一个可用的包群需要大量的知识。这是任何一个开发人员或系统管理员都无法合理地学习和保留的知识。我描述的每个问题都适用于你的 容器主机(内核和系统软件)和 容器镜像(系统软件和所有其他包)——请注意:在容器镜像中还包含有编译器 、C 库、解释器和 JVM。

解决方案

所以你也看到了,其实使用 Linux 发行版就是解决方案。别再看了,给离你最近的软件包维护者(再次向维护人员致敬!)发张电子卡吧(等等,我是不是把我的年龄告诉别人了?)。不过说真的,这些人做了大量的工作,这真的是被低估了。Kubernetes、Istio、Prometheus,还有 Knative:我在看着你们。你们的时代要来了,到时候你们会进入维护模式,被过度使用,被低估。大约七到十年后,我将再次写这篇文章,可能是关于 Kubernetes 的。

容器构建的首要原则

从零开始构建和从基础镜像构建之间存在权衡。

从基础镜像构建

从基础镜像构建的优点是,大多数构建操作只不过是安装或更新包。它依赖于 Linux 发行版中包维护人员所做的大量工作。它还有一个优点,即六个月甚至十年后的修补事件(使用 RHEL)是运维/系统管理员事件 (yum update),而不是开发人员事件(这需要通过代码找出某些函数参数不再工作的原因)。

你想想,应用程序代码依赖于许多库,从 JSON mung 库到对象关系映射器。与 Linux 内核和 Glibc 不同,这些类型的库很少改变 API 兼容性。这意味着三年后你的修补事件可能会变成代码更改事件,而不是 yum 更新事件。因此让他自己深入下去吧。开发人员,如果安全团队找不到防火墙黑客来阻止攻击,你将在凌晨 2 点收到短信。

从基础镜像构建不是完美的;还有一些缺点,比如所有被拖入的依赖项的大小。这几乎总是会使容器镜像比从头开始构建的镜像更大。另一个缺点是你并不总是能够访问最新的上游代码。这可能会让开发人员感到沮丧,尤其是当你只想使用依赖项中的一部分功能时,但是你仍然不得不将你根本用不着的东西一起打包带走,因为上游的维护人员一直在改变这个库。

如果你是一个 web 开发人员,正在对我翻白眼,我有一个词可以形容你:DevOps。那意味着你带着寻呼机,我的朋友。

Scratch 构建

Scratch 构建的优点是镜像非常小。当你不依赖容器中的 Linux 发行版时,你有很多控制权,这意味着你可以根据需要定制所有内容。这是一个最佳模型,在某些用例中是很有效的。另一个优势是你可以访问最新的软件包。你不必等待 Linux 发行版更新任何内容。是你自己在控制,所以你可以自行选择什么时候去费功夫纳入新的软件。

记住,控制一切都是有代价的。通常,更新到具有新特性的新库会拖如不必要的 API 更改,这意味着修复代码中的不兼容(换句话说,这就像给牦牛剪毛)。在凌晨 2 点应用程序不起作用的时候给牦牛剪毛是不好玩的。幸运的是,使用容器,你可以在下一个工作日回滚并给牦牛剪毛,但它仍会占用你为业务提供新价值、为应用程序提供新功能的时间。欢迎来到系统管理员的生活。

好吧,也就是说,有些时候,Scratch 构建是有意义的。我完全承认,静态编译的 Golang 程序和 C 程序是 scratch/distorless 构建的两个不错的候选程序。对于这些类型的程序,每个容器构建都是一个编译事件。三年后你仍然需要担心 API 的损坏,但是如果你是一个 Golang 商店,你应该有能力随着时间的推移修复问题。

结论

基本上,Linux 发行版做了大量工作来节省你在常规 Linux 系统或容器上的时间。维护人员所拥有的知识是巨大的,而且没有得到真正的赞赏。容器的采用使得问题更加严重,因为它被进一步抽象了。

通过容器主机,Linux 发行版可以让你访问广泛的硬件生态系统,从微型 ARM 系统到 128 核 CPU x86 巨型机箱,再到云服务商的虚拟机。他们提供可工作的容器引擎和开箱即用的容器运行时环境,所以你只需启动你的容器,让其他人担心事情的进展。

对于容器镜像,Linux 发行版为你的项目提供了对大量软件的轻松访问。即使你从头开始构建,你也可能会看到一个包维护人员是如何构建和运送东西的 —— 一个好的艺术家是一个好的偷学者,所以不要低估这项工作的价值。

所以,感谢 Fedora、RHEL(Frantisek,你是我的英雄 )、Debian、Gentoo 和其他 Linux 发行版的所有维护人员。我很感激你所做的工作,尽管我是个“容器工人”


via: https://opensource.com/article/19/2/linux-distributions-still-matter-containers

作者:Scott McCarty 选题:lujun9972 译者:Chao-zhi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

云原生时代的华为,不但打造了迅猛发展的云服务业务,也为自己的云服务打造了新“引擎”。

云原生时代的容器引擎的变化

随着“云原生”逐渐从一个流行词变成了一个不那么新鲜的技术基座。以 Kubernetes 为代表的容器编排技术、以 Docker、Containerd 占据主要份额的容器引擎,云原生技术也在不断的迭代升级中日益发展成熟。

Sysdig 2019 年的容器使用报告统计,全球整体容器市场规模以高达 30% 的速度增长,容器的规模、密度愈加扩大。在企业内部的容器规模方面,9% 的企业用户容器规模已经达到 5000 以上;在容器密度方面,与 2018 年相比,每台主机中的容器密度提高了 100%,从 15 个增加到了 30 个,其中最大节点密度已经达到 250 个。

而在这一切的背后,容器技术在某些场景中也呈现了一些不足,比如:

  • 在资源敏感环境,或需要部署高密度容器节点时,容器对基础设施的资源占用会急剧升高;
  • 当大规模应用拉起或遇到突发流量时,并发速度可能成为了瓶颈。

因此,主流的 Docker 等容器引擎在特定用例下,看起来有一些力不从心,因此一些针对某种用例进行过专门优化的容器引擎技术这些年纷纷入场。比如说,以 Kata Container 为代表的专门针对容器隔离性不够严格而设计的安全容器技术;以 Container Linux 为代表的专门针对重型应用而设计的系统容器;以 iSula 为代表的专门针对资源受限的边缘计算和 IoT 环境设计的轻量级容器技术。

这里,让我们来看一个源自于摄像头场景中的轻量级容器引擎。

来自摄像头的容器引擎

说起来你可能不信,一个摄像头里面居然还能有容器引擎。

起初,华为为了在智能摄像头上达到快速、简单切换算法应用部署的功能,经过技术研究,他们决定使用容器来实现所需的功能。

一开始,技术团队考虑对开源容器引擎 Docker 进行轻量化改造,对其裁剪和精简化、去除不需要的功能、优化组件结构等,甚至还对 Go 语言环境的编译进行了优化。但是,由于要运行在端侧的嵌入式设备上,这种裁剪和压榨资源的做法所能取得的效果有限。

在这种情况下,针对端侧和 IoT 环境,华为的 iSula 容器团队做了一个大胆的决定,使用 C/C++ 来量身打造一套轻量级的容器引擎!这真是一个大胆而充满勇气的决定。要知道,随着容器技术时代被 Docker 的出现而引爆,开发 Docker 所使用的 Go 语言就成为容器技术领域的首选,几乎所有的容器技术的组件和框架,都是采用 Go 语言开发的。而要使用 C/C++ 语言全新开发一个容器引擎,面临着所有基础组件,甚至一些开发语言缺乏的特性都需要另行解决。比如说,在 C 语言中要解析容器技术中普遍使用 JSON 数据,而 C 语言并没有 Go 语言等现代编程语言内置的反射机制,这就需要自行实现一个合理的 JSON 数据解析引擎。

2017 年,iSula 容器团队开始了重新开发一个容器引擎的计划。

旁白:iSula 是中南美洲亚马逊丛林中的一种非常强大的蚂蚁,被称为“子弹蚁”,因为被它咬一口,犹如被子弹打到那般疼痛,它是世界上最强大的昆虫之一。

所幸的是,虽然拦路虎众多,但是这些付出是有丰厚回报的,采用 C/C++ 开发的容器引擎,也因此具有了 Docker 所不具有的一些优势。相比 Golang 编写的 Docker,使用 C/C++ 实现的 iSula 容器引擎,具有轻、灵、巧、快等特点,不受硬件规格和架构的限制,底噪开销更小,可应用领域更为广泛。在严苛的资源要求环境下,轻量模式下的 iSulad 本身占用资源极低(< 15M),再结合上特殊的轻量化镜像,可以达成极致的资源占用效果。

2018 年,iSula 开始在华为内部的部分产品上使用。2019 年,华为决定将 iSula 开源出来,让开源社区和 iSula 共同发展,因此针对 CRI 接口进行了一次大范围的重构和补全后,与 openEuler 操作系统一并开源发布。

新造的轮子野心大

以 2019 年的统计数据看,容器引擎领域中,Docker 占据了 80% 左右的份额,但是随着 Docker 引擎自身的发展不明朗,以及容器引擎规范的标准化,出现了更多的容器引擎竞争者。这其中,iSula 作为一个悄悄发展了 3 年的轻量级容器引擎,已经迭代到了 2.0 版本,并凭借其“轻快易灵”的优势,逐渐显露出了更大的“野心”。

在智能摄像头资源的端侧大显身手之后,iSula 容器团队决定将它更进一步。得益于 iSula 所打下的良好基础,iSula 团队认为这个引擎具备更大的潜力,可以发展为通用的端、边、云平台一体的容器引擎,提供统一的架构设计来满足云、IoT、边缘计算等多个场景的应用。

虽然由于发展时间较短,加之其起源于端侧场景,目前 iSula 还没有大规模地应用在云计算集群方面,但是从与 iSula 团队沟通了解到,他们对下一步将其推广至更广泛的云计算集群领域充满信心。按照他们的说法,鉴于华为优质的软件开发质量品控,以及社区对 iSula 特有优势的青睐,它的发展值得期许。

当然,事物总是具有两面性,iSula 在取得“轻快易灵”的独特优势的同时,其使用 C/C++ 作为开发语言,也对 iSula 的快速发展带来了一些影响。因为我们知道,合格甚至优秀的 C/C++ 程序员是有多么的难得,这也造成了 iSula 项目开源后,社区贡献者数量和参与的贡献难以取得大的突破。

鉴于此,据 iSula 团队内部消息,他们正在计划将 iSula 逐渐迁移到 Rust 语言来实现,目前已经有部分模块采用 Rust 开发。Rust 作为近些年来一个明星级的系统编程语言,已经在系统编程语言方面显露出来取代 C/C++ 的潜力。如果能够顺利地平滑过渡到 Rust 语言,想必对 iSula 的开发进展、软件质量和社区参与程度,有着积极的作用。

何以轻快易灵?

iSula 是全量的容器软件栈,包括了引擎、网络、存储、工具集与容器操作系统;而 iSulad 作为其中轻量化的容器引擎,可以为多种场景提供灵活、稳定、安全的底层支撑。

根据 iSulad 的设计目标和实现情况,它具有轻、快、易、灵等优势。

iSulad 之轻

iSulad 的第一个使用场景是在端侧设备上,这自然要求这个容器引擎具有轻量级资源占用的特性。再结合为端侧设备特殊定制的轻量化镜像,它可以达成极致的资源占用的效果。

除了在端侧环境,在通用场景下,iSulad 也具有不错的轻量化表现。利用轻量化的 LXC 运行时以及极其轻量的 monitor 进程,这简化了整个调用链路。

iSulad 之快

顺理成章的,采用 C/C++ 语言实现的 iSulad,自然具备运行速度快、底噪低等特性。再加上 iSulad 独特的架构设计,除了启动容器部分需要通过 fork/exec 的方式,其他部分均使用调用函数库的方式加快执行速度。

iSulad 之易

在对 CRI 接口进行了大范围的重构和补全后,iSulad 已经能在相当程度上兼容标准化的容器规范和工具,让使用者的使用习惯和应用迁移变得轻松。

为了使开发者迁移方便,iSulad 在开发一系列迁移工具,以帮助开发者将自己的应用平滑迁移到 iSulad 上来。甚至据透露,iSulad 还会支持热迁移,能更便捷的迁移开发者的应用。

iSulad 之灵

iSulad 还针对不同的使用场景提供了不同的模式,可以根据需要灵活配置切换注重性能的性能模式和注重资源占用的轻模式。

另外,作为一个具有支持全场景容器环境的引擎,iSulad 也支持了多种不同的容器形态,它内置了支持系统容器、安全容器和普通容器以及轻量化容器的支持。

iSula 和 openEuler

iSula 是华为的 openEuler 开源社区旗下的项目之一,因此这个项目也是根植于 openEuler 系统的。这对于推动 openEuler 在企业级应用的发展具有积极意义。

不过,作为一个野心勃勃的容器引擎来说,必然不会将自己局限在某个特定操作系统之上。根据 iSula 团队的信息,目前 iSula 在 openEuler 系统上具有一些独特的优势,但是该团队也在做将 iSula 向其它 Linux 系统迁移的工作,这涉及到内核的一些特殊特性和补丁,需要得到 Linux 主线内核的支持和与内核开发者社区的沟通。

推动云原生的新引擎

毋庸置疑,容器计算已经成为云计算领域的主流。无论你是否愿意,考虑将企业的传统计算环境和古典虚拟机环境迁移到以容器计算为代表的现代云计算平台,已经是大部分 CTO 和架构师们需要迫切考虑的工作了。

而华为开源的 iSula 容器引擎,相比 Docker,是一种新的容器解决方案,它提供了统一的架构设计来满足 CT 和 IT 领域的不同需求。这匹崭露头角的新黑马,是华为攻略云原生领域的新引擎之一。

无需去历数华为在云原生领域做了多少事情,这个崭露头角的 iSula 容器引擎只是华为云这辆快车上的一枚新引擎,它将会同其它开源组件将华为云带到什么高度,让我们拭目以待。

随着 Docker 的使用量越来越大,监控 Docker 容器正在变得更有挑战性。每天都有大量的 Docker 容器被创建,因此如何监控它们就变得非常重要。目前已经有一些内置的工具和技术,不过对它们进行配置有一些复杂。随着基于微服务的架构正在变成接下来事实上的标准,学会这种技术将为你的知识库再添一项新技能。

基于上述场景,对一种轻量、健壮的镜像管理工具的需求日益增加。Portainer.io 解决了这个问题。 Portainer.io(最新版本是 1.20.2)非常轻量,只需 2-3 个命令就可以配置好,已经在 Docker 用户中流行起来。

比起其他工具,这个工具有很多优势,其中一些如下所示:

  • 轻量(安装此工具仅需 2 到 3 个命令,与此同时安装镜像的大小在 26 M 到 30 M 之间)
  • 健壮且易用
  • 可用于 Docker 监控和构建
  • 提供对 Docker 环境的详细概况
  • 可以管理容器、镜像、网络和卷
  • Portainer 部署方便,仅需一个 Docker 命令(可以在任意地方运行)
  • 可以对完整的 Docker 容器环境进行监控

Portainer 同时具有以下服务:

  • 社区支持
  • 企业支持
  • 与合作伙伴 OEM 服务一起的专业服务

Portainer 的功能和特性如下:

1. 配备了漂亮的仪表盘,易于使用和监控
2. 自带大量内置模板,便于操作和创建
3. 服务支持(仅 OEM 和企业用户)
4. 对容器、镜像、网络、卷以及配置进行几乎实时的监控
5. 包含 Docker 集群监控功能
6. 功能多样的用户管理

另请阅读:如何在 Ubuntu 16.04 / 18.04 LTS 版本中安装 Docker CE

如何在 Ubuntu Linux / RHEL / CentOS 系统上安装和配置 Portainer.io

注意:下面的安装过程是在 Ubuntu 18.04 上完成的,但是对 RHEL 和 CentOS 同样适用,同时假设你已经在系统上安装了 Docker CE。

root@linuxtechi:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04 LTS
Release:        18.04
Codename:       bionic
root@linuxtechi:~$

为 Portainer 创建卷:

root@linuxtechi:~$ sudo docker volume create portainer_data
portainer_data
root@linuxtechi:~$

使用下面的 Docker 命令来运行 Portainer 容器:

root@linuxtechi:~$ sudo docker run -d -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
Unable to find image 'portainer/portainer:latest' locally
latest: Pulling from portainer/portainer
d1e017099d17: Pull complete
0b1e707a06d2: Pull complete
Digest: sha256:d6cc2c20c0af38d8d557ab994c419c799a10fe825e4aa57fea2e2e507a13747d
Status: Downloaded newer image for portainer/portainer:latest
35286de9f2e21d197309575bb52b5599fec24d4f373cc27210d98abc60244107
root@linuxtechi:~$

安装完成之后,通过主机或 Docker 的 IP 加上 Docker 引擎使用的 9000 端口在浏览器中打开 Portainer。

注意:如果 Docker 所在主机的系统防火墙开启,需要确保 9000 端口被放行,否则浏览器页面将无法打开。

在我这边,我的 Docker 主机/引擎的 IP 是 192.168.1.16,所以 URL 就是 http://192.168.1.16:9000

Portainer-Login-User-Name-Password

在创建管理员用户时,请确保密码是 8 个字符,同时用户名为 admin,然后点击 “Create User”。

接下来进入如下所示的页面,选中 “Local” 矩形框。

Connect-Portainer-Local-Docker

点击 “Connect”,

可以看到 admin 用户的漂亮首页如下所示,

Portainer-io-Docker-Monitor-Dashboard

现在 Portainer 已经准备好运行和管理你的 Docker 容器了,同时也可用于容器监控。

在 Portainer 中管理容器镜像

Portainer-Endpoints

检查当前的状态,可以看到有两个容器已经在运行了,如果你创建另一个也会立即显示出来。

像下面这样,在命令行中启动一个或两个容器,

root@linuxtechi:~$ sudo docker run --name test -it debian
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
e79bb959ec00: Pull complete
Digest: sha256:724b0fbbda7fda6372ffed586670573c59e07a48c86d606bab05db118abe0ef5
Status: Downloaded newer image for debian:latest
root@linuxtechi:/#

然后在 Portainer 页面中点击刷新按钮(会出现一条让你确认的消息,点击上面的 “Continue”),就可以像下面高亮显示的一样看到 3 个容器了。

Portainer-io-new-container-image

点击上图中红圈圈出来的 “containers”,下一个页面会显示 “Dashboard Endpoint summary”。

Portainer-io-Docker-Container-Dash

在这个页面中,点击上图高亮和红圈圈出来的 “Containers”,就可以对容器进行监控了。

以简单的方式对容器进行监控

继续上面的步骤,就会出现一个如下所示精致、漂亮的 “Container list” 页面。

Portainer-Container-List

所有的容器都可以在这里进行控制(停止、启动等等)。

1、在这个页面上,停止我们之前启动的 “test” 容器(这是一个我们早先启动的 debian 容器)。

选中此容器前面的复选框,然后点击上面的“Stop”按钮来停止。

Stop-Container-Portainer-io-dashboard

在命令行中,你也会看到这个容器现在已经停止或退出了:

root@linuxtechi:~$ sudo docker container ls -a
CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS                       PORTS                    NAMES
d45902e717c0        debian                "bash"              21 minutes ago      Exited (0) 49 seconds ago                             test
08b96eddbae9        centos:7              "/bin/bash"         About an hour ago   Exited (137) 9 minutes ago                            mycontainer2
35286de9f2e2        portainer/portainer   "/portainer"        2 hours ago         Up About an hour             0.0.0.0:9000->9000/tcp   compassionate_benz
root@linuxtechi:~$

2、现在,在 Portainer 页面中启动已经停止的两个容器(test 和 mycontainer2)

选中已停止的这两个容器前面的复选框,然后点击 “Start”。

Start-Containers-Portainer-GUI

你会立即看到两条窗口提醒,内容是“容器成功启动”,并且两个容器的状态变为正在运行。

Conatiner-Started-successfully-Portainer-GUI

一步步探索其他多种选项和特性

1、点击高亮的“Images”,你会看到如下页面:

Docker-Container-Images-Portainer-GUI

这是可用的容器列表,其中一些可能没在运行。这些容器可以被导入、导出或者上传到不同的位置,截图如下所示。

Upload-Docker-Container-Image-Portainer-GUI

2、点击高亮的“Volumes”,显示如下页面:

Volume-list-Portainer-io-gui

3、通过下面的操作,可以很容易的添加卷。点击添加卷按钮,出现如下页面,在名称输入框中输入卷名称,例如 “myvol”,然后点击 “Create the volume” 按钮:

Volume-Creation-Portainer-io-gui

新创建的卷如下所示(状态为未使用):

Volume-unused-Portainer-io-gui

结论

通过上面的安装步骤,你可以到配置和使用 Portainer.io 的多种选项是多么简单和精美,它提供了用于构建和监控 Docker 容器的多种功能和选项。如前所述,这个一个非常轻量的工具,因此不会给主机系统增加任何负担。下一组选项将在本系列的第 2 部分中进行探讨。

另请阅读: 用 Portainer.io 来监控和管理 Docker 容器(2)


via: https://www.linuxtechi.com/monitor-manage-docker-containers-portainer-part1/

作者:Shashidhar Soppin 选题:lujun9972 译者:jlztan 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

代码英雄讲述了开发人员、程序员、黑客、极客和开源反叛者如何彻底改变技术前景的真实史诗。

什么是《代码英雄》

代码英雄 Command Line Heroes 是世界领先的企业开源软件解决方案供应商红帽(Red Hat)精心制作的原创音频播客,讲述开发人员、程序员、黑客、极客和开源反叛者如何彻底改变技术前景的真实史诗。该音频博客邀请到了谷歌、NASA 等重量级企业的众多技术大牛共同讲述开源、操作系统、容器、DevOps、混合云等发展过程中的动人故事。

本文是《代码英雄》系列播客第一季(5):容器竞赛音频脚本。

容器的兴起为开发者们打开了一道新的大门,它简化了在机器与机器之间传递项目的成本。随着它变得广受欢迎,一场大战也悄悄拉开帷幕。这场战斗的奖品是容器编排的控制权,参赛者包括这个行业最快最强的玩家。

容器是开源运动中最重要的一项突破之一。在这一集里,特邀嘉宾 Kelsey Hightower、Laura Frank 和 Clayton Coleman 将告诉我们容器如何为未来添砖加瓦,以及编排技术为何如此重要。

Saron Yitbarek

你有看过赛马吗?赛马们排成一行,蹄子刨着脚下的土壤。你可以想象出这么一副画面。比赛即将开始,在这些竞争者中脱颖而出的将是优胜者。

00:00:30

不同的是,比赛的不是马。而是科技世界的诸侯。那么是什么让比赛如此重要?是怎样的珍贵的奖励,才会让这些参赛者们排着队,迫不及待地想要得到它? 这是一场赢家将掌握容器编排技术规则的竞赛,而且胜利者只有一个。重要的是,不同于其他的比赛,赢得这场比赛,你不仅仅会成为今天的冠军,更有可能在来持续领先。

00:01:30:

我是 Saron Yitbarek,这里是代码英雄,一款红帽公司原创的博客。

第五集,容器竞赛。上一集我们见证了 DevOps 的崛起,以及一组新工具如何影响了其他人对开发者这一概念的看法。在这一集栏目中,我们会追溯容器技术崛起的历史,讲述容器技术如何通过拥有支持全新工作的可能性,来进一步扩展开发者这一角色的概念。然后我们会一起见证容器标准化是如何为容器编排奠定比赛基础的。

00:01:30

这是一场严肃的比赛,也是一场全球性的比赛,吸引了行业里最快,最强大的选手。他们都准备好了为冲刺终点线而奋力一搏。准备好了吗? 比赛开始了!

现在,随着这些“赛马”离开起点,也许我们应该弄清楚为什么这场比赛如此重要。谁会关心容器呢?好吧,算我一个。但是实际上,一开始我也并不知道容器是什么。以下我将讲述一个小故事 —— 我是如何醒悟容器之美的。

00:02:00

不久之前,我还在为我网站写代码,然后有天我让我的朋友 Nadia 过来实现一些新的功能。我在保持代码干爽和可读性方面做得很好,当然,代码也经过了很好的测试。所以再加入一个新的网站开发者也不是一件难事。对吗?如果你也这样以为,那就错了。这是一个非常繁琐的过程,特别是当我们跑规范化测试时,这个问题尤为明显。

00:02:30

代码运行正常,但我们不能在两台电脑上同时通过所有测试。我们有很奇怪的电脑时区设置问题,而且她的 Ruby on Rails 版本跟我的不同。就是一个很经典的问题:“我的电脑上可以代码运行”,“可是在我的电脑上就是不行”。我只好对代码做一些修改,直到它在我这里正常运行,但当我把它发送给 Nadia 时,程序又会崩溃。

00:03:00

我很清楚,我和 Nadia 所碰到的这些问题,对于所有的开发者来说都或多或少经历过,甚至他们把这种经历当作玩笑来讲。有时候,我只能把这个当做是在我工作时必须要忍受的一部分。我没有意识到的是,这个问题有个最终解决办法。想象有一种方式可以降低人与人之间的隔阂;想象有一种方法可以让我们在开发中使用任意喜欢的工具,并且在传递工作成果时毫无阻碍;想象一下有一种办法,无论有多少人同时进行一个项目的开发,不管这些人散布在世界何地,都可以让项目从开发到测试,再到生产环境,保持连贯性。如果在我浪费好几周,用最笨的方式传递工作成果前就想到了容器该多好。

00:03:30 - Liz Rice

一个容器实际上就是一个进程。

Saron Yitbarek

Liz Rice 是 Aqua Security 的一名技术布道师。她描述了为何容器会如此实用。事实上容器把一切打包到了一个整洁、并且可以迁移的包中。

00:04:00 - Liz Rice

这就像任何其他的进程一样,不同的是容器的世界非常小。比如,如果你启动一个容器,进程会被授予它自己的根目录。然后它认为自己在查看的是整台计算机的根目录,但实际上它只是在查看这个文件系统很小的一个子集。

00:04:30 - Saron Yitbarek

通过打包一个可执行文件及其所有的依赖,容器可以在任何笔记本或者云中的虚拟机上运行。带着它自己的执行文件、库和依赖。所有的一切都包含在了容器中。所以,这就是容器神奇之处,容器在每个环境中的运行都会完全一样。这也就意味着开发者可以轻松地分享并协作应用开发,而不用担心计算机之间相互不兼容这个老问题。

00:05:00

举一个类比的例子希望能够帮助你理解。你有听说过 蓝围裙 Blue Apron 这个服务吗?该服务提供你做饭所需的一切,包括精心按照菜谱卡片搭配好的,所有做饭需要的原料。好的,想象一下如果蓝围裙所能带给你的不仅仅只是还没有处理过的食材,而是一整个厨房,有煤气灶,还有你所需要的全部餐具,一切你需要的都会装到小盒子里,放在门阶上。这就是一个容器。在我提到的那种情况下,容器技术就可以很好地解决 Nadia 加入进来时所碰到的问题,简单到像使用蓝围裙服务做一顿晚餐一样。虚拟机同样也可以提供一个预装好的环境。但要解释这个,我们就不得不抛弃蓝围裙这个比喻,让我们来看一看具体的细节。

00:05:30 - Liz Rice

许多人都认为容器是某种轻量级的虚拟化技术、轻量级的虚拟机,事实上并不是。容器与虚拟机有很大不同。虚拟机有独属于自己的一整个操作系统,相比起来容器是共享操作系统的。一个计算机上的所有容器共享同一个操作系统的。

00:06:00 - Saron Yitbarek

最后一点,容器和虚拟机可以并肩工作。容器不能替代虚拟机。虚拟化技术仍然可以提高过时系统的效率,并且对于服务器整合非常关键。但容器技术的兴起也为我们打开了新的大门。不妨这样想,如果我们全部依靠虚拟机的话,运行所有仿真服务器将产生大量的额外负担。

00:06:30

一台虚拟机的大小至少是以 G 为单位的,然而一个容器可能也就只有 20 M 左右。一台虚拟机可能会需要若干分钟来启动,如果我尝试用它部署一个网页应用的话,这可不是一个好消息。很长时间以来,人们都期盼一个轻量级的、更快速的完整机器虚拟化替代方案出现。

00:00:07

回顾一下历史,1979 年就出现了容器的原型。Unix V7 的开发者们设计了一种根系统调用,使环境中只包括特定的程序。该突破为我们现在看到的容器技术指明了道路。另一个巨大的进展来源于 2008 年的 Linux 容器技术。现在,我们有了操作系统级的虚拟化技术。

00:07:30

我们终于可以在一个单独的 Linux 内核上运行多个容器,而无需使用完整的虚拟机。这也就意味着程序对于基础架构的需求逐渐减少,但不是每一个人都能立马看到容器技术的潜力。

Laura Frank

容器化真的是前所未有的、崭新的一个天才般的想法。

Saron Yitbarek

Laura Frank 是 CloudBees 的技术总监。

00:08:00 - Laura Frank

只有少部分人了解容器技术的来龙去脉,并可以运用它。不过相信随着时间的推移越来越多的人会接触到容器化的概念,随着越来越多的人开始使用这项技术,并且这些知识通过工程团队和工程组织,通过社区进行传播,就会变得更容易获得。

Saron Yitbarek

因为和我们之前提到的与虚拟机的相似性,Laura 认为,因为我们之前提到的容器技术与虚拟机的相似性,容器的潜力被低估了。

00:08:30 - Laura Frank

我在回想我的职业生涯,那是我还只是个普通的日常技术人员。如果你不是一个系统管理员或者 Linux 资深用户的话,容器还是一个你刚刚了解到的全新概念。我把它理解为使用一台虚拟机模式类似的东西,我可以去建立一个可以用完即弃的环境,而且这个环境完全独立,清理之后不留痕迹。

Saron Yitbarek

容器除了能保持系统整洁之外,其实还大有可为。容器将会革新整个行业,并且随着开源项目和社区的兴起,在不久之后,容器标准化的充分实施将变为可能。

00:09:00 - Scott McCarty

整个界面已经变得非常简单。

Saron Yitbarek

Scott McCarty 是红帽的一名资深的容器策略顾问。他称得上是这个行业的资深人士,他在容器出现前,甚至是虚拟机出现前,就在做这方面的工作了。

00:09:30 - Scott McCarty

在互联网 1.0 时代,我在一家线上零售商工作,我们有上千台实体机,我们用不同的方式,在所有这些不同的服务器上一遍又一遍地安装相同的软件。我们尝试了所有的方法。当你从原始的操作系统迁移到虚拟机,然后再到 Linux 容器、Solaris 容器,同样的问题一再出现,你仍然不得不在不同的虚拟机,或者类似操作系统实例的结构体之间管理配置。

Saron Yitbarek

一旦容器变的规范化,一切都将改变。

00:10:00 - Scott McCarty

比如,有了很多非常标准化的方式可以去处理现在这些打包好的应用,我认为容器技术的出现,从根本上改变了一切。它使得那些应用非常容易使用,而且容器还不会对系统本身造成损害,同时相比虚拟机更加小巧快捷。

00:10:30 - Saron Yitbarek

借助 Linux 容器带来的进步,这些新的开源项目和社区使得开发者们可以更好地携手合作。很多我们对于后端的焦虑都被一扫而光。突然间,容器和由它促进的微服务变得十分有吸引力。一旦一种共同的容器语言出现了,障碍就消失了,与此同时容器技术改变了我们的工作方式,也改变了我们学习新技术的步伐。

00:11:00

还记得之前我和同事 Nadia 遇到的反复出现的问题吗?“在我这代码能跑”的场景?在容器的世界,这个问题将不复存在。相比于我们之前使用的标准的操作系统,开发者社区见证了容器是如何变得更加快速,成本低廉,并且容易使用的 —— 比传统操作系统更加容易。容器技术被采纳的速度十分惊人。但是要记得:容器标准的出现仅仅是容器编排这场竞赛的热身。

赛马们已经整齐排列好,随着信号枪一声令下,它们为了这场比赛的冠军而拼尽全力。竞争的不是容器本身,而是我们部署和管理容器所使用的工具。

00:11:30

我是 Saron Yitbarek,这里是代码英雄。在这场标准容器编排竞赛中,哪位会胜出成为管理所有容器的平台呢?起初有两位竞争者处于领先地位。

00:12:00

由 Apache 驾驭的 Swarm,和 Docker 驾驭的 Mesos。但是等等,怎么?现在出现了一匹黑马改变了这个格局,那就是谷歌。Linux 设立了云原生计算基金会(CNCF),随后 CNCF 推动了谷歌开源的编排引擎 Kubernetes。

00:12:30

现在,相比 Kubernetes,Mesos 和 Swarm 已经抢占了先机,对吗?它们得到了 Apache 和 Docker 的支持,已经入场了一段时间了。但是 Kubernetes 有其他的“赛马”所不具备的优势。Clayton Coleman 会告诉我们这个秘密是什么。Clayton 是红帽负责 Kubernetes 和 OpenShift 的一名架构师。

00:13:00 - Clayton Coleman

在 Kubernetes 诞生之初,谷歌就在项目的开放上做的很好,它降低了项目的贡献和参与的难度。谷歌极其关注让开发者和运维人员能更加容易地开展工作。有这样一个强烈的关注点,就是要做一个能让大多数开发者和运维的生活更轻松的东西。我觉得 Kubernetes 和围绕着Kubernetes 的社区找到了一个足够好的方式,让大部分人参与进来,他们让 Kubernetes 具有足够的可扩展性,还可以解决一些极端的用例。

Saron Yitbarek

在早期,来自于红帽、CoreOS 和谷歌的工程师们都参与到了 Kubernetes 的开发中。随着 Kubernetes 开发到 1.0,不管是初创公司还是大公司都参与其中,一起构建和完善它。关键的是,所有这些增长从来都不是只归功于谷歌或者任何一方。

00:13:30 - Clayton Coleman

在这个例子中,我喜欢以 Linux 打比方。Linux 并不是始于 Linus 开始编写内核,然后告诉所有人,在用户空间如何写 GCC,如何去建立 NGINX 或者 Apache。相反,内核团队专注于建立一个高效的操作系统内核,并与其他诸如 GNU 项目的开源社区合作,并且将可以在其他 Unix 系统上工作的工具引入 Linux。

00:14:00

因此,我们如今所使用的许多工具,都不是 Linux 核心团队交付的。

但是 Linux 作为一个整体,相比于其内核涵盖的范围要宽泛得多,而且我认为这种模式的优势是 Kubernetes 取得现在成就所不可或缺的。当我们建立社区并且专注于 Kubernetes 范围时,我们可以试图从“Kubernetes 内核”的角度来考虑它,这是分布式集群操作系统的内核。

00:14:30 - Saron Yitbarek

Kubernetes 证明了自己在开源世界中建立社区的能力,令人难以置信。正如我们在操作系统之战中谈到的 Linux 崛起一样,现如今这场关于容器的战争中,获胜者往往懂得如何借助社区力量。事实上,尽管谷歌可能开创了 Kubernetes,但目前它属于每一位开发者,并由云原生计算基金会(CNCF)管理。

00:15:00

在 GitHub 上,Kubernetes 有大约 3 万的星标数,而 Swarm 和 Mesos 只有数千,这已经很能说明问题了。这就是由社区所生,为社区所用的技术。

我想了解谷歌的态度,一个如此庞大并且以效益为导向的大公司,是怎么做到如此擅长跟其他开发者合作的呢?我找到了很适合回答这个问题的人 —— Kelsey Hightower,他是谷歌负责容器技术支持的技术专家。

00:15:30

想想谷歌的地位:它在分布式系统领域具备丰富的经验,还运行着分布在世界各地的许许多多的服务器,因此它开发的 Kubernetes 似乎有着很大的优势,并且有信心一定能在这场容器竞赛中胜出。那么,当你想到 Kubernetes 和开源时,你是如何看待这种关系的?

00:16:00 - Kelsey Hightower

我想当谈到基础架构工具,甚至编程语言时,大家没有什么选择 —— 你不可能用个专有工具,即使它很棒。如果它不是开源的,大多数人可能甚至都不会想去了解。而且我认为这也是大多数人会采用像 Kubernetes 这样的基础架构工具的原因,你可能会对自己说:“好吧,我们就要坚持使用这个版本四、五年,也可能我们需要根据自己的一些独特需求来对其进行修改。”

00:16:30

一旦走到这一步,就很难说服企业接受,“嘿,每台服务器使用程序的价格是 200 美元,而且你看不到源代码,所以有需要的话也必须等我们来修改”。

那样的日子一去不复返了,所以我不确定是否真的可以在没有开源的情况下建立基础架构。开源的另一个意味是拥有一个与项目紧密联合的社区,所以我认为 Kubernetes 一开始就锁定了胜利。

Saron Yitbarek

让我们回到这场容器竞赛。在这里不仅仅有你提到的 Kubernetes,还有 Docker 的 Swarm Apache 的 Mesos……

00:17:00 - Kelsey Hightower

所以,我想当人们谈论容器竞赛时,我不确定竞争是否发生在我们和 Mesos、Docker 使用者之间。我认为,真正的竞争发生在争取目前没有使用容器的潜在用户身上。是的,你还在使用原生 Bash 脚本,你迷茫着,不知道自己该归属何方。这些尚未选择编排工具和平台之人的市场,比起已选择了 Mesos 或 Swarm 的一方,要多得多。

00:17:30

这就是容器战争存在并将继续的原因,真正的关键点在于如何帮助最终用户。Mesos、Kubernetes 或 Docker Swarm 是否会成为寻求更好解决方案的人们的首选?这一切都还悬而未决(SIG 译注:现在已经尘埃落定,Kubernetes 取得了全胜),但我会告诉你,像我一样,在这个领域工作的工程师来说,如果你不考虑市场营销和供应商,我会使用这个短语“不同的公司,相同的团队。”

00:18:00

我们为彼此开发了许多工具,最终以某种方式出现在其他产品中。没错吧?好主意就是好主意。没有理由说,“哦,这是 Mesos 的人正在做的事情,那就忽略吧”,这有点愚蠢。所以从技术和社区的角度来看,我们的想法需要交流。同时也需要竞争来迫使我们来进行独立思考,然后最棒的点子就会浮出水面,接着我们再选择采用哪种方式来正确满足用户的需要。

00:18:30

因此,就这场竞赛而言,仍处于初期阶段,而且这个事情本身不会带来利润。明白我的意思吗?我们不是直接向任何人销售这个产品,这更像是一个平台之间的游戏,对所有人开放,然后用户会选择满足他们需求的那个,这就是我认为 Kubernetes 在社区方面做得很好的地方,真正开放,真正能解决实际问题。

Saron Yitbarek

听起来很棒啊。我喜欢这个想法:在同一个球队踢球,而不要管球队是在什么地方。你对于容器和编排工具,还有 Kbubernetes 的未来有什么展望吗?

00:19:00 - Kelsey Hightower

是的,我在 KubeCon 上做了一次主题演讲。所有这些工具都很棒,它们就像是乐高积木,我们有 Kubernetes,你可以选择一种产品用于安全,选择另一种产品用于网络,但最终,作为开发人员而言,你所想要的只是检查你的代码,并希望你的代码可以某种方式以呈现在客户面前。而我认为 Kubernetes 还有容器都会作为底层技术或者成为类似 Serverless 这种技术的基础平台。

00:19:30

这是我的代码片段,已经打包完毕了。所有的平台都会把你的代码片段,用容器包装起来,然后帮你运行,但是不需要向你公开所有这些过程。因此,在未来,我认为随着 Kubernetes 变得普及,容器的应用场景将从大大小小的供应商或个人,提升到云供应商,因为这些事情往往需要专业知识和软件投资。容器将会遍布各个角落,但同时也就此隐藏起来。它会随着应用场景的扩展而渐渐隐形。

00:20:00 - Saron Yitbarek

Kelsey Hightower 是 Google 的员工开发人员。在 2017 年秋天,Docker 宣布支持 Kubernetes。他们并不是说就放弃 Swarm 了,只是决定与容器编排竞赛的明显赢家和解。

00:20:30

并不只有它一方,Azure 和 AWS 都宣布了对 Kubernetes 的支持。与此同时,像 OpenShift 这样的 Kubernetes 发行版仍在不断发展。我们得到的是一个可以扩展,支持新的用例的 Kubernetes 内核,这些用例包括微服务或持续集成项目。

00:21:00 - Clayton Coleman

这个生态系统在类似 Linux 的模式下能得到最好的发展,而且我认为我们正朝着这条道路迈进。因此,就像所有优秀的开源项目一样,相对于单打独斗,让每个人都能够参与进来构建更好的东西,那就算是成功了。

00:21:30 - Saron Yitbarek:

所有这一切都在快速发生着,毕竟,这是一场竞赛,而这正是我们期望能从开源中获得的东西。在我们才刚刚理解什么是容器时,第一轮几乎就结束了,

这是来自 Red Hat 的 Scott McCarty。

Scott McCarty

回想一下两年前,容器镜像格式还是一个巨大的战场,然后回到六个月至一年前,容器编排就成为了下一个巨大的战场。紧接着,如果你看看 2017 年的 KubeCon 及前几周,几乎每个主要供应商都宣布支持 Kubernetes。因此,很明显 Kubernetes 在这一方面上获胜了。

00:22:00 - Saron Yitbarek

这章关于容器战争的故事即将结束。就像容器技术的开始一样迅速。

Scott McCarty

因此,Kubernetes 已经成为标准,其美妙之处是,现在的应用定义已经变得标准化了。因此,任何人都可以在这些 YAML 文件中使用 Kubernetes 对象并定义应用,这就是我们共同所追求的事情。事实上,对于容器技术足够处理处理大型扩展系统这件事,我已经期待了 20 年。

00:22:30 - Saron Yitbarek

Kubernetes 的成功看起来板上钉钉,但即使竞赛尘埃落定,我们仍然面临更大的一些问题。容器是否会成为未来几年的默认选择?是否会促使更多的云原生开发?这些转变将促生哪些工具和服务上?以下是我们目前所知道的。

00:23:00

社区将通过 CNCF 继续改进 Kubernetes,并作为它最重要的使命之一,我们将建立一套全新的容器技术。

容器已经催生了大量新的基础设施,伴随而来的是全新的服务的需求。举个例子让你感受下容器的整合程度和发展速度,仅 Netflix 每周就运行超过一百万个容器。毫不夸张得说,容器是未来的构件。

00:23:30

这一整季的栏目中,我们一直在追踪开源运动的演变。首先看到 Linux 如何主导战场,以及开源理念是如何改变商业、工作流程和每日使用的工具。容器真的是开源运动中最重要的里程碑之一。它们具有很好的迁移性、轻量、易于扩展。

00:24:00

容器技术很好地体现了开源的优势,开源项目自然而然也推动了容器技术的发展。这是一个全新的世界,我们不用再担心从不同计算机或者云间的迁移产生的隔阂。

00:24:30

容器的标准化比任何人预测的都要快。接下来的一集,我们将转向另一场悬而未决的战争。这场云间战争史无前例地催生者行业重量级人物。微软、阿里巴巴、谷歌和亚马逊四家云供应商的摩擦正在升温,随之而来的将是一场暴风骤雨。我们将会追随它们激发的闪电,和广受欢迎的几位代码英雄一起探讨云间战争。

00:25:00

《代码英雄》是红帽公司推出的原创播客栏目。想要了解更多关于本期节目和以往节目的信息,请访问 redhat.com/commandlineheroes 。在那里,你还可以注册我们的新闻资讯。想免费获得新剧集的自动推送,请务必订阅该节目。

只要在苹果播客、Spotify、Google Play、CastBox 中搜索 “Command Line Heroes”,或者通过其他方式收听,并点击订阅,这样你就能在第一时间知道最新剧集。我是 Saron Yitbarek。感谢您的收听,编程不止。

什么是 LCTT SIG 和 LCTT LCRH SIG

LCTT SIG 是 LCTT 特别兴趣小组 Special Interest Group ,LCTT SIG 是针对特定领域、特定内容的翻译小组,翻译组成员将遵循 LCTT 流程和规范,参与翻译,并获得相应的奖励。LCRH SIG 是 LCTT 联合红帽(Red Hat)发起的 SIG,当前专注任务是《代码英雄》系列播客的脚本汉化,已有数十位贡献者加入。敬请每周三、周五期待经过我们精心翻译、校对和发布的译文。

欢迎加入 LCRH SIG 一同参与贡献,并领取红帽(Red Hat)和我们联合颁发的专属贡献者证书。


via: https://www.redhat.com/en/command-line-heroes/season-1/the-containers-derby

作者:Red Hat 选题:bestony 译者:lujun9972 校对:acyanbird

本文由 LCRH 原创编译,Linux中国 荣誉推出

在编辑“容器如何工作”爱好者杂志的能力页面时,我想试着解释一下为什么 strace 在 Docker 容器中无法工作。

这里的问题是 —— 如果我在笔记本上的 Docker 容器中运行 strace,就会出现这种情况:

$ docker run  -it ubuntu:18.04 /bin/bash
$ # ... install strace ...
[email protected]:/# strace ls
strace: ptrace(PTRACE_TRACEME, ...): Operation not permitted

strace 通过 ptrace 系统调用起作用,所以如果不允许使用 ptrace,它肯定是不能工作的! 这个问题很容易解决 —— 在我的机器上,是这样解决的:

docker run --cap-add=SYS_PTRACE  -it ubuntu:18.04 /bin/bash

但我对如何修复它不感兴趣,我想知道为什么会出现这种情况。为什么 strace 不能工作,为什么--cap-add=SYS_PTRACE 可以解决这个问题?

假设 1:容器进程缺少 CAP_SYS_PTRACE 能力。

我一直以为原因是 Docker 容器进程默认不具备 CAP_SYS_PTRACE 能力。这和它可以被 --cap-add=SYS_PTRACE 修复是一回事,是吧?

但这实际上是不合理的,原因有两个。

原因 1:在实验中,作为一个普通用户,我可以对我的用户运行的任何进程进行 strace。但如果我检查我的当前进程是否有 CAP_SYS_PTRACE 能力,则没有:

$ getpcaps $$
Capabilities for `11589': =

原因 2:capabilities 的手册页对 CAP_SYS_PTRACE 的介绍是:

CAP_SYS_PTRACE
       * Trace arbitrary processes using ptrace(2);

所以,CAP_SYS_PTRACE 的作用是让你像 root 一样,可以对任何用户拥有的任意进程进行 ptrace。你不需要用它来对一个只是由你的用户拥有的普通进程进行 ptrace

我用第三种方法测试了一下(LCTT 译注:此处可能原文有误) —— 我用 docker run --cap-add=SYS_PTRACE -it ubuntu:18.04 /bin/bash 运行了一个 Docker 容器,去掉了 CAP_SYS_PTRACE 能力,但我仍然可以跟踪进程,虽然我已经没有这个能力了。什么?为什么?!

假设 2:关于用户命名空间的事情?

我的下一个(没有那么充分的依据的)假设是“嗯,也许这个过程是在不同的用户命名空间里,而 strace 不能工作,因为某种原因而行不通?”这个问题其实并不相关,但这是我观察时想到的。

容器进程是否在不同的用户命名空间中?嗯,在容器中:

root@e27f594da870:/# ls /proc/$$/ns/user -l
... /proc/1/ns/user -> 'user:[4026531837]'

在宿主机:

bork@kiwi:~$ ls /proc/$$/ns/user -l
... /proc/12177/ns/user -> 'user:[4026531837]'

因为用户命名空间 ID(4026531837)是相同的,所以容器中的 root 用户和主机上的 root 用户是完全相同的用户。所以,绝对没有理由不能够对它创建的进程进行 strace!

这个假设并没有什么意义,但我(之前)没有意识到 Docker 容器中的 root 用户和主机上的 root 用户同一个,所以我觉得这很有意思。

假设 3:ptrace 系统的调用被 seccomp-bpf 规则阻止了

我也知道 Docker 使用 seccomp-bpf 来阻止容器进程运行许多系统调用。而 ptrace被 Docker 默认的 seccomp 配置文件阻止的系统调用列表中!(实际上,允许的系统调用列表是一个白名单,所以只是ptrace 不在默认的白名单中。但得出的结果是一样的。)

这很容易解释为什么 strace 在 Docker 容器中不能工作 —— 如果 ptrace 系统调用完全被屏蔽了,那么你当然不能调用它,strace 就会失败。

让我们来验证一下这个假设 —— 如果我们禁用了所有的 seccomp 规则,strace 能在 Docker 容器中工作吗?

$ docker run --security-opt seccomp=unconfined -it ubuntu:18.04  /bin/bash
$ strace ls
execve("/bin/ls", ["ls"], 0x7ffc69a65580 /* 8 vars */) = 0
... it works fine ...

是的,很好用!很好。谜底解开了,除了…..

为什么 --cap-add=SYS_PTRACE 能解决问题?

我们还没有解释的是:为什么 --cap-add=SYS_PTRACE 可以解决这个问题?

docker run 的手册页是这样解释 --cap-add 参数的。

--cap-add=[]
   Add Linux capabilities

这跟 seccomp 规则没有任何关系! 怎么回事?

我们来看看 Docker 源码

当文档没有帮助的时候,唯一要做的就是去看源码。

Go 语言的好处是,因为依赖关系通常是在一个 Go 仓库里,你可以通过 grep 来找出做某件事的代码在哪里。所以我克隆了 github.com/moby/moby,然后对一些东西进行 grep,比如 rg CAP_SYS_PTRACE

我认为是这样的。在 containerd 的 seccomp 实现中,在 contrib/seccomp/seccomp/seccomp\_default.go 中,有一堆代码来确保如果一个进程有一个能力,那么它也会(通过 seccomp 规则)获得访问权限,以使用与该能力相关的系统调用。

case "CAP_SYS_PTRACE":
       s.Syscalls = append(s.Syscalls, specs.LinuxSyscall{
           Names: []string{
               "kcmp",
               "process_vm_readv",
               "process_vm_writev",
               "ptrace",
           },
           Action: specs.ActAllow,
           Args:   []specs.LinuxSeccompArg{},
       })

在 moby 中的 profile/seccomp/seccomp.go默认的 seccomp 配置文件中,也有一些其他的代码似乎做了一些非常类似的事情,所以有可能就是这个代码在做这个事情。

所以我想我们有答案了!

Docker 中的 --cap-add 做的事情比它说的要多

结果似乎是,--cap-add 并不像手册页里说的那样,它更像是 --cap-add-and-also-whiteelist-some-extra-system-calls-if-required。这很有意义! 如果你具有一个像 --CAP_SYS_PTRACE 这样的能力,可以让你使用 process_vm_readv 系统调用,但是该系统调用被 seccomp 配置文件阻止了,那对你没有什么帮助!

所以当你给容器 CAP_SYS_PTRACE 能力时,允许使用 process_vm_readvptrace 系统调用似乎是一个合理的选择。

就这样!

这是个有趣的小事情,我认为这是一个很好的例子,说明了容器是由许多移动的部件组成的,它们以不完全显而易见的方式一起工作。


via: https://jvns.ca/blog/2020/04/29/why-strace-doesnt-work-in-docker/

作者:Julia Evans 选题:lujun9972 译者:wxy 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

搭建一个通过容器分发应用的可复用系统可能很复杂,但这儿有个好方法。

一个用于将源代码转换成可运行的应用的构建系统是由工具和流程共同组成。在转换过程中还涉及到代码的受众从软件开发者转变为最终用户,无论最终用户是运维的同事还是部署的同事。

在使用容器搭建了一些构建系统后,我觉得有一个不错的可复用的方法值得分享。虽然这些构建系统被用于编译机器学习算法和为嵌入式硬件生成可加载的软件镜像,但这个方法足够抽象,可用于任何基于容器的构建系统。

这个方法是以一种易于使用和维护的方式搭建或组织构建系统,但并不涉及处理特定编译器或工具容器化的技巧。它适用于软件开发人员构建软件,并将可维护镜像交给其他技术人员(无论是系统管理员、运维工程师或者其他一些头衔)的常见情况。该构建系统被从终端用户中抽象出来,这样他们就可以专注于软件。

为什么要容器化构建系统?

搭建基于容器的可复用构建系统可以为软件团队带来诸多好处:

  • 专注:我希望专注于应用的开发。当我调用一个工具进行“构建”时,我希望这个工具集能生成一个随时可用的二进制文件。我不想浪费时间在构建系统的查错上。实际上,我宁愿不了解,或者说不关心构建系统。
  • 一致的构建行为:无论在哪种使用情况下,我都想确保整个团队使用相同版本的工具集并在构建时得到相同的结果。否则,我就得不断地处理“我这咋就是好的”的麻烦。在团队项目中,使用相同版本的工具集并对给定的输入源文件集产生一致的输出是非常重要。
  • 易于部署和升级:即使向每个人都提供一套详细说明来安装一个项目的工具集,也可能会有人翻车。问题也可能是由于每个人对自己的 Linux 环境的个性化修改导致的。在团队中使用不同的 Linux 发行版(或者其他操作系统),情况可能还会变得更复杂。当需要将工具集升级到下一版本时,问题很快就会变得更糟糕。使用容器和本指南将使得新版本升级非常简单。

对我在项目中使用的构建系统进行容器化的这些经验显然很有价值,因为它可以缓解上述问题。我倾向于使用 Docker 作为容器工具,虽然在相对特殊的环境中安装和网络配置仍可能出现问题,尤其是当你在一个使用复杂代理的企业环境中工作时。但至少现在我需要解决的构建系统问题已经很少了。

漫步容器化的构建系统

我创建了一个教程存储库,随后你可以克隆并检查它,或者按照本文内容进行操作。我将逐个介绍存储库中的文件。这个构建系统非常简单(它运行 gcc),从而可以让你专注于这个构建系统结构上。

构建系统需求

我认为构建系统中有两个关键点:

  • 标准化构建调用:我希望能够指定一些形如 /path/to/workdir 的工作目录来构建代码。我希望以如下形式调用构建:
./build.sh /path/to/workdir

为了使得示例的结构足够简单(以便说明),我将假定输出也在 /path/to/workdir 路径下的某处生成。(否则,将增加容器中显示的卷的数量,虽然这并不困难,但解释起来比较麻烦。)

  • 通过 shell 自定义构建调用:有时,工具集会以出乎意料的方式被调用。除了标准的工具集调用 build.sh 之外,如果需要还可以为 build.sh 添加一些选项。但我一直希望能够有一个可以直接调用工具集命令的 shell。在这个简单的示例中,有时我想尝试不同的 gcc 优化选项并查看效果。为此,我希望调用:
./shell.sh /path/to/workdir

这将让我得到一个容器内部的 Bash shell,并且可以调用工具集和访问我的工作目录(workdir),从而我可以根据需要尝试使用这个工具集。

构建系统的架构

为了满足上述基本需求,这是我的构架系统架构:

 title=

在底部的 workdir 代表软件开发者用于构建的任意软件源码。通常,这个 workdir 是一个源代码的存储库。在构建之前,最终用户可以通过任何方式来操纵这个存储库。例如,如果他们使用 git 作为版本控制工具的话,可以使用 git checkout 切换到他们正在工作的功能分支上并添加或修改文件。这样可以使得构建系统独立于 workdir 之外。

顶部的三个模块共同代表了容器化的构建系统。最左边的黄色模块代表最终用户与构建系统交互的脚本(build.shshell.sh)。

在中间的红色模块是 Dockerfile 和相关的脚本 build_docker_image.sh。开发运营者(在这个例子中指我)通常将执行这个脚本并生成容器镜像(事实上我多次执行它直到一切正常为止,但这是另一回事)。然后我将镜像分发给最终用户,例如通过 容器信任注册库 container trusted registry 进行分发。最终用户将需要这个镜像。另外,他们将克隆构建系统的存储库(即一个与教程存储库等效的存储库)。

当最终用户调用 build.sh 或者 shell.sh 时,容器内将执行右边的 run_build.sh 脚本。接下来我将详细解释这些脚本。这里的关键是最终用户不需要为了使用而去了解任何关于红色或者蓝色模块或者容器工作原理的知识。

构建系统细节

把教程存储库的文件结构映射到这个系统结构上。我曾将这个原型结构用于相对复杂构建系统,因此它的简单并不会造成任何限制。下面我列出存储库中相关文件的树结构。文件夹 dockerize-tutorial 能用构建系统的其他任何名称代替。在这个文件夹下,我用 workdir 的路径作参数调用 build.shshell.sh

dockerize-tutorial/
├── build.sh
├── shell.sh
└── swbuilder
    ├── build_docker_image.sh
    ├── install_swbuilder.dockerfile
    └── scripts
        └── run_build.sh

请注意,我上面特意没列出 example_workdir,但你能在教程存储库中找到它。实际的源码通常存放在单独的存储库中,而不是构建工具库中的一部分;本教程为了不必处理两个存储库,所以我将它包含在这个存储库中。

如果你只对概念感兴趣,本教程并非必须的,因为我将解释所有文件。但是如果你继续本教程(并且已经安装 Docker),首先使用以下命令来构建容器镜像 swbuilder:v1

cd dockerize-tutorial/swbuilder/
./build_docker_image.sh
docker image ls  # resulting image will be swbuilder:v1

然后调用 build.sh

cd dockerize-tutorial
./build.sh ~/repos/dockerize-tutorial/example_workdir

下面是 build.sh 的代码。这个脚本从容器镜像 swbuilder:v1 实例化一个容器。而这个容器实例映射了两个卷:一个将文件夹 example_workdir 挂载到容器内部路径 /workdir 上,第二个则将容器外的文件夹 dockerize-tutorial/swbuilder/scripts 挂载到容器内部路径 /scripts 上。

docker container run                              \
    --volume $(pwd)/swbuilder/scripts:/scripts    \
    --volume $1:/workdir                          \
    --user $(id -u ${USER}):$(id -g ${USER})      \
    --rm -it --name build_swbuilder swbuilder:v1  \
    build

另外,build.sh 还会用你的用户名(以及组,本教程假设两者一致)去运行容器,以便在访问构建输出时不出现文件权限问题。

请注意,shell.shbuild.sh 大体上是一致的,除了两点不同:build.sh 会创建一个名为 build_swbuilder 的容器,而 shell.sh 则会创建一个名为 shell_swbuilder 的容器。这样一来,当其中一个脚本运行时另一个脚本被调用也不会产生冲突。

两个脚本之间的另一处关键不同则在于最后一个参数:build.sh 传入参数 buildshell.sh 则传入 shell。如果你看了用于构建容器镜像的 Dockerfile,就会发现最后一行包含了下面的 ENTRYPOINT 语句。这意味着上面的 docker container run 调用将使用 buildshell 作为唯一的输入参数来执行 run_build.sh 脚本。

# run bash script and process the input command
ENTRYPOINT [ "/bin/bash", "/scripts/run_build.sh"]

run\_build.sh 使用这个输入参数来选择启动 Bash shell 还是调用 gcc 来构建 helloworld.c 项目。一个真正的构建系统通常会使用 Makefile 而非直接运行 gcc

cd /workdir

if [ $1 = "shell" ]; then    
    echo "Starting Bash Shell"
    /bin/bash
elif [ $1 = "build" ]; then
    echo "Performing SW Build"
    gcc helloworld.c -o helloworld -Wall
fi

在使用时,如果你需要传入多个参数,当然也是可以的。我处理过的构建系统,构建通常是对给定的项目调用 make。如果一个构建系统有非常复杂的构建调用,则你可以让 run_build.sh 调用 workdir 下最终用户编写的特定脚本。

关于 scripts 文件夹的说明

你可能想知道为什么 scripts 文件夹位于目录树深处而不是位于存储库的顶层。两种方法都是可行的,但我不想鼓励最终用户到处乱翻并修改里面的脚本。将它放到更深的地方是一个让他们更难乱翻的方法。另外,我也可以添加一个 .dockerignore 文件去忽略 scripts 文件夹,因为它不是容器必需的部分。但因为它很小,所以我没有这样做。

简单而灵活

尽管这一方法很简单,但我在几个相当不同的构建系统中使用过,发现它相当灵活。相对稳定的部分(例如,一年仅修改数次的给定工具集)被固定在容器镜像内。较为灵活的部分则以脚本的形式放在镜像外。这使我能够通过修改脚本并将更改推送到构建系统存储库中,轻松修改调用工具集的方式。用户所需要做的是将更改拉到本地的构建系统存储库中,这通常是非常快的(与更新 Docker 镜像不同)。这种结构使其能够拥有尽可能多的卷和脚本,同时使最终用户摆脱复杂性。


via: https://opensource.com/article/20/4/how-containerize-build-system

作者:Ravi Chandran 选题:lujun9972 译者:LazyWolfLin 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出