halcon实例实战第二版_Kubernetes实战(第二版)第2章 理解容器(续1)

关注公众号: 登峰大数据 ,阅读Kubernetes实战(第二版)(完整中文版),系统学习Kubernetes! 95306ee1fe020734e6f5e1ea124ce754.png 图中显示容器A和B共享一个镜像层,这意味着应用程序A和B读取一些相同的文件。此外,它们还与容器c共享底层。但是,如果这三个容器都可以访问相同的文件,它们如何能够彼此完全隔离呢?应用程序A对存储在共享层中的文件所做的更改是否对应用程序B不可见?是不可见的。为什么呢。 文件系统通过“写即拷”(Copy-on-Write CoW)机制进行隔离。容器的文件系统由来自容器镜像的只读层和堆叠在上面的附加读/写层组成。当运行在容器A中的应用程序更改其中一个只读层中的文件时,整个文件将被复制到容器的读/写层中,文件内容将在那里更改。因为每个容器都有自己的可写层,所以对共享文件的更改在任何其他容器中都是不可见的。 当你删除一个文件时,它只在读/写层被标记为已删除,但它仍然存在于下面的一个或多个层中。而且,删除文件不会减少镜像的大小。 警告 即使看起来无害的操作,如更改文件的权限或所有权,也会导致在读/写层中创建整个文件的新副本。如果您在一个大文件或许多文件上执行这种类型的操作,镜像大小可能会显著膨胀。 理解容器镜像的可移植性限制 理论上,基于Docker的容器镜像可以在任何运行Docker的Linux计算机上运行,但是有一个小警告,因为容器没有自己的内核。如果一个容器化的应用程序需要一个特定的内核版本,它可能不能在每台计算机上工作。如果一台计算机运行的是不同特定版本的Linux内核,或者没有加载所需的内核模块,应用程序就不能在它上面运行。这个场景如下图所示。

509a605759bc3af37ac2a5162898f583.png

图2.9 如果一个容器需要特定的内核特性或模块,它可能不会在任何地方都正常运行 容器B需要一个特定的内核模块才能正常运行。这个模块在第一台计算机的内核中加载,而不是在第二台计算机中。可以在第二台计算机上运行容器镜像,但是当尝试使用缺失的模块时,它将中断出错。 不仅仅是关于内核和模块。还应该清楚的是,为特定硬件架构构建的容器化应用程序只能在具有相同架构的计算机上运行。您不能仅仅因为有Docker就将为x86 CPU架构编译的应用程序放入容器中,然后期望它在基于arm的计算机上运行。为此,您需要一个VM来模拟x86体系结构。

2.1.3介绍Docker替代品和开放容器计划(Open Container Initiative OCI)

Docker是第一个使容器成为主流的容器平台。我希望我已经清楚地说明了Docker本身并不提供进程隔离。容器的实际隔离是在Linux内核级使用它提供的机制进行的。Docker使这些机制的使用变得更加容易,并允许您将容器镜像分发到不同的主机上。 开放容器计划(OCI)简介 在Docker成功之后,开放容器倡议(OCI)诞生了,旨在围绕容器格式和运行时创建开放行业标准。Docker是这一倡议的一部分,其他容器运行时和许多对容器技术感兴趣的组织也是。 OCI成员创建了OCI镜像格式规范(规定了容器镜像的标准格式)和OCI运行时规范(为容器运行时定义了标准接口,目的是标准化容器的创建、配置和执行)。 容器运行时接口(CRI)及其实现(CRI-O)简介 这本书着重于使用Docker作为Kubernetes的容器运行时,因为它最初是Kubernetes唯一支持的并且仍然是使用最广泛的。但是Kubernetes现在通过容器运行时接口(CRI)支持许多其他容器运行时。 CRI的一种实现是CRI-O,它是Docker的一种轻量级替代方案,允许您使用Kubernetes利用任何符合OCI的容器运行时环境。符合oci的运行时示例包括rkt(发音为Rocket)、runC和Kata容器。

2.2动手探索容器

您现在对容器是什么有了一些了解,但是我还没有解释它们是如何工作的。在此之前,您需要创建一个应用程序,将其打包到容器镜像中并运行它。您将需要Docker,所以让我们先安装它并运行一个Hello world容器。

