Docker

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feilengcui008/article/details/52758877 本文主要介绍Docker的一些基本概念、Docker的源码分析、Docker的一些issue、Docker周边生态等等。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/feilengcui008/article/details/52758877

本文主要介绍Docker的一些基本概念、Docker的源码分析、Docker的一些issue、Docker周边生态等等。


基本概念

Basics

docker大体包括三大部分,runtime(container)、image(graphdriver)、registry,runtime提供环境的隔离与资源的隔离和限制,image提供layer、image、rootfs的管理、registry负责镜像存储与分发。当然,还有其他一些比如data volume, network等等,总体来说还是分为计算、存储与网络。

computing

  • 接口规范
  • 命名空间隔离、资源隔离与限制的实现
  • 造坑与入坑

network

  • 接口规范与实现

    • bridge
      • veth pair for two namespace communication
      • bridge and veth pair for multi-namespace communication
      • do not support multi-host
    • overlay

      • docker overlay netowrk: with swarm mode or with kv etcd/zookeeper/consul -> vxlan
      • coreos flannel -> 多种backend,udp/vxlan…
      • ovs
      • weave -> udp and vxlan,与flannel udp不同的是会将多container的packet一块打包
      • 一篇对比
        • 对比图
    • calico

      • pure layer 3
    • null
      • 与世隔绝
    • host
      • 共享主机net namespace

storage

  • graphdriver(layers,image and rootfs)
    • graph:独立于各个driver,记录image的各层依赖关系(DAG),注意是image不包括运行中的container的layer,当container commit生成image后,会将新layer的依赖关系写入
    • device mapper
      • snapshot基于block,allocation-on-demand
      • 默认基于空洞文件(data and metadata)挂载到回环设备
    • aufs
      • diff:实际存储各个layer的变更数据
      • layers:每个layer依赖的layers,包括正在运行中的container
      • mnt:container的实际挂载根目录
    • overlayfs
    • vfs
    • btrfs
  • volume
    • driver接口
      • local driver
      • flocker: container和volume管理与迁移
      • rancher的convoy:多重volume存储后端的支持device mapper, NFS, EBS…,提供快照、备份、恢复等功能
    • 数据卷容器
  • registry:与docker registry交互
    • 支持basic/token等认证方式
    • token可以基于basic/oauth等方式从第三方auth server获取bearer token
    • tls通信的支持
  • libkv
    • 支持consul/etcd/zookeeper
  • 分布式存储的支持

security

  • docker
    • libseccomp限制系统调用(内部使用bpf)
    • linux capabilities限制root用户权限范围scope
    • user namespace用户和组的映射
    • selinux
    • apparmor
  • image and registry

Other Stuffs


源码分析

for docker 1.12.*

主要模块

  • docker client
    • DockerCli => 封装客户端的一些配置
    • command => 注册docker client支持的接口
    • docker/engine-api/client/[Types|Client|Request|Transport|Cancellable] => 规范访问dockerd apiserver的接口
  • docker engine daemon
    • DaemonCli
      • apiserver => 接受docker client请求,转发到daemon rpc
      • daemon => 其他功能比如设置docker根目录、inti process、dockerd运行的user namespace等其他信息
        • 包含一个很重要的部分: remote => 通过libcontainerd与containerd的grpc server后端打交道
      • cluster => swarm mode相关
  • containerd
    • containerd => grpc server,提供给dockerd操作容器、进程等的接口,提供containerd、containerd-shim、containerd-ctr工具
  • libcontainer(runc)
    • libcontainer(runc) 提供容器的生命周期相关的接口标准,提供runc工具
  • 基本流程:docker client ==http==> dockerd apiserver ====> remote grpc client(libcontainerd) ==grpc==> containerd ==cmd==> containerd-shim ==cmd==> runc exec/create等 ==cmd==> runc init初始化坑内init进程环境,然后execve替换成容器指定的应用程序

详细分析

