写点什么

docker 的 /var/run/docker.sock 参数

作者:程序员欣宸
  • 2022 年 9 月 26 日
    广东
  • 本文字数:6885 字

    阅读完需:约 23 分钟

docker的/var/run/docker.sock参数

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos

关于/var/run/docker.sock 参数

  • 在创建 docker 容器时,有时会用到 /var/run/docker.sock 这样的数据卷参数,例如以下 docker-compose.yml,可以看到 kafka 容器的数据卷参数带有 /var/run/docker.sock


version: '2'services:  zookeeper:    container_name: zookeeper    image: wurstmeister/zookeeper    ports:      - "2181:2181"  kafka:    container_name: kafka    image: wurstmeister/kafka:2.11-0.11.0.3    ports:      - "9092"    environment:      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://:9092      KAFKA_LISTENERS: PLAINTEXT://:9092      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181    volumes:      - /var/run/docker.sock:/var/run/docker.sock
复制代码


预备知识

  • 搞清楚/var/run/docker.sock 参数的前提是了解 docker 的 client+server 架构,如下是执行 docker version 命令的结果:


[root@minikube ~]# docker versionClient: Version:         1.13.1 API version:     1.26 Package version: docker-1.13.1-96.gitb2f74b2.el7.centos.x86_64 Go version:      go1.10.3 Git commit:      b2f74b2/1.13.1 Built:           Wed May  1 14:55:20 2019 OS/Arch:         linux/amd64
Server: Version: 1.13.1 API version: 1.26 (minimum version 1.12) Package version: docker-1.13.1-96.gitb2f74b2.el7.centos.x86_64 Go version: go1.10.3 Git commit: b2f74b2/1.13.1 Built: Wed May 1 14:55:20 2019 OS/Arch: linux/amd64 Experimental: false
复制代码


  • 可见在电脑上运行的 docker 由 client 和 server 组成,我们输入 docker version 命令实际上是通过客户端将请求发送到同一台电脑上的 Doceker Daemon 服务,由 Docker Daemon 返回信息,客户端收到信息后展示在控制台上,来自 stack overflow 的架构图如下:


  • 做好了准备工作就可以进入正题了。

官方解释

  • 从下面这个官方文档看起,地址是:https://docs.docker.com/v17.09/engine/reference/commandline/dockerd/#description


  • 上图是 Docker Daemon 的配置参数,红框处可见 daemon 默认监听的是/var/run/docker.sock 这个文件,所以 docker 客户端只要把请求发往这里,daemon 就能收到并且做出响应。

  • 按照上面的解释来推理:我们也可以向/var/run/docker.sock 发送请求,也能达到 docker ps、docker images 这样的效果;

  • 好吧,来试试!

向 Docker Daemon 发送请求

  • 为了验证 Docker Daemon 可以通过/var/run/docker.sock 接收请求,我们用 curl 命令来验证,测试环境如下:

  • 操作系统:CentOS Linux release 7.6.1810

  • Docker: 1.13.1

  • 接下来开始动手验证:

  • 执行 docker image 命令看本地有哪些镜像:


[root@centos7 ~]# docker imagesREPOSITORY          TAG                        IMAGE ID            CREATED             SIZEdocker.io/tomcat    8.5.42-jdk8-openjdk-slim   d9f443abac03        7 days ago          286 MBdocker.io/nginx     1.16.0-alpine              ef04b00b089d        6 weeks ago         20.4 MB
复制代码


  • 可见有 tomcat 和 nginx 两个镜像;

  • 执行 docker ps 命令看本地有哪些正在运行的容器:


[root@centos7 ~]# docker psCONTAINER ID        IMAGE                                       COMMAND             CREATED             STATUS              PORTS               NAMES37df022f2429        docker.io/tomcat:8.5.42-jdk8-openjdk-slim   "catalina.sh run"   7 minutes ago       Up 7 minutes        8080/tcp            tomcat
复制代码


  • 可见只运行了一个 tomcat 容器;

  • 执行以下命令,可以直接发 http 请求到 Docker Daemon,获取本地镜像列表,等同于 docker image


curl -s --unix-socket /var/run/docker.sock http:/images/json
复制代码


  • 收到的响应是 JSON,格式化后如下所示,可见通过/var/run/docker.sock 向 Docker Daemon 发送请求是没有问题的:


[    {        "Containers": -1,        "Created": 1560552952,        "Id": "sha256:d9f443abac03d29c12d600d5e65dbb831fb75d681ade76a541daa5ecfeaf54df",        "Labels": null,        "ParentId": "",        "RepoDigests": [            "docker.io/tomcat@sha256:aa736d24929d391d98ece184b810cca869a31312942f2b45309b9acd063d36ae"        ],        "RepoTags": [            "docker.io/tomcat:8.5.42-jdk8-openjdk-slim"        ],        "SharedSize": -1,        "Size": 286484547,        "VirtualSize": 286484547    },    {        "Containers": -1,        "Created": 1557535081,        "Id": "sha256:ef04b00b089d1dc0f8afe7d9baea21609ff3edf91893687aed0eec1351429ff6",        "Labels": {            "maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"        },        "ParentId": "",        "RepoDigests": [            "docker.io/nginx@sha256:270bea203d2fc3743fb9ce0193325e188b7e6233043487e3d3cf117ea4d3f337"        ],        "RepoTags": [            "docker.io/nginx:1.16.0-alpine"        ],        "SharedSize": -1,        "Size": 20421143,        "VirtualSize": 20421143    }]
复制代码


  • 执行以下命令,可以直接发 http 请求到 Docker Daemon,获取运行中的容器列表,等同于 docker ps


curl -s --unix-socket /var/run/docker.sock http:/containers/json
复制代码


  • 收到的响应是 JSON,格式化后如下所示:


[    {        "Id": "37df022f242924526750cda7580edb487085f9acde0ae65e2cebc7529fb02d5d",        "Names": [            "/tomcat"        ],        "Image": "docker.io/tomcat:8.5.42-jdk8-openjdk-slim",        "ImageID": "sha256:d9f443abac03d29c12d600d5e65dbb831fb75d681ade76a541daa5ecfeaf54df",        "Command": "catalina.sh run",        "Created": 1561172541,        "Ports": [            {                "PrivatePort": 8080,                "Type": "tcp"            }        ],        "Labels": {},        "State": "running",        "Status": "Up 18 minutes",        "HostConfig": {            "NetworkMode": "default"        },        "NetworkSettings": {            "Networks": {                "bridge": {                    "IPAMConfig": null,                    "Links": null,                    "Aliases": null,                    "NetworkID": "4509fb8eabe34dc61145284a637f138c2b734683749e590be878afb1763f07a9",                    "EndpointID": "ebb5de894f92c36a88aa01f785be4b4782723c565e1628ea77bccf7a9c32017a",                    "Gateway": "172.17.0.1",                    "IPAddress": "172.17.0.2",                    "IPPrefixLen": 16,                    "IPv6Gateway": "",                    "GlobalIPv6Address": "",                    "GlobalIPv6PrefixLen": 0,                    "MacAddress": "02:42:ac:11:00:02"                }            }        },        "Mounts": []    }]
复制代码




  • 至此,我们对 docker 的 client、server 架构有了清楚的认识:Docker Daemon 相当于一个 server,监听来自 /var/run/docker.sock 的请求,然后做出各种响应,例如返回镜像列表,创建容器。

顺便搞清楚一个常见问题

  • 有个常见的问题相信大家都遇见过,执行 docker 命令时控制台报错如下:


[root@centos7 ~]# docker psCannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
复制代码


  • 此时的您一定很清楚问题原因了:Docker Daemon 服务不正常,所以客户端发送请求得不到响应

  • systemctl status docker 命令看看 Docker Daemon 状态,应该是停止或报错:


[root@centos7 ~]# systemctl status docker● docker.service - Docker Application Container Engine   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)   Active: inactive (dead) since 六 2019-06-22 11:45:14 CST; 3min 58s ago     Docs: http://docs.docker.com  Process: 9134 ExecStart=/usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json $OPTIONS $DOCKER_STORAGE_OPTIONS $DOCKER_NETWORK_OPTIONS $ADD_REGISTRY $BLOCK_REGISTRY $INSECURE_REGISTRY $REGISTRIES (code=exited, status=0/SUCCESS) Main PID: 9134 (code=exited, status=0/SUCCESS)
复制代码


  • 如果是停止状态,执行 systemctl start docker 启动服务即可,如果是错误就要 case by case 去分析了。

开篇问题

  • 再回到文章开篇处的问题,启动容器时的数据卷参数"/var/run/docker.sock:/var/run/docker.sock"有什么用?相信您已经猜到了:

  • 宿主机的 /var/run/docker.sock 被映射到了容器内,有以下两个作用:

  • 在容器内只要向/var/run/docker.sock 发送 http 请求就能和 Docker Daemon 通信了,可以做的事情前面已经试过了,官方提供的 API 文档中有详细说明,镜像列表、容器列表这些统统不在话下;

  • 如果容器内有 docker 文件,那么在容器内执行 docker ps、docker port 这些命令,和在宿主机上执行的效果是一样的,因为容器内和宿主机上的 docker 文件虽然不同,但是他们的请求发往的是同一个 Docker Daemon;

  • 基于以上结论,开篇问题中的镜像 wurstmeister/kafka:2.11-0.11.0.3 既然用到了/var/run/docker.sock 参数,那么该容器应该会向 Docker Daemon 发送请求,接下来我们尝试着分析一下,看看能否证实这个推测;

证实推测

  • 去镜像的官网找到容器启动时自动执行的脚本 start-kafka.sh,地址是:https://github.com/wurstmeister/kafka-docker/blob/0.10.0/start-kafka.sh ,如下图红框所示,果然有用到 docker 客户端,执行的是 docker port 命令:


  • 上图红框中的功能:通过 docker port 命令得到该容器的端口映射信息,再通过 sed 命令从该信息中取得端口号,然后再用 export 命令暴露出去。

  • 还剩最后一个问题:上图红框中的 docker 命令在容器中可以执行么?会不会提示"找不到 docker 命令"?对于这个问题,我的猜测是该镜像已经包含了可执行文件"docker",所以去看看该镜像的 Dockerfile 文件吧,地址是:https://github.com/wurstmeister/kafka-docker/blob/0.10.0/Dockerfile 如下图红框,果然在构建镜像的时候就安装了 docker 应用,因此在容器中执行 docker xxx 命令是没问题的:



  • 至此,所有理论上的推测都找到了直接证据,可以动手验证:进 kafka 容器内试试 docker 命令。

验证上述分析

  • 首先确保您的电脑上 docker、docker-compose 都已经装好可以正常使用;

  • 创建名为 docker-compose.yml 的文件,内容如下(其实就是开篇贴出的那个):


version: '2'services:  zookeeper:    container_name: zookeeper    image: wurstmeister/zookeeper    ports:      - "2181:2181"  kafka:    container_name: kafka    image: wurstmeister/kafka:2.11-0.11.0.3    ports:      - "9092"    environment:      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://:9092      KAFKA_LISTENERS: PLAINTEXT://:9092      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181    volumes:      - /var/run/docker.sock:/var/run/docker.sock
复制代码


  • 在 docker-compose.yml 所在目录执行命令 docker-compose up -d 创建容器:


[root@centos7 22]# docker-compose up -dCreating network "22_default" with the default driverCreating zookeeper ... doneCreating kafka ...
复制代码


  • 执行以下命令进入 kafka 容器:


docker exec -it kafka /bin/bash
复制代码


  • 在容器内执行命令 docker ps ,看到的内容和在宿主机上执行 docker ps 命令是一样的:


bash-4.4# docker psCONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                                                NAMESd612301ea365        wurstmeister/zookeeper             "/bin/sh -c '/usr/sb…"   3 hours ago         Up 2 hours          22/tcp, 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp   zookeeper9310ab2d82f4        wurstmeister/kafka:2.11-0.11.0.3   "start-kafka.sh"         3 hours ago         Up 2 hours          0.0.0.0:32769->9092/tcp                              kafka
复制代码


  • 可见容器内的 docker 客户端发出的请求的确是到达了宿主机的 Docker Daemon,并且收到了响应。

  • 在容器内执行命令 ps -ef|grep docker ,没有结果,证明容器内没有 Docker Daemon 服务在运行,在宿主机执行此命令可以看到如下内容,证明宿主机上的 Docker Daemon 服务是正常的:


[root@centos7 22]# ps -ef|grep dockerroot      14604      1  0 12:00 ?        00:00:46 /usr/bin/dockerd-current --add-runtime docker-runc=/usr/libexec/docker/docker-runc-current --default-runtime=docker-runc --exec-opt native.cgroupdriver=systemd --userland-proxy-path=/usr/libexec/docker/docker-proxy-current --init-path=/usr/libexec/docker/docker-init-current --seccomp-profile=/etc/docker/seccomp.json --selinux-enabled --log-driver=journald --signature-verification=false --storage-driver overlay2root      14610  14604  0 12:00 ?        00:00:11 /usr/bin/docker-containerd-current -l unix:///var/run/docker/libcontainerd/docker-containerd.sock --metrics-interval=0 --start-timeout 2m --state-dir /var/run/docker/libcontainerd/containerd --shim docker-containerd-shim --runtime docker-runc --runtime-args --systemd-cgroup=trueroot      27981  14604  0 16:03 ?        00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 32769 -container-ip 172.18.0.2 -container-port 9092root      27999  14610  0 16:03 ?        00:00:00 /usr/bin/docker-containerd-shim-current 9310ab2d82f41629f734a9dcf54d0002945eaccb7cfcc2352d5a76141a709a14 /var/run/docker/libcontainerd/9310ab2d82f41629f734a9dcf54d0002945eaccb7cfcc2352d5a76141a709a14 /usr/libexec/docker/docker-runc-currentroot      28022  14604  0 16:03 ?        00:00:00 /usr/libexec/docker/docker-proxy-current -proto tcp -host-ip 0.0.0.0 -host-port 2181 -container-ip 172.18.0.3 -container-port 2181root      28029  14610  0 16:03 ?        00:00:00 /usr/bin/docker-containerd-shim-current d612301ea365ac6c6e2b8987e28beb2c2c3eccca720e7d5d7214bf9945c15034 /var/run/docker/libcontainerd/d612301ea365ac6c6e2b8987e28beb2c2c3eccca720e7d5d7214bf9945c15034 /usr/libexec/docker/docker-runc-currentroot      38299  10540  0 19:23 pts/0    00:00:00 grep --color=auto docker
复制代码

优化建议

  • 目前我们 docker 的 client、server 架构已经比较清楚了,对开篇的问题也找到了答案,不过细心的您是否注意到一个问题,如下图,这是 kafka 镜像的 Dockerfile 文件:


  • 上图显示 kafka 镜像中安装了 docker 应用,这里面包含了 client 和 daemon,但实际上只用到了 client,这样是否有些浪费呢?如果以后我们制作镜像的时候要用到 docker 客户端,难道我们的镜像也要这样把整个 docker 应用装好么?

  • 一篇来自官方的文档给我们了启发,地址是:https://docs.docker.com/docker-for-azure/upgrade/ ,如下图红框所示,将宿主机的可执行文件 docker 映射到容器的/usr/bin 目录下,这样容器启动后就可以直接执行 docker 命令了:



  • 至此,对 docker 的/var/run/docker.sock 参数的学习和实战就全部完成了,希望本文能帮助您加深对 docker 的理解,灵活的使用该参数可以助您设计出更强大的 docker 镜像。

  • 再加一句:现在您可以去了解 Docker in Docker 了,相信您会学得很轻松愉快。

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...


发布于: 刚刚阅读数: 3
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018.04.19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
docker的/var/run/docker.sock参数_Docker_程序员欣宸_InfoQ写作社区