2.2.1安装Docker并运行Hello World容器

理想情况下,可以直接在Linux计算机上安装Docker,这样就不必处理在主机操作系统中运行的虚拟机中运行容器的额外复杂性。但是,如果使用macOS或Windows,不知道如何设置Linux虚拟机,Docker桌面应用程序将为您设置它。首先安装运行容器的Docker命令行(CLI)工具在您的主机OS中,Docker守护进程将在虚拟机中运行,就像它创建的所有容器一样。 Docker平台由许多组件组成,但是您只需要安装Docker Engine就可以运行容器。如果你使用macOS或Windows,安装Docker Desktop。有关详细信息,请遵循 http://docs.docker.com/install 上的说明。 请注意:Docker Desktop for Windows可以运行Windows或Linux容器。请确保将其配置为使用Linux容器。 运行一个Hello World容器 安装完成后,使用docker CLI工具运行docker命令。首先,让我们尝试从Docker Hub拉取并运行一个现有的镜像,Docker Hub是一个公共映像注册中心,它包含许多知名软件包的现成容器映像。其中一个是busybox镜像,使用它在第一个容器中运行简单的echo“Hello world”命令。 您可能不熟悉busybox,它是一个组合了许多标准UNIX命令行工具(如echo、ls、gzip等)的单一可执行文件。除了busybox镜像,还可以使用任何其他成熟的OS容器镜像,如Fedora、Ubuntu,或者包含echo可执行文件的任何其他镜像。 运行busybox镜像不需要下载或安装任何东西。通过指定要下载的镜像和在其中运行的命令,可以使用一个docker run命令完成所有操作。要运行简单的Hello world容器,请执行下面清单中所示的命令。
Listing 2.1 Running a Hello World container with Docker$ docker run busybox echo "Hello World"Unable to find image 'busybox:latest' locallylatest: Pulling from library/busybox7c9d20b9b6cd: Pull completeDigest: sha256:fe301db49df08c384001ed752dff6d52b4…Status: Downloaded newer image for busybox:latestHello World
这看起来不太令人印象深刻,但请记住,整个“应用程序”是通过一个命令下载并执行的,而不需要安装该应用程序或它的任何依赖项。 在例子中,该应用程序只是一个单一的可执行文件,但它可能是一个具有数十个库和附加文件的难以置信的复杂应用程序。安装和运行应用程序的整个过程都是一样的。不同的是,应用程序运行在一个容器中,与计算机上的其他进程隔离。在接下来的例子中你会看到这是真的。 理解运行容器时会发生什么 图2.10准确地显示了执行docker run命令时发生的情况。

17f83624d83c8dd4c9e50cd4f8160043.png

图2.10 在一个基于busybox容器镜像的容器中运行 echo“Hello world docker CLI工具向docker守护进程发送了一条运行容器的指令,该指令检查busybox镜像是否已经存在于其本地镜像缓存中。如果没有,会从Docker Hub注册中心拉取它。 将镜像下载到计算机后,Docker守护进程从该镜像创建一个容器,并在其中执行echo命令。该命令将文本打印到标准输出,然后进程终止,容器停止。 如果您的本地计算机运行Linux操作系统,那么Docker CLI工具和守护进程都在这个操作系统中运行。如果它运行macOS或Windows,则守护进程和容器在Linux VM中运行。 运行其他镜像 运行其他现有容器镜像与运行busybox镜像非常相似。实际上,它通常甚至更简单,因为通常不需要指定要执行什么命令,就像前面示例中的echo命令一样。应该执行的命令通常写在镜像本身中,但是可以在运行它时覆盖它。 例如,如果你想运行Redis数据存储,你可以在 http://hub.docker.com 或其他公共注册中心上找到镜像名称。在Redis的情况下,其中一个图像被称为Redis:alpine,所以你可以这样运行:
$ docker run redis:alpine
要停止并退出容器,请按Control-C(在Mac上按Command-C)。 提示:如果希望从不同的注册中心运行镜像,则必须指定注册中心和镜像名称。例如,如果您想从Quay.io注册中心运行镜像,Quay.io是另一个公开访问的镜像注册中心,运行它如下:docker run quay.io/some/image. 理解镜像标签 如果你在Docker Hub上搜索过Redis图像,你会发现有很多镜像标签可供选择。对于Redis,标签是latest,buster, alpine,但也有5.0.7-buster, 5.0.7-alpine,等等。 Docker允许在相同的名称下有相同镜像的多个版本或变体。每个变体都有一个唯一的标签。如果您引用镜像而没有显式地指定标签,Docker会假设您引用的是特殊的latest标签。当上传一个新版本的镜像,镜像作者通常使用实际版本号和latest标记它。当你想要运行最新版本的一个镜像,使用latest标签,而不是指定版本。 请注意:docker run命令只在之前没有拉取镜像的情况下拉取镜像。使用latest标记可确保在第一次运行镜像时获得最新版本。一旦拉取,就使用本地缓存的镜像。 即使是一个版本,镜像通常也有几个变体。对于Redis,我提到了5.0.7-buster和5.0.7-alpine。他们都包含相同的版本的Redis,但它们建立在不同基础镜像之上。5.0.7-buster基于Debian版本“Buster”,而5.0.7-alpine基于Alpine Linux基础镜像,一个非常精简镜像总共只有5MB --在一个典型的Linux发行版中,它只包含少量的安装二进制文件。 要运行镜像的特定版本和/或变体,请在镜像名称中指定标记。例如,要运行5.0.7-alpine标签,需要执行以下命令:
$ docker run redis:5.0.7-alpine