客户端部分省略,这里主要介绍docker engine daemon(DaemonCli)、containerd以及libcontainer(runc)三大部分。

  • DaemonCli: 启动docker daemon与containerd daemon的核心对象,包含三大部分,apiserver、Daemon对象和cluster

    • apiserver
      • middleware
      • routers
        • 通用模式
          • 提供backend具体操作的后端接口(实际全在daemon.Daemon实现,而daemon.Daemon会作为所有router的backend)
          • 提供解析请求的routers函数(实际调用backend接口)
          • 注册routers
        • build => docker build
        • container => container创建启停等
        • image => 镜像
        • network => 网络
        • plugin => 插件机制
        • swarm => swarm模式相关
        • volumn => 数据卷
        • system => 系统信息等
      • 我们可以用nc手动测试apiserver,具体实现的接口可以参考标准文档或者api/server下的源码
        • 执行命令即可看到json输出(还有个python的客户端lib docker-py)
        • echo -e “GET /info HTTP/1.0\r\n” | nc -U /var/run/docker.sock
        • echo -e “GET /images/json HTTP/1.0\r\n” | nc -U /var/run/docker.sock
    • daemon.Daemon对象
      • daemon除了处理engine daemon需要的通用环境(比如storage driver等)外,还包括registry部分和与containerd交互的grpc接口client(libcontainerd.Client/libcontainerd.Remote相关)。在DaemonCli的初始化过程中会由libcontainerd.New创建libcontainerd.remote,启动containerd daemon(grpc server)并且为docker engine daemon注入containerd/types中规范的与containerd daemon通信的grpc接口client
      • 以docker pause為例,整個調用鏈條為:
        • docker client -> apiserver container router postContainerPause -> daemon.Daemon.ContainerPause(backend) -> backend.containerd.Pause
          -> libcontainerd.Client.Pause -> remote.apiClient.UpdateContainer -> containerd.APIClient.UpdateContainer -> grpc.UpdateContainer -> containerd daemon UpdateContainer -> 调用containerd-shim containerid container_path runc -> 调用runc命令
          • 说明: containerd是一个从docker daemon中抽出来的项目,提供操作runc的界面(包括一个daemon grpc server、一个ctr客户端工具用grpc.APIClient与grpc server通信、以及containerd-shim负责调用runc命令处理容器生命周期),runc提供的只是一个容器生命周期lib标准和cli工具,而没有daemon。
      • 可以看出,runc(libcontainerd)提供了runtime的lib接口标准,不同os可以实现此接口屏蔽容器的具体实现技术细节;而containerd提供了一个基于libcontainerd接口的server以及cli工具(主要是grpc规范了);而docker daemon(engine)的apiserver提供的是docker client的restful http接口,会通过containerd的grpc Client标准接口与containerd的server通信。我们可以看到”/var/run/docker/libcontainerd/docker-containerd.sock”和”/var/run/docker.sock”,如上面通过nc与docker daemon直接通信,我们也可以使用grpc client与libcontainerd的daemon直接通信
      • 综上,不难看出docker提供的几个主要二进制文件是干嘛的了…(docker/dockerd/docker-containerd/docker-containerd-shim/docker-containerd-ctr/docker-runc)
        • 用runc直接操作容器: docker-runc list
        • 用docker-containerd-ctr 通过docker-containerd grpc Server操作容器: docker-containerd-ctr –address “unix:///var/run/docker/libcontainerd/docker-containerd.sock” containers list
        • 用docker通过dockerd、docker-containerd操作容器: docker ps
        • 拆分的好处显而易见:标准化、解耦、新特性的实验、换daemon无需停止容器等等
    • cluster
      • 這一部分與swarm相关,实际上是把swarmkit集成到了docker engine daemon中
      • 每次启动docker engine daemon时会检查/var/lib/docker/swarm目录下是否有状态文件,如果有则需要恢复集群,重新启动节点;否则,直接返回,不开启swarm mode
      • swarm中的节点有ManagerNode和WorkerNode之分,worker可以被promote成manager,manager也可以被demote回worker。在节点加入集群时可以指定加入的角色是worker还是manager。默认启动一个manager节点
  • containerd

    • 容器元数据、提供管理容器生命周期的grpc server以及ctr 客户端工具,具体的容器的操作是通过containerd-shim调用runc命令,每个容器的init进程在容器外部会有对应的containerd-shim进程。
    • 提供了一套任务执行机制,把对容器的生命周期的操作用Task/Worker模型抽象,提供更高的性能
    • 从docker engine daemon拆分,使得engine daemon升级时容器不用stop
    • 简单流程
      • 核心的对象: grpc server、supervisor、worker、task、runtime(處理container和process相關元數據等)等
      • 主routine的grpc apiserver等待grpc请求 -> supervisor server handleTask -> 放入supervisor的tasks chan -> worker从tasks chan中取出执行 -> shim -> runc
  • libcontainer(or runc)

    • 未完待续
  • 从containerd到runc到实际的坑内进程起来经过的进程模型(以下起进程都是通过go的cmd)

    • containerd的worker启动containerd-shim进程,传递参数shim containerdid containerpath runtime(其中runtime默认为runc),并且给runc传递exec/create的行为参数,起好坑。
    • containerd-shim启动runc exec/create进程,等待runc进程的结束,负责容器内的init进程的退出时的清理工作。containerd-shim与containerd daemon进程通信是通过control和exit两个具名管道文件。
    • runc exec/create作为父进程负责创建容器内的init进程,并用管道与init进程通信,这个init进程实际上是执行runc init命令,初始化容器环境,然后等待containerd执行runc start的信号,让用户的进程替换容器中的init,在容器中执行起来。
      • runc init进程负责初始化整个环境,包括清除所有runc exec/create父进程的环境变量,加载docker engine daemon传下来的docker client和docker image中指定的环境变量,设置namespace等等,然后等在管道的child上,等待runc exec/create父进程发送process的json配置文件,runc init坑内进程拿到这个配置文件,初始化所有的坑内环境,然后等待在exec.fifo具名管道文件上,等待runc start发送信号,然后开始execve用用户的程序替换掉runc init。

相关系统

Docker和Mesos Container建坑流程和进程模型对比

