GVKun编程网logo

docker 的 /var/run/docker.sock 参数(docker /var/lib/docker详解)

10

想了解docker的/var/run/docker.sock参数的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于docker/var/lib/docker详解的相关问题,此外,我们还将为您介

想了解docker 的 /var/run/docker.sock 参数的新动态吗?本文将为您提供详细的信息,我们还将为您解答关于docker /var/lib/docker详解的相关问题,此外,我们还将为您介绍关于/var/run/docker.sock的Docker安全风险是什么?、167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo、Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?、Docker in Docker(实际上是 Docker outside Docker): /var/run/docker.sock的新知识。

本文目录一览:

docker 的 /var/run/docker.sock 参数(docker /var/lib/docker详解)

docker 的 /var/run/docker.sock 参数(docker /var/lib/docker详解)

关于 /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-compose.yml 的作用和相关实战,请参考《kafka 的 Docker 镜像使用说明 (wurstmeister/kafka)》;

预备知识

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

[root@minikube ~]# docker version
Client:
 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 命令来验证,测试环境如下:

  1. 操作系统:CentOS Linux release 7.6.1810
  2. Docker: 1.13.1

接下来开始动手验证:

  1. 执行 docker image 命令看本地有哪些镜像:
[root@centos7 ~]# docker images
REPOSITORY          TAG                        IMAGE ID            CREATED             SIZE
docker.io/tomcat    8.5.42-jdk8-openjdk-slim   d9f443abac03        7 days ago          286 MB
docker.io/nginx     1.16.0-alpine              ef04b00b089d        6 weeks ago         20.4 MB

可见有 tomcat 和 nginx 两个镜像;
2. 执行 docker ps 命令看本地有哪些正在运行的容器:

[root@centos7 ~]# docker ps
CONTAINER ID        IMAGE                                       COMMAND             CREATED             STATUS              PORTS               NAMES
37df022f2429        docker.io/tomcat:8.5.42-jdk8-openjdk-slim   "catalina.sh run"   7 minutes ago       Up 7 minutes        8080/tcp            tomcat

可见只运行了一个 tomcat 容器;
3. 执行以下命令,可以直接发 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
    }
]
  1. 执行以下命令,可以直接发 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": []
    }
]
  1. 更多与 Docker Daemon 交互的请求信息请参考官方文档:https://docs.docker.com/engine/api/v1.39 ,信息很全面,如下图:
    在这里插入图片描述
    至此,我们对 docker 的 client、server 架构有了清楚的认识:Docker Daemon 相当于一个 server,监听来自 /var/run/docker.sock 的请求,然后做出各种响应,例如返回镜像列表,创建容器。

顺便搞清楚一个常见问题

  1. 有个常见的问题相信大家都遇见过,执行 docker 命令时控制台报错如下:
[root@centos7 ~]# docker ps
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

此时的您一定很清楚问题原因了:Docker Daemon 服务不正常,所以客户端发送请求得不到响应
2. 用 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)
  1. 如果是停止状态,执行 systemctl start docker 启动服务即可,如果是错误就要 case by case 去分析了。

开篇问题

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

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

  1. 在容器内只要向 /var/run/docker.sock 发送 http 请求就能和 Docker Daemon 通信了,可以做的事情前面已经试过了,官方提供的 API 文档中有详细说明,镜像列表、容器列表这些统统不在话下;
  2. 如果容器内有 docker 文件,那么在容器内执行 docker ps、docker port 这些命令,和在宿主机上执行的效果是一样的,因为容器内和宿主机上的 docker 文件虽然不同,但是他们的请求发往的是同一个 Docker Daemon;

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

证实推测

  1. 去镜像的官网找到容器启动时自动执行的脚本 start-kafka.sh,地址是:https://github.com/wurstmeister/kafka-docker/blob/0.10.0/start-kafka.sh ,如下图红框所示,果然有用到 docker 客户端,执行的是 docker port 命令:
    在这里插入图片描述
    上图红框中的功能:通过 docker port 命令得到该容器的端口映射信息,再通过 sed 命令从该信息中取得端口号,然后再用 export 命令暴露出去。

  2. 还剩最后一个问题:上图红框中的 docker 命令在容器中可以执行么?会不会提示 "找不到 docker 命令"?
    对于这个问题,我的猜测是该镜像已经包含了可执行文件 "docker",所以去看看该镜像的 Dockerfile 文件吧,地址是:https://github.com/wurstmeister/kafka-docker/blob/0.10.0/Dockerfile 如下图红框,果然在构建镜像的时候就安装了 docker 应用,因此在容器中执行 docker xxx 命令是没问题的:
    在这里插入图片描述
    至此,所有理论上的推测都找到了直接证据,可以动手验证:进 kafka 容器内试试 docker 命令。

验证上述分析

  1. 首先确保您的电脑上 docker、docker-compose 都已经装好可以正常使用;
  2. 创建名为 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
  1. 在 docker-compose.yml 所在目录执行命令 docker-compose up -d 创建容器:
[root@centos7 22]# docker-compose up -d
Creating network "22_default" with the default driver
Creating zookeeper ... done
Creating kafka ...
  1. 执行以下命令进入 kafka 容器:
docker exec -it kafka /bin/bash
  1. 在容器内执行命令 docker ps,看到的内容和在宿主机上执行 docker ps 命令是一样的:
bash-4.4# docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                                                NAMES
d612301ea365        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   zookeeper
9310ab2d82f4        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,并且收到了响应。
6. 在容器内执行命令 ps -ef|grep docker,没有结果,证明容器内没有 Docker Daemon 服务在运行,在宿主机执行此命令可以看到如下内容,证明宿主机上的 Docker Daemon 服务是正常的:

[root@centos7 22]# ps -ef|grep docker
root      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 overlay2
root      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=true
root      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 9092
root      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-current
root      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 2181
root      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-current
root      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 了,相信您会学得很轻松愉快。

欢迎关注我的公众号:程序员欣宸

在这里插入图片描述

本文分享 CSDN - 程序员欣宸。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

/var/run/docker.sock的Docker安全风险是什么?

/var/run/docker.sock的Docker安全风险是什么?

在this blog article,我在评论中找到了以下引用:

Ben Firshman

Yes – you’re right I should have pointed out the security issue with the Docker socket. That’s currently the main blocker to this being practical in production and we’re definitely looking for help to make it work better,as you noticed from the to-do list.

虽然我确信这对许多人来说是有道理的,对于我们其他人来说,有人可以用明确的术语来解释这个“安全问题”究竟是什么吗?我认为它指的是:

    volumes:
  - "/var/run/docker.sock:/var/run/docker.sock"

在docker-compose文件中.那是对的吗?如何被利用?这是否有效地禁止了生产使用的这种方法?如果是这样,有解决方法吗?

最佳答案

for the rest of us,Could someone explain in clear terminology exactly what this “security issue” is?

docker /var/run/docker.sock的所有者是运行容器的主机的root,其默认组成员身份为docker group.这就是为什么在另一个容器中安装var / run / docker.sock会为您提供root权限,因为现在您可以执行具有docker组成员身份的root用户可以执行的任何操作.

Does this effectively prohibit this approach from Production usage? If so,is there a workaround?

对于解决方法,这些帖子可能会有所帮助:https://integratedcode.us/2016/04/08/user-namespaces-sharing-the-docker-unix-socket/和https://integratedcode.us/2016/04/20/sharing-the-docker-unix-socket-with-unprivileged-containers-redux/

退一步,理解你需要挂载var / run / docker.sock的用例并查看是否有其他方法来满足usecase是很有用的.遗憾的是,如果没有问题中的用例描述,很难提供避免安装unix插槽的替代方案.

祝你做正确的事情,祝你好运并感到荣幸!

167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo

167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo

docker构建nginx容器系列问题


background : 最近为小伙伴们筹划docker系列的技术分享,研究了一会docker相关技术, 在此记录一下构建nginx容器时候的坑

1.nginx服务器根目录问题

docker 官方镜像提供的nginx基于debian/jessie平台,其文件结构和ubuntu中的nginx中并不相同

eg:

run一个niginx容器

<span>//80端口被占用,so...</span>
$ sudo docker run <span>-it</span><span>-p</span><span>800</span>:<span>800</span> nginx
$ sudo docker ps 

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                   NAMES
<span>1801</span>a32aab54        nginx               <span>"nginx -g ''daemon off"</span><span>2</span> minutes ago       Up <span>2</span> minutes        <span>80</span>/tcp, <span>443</span>/tcp, <span>0.0</span><span>.0</span><span>.0</span>:<span>800</span><span>-&gt;</span><span>800</span>/tcp   berserk_kare
登录后复制

进入容器内部

<span>$ </span>sudo docker exec -it <span>1801</span>a32aab54 /bin/bash
root<span>@1801a32aab54</span><span>:/</span><span># </span>
登录后复制

查看nginx目录

<span># cd /etc/nginx/</span>
conf<span>.d</span>/         koi-utf         mime<span>.types</span>      nginx<span>.conf</span>      uwsgi_params    
fastcgi_params  koi-win         modules/        scgi_params     win-utf  
登录后复制

可以看到不仅没有熟悉的 /sites-available,也没有 /sites-enabled

继续查看nginx配置

<span># cat /conf.d/default.conf</span><span>server</span> {
    listen       <span>80</span>;
    server_name  localhost;

    <span>#charset koi8-r;</span><span>#access_log  /var/log/nginx/log/host.access.log  main;</span>    location / {
        root   /usr/share/nginx/html;
        <span>index</span><span>index</span>.html <span>index</span>.htm;
    }

    <span>#error_page  404              /404.html;</span><span># redirect server error pages to the static page /50x.html</span><span>#</span>
    error_page   <span>500</span><span>502</span><span>503</span><span>504</span>  /<span>50</span>x.html;
    location = /<span>50</span>x.html {
        root   /usr/share/nginx/html;
    }
    <span>#...省略php-fpm配置,好长..</span>
}
登录后复制

根目录配置: root /usr/share/nginx/html;

测试

<span># cd /usr/share/nginx/html</span><span># touch index.html</span><span># echo "test nginx in docker" &gt;index.html</span>
登录后复制

php-fpm配置相关

'').addClass(''pre-numbering'').hide(); $(this).addClass(''has-numbering'').parent().append($numbering); for (i = 1; i '').text(i)); }; $numbering.fadeIn(1700); }); });

以上就介绍了167 docker docker构建nginx容器系列问题,包括了docker,nginx方面的内容,希望对PHP教程有兴趣的朋友有所帮助。

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

启动docker报错:

Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

systemctl status docker

解决方法:
vim /etc/docker/daemon.json

{
 "registry-mirrors": ["https://registry.docker-cn.com"]
}

systemctl restart docker.service
docker正常启动

Docker in Docker(实际上是 Docker outside Docker): /var/run/docker.sock

Docker in Docker(实际上是 Docker outside Docker): /var/run/docker.sock

在 Docker 容器里面使用 docker run/docker build

Docker 容器技术目前是微服务/持续集成/持续交付领域的第一选择。而在 DevOps 中,我们需要将各种后端/前端的测试/构建环境打包成 Docker 镜像,然后在需要的时候,Jenkins 会使用这些镜像启动容器以执行 Jenkins 任务。

为了方便维护,我们的 CI 系统如 Jenkins,也会使用 Docker 方式部署。 Jenkins 任务中有些任务需要将微服务构建成 Docker 镜像,然后推送到 Harbor 私有仓库中。 或者我们所有的 Jenkins Master 镜像和 Jenkins Slave 镜像本身都不包含任何额外的构建环境,执行任务时都需要启动包含对应环境的镜像来执行任务。

我们的 Jenkins Master、Jenkins Slaves 都是跑在容器里面的,该如何在这些容器里面调用 docker run 命令启动包含 CI 环境的镜像呢? 在这些 CI 镜像里面,我们从源码编译完成后,又如何通过 docker build 将编译结果打包成 Docker 镜像,然后推送到内网仓库呢?

答案下面揭晓。

一、原理说明:/var/run/docker.sock

Docker 采取的是 Client/Server 架构,我们常用的 docker xxx 命令工具,只是 docker 的 client,我们通过该命令行执行命令时,实际上是在通过 client 与 docker engine 通信。

我们通过 apt/yum 安装 docker-ce 时,会自动生成一个 systemd 的 service,所以安装完成后,需要通过 sudo systemctl enable docker.service 来启用该服务。 这个 Docker 服务启动的,就是 docker engine,查看 /usr/lib/systemd/system/docker.service,能看到有这样一条语句:

ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

默认情况下,Docker守护进程会生成一个 socket(/var/run/docker.sock)文件来进行本地进程通信,因此只能在本地使用 docker 客户端或者使用 Docker API 进行操作。 sock 文件是 UNIX 域套接字,它可以通过文件系统(而非网络地址)进行寻址和访问。

因此只要以数据卷的形式将 docker 客户端和上述 socket 套接字挂载到容器内部,就能实现 "Docker in Docker",在容器内使用 docker 命令了。具体的命令见后面的「示例」部分。

要记住的是,真正执行我们的 docker 命令的是 docker engine,而这个 engine 跑在宿主机上。所以这并不是真正的 "Docker in Docker".

二、示例

在容器内部使用宿主机的 docker,方法有二:

  1. 命令行方式:将 /usr/bin/docker 映射进容器内部,然后直接在容器内部使用这个命令行工具 docker
    • 需要的时候,也可以将 /etc/docker 文件夹映射到容器内,这样容器内的 docker 命令行工具也会使用与宿主机同样的配置。
  2. 编程方式:在容器内部以编程的方式使用 docker
    • 通过 python 使用 docker: 在 Dockerfile 中通过 pip install docker 将 docker client 安装到镜像中来使用

容器的启动方式也有两种,如下:

1. 直接通过 docker 命令启动

示例命令如下:

docker run --name <name> \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v /usr/bin/docker:/usr/bin/docker \
    --user root \
    <image-name>:<tag>

**必须以 root 用户启动!(或者其他有权限读写 /var/run/docker.sock 的用户)**然后,在容器内就能正常使用 docker 命令,或者访问宿主机的 docker api 了。

2. 使用 docker-compose 启动

docker-compose.yml 文件内容如下:

version: ''3.3''
services:
  jenkins-master:
    image: jenkinsci/blueocean:latest
    container_name: jenkins-master
    environment:
      - TZ=Asia/Shanghai  # 时区
    ports:
      - "8080:8080"
      - "50000:50000"
    volumes:
      - ./jenkins_home:/var/jenkins_home  # 将容器中的数据映射到宿主机
      - /usr/bin/docker:/usr/bin/docker  # 为容器内部提供 docker 命令行工具(这个随意)
      - /var/run/docker.sock:/var/run/docker.sock  # 容器内部通过 unix socket 使用宿主机 docker engine
    user: root  # 必须确保容器以 root 用户启动!(这样它才有权限读写 docker.socket)
    restart: always

然后通过 docker-compose up -d 即可后台启动容器。

Docker 中的 uid 与 gid

通过上面的操作,我们在容器内执行 docker ps 时,还是很可能会遇到一个问题:权限问题

如果你容器的默认用户是 root,那么你不会遇到这个问题,因为 /var/run/docker.sock 的 onwer 就是 root.

但是一般来说,为了限制用户的权限,容器的默认用户一般都是 uid 和 gid 都是 1000 的普通用户。这样我们就没有权限访问 /var/run/docker.sock 了。

解决办法:

方法一(不一定有效):在构建镜像时,最后一层添加如下内容:

# docker 用户组的 id,通常都是 999
RUN groupadd -g 999 docker \
    && usermod -aG docker <your_user_name>

这样我们的默认用户,就能使用 docker 命令了。

P.S. 999 不一定是 docker 用户组,所以上述方法某些情况下可能失效。这时还是老老实实通过 docker run -u root 启动容器吧。(或者在 docker-compose.yml 中添加 user: root 属性)

参考

  • Docker in Docker - 王柏元

关于docker 的 /var/run/docker.sock 参数docker /var/lib/docker详解的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于/var/run/docker.sock的Docker安全风险是什么?、167 docker docker构建nginx容器系列问题 docker registry docker run docker toolbo、Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?、Docker in Docker(实际上是 Docker outside Docker): /var/run/docker.sock的相关知识,请在本站寻找。

本文标签: