在 dockerd -H fd:// 中,fd:// 的确切含义是什么?

47

Docker守护进程文档建议在大多数设置中使用以下hosts选项:

dockerd -H fd://

我猜 fd 是文件描述符的缩写,但我不理解 fd 如何用于套接字通信。

我理解如下选项:

-H unix:///var/run/docker.sock -H tcp://192.168.59.106 -H tcp://10.10.10.2

这些是Unix域套接字和TCP套接字。我知道如何使用这些套接字调用Docker守护进程:

docker -H tcp://0.0.0.0:2375 ps

但是如果我使用-H fd://启动Docker守护程序,则会出现以下错误:

$ docker -H fd:// ps
error during connect: Get http:///v1.26/containers/json: http: no Host in request URL

那么 fd://的意思是什么? 它有什么用处吗?

2个回答

75
当您启动Docker守护进程时,-H fd://将告诉Docker该服务由Systemd启动并使用套接字激活。然后,systemd将创建目标套接字并将其传递给Docker守护程序以供使用。这在介绍Systemd介绍套接字激活中有描述。博客内容相当长,但确实值得一读,以下是理解此问题的关键要点的简短总结:
  • Systemd是一个旨在取代传统SysV init系统的新型init系统,其关键特性之一是更快的初始化过程。
  • 套接字激活是Systemd中用于加速服务初始化的技术之一。
  • 为了接收请求,服务需要侦听的套接字。以Docker为例,它需要像/var/run/docker.sock这样的unix域套接字或TCP套接字。当然,大多数情况下,服务本身会在启动时创建这些套接字。
  • 使用套接字激活时,Systemd将创建这些套接字并侦听服务,并在服务启动时使用exec将这些套接字传递给服务。其中一个好处是,一旦成功创建套接字,客户端请求可以排队在套接字缓冲区中,即使相关服务尚未启动。
  • Systemd使用的特定服务的套接字信息位于socket单元文件中,对于Docker来说,它是[docker.socket][3],其内容如下:
  •   [Unit]
      Description=Docker Socket for the API
      PartOf=docker.service
    
      [Socket]
      ListenStream=/var/run/docker.sock
      SocketMode=0660
      SocketUser=root
      SocketGroup=docker
    
      [Install]
      WantedBy=sockets.target
    

现在让我们看看整个过程是如何工作的。我在/etc/systemd/system下有文件docker.socketdocker.service。对于docker.serviceExecStart行是:

ExecStart=/usr/bin/dockerd -H fd://
  1. 停止Docker服务:systemctl stop docker

$> ps aux | grep 'docker' # the `grep` itself in the output is ignored
$> lsof -Ua | grep 'docker'
$> 
没有正在运行的Docker进程,也没有docker.sock文件。 执行命令systemctl start docker.socket
$> systemctl start docker.socket
$> ps aux | grep 'docker' 
$> lsof -Ua | grep 'docker'
systemd       1    root   27u  unix 0xffff880036da6000      0t0 140748188 /var/run/docker.sock

启动docker.socket后,我们可以看到仍然没有docker进程运行,但是套接字/var/run/docker.sock已经被创建,并且属于systemd进程。

(离题:实际上,现在套接字已经准备好接收请求,尽管docker还没有运行。当第一个请求到来时,systemd将启动docker.service,并将已经创建的套接字传递给Docker。这被称为按需自动生成)

  • 启动docker.service

  • $> systemctl start docker.service
    $> ps aux | grep 'docker'
    root     26302  0.0  1.8 431036 38712 ?        Ssl  14:57   0:00 /usr/bin/dockerd -H fd://
    <....>
    

    你可以看出Docker现在正在运行。让我们往回走一步,尝试从终端手动执行/usr/bin/dockerd -H fd://

    $> /usr/bin/dockerd -H fd://
    FATA[0000] no sockets found via socket activation: make sure the service was started by systemd 
    

    现在你看到了区别。当你使用-H fd://时,Docker将期望它的父进程传递套接字而不是自己创建。当它由Systemd启动时,Systemd会执行这项工作,但当您在终端上手动启动它时,您没有这样做,因此Docker守护进程进程失败并中止。 这是Docker进程在Docker守护程序启动时如何处理fd://的代码,如果您有兴趣,可以查看。

    另一方面,对于Docker客户端,Docker CLI将从-H中指定的host解析协议/地址,并向Docker守护程序发出http请求。默认主机是unix:///var/run/docker.sock。支持的协议包括tcpunixnpipefd。就我从源代码中探索到的内容来看,fd的传输配置与tcp相同,因此如果您具有正在侦听的tcp套接字,则可以使用以下命令进行操作:

    $> docker -H fd://localhost:4322 ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    

    这与以下内容相同:

    docker -H tcp://localhost:4322 ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
    

    2
    很好的描述 @shizhz - Bernard
    1
    感谢@Alkaline改进答案,英语不是我的母语 :-) - shizhz
    很好的解释!即使它是systemd特定的,这应该出现在dockerd man页面中。我能找到的唯一一件事是https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-socket-option - swoop81
    非常感谢您提供如此详细的答案。 - Suraj K
    @shizhz FYI,“如何使用docker处理fd://…”的链接已经失效。 - Atralb
    @Atralb,我更新了链接,使用了一个更稳定的链接(使用代码中的blob而不是可能会发生变化的“master”)。 - yaobin

    5

    -H fd://语法在使用systemd内的docker时使用。Systemd将在docker.socket单元文件中创建一个套接字并侦听它,该套接字使用docker.service单元文件中的fd://语法连接到docker守护进程。


    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接