2.2.2 创建一个容器化Node.js web应用程序

现在您已经有了一个可工作的Docker配置,接下来将创建一个贯穿全书的应用程序。创建一个简单的Node.js web应用程序,并将其打包到一个容器镜像中。应用程序将接受HTTP请求,并使用运行它的计算机的主机名进行响应。 通过这种方式,您将看到在容器中运行的应用程序看到的是不同的主机名,而不是主机计算机的主机名,尽管它像其他进程一样在主机上运行。当你在Kubernetes上部署应用程序并向外扩展(水平扩展;也就是说,运行应用程序的多个实例)。您将看到HTTP请求触及应用程序的不同实例。 该应用程序由一个名为app.js的文件组成。其内容在下一个清单中显示。
代码清单2.2 一个简单的Node.js web应用程序:app.js//加载http和os模块const http = require('http');const os = require('os');//定义服务器监听的端口const listenPort = 8080;//将服务器信息打印到标准输出console.log("Kubia server starting...");console.log("Local hostname is " + os.hostname());console.log("Listening on port " + listenPort);//此函数处理传入的HTTP请求var handler = function(request, response) {  //从HTTP请求获取客户端IP    let clientIP = request.connection.remoteAddress;  //将有关请求的信息记录到标准输出    console.log("Received request for "+request.url+" from "+clientIP);  //创建HTTP响应    response.writeHead(200);  response.write("Hey there, this is "+os.hostname()+". ");  response.write("Your IP is "+clientIP+". ");  response.end("\n");};//启动HTTP服务器var server = http.createServer(handler);server.listen(listenPort);
清单中的代码应该很容易理解。它在端口8080上启动一个HTTP服务器。对于每个请求,它将请求信息记录到标准输出,并发送状态码200 OK的响应和如下文本:
Hey there, this is <server-hostname>. Your IP is <client-IP>.
请注意:响应中的主机名是服务器的实际主机名,而不是客户机在请求的主机头中发送的主机名。这个细节在后面会很重要。现在可以在本地下载和安装Node.js并直接测试您的应用程序,但这不是必须的。将其打包到容器镜像中并使用Docker运行更容易。这使您可以在任何其他启用docker的主机上运行该应用程序,而无需在那里安装Node.js。

2.2.3创建Dockerfile来构建容器镜像

要将应用程序打包到镜像中,您必须首先创建一个名为Dockerfile的文件,该文件包含Docker在构建镜像时应该执行的指令列表。在与app.js文件相同的目录中创建该文件,并确保它包含以下清单中的三个指令。
代码清单2.3 为应用程序构建容器镜像的最小Dockerfile//从基础镜像构建FROM node:12//将app.js文件添加到容器镜像中ADD app.js /app.js//指定镜像运行时要执行的命令ENTRYPOINT ["node", "app.js"]

(未完待续......)  欢迎关注公众号,及时获得最新翻译内容:

0f155ca4a64ce213b9fd06373fb45200.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值