快乐学习
前程无忧、中华英才非你莫属!

Docker实战-Day2*深入引擎室(架构、守护进程)

本章主要内容Docker的架构在用户的宿主机上追溯Docker的内部结构使用Docker Hub查找和下载镜像设置自己的Docker注册中心(registry)

实现容器间的相互通信

掌握Docker的架构是更全面地理解Docker的关键。在本章中,读者将在自己的主机和网络上对Docker的主要组件进行大致了解,并学习一些有助于增进这种理解的技巧。

在这个过程中,将学习一些有助于更有效地使用Docker(及Linux)的小窍门。后续的更高级的很多技巧都是基于这里所见的部分,因此请特别留意以下内容。

2.1 Docker的架构

图2-1展示了Docker的架构,这将是本章的核心内容。我们将从高层次视角入手,然后聚焦到每个部分,使用设计好的技巧来巩固理解。宿主机上的Docker(在编写本书时)分成两个部分:一个具有REST风格API的守护进程,以及一个与守护进程通信的客户端。图2-1展示的是运行着Docker客户端和守护进程的宿主机。cmd

REST风格 一个REST风格API是指使用标准HTTP请求类型,如GET、POST、DELETE等,来执行通常符合HTTP设计者预想的功能的API。

调用Docker客户端可以从守护进程获取信息或给它发送指令。守护进程是一个服务器,它使用HTTP协议接收来自客户端的请求并返回响应。相应地,它会向其他服务发起请求来发送和接收镜像,使用的同样是HTTP协议。该服务器将接收来自命令行客户端或被授权连接的任何人的请求。守护进程还负责在幕后处理用户的镜像和容器,而客户端充当的是用户与REST风格API之间的媒介。

图2-1 Docker架构概览

私有Docker注册中心是存储Docker镜像的一项服务,可以从任何有相应权限的Docker守护进程向其发送请求。这个注册中心处于内部网络中,不能公开访问,因此被视为是私有的。宿主机一般坐落在一个私有网络上。在收到请求时,Docker守护进程将连接互联网来获取镜像。Docker Hub是由Docker公司运营的一个公共的注册中心。互联网上也存在其他公共的注册中心,且Docker守护进程可与之进行交互。

在第1章中我们说可以将Docker容器分发到任何能运行Docker的地方——这并不完全正确。实际上,只有当守护进程可以被安装到机器上时,容器才能在这台机器上运行。最明显的事实是,Docker客户端可以运行在Windows上,但守护进程(还)不行。理解这张图的关键在于,当用户在自己的机器上运行Docker时,与其进行交互的可能是自己机器上的另一个进程,或者甚至是运行在内部网络或互联网上的服务。

现在,对Docker的结构有了大致的印象,我们来介绍几个与图中不同部分有关的技巧。

2.2 Docker守护进程

Docker守护进程(见图2-2)是用户与Docker交互的枢纽,因而它是理解所有相关部分的最佳切入点。它控制着用户机器上的Docker访问权限,管理着容器与镜像的状态,同时代理着与外界的交互。

守护进程与服务器 守护进程是运行在后台的一个进程,不在用户的直接控制之下。服务器是负责接受客户端请求,并执行用于满足该请求所需的操作的一个进程。守护进程通常也是服务器,接收来自客户端的请求,为其执行操作。docker命令是一个客户端,而Docker守护进程则作为服务器对Docker容器和镜像进行操作。

我们来看几个技巧,这些技巧用于展示Docker作为守护进程高效运行,同时使用docker命令与其进行的交互被限制为执行操作的简单请求,就像与Web服务器进行交互一样。

第一个技巧允许其他人连接你的Docker守护进程,并执行与你在宿主机上所能执行的相同操作,第二个技巧说明的是Docker容器是由守护进程管理的,而不是你的shell会话。

技巧1

向世界开放Docker守护进程虽然默认情况下Docker的守护进程只能在宿主机上访问,但是有些情况下还是需要允许其他人访问它。

读者可能遇到了一个问题,需要其他人来远程调试,或者可能想让DevOps工作流中的某一部分在宿主机上启动一个进程。

不安全!尽管这个技巧很强大也很有用,但它被认为是不安全的。开放的Docker守护进程可能被别有用心的人所利用,并获得提升的权限。

问题想要将Docker服务器开放给其他人访问。解决方案使用开放的TCP地址启动Docker守护进程。讨论图2-3给出了这个技巧的工作概览。

图2-3 Docker可访问性:正常情况与公开情况

在开放Docker守护进程之前,必须先停止正在运行的实例。操作的方式因操作系统而异。如果不清楚怎么做,可以首先试试这个命令

sudo service docker stop

如果得到一个类似下面这样的消息,说明这是一个基于systemctl的启动系统:

The service command supports only basic LSB actions (start, stop, restart,  try-restart, reload, force-reload, status). For other actions, please tryto use systemctl.

可以试试这个命令:

$ systemctl stop docker

如果这个方法有效,以下命令将看不到任何输出:

ps -ef | grep -E 'docker (-d|daemon)b' | grep -v grep

旦Docker守护进程停止,就可以使用以下命令手工重启并向外界用户开放它:

docker daemon -H tcp://0.0.0.0:2375

这个命令以守护进程方式启动Docker(docker daemon),使用-H标志定义宿主机服务器,使用TCP协议,绑定到所有IP地址上(使用0.0.0.0),并以标准的Docker服务器端口(2375)开放。如果Docker提示daemon不是一个有效的子命令,请尝试使用旧版的-d参数。

可以从外部使用如下命令进行连接:

$ docker -H tcp://<宿主机IP>:2375

需要注意的是,在本地机器内部也需要这么做,因为Docker已经不再在其默认位置进行监听了。

如果想在宿主机上让这项变更永久生效,需要对启动系统进行配置。其操作方式参见附录B。

使用IP限制 如果开放了守护进程,请务必只向特定IP范围开放,同时不要绑定到0.0.0.0上,这样非常不安全!

技巧2 

以守护进程方式运行容器在熟悉了Docker之后,(与我们一样)读者会开始思考Docker的其他使用场景,首先想到的使用场景之一是以运行服务的方式来运行Docker容器。以服务方式运行Docker容器,通过软件隔离实现可预测行为,是Docker的主要使用场景之一。本技巧将让读者使用适合自己的操作的方式来管理服务。问题想要以服务方式在后台运行一个Docker容器。

问题想要以服务方式在后台运行一个Docker容器。解决方案在docker run命令中使用-d标志,并使用相关的容器管理标志定义此服务特性。

讨论Docker容器与多数进程一样,默认在前台运行。在后台运行Docker容器最常见的方式是使用标准的&控制操作。

虽然这行得通,但如果用户注销终端会话就可能出现问题,用户被迫使用nohup标志,而这将在本地目录中创建一个不得不管理的输出文件……是的,使用Docker守护进程的功能完成这一点将简洁得多。要做到这一点,可使用-d标志。

$ docker run -d -i -p 1234:1234 –name daemon ubuntu nc -l 1234

与docker run一起使用的-d标志将以守护进程方式运行容器。-i标志则赋予容器与Telnet会话交互的能力。使用-p将容器的1234端口公布到宿主机上。

通过–name标志赋予容器一个名称,以便后期用来对它进行引用。最后,使用netcat(nc)在1234端口上运行一个简单的监听应答(echo)服务器。如果现在使用Telnet连接它并发送消息,就可以使用docker logs命令看到容器已经接收到该消息,如代码清单2-1所示。代码清单2-1 使用Telnet连接容器netcat服务器

$ telnet localhost 1234 (1)

Trying ::1… Connected to localhost. Escape character is &apos;^]&apos;. hello daemon (2)

^] (3)    

telnet> q (4)

Connection closed. $ docker logs daemon (5)

hello daemon $ docker rm daemon (6) 

daemon

$

(1)使用telnet命令连接到容器的netcat服务器

(2)输入发送给netcat服务器的一行文本

(3)按Ctrl+]然后按回车键退出Telnet会话

(4)输入q然后按回车键退出Telnet程序

(5)运行docker logs命令查看容器的输出

(6)使用rm命令清除容器

