12

Docker 基础

 3 years ago
source link: http://www.cnblogs.com/zhengyuan/p/13700826.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Docker 基础

一、简介

1. 什么是 Docker

docker 是一个开源的应用容器引擎,基于go语言开发并遵循了apache2.0协议开源。docker本质就是 宿主机的一个进程。 docker是通过 namespace 实现资源隔离,通过 cgroup 实现资源限制,通过 写时复制技术(copy-on-write) 实现了高效的文件操作(类似虚拟机的磁盘比如分配500g并不是实际占用物理磁盘500g)

namespace的六项隔离

namespace 系统调用参数 隔离内容 UTS CLONE_NEWUTS 主机名,域名 IPC CLONE_NEWWIPC 信号量,消息堆列和共享内存 PID CLONE_NEWPID 进程编号 NETWORK CLONE_NEWNET 网络设备、网络栈、端口等 MOUNT CLONE_NEWNS 挂载点(文件系统) USER CLONE_NEWUSER 用户和用户组(3.8以后的内核才支持)

名字空间是 Linux 内核一个强大的特性。每个容器都有自己单独的名字空间,运行在其中的应用都像是在独立的操作系统中运行一样。名字空间保证了容器之间彼此互不影响。

1 pid 名字空间

不同用户的进程就是通过 pid 名字空间隔离开的,且不同名字空间中可以有相同 pid。所有的 LXC 进程在Docker 中的父进程为Docker进程,每个 LXC 进程具有不同的名字空间。同时由于允许嵌套,因此可以很方便的实现嵌套的 Docker 容器。

2 net 名字空间

有了 pid 名字空间, 每个名字空间中的 pid 能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net 名字空间实现的, 每个 net 名字空间有独立的 网络设备, IP 地址, 路由表, /proc/net 目录。这样每个容器的网络就能隔离开来。Docker 默认采用 veth 的方式,将容器中的虚拟网卡同 host 上的一 个Docker网桥 docker0 连接在一起。

3 ipc 名字空间

容器中进程交互还是采用了 Linux 常见的进程间交互方法(interprocess communication – IPC), 包括信号量、消息队列和共享内存等。然而同 VM 不同的是,容器的进程间交互实际上还是 host 上具有相同 pid 名字空间中的进程间交互,因此需要在 IPC 资源申请时加入名字空间信息,每个 IPC 资源有一个唯一的 32位 id。

4 mnt 名字空间

类似 chroot,将一个进程放到一个特定的目录执行。mnt 名字空间允许不同名字空间的进程看到的文件结构不同,这样每个名字空间 中的进程所看到的文件目录就被隔离开了。同 chroot 不同,每个名字空间中的容器在 /proc/mounts 的信息只包含所在名字空间的 mount point。

5 uts 名字空间

UTS(“UNIX Time-sharing System”) 名字空间允许每个容器拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 主机上的一个进程。

6 user 名字空间

每个容器可以有不同的用户和组 id, 也就是说可以在容器内用容器内部的用户执行程序而非主机上的用户。

原文链接: https://blog.csdn.net/CleverCode/article/details/83863925

control Group 控制组

特点

  1. cgroup的api以一个 伪文件系统 的实现方式,用户的程序可以通过文件系统实现cgroup的 组件管理
  2. cgroup的组件管理操作单元可以 细粒度到线程级别 ,另外用户可以 创建和销毁 cgroup,从而实现资源的分配和再利用;
  3. 所有资源管理的功能都以 子系统的方式实现 ,接口统一子任务创建之初与其父任务处于同一个cgroup的控制组

功能

  1. 资源限制 :可以对任务使用的资源总额进行限制;
  2. 优先级分配 :通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级;
  3. 资源统计 :可以统计系统的资源使用量,如cpu时长,内存用量等;
  4. 任务控制 :cgroup可以对任务执行挂起、恢复等操作;

2. 容器的优点

  • 灵活:即使是最复杂的应用也可以集装箱化。
  • 轻量级:容器利用并共享主机内核。
  • 可互换:您可以即时部署更新和升级。
  • 便携式:您可以在本地构建,部署到云,并在任何地方运行。
  • 可扩展:您可以增加并自动分发容器副本。
  • 可堆叠:您可以垂直和即时堆叠服务。

3. Docker 三个重要的概念

docker 是一个 C/S 架构模型。

1)image镜像

docker镜像就是一个只读模板,比如,一个镜像可以包含一个完整的centos,里面仅安装apache或用户的其他应用,镜像可以用来 创建docker容器 ,另外docker提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下一个已经做好的镜像来直接使用。