注: P代表进程, L代表线程

  • Docker

    • containerd的worker启动containerd-shim进程,传递参数shim containerdid containerpath runtime(其中runtime默认为runc),并且给runc传递exec/create的行为参数,起好坑。
    • containerd-shim启动runc exec/create进程,等待runc进程的结束,负责容器内的init进程的退出时的清理工作。containerd-shim与containerd daemon进程通信是通过control和exit两个具名管道文件。
    • runc exec/create作为父进程负责创建容器内的init进程,并用管道与init进程通信,这个init进程实际上是执行runc init命令,初始化容器环境,然后等待containerd执行runc start的信号,让用户的进程替换容器中的init,在容器中执行起来。
      • runc init进程负责初始化整个环境,包括清除所有runc exec/create父进程的环境变量,加载docker engine daemon传下来的docker client和docker image中指定的环境变量,设置namespace等等,然后等在管道的child上,等待runc exec/create父进程发送process的json配置文件,runc init坑内进程拿到这个配置文件,初始化所有的坑内环境,然后等待在exec.fifo具名管道文件上,等待runc start发送信号,然后开始execve用用户的程序替换掉runc init。
  • Mesos Native Linux Container

    • 基本模型
      • 与docker containerd的主进程和matrix-agent的ContainerManager主线程类似,executor(mesos默认提供Command、Container两种executor)起一进程负责维护containers list的内存状态,并且fork&exec执行容器的启动
    • 建坑流程
      • Creates a “freezer” cgroup for the container.
      • Creates posix “pipe” to enable communication between host (parent process) and container process.
      • Spawn child process(container process) using clone system call.
      • Moves the new container process to the freezer hierarchy.
      • Signals the child process to continue (exec’ing) by writing a character to the write end of the pipe in the parent process.
  • Mesos

    • todo
  • Kubernetes

    • todo

issues

记录一些Docker相关项目遇到的一些bug或者issue

  • Docker

    • overlayfs在centos6上的bug,某些容器启动时会触发(比如ubuntu)
    • 127.16.0.0网段的路由默认被设置导致创建网络失败 -> route del … -> 但是导致公司内网无法访问机器
      • 解决办法
        • 手动创建bridge,启动docker时,避开机器路由的默认网段(比如10.,172.,192.*),尤其注意公司机器路由了大网段,docker可能找到一个子网段,还是能成功启动,但是后续创建网络会失败。。。
        • 先route del机器的路由网段,docker network create,再设置route(选这种方式绕过…)
      • docker default local pool
    • devicemapper storage driver依赖udev,而udev不支持static linked的docker binary,需要dynamic的docker binary
  • Harbor

    • harbor的tags和manifests api连接registry泄露fd导致进程超过最大可用fd在新的请求解析dns时失败
      • 定位bug应该是每次请求接口时新建client的同时新建了tarnsport对象,从而导致上一次请求的transport的连接无法复用,从而泄露fd。解决办法是使用对每个host的请求使用一个全局的transport和client
      • 或者关闭transport的keepalive或者在发请求的时候加req.Close=true,关闭连接重用
  • Distribution(Registry v2)

    • Distribution的http.Server没有设置ReadTimeout和WriteTimeout,如果客户端与registry通信没有注意连接重用的问题,则可能导致泄露fd
      • harbor与distribution通信建立的连接会泄露fd,导致registry和harbor都会由于操作进程限制的fd数量而请求失败
      • 通常不可能直接设置registry的timeout,因为对于较大的镜像可能导致下载超时
  • Mesos

    • todo
  • Kubernetes

    • todo
相关文章
|
6月前
|
Linux 虚拟化 开发者
docker介绍之一
docker介绍之一
29 1
|
7月前
|
关系型数据库 MySQL Docker
|
3月前
|
Linux 虚拟化 开发者
Docker(1)
Docker定义 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
|
7月前
|
关系型数据库 MySQL 应用服务中间件
Docker
Docker 是一个开源的应用容器引擎,基于 Go语言并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app),更重要的是容器性能开销极低。
170 0
|
10月前
|
Linux 测试技术 API
【Docker】Docker最近这么火,它到底是什么
【Docker】Docker最近这么火,它到底是什么
|
10月前
|
存储 运维 关系型数据库
Docker(2)
Docker(2)
|
Ubuntu NoSQL Linux
了解和理解Docker的使用
Docker背景 Docker技术是基于Linux容器 虚拟容器技术的 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的
122 0
了解和理解Docker的使用
|
运维 NoSQL 关系型数据库
docker详细介绍
作者主页:https://www.couragesteak.com/
docker详细介绍
|
NoSQL jenkins 关系型数据库
你应该学会的docker使用技巧
这是之前在简书写的一篇旧文;没有读过的小伙伴可以读读。
114 0
|
Java Docker 容器
服务 Docker 化
文章首发于公众号《程序员果果》地址:https://mp.weixin.qq.com/s/DzF-ZwaY4QtlgM32I5wybg 一、简介 ​Docker的出现让容器化技术得以普及,更快的部署和维护与Spring Cloud的结合,能让我们不再像以前一样为了某一个模块的增加而服务器上大动干戈,还需要考虑环境的问题。