由此可见,以守护进程方式运行一个容器是相当简单的,但在实际操作中,还有一些问题有待解答:如果服务失败了会发生什么?在服务结束时会发生什么?如果服务不断失败会发生什么?幸运的是,Docker为每个问题都提供了相应标志!

非必需的标志 尽管重启标志经常会与守护进程标志(-d)一起使用,但从技术角度来说,与-d一起运行这些标志并不是必需的。

重启标志docker run –restart标志允许用户应用一组容器终止时需要遵循的规则(就是所谓的“重启策略”,见表2-1)。

no策略很简单:当容器退出时,它不会被重启。这是默认值。

always策略也很简单,不过还是值得简要讨论一下:

$ docker run -d –restart=always ubuntu echo done

这个命令以守护进程方式(-d)运行容器,并总是在容器终止时自动重启(–restart=always)。它发送了一个简单的快速完成的echo命令,然后退出容器。

如果运行了上述命令,然后运行docker ps命令,就会看到类似下面这样的输出:


$ docker ps CONTAINER ID    IMAGE     COMMAND     

CREATED     

➥ STATUS     PORTS            

NAMES

69828b118ec3    ubuntu:14.04  "echo


done"   4 seconds ago

➥ Restarting (0) Less than a second ago   

sick_brattain

brattaindocker ps命令列出了所有运行中的容器及其信息,包括以下内容:容器什么时候被创建的(CREATED);容器的当前状态——通常将是Restarting,因为它只运行了很短的时间(STATUS);容器上一次运行的退出码(也在STATUS下面)。0代表运行成功;容器名称。

默认情况下,Docker会通过连接两个随机单词为容器命名。有时这会造成一些奇怪的结果!注意,STATUS一栏还告诉我们,容器在不到一秒前退出并正在重启。

这是因为echo done命令会立即退出,而Docker必须不断地重启这个容器。需要特别说明的是,Docker复用了容器ID。

这个ID在重启时不会改变,并且对于这个Docker调用来说,ps表里永远只会有一条。

最后,on-failure策略只在容器从它的主进程返回一个非0(一般表示失败)退出码时重启:


$ docker run -d –restart=on-failure:10 ubuntu /bin/false

这条命令以守护进程(-d)形式运行容器,并设置了重启的尝试次数限制(–restart=on- failure:10),如果超出限制则退出。它运行了一个快速完成并肯定失败的简单的命令(/bin/ false)。

如果运行上述命令并等待一分钟,然后运行docker ps -a,就会看到类似下面这样的输出:

$ docker ps -a

CONTAINER ID    IMAGE      COMMAND     CREATED 

➥ STATUS          PORTS       NAMES b0f40c410fe3    ubuntu:14.04  "/bin/false"   2 minutes ago  

➥ Exited (1) 25 seconds ago         loving_rosalind

技巧3 

将Docker移动到不同分区Docker把所有与容器和镜像有关的数据都存储在一个目录下。由于它可能会存储大量不同的镜像,这个目录可能会迅速变大!

如果宿主机具有不同分区(这在企业Linux工作站上很常见),用户可能会更快遭遇空间限制。在这种情况下,用户会想移动Docker所操作的目录。

问题

想要移动Docker存储数据的位置。

解决方案

停止Docker守护进程,并使用-g标志指定新的位置来启动。

讨论

首先必须将Docker守护进程停止(有关这个问题的讨论参见附录B)。假设想在/home/dockeruser/mydocker运行Docker。运行下列命令将在这个目录中创建一组新的目录和文件:

docker daemon -g /home/dockeruser/mydocker

这些目录是Docker内部使用的,对其进行操作风险自担(因为我们已经尝过滋味了!)。

请注意,这看起来像是把容器和镜像从之前的Docker守护进程清除了。不过不用担心。如果杀掉刚才运行的Docker进程,并重启Docker服务,Docker客户端就会指回它原来的位置,容器和镜像也将回归。如果想让这个移动永久有效,需要对宿主机系统的启动进程进行相应配置。

来源:Docker实战  作者:Jeff Nickoloff 

打赏

未经允许不得转载:同乐学堂 » Docker实战-Day2*深入引擎室(架构、守护进程)

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

特别的技术,给特别的你!

联系QQ:1071235258QQ群:226134712
error: Sorry,暂时内容不可复制!