2)container容器

docker利用容器来运行应用, 容器是从镜像创建的运行实例 ,它可以被 启动,开始、停止、删除、每个容器都是互相隔离的, 保证安全的平台,可以吧容器看做是要给 简易版的linux 环境(包括root用户权限、镜像空间、用户空间和网络空间等)和运行再其中的应用程序

3)repostory仓库

仓库是集中存储镜像文件的沧桑,registry是仓库主从服务器,实际上参考注册服务器上存放着多个仓库,每个仓库中又 包含了多个镜像 ,每个镜像 有不同的标签 (tag)

仓库分为两种, 公有仓库和私有仓库 ,最大的公开仓库是docker Hub,存放了数量庞大的镜像供用户下周,国内的docker pool,这里仓库的概念与Git类似,registry可以理解为github这样的托管服务

二、Docker 架构

1. 看得见的架构

Docker使用了 C/S 体系架构。

  1. Docker客户端与Docker守护进程(daemon)通信, 守护进程 负责 构建,运行和分发 Docker容器。
  2. Docker客户端和守护进程可以在同一个系统上运行,也可以将Docker 客户端连接到远程 Docker守护进程。
  3. Docker客户端和守护进程使用 REST API通过UNIX套接字或网络接口 进行通信。

yEz2ymA.png!mobile

2. 总体架构

用户是使用 Docker ClientDocker Daemon 建立通信,并发送请求给后者。

  1. 而Docker Daemon 作为Docker架构中的 主体部分 ,首先 提供Server的功能 使其可以接受Docker Client的请求;
  2. 而后 Engine 执行Docker内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。Job的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 graphdriver 将下载镜像以 Graph 的形式存储;
  3. 当需要为Docker创建 网络 环境时,通过网络管理驱动 networkdriver 创建并配置Docker 容器网络环境
  4. 当需要限制Docker容器运行资源或执行用户指令等操作时,则通过 execdriver 来完成。
  5. libcontainer 是一项独立的 容器管理包networkdriver 以及 execdriver 都是通过 libcontainer 来实现具体对容器进行的操作。
  6. 当执行完运行容器的命令后,一个实际的Docker容器就处于运行状态,该容器拥有 独立的文件系统独立并且安全的运行环境 等。

raMZRbq.png!mobile

三、各个模块的介绍

主要模块

  • Docker Client
  • Docker Daemon
  • Docker Registry
  • Graph
  • Driver
  • libcontainer
  • Docker container

1. Docker Client

docker client 是docker架构中用户用来和docker daemon建立通信的客户端,用户使用的可执行文件为docker,通过docker命令行工具可以发起众多管理container的请求。

docker client可以通过以下三种方式和docker daemon建立通信:

tcp://host:port; unix:path_to_socket; fd://socketfd

docker client可通过设置命令行flag参数的形式设置安全传输层协议(TLS)的有关参数,保证传输的 安全性

docker client发送容器管理请求后,由docker daemon接受处理 请求,当docker client 接收到返回的请求相应并简单处理后,docker client 一次完整的生命周期就结束了。当需要继续发送容器管理请求时,用户必须再次通过docker可以执行文件创建docker client。

2. Docker Daemon

docker daemon 是docker架构中一个常驻在后台的 系统 进程。功能是: 接收处理docker client发送的请求 。该守护进程在后台启动一个 serverserver 负载接受docker client发送的请求;接受请求后,server通过 路由 与分发调度,找到相应的 handler 来执行请求。

docker daemon启动所使用的可执行文件也为docker,与docker client启动所使用的可执行文件docker相同,在docker命令执行时,通过传入的参数来判别docker daemon与docker client。

docker daemon的架构可以分为: docker serverenginejobdaemon

a)docker server

在docker 架构 中时专门服务于docker clientserver ,该server的功能时:接受并调度分发docker client发送的请求,架构图如下:

yIBJVnr.png!mobile

在Docker的启动过程中,通过包 gorilla / mux (golang的类库解析),创建了一个 mux . Router ,提供请求的路由功能。在Golang中, gorilla /mux是一个 强大的URL路由器 以及 调度分发器 。该 mux . Router 中添加了众多的路由项,每一个路由项由HTTP请求方法(PUT、POST、GET或DELETE)、URL、Handler三部分组成。

若Docker Client通过HTTP的形式访问Docker Daemon,创建完mux.Router之后,Docker将Server的监听地址以及mux.Router作为参数,创建一个 httpSrv=http.Server{} ,最终执行 httpSrv.Serve() 为请求服务。

Server 的服务过程中,Server在 listener 上接受Docker Client 的访问请求,并创建一个全新的 goroutine 来服务该请求。在 goroutine 中,首先 读取 请求内容,然后做 解析 工作,接着找到相应的 路由项 ,随后调用相应的 Handler 来处理该请求,最后 Handler 处理完请求之后回复该请求。

需要注意的是:Docker Server的运行在Docker的启动过程中,是靠一个名为” serveapi ”的 job 的运行来完成的。原则上,Docker Server的运行是众多 job 中的一个,但是为了强调Docker Server的重要性以及为后续job服务的重要特性,将该” serveapi ”的job单独抽离出来分析,理解为Docker Server。

b)engine

Engine是Docker架构中的 运行引擎 ,同时也Docker运行的 核心模块 。它扮演Docker container存储仓库 的角色,并且通过执行 job 的方式来 操纵管理 这些 容器

在Engine数据结构的设计与实现过程中,有一个 handler 对象。该 handler 对象存储的都是关于众多特定job的handler 处理访问 。举例说明,Engine的handler对象中有一项为:{“create”: daemon.ContainerCreate,},则说明当名为”create”的job在运行时,执行的是daemon.ContainerCreate的handler。

c)job

一个Job可以认为是Docker架构中 Engine 内部最基本的工作执行单元。Docker可以做的每一项工作,都可以抽象为一个 job例如 :在容器内部运行一个进程,这是一个 job ;创建一个新的 容器 ,这是一个job,从 Internet 上下载一个文档,这是一个 job ;包括之前在 Docker Server 部分说过的,创建 Server 服务于 HTTPAPI ,这也是一个job,等等。

Job的设计者,把Job设计得 与Unix进程相仿 。比如说:Job有一个名称,有 参数 ,有 环境变量 ,有标准的 输入输出 ,有 错误处理 ,有 返回状态 等。

3. Docker Registry

Docker Registry 是一个存储 容器 镜像的仓库。而容器镜像是在容器被创建时,被加载用来初始化容器的 文件架构与目录

在Docker的运行过程中,Docker Daemon会与Docker Registry 通信 ,并实现 搜索 、下载 镜像 、上传 镜像 三个功能,这三个功能对应的job名称分别为”search”,”pull” 与 “push”。

其中,在Docker架构中,Docker可以使用公有的Docker Registry,即大家熟知的Docker Hub,如此一来,Docker获取容器镜像文件时,必须通过互联网访问Docker Hub;同时Docker也允许用户构建本地私有的Docker Registry,这样可以保证容器镜像的获取在内网完成。

4. Graph

Graph在Docker架构中扮演已下载容器镜像的保管者,以及已下载容器镜像之间关系的记录者。一方面,Graph存储着本地具有版本信息的文件系统镜像,另一方面也通过GraphDB记录着所有文件系统镜像彼此之间的关系。Graph的架构如下:

YBz6Vf.png!mobile

其中, GraphDB 是一个构建在 SQLite 之上的小型图 数据 库,实现了节点的 命名 以及节点之间关联关系的记录。它仅仅实现了大多数图数据库所拥有的一个小的子集,但是提供了简单的接口表示节点之间的关系。

同时在 Graph 的本地目录中,关于每一个的 容器 镜像,具体存储的信息有:该容器镜像的元数据,容器镜像的大小信息,以及该容器镜像所代表的具体 rootfs

5. Driver

Driver是 Docker 架构中的 驱动模块 。通过Driver驱动,Docker可以实现对Docker容器执行环境的定制。由于Docker运行的生命周期中,并非用户所有的操作都是针对Docker 容器 的管理,另外还有关于Docker运行信息的获取, Graph 的存储与记录等。因此,为了将 Docker容器 的管理从Docker Daemon 内部业务逻辑中区分开来,设计了Driver层驱动来接管所有这部分请求。

在Docker Driver的实现中,可以分为以下三类驱动: graphdrivernetworkdriverexecdriver

a)graphdriver

graphdriver主要用于完成容器镜像的管理,包括 存储获取 。即当用户需要下载指定的容器镜像时, graphdriver 将容器镜像存储在本地的指定目录;同时当用户需要使用指定的容器镜像来创建容器的 rootfs 时, graphdriver 从本地镜像存储目录中获取 指定的容器镜像

graphdriver 的初始化过程之前,有4种 文件系统 或类文件系统在其内部注册,它们分别是 aufsbtrfsvfsdevmapper 。而 Docker 在初始化之时,通过获取系统环境变量” DOCKER_DRIVER ”来提取所使用driver的指定类型。而之后所有的 graph 操作,都使用该driver来执行。

graphdriver的架构如下:

UbyIFnf.png!mobile

b)networkdriver

networkdriver的用途是完成Docker容器 网络环境的配 置,其中包括Docker启动时为Docker环境 创建网桥 ;Docker容器创建时为其创建专属 虚拟网卡设备 ;以及为 Docker 容器分配 IP端口 并与宿主机做 端口映射 ,设置容器 防火墙策略 等。 networkdriver 的架构如下:

qiIj6b2.png!mobile

c)execdriver

execdriver作为 Docker 容器的 执行驱动 ,负责 创建容器运行命名空间负责容器资源使用的统计与限制 ,负责容器内部进程的 真正运行 等。在 execdriver 的实现过程中,原先可以使用 LXC 驱动调用 LXC接口 ,来操纵容器的配置以及生命周期,而现在 execdriver 默认使用 native 驱动,不依赖于 LXC 。具体体现在 Daemon 启动过程中加载的 ExecDriverflag 参数,该参数在配置文件已经被设为” native ”。这可以认为是 Docker 在1.2版本上一个很大的改变,或者说Docker实现跨平台的一个先兆。 execdriver 架构如下:

Uju6Vfz.png!mobile

6. libcontainer

libcontainer是 Docker 架构中一个使用Go语言设计实现的库,设计初衷是希望该库可以不依靠任何依赖,直接访问内核中与容器相关的API。

正是由于 libcontainer 的存在,Docker可以直接调用 libcontainer ,而最终操纵容器的 namespacecgroupsapparmor网络设备 以及 防火墙规则 等。这一系列操作的完成都不需要依赖 LXC 或者 其他 包。libcontainer架构如下:

63i2q2.png!mobile

另外, libcontainer 提供了一整套标准的接口来满足 上层对容器管理的需 求。或者说, libcontainer 屏蔽了 Docker 上层对容器的直接管理。又由于 libcontainer 使用Go这种跨平台的语言开发实现,且本身又可以被上层多种不同的编程语言访问,因此很难说,未来的Docker就一定会紧紧地和Linux捆绑在一起。而于此同时,Microsoft在其著名云计算平台Azure中,也添加了对Docker的支持,可见Docker的开放程度与业界的火热度。

暂不谈Docker,由于libcontainer的功能以及其本身与系统的 松耦合 特性,很有可能会在其他以容器为原型的平台出现,同时也很有可能催生出云计算领域全新的项目。

7. Docker container

Docker container (Docker容器)是Docker架构中服务交付的最终 体现 形式。

Docker按照用户的需求与指令,订制相应的Docker容器:

用户通过指定容器镜像,使得Docker容器可以自定义 rootfs 等文件系统; 用户通过指定计算资源的配 ,使得Docker容器使用指定的 计算资源 ; 用户通过 配置网络及其安全策略 ,使得Docker容器拥有独立且安全的网络环境; 用户通过指定运行的命令,使得Docker容器执行指定的工作。

nUzqM3j.png!mobile

四、Docker 安装

  • linux内核版本依赖

kernel version >= 3.8

可以使用如下命令查看

uname -a | awk '{split($3, arr, "-"); print arr[1]}'

# 关闭selinux 
setenforce 0
sed -i'/^SELINUX=/c\SELINUX=disabled' /etc/selinux/config

# 关闭防火墙 
systemctl stopfirewalld.service
systemctl disablefirewalld.service
systemctl stop iptables.service
systemctl disableiptables.service

# 卸载旧版本
yum remove docker \ 
		docker-client \ 
    docker-client-latest \ 
    docker-common \ 
    docker-latest \ 
    docker-latest-logrotate \ 
    docker-logrotate \ 
    docker-selinux \ 
    docker-engine-selinux \ 
    docker-engine

# 设置stable镜像仓库
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast

# 安装最新版本
yum -y install docker-ce

# 运行
systemctl enable docker
systemctl start docker

当要以非 root 用户可以直接运行 docker 时,需要执行 usermod -aG docker $USER当要以非 root 用户可以直接运行 docker 时,需要执行

五、常用命令

菜鸟教程

六、延伸资料


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK