Docker原理分析及Dockfile实践

目录

概况

用途

架构

原理

Namespace

Cgroup

Union FS

总体架构

Docker 组件

Docker 存储驱动

Docker 数据共享与持久化

Docker 网络模式

Docker 状态转化

制作基础镜像

DockerHub

常用docker命令

Docker与虚拟机区别


概况

Docker 官网:https://www.docker.com

Github Docker 源码:https://github.com/docker/docker-ce

Docker是一个开源的应用容器引擎,基于GO语言,遵从Apache2.0开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

用途

  • 提供轻量级简化的自动部署环境
  • 提供弹性的动态云服务:随时开关机,适合动态扩缩容
  • 组建微服务架构:一台机器可部署多个服务

架构

原理

Docker利用Linux中的核心分离机制,来创建独立的容器。一句话概括起来Docker就是利用Namespace做资源隔离,用Cgroup做资源限制,利用Union FS做容器文件系统的轻量级虚拟化技术。

Docker容器的本质还是一个直接运行在宿主机上面的特殊进程,看到的文件系统是隔离后的,但是操作系统内核是共享宿主机OS,所以说Docker是轻量级的虚拟化技术。

Namespace

Linux Namespace 是Linux 提供的一种内核级别环境隔离的方法,使其中的进程好像拥有独立的操作系统环境。Linux Namespace 有 Mount Namespace,UTS Namespace, IPC Namespace, PID Namespace, Network Namespace, User Namespace, Cgroup Namespace。详情看下表:

分类 系统调用参数 隔离内容 内核版本
Mount Namespace CLONE_NEWNS 文件系统挂载点 Linux 2.4.19(2002年)
UTS Namespace CLONE_NEWUTS Hostname和domain name Linux 2.6.19
IPC Namespace CLONE_NEWIPC 进程间通信方式,例如消息队列 Linux 2.6.19
PID Namespace CLONE_NEWPID 进程ID编号 Linux 2.6.24
Network Namespace, CLONE_NEWNET 网络设备,协议栈,路由表,防火墙规则,端口等 Linux 2.6.24 start Linux 2.6.29 end
User Namespace CLONE_NEWUSER 用户及组ID Linux 2.6.23 start Linux 3.8 end
Cgroup Namespace CLONE_NEWCGROUP Cgroup根目录 Linux 4.6

上述系统调用参数CLONE_NEWNS等主要应用于以下三个系统调用:

  • clone 创建新进程并设置它的Namespace,类似于fork系统调用,可创建新进程并且指定子进程将要执行的函数,通过上述CLONE_NEWNS等参数使某类资源处于隔离状态

Cgroup

Docker 容器运行起来是一个直接运行在宿主机上面的进程,那么如果限定每个容器最多消耗多少CPU资源呢?如果一个容器疯狂的消耗资源岂不是会影响同一宿主机上面其他的容器?所以Docker就需要一个限制容器能够使用资源上限的机制,那就是Linux Cgroup技术。Linux Cgroup 全称是Linux Control Group。它最主要的作用是限制一个进程组能够使用的资源上限,包括CPU,MEM,DISK,NET等等。当容器的内存使用量超过了Cgroup限定值会被系统OOM。

Union FS

每个容器运行起来后都有一个独立的文件系统,例如Ubuntu镜像的容器能够看到Ubuntu的文件系统,Centos能够看到Centos的文件系统, 不是说容器是运行在宿主机上面的进程吗,为什么能够看到和宿主机不一样的文件系统呢?那就要归功于Union FS,全称是Union File System,联合文件系统。将多个不同位置的目录联合挂载到同一个目录,将相同的部分合并。Docker利用这种联合挂载能力,将容器镜像里面的多层内容呈现为统一的rootfs(根文件系统),即root用户能够看到的根目录底下所有的目录文件。rootfs打包了整个操作系统的文件和目录,是应用运行时所需要的最完整的“依赖库”,也就是我们说的“镜像”。

镜像分为基础镜像只读层,和Init层,和读写层。

  • Init 层存放的是/etc/hostname,/etc/resolv.conf 等, docker commit的时候不提交。
  • 读写层一开始的时候为空,用户如果修改了文件系统,比如说增删改了文件,docker commit的时候就会提交这一层信息。

总体架构

Docker原理分析及Dockfile实践_第1张图片

Docker使用了C/S体系架构,Docker客户端与Docker守护进程通信,Docker守护进程负责构建,运行和分发Docker容器。Docker客户端和守护进程可以在同一个系统上运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程使用REST API通过UNIX套接字或网络接口进行通信。

Docker 组件

  • Docker daemon( Docker守护进程):Docker daemon是一个运行在宿主机( DOCKER-HOST)的后台进程。可通过 Docker客户端与之通信,用来监听Docker API的请求和管理Docker对象。
  • Client( Docker客户端):Docker客户端是 Docker的用户界面,它可以接受用户命令和配置标识,并与 Docker daemon通信。图中, docker build等都是 Docker的相关命令。
  • Images( Docker镜像):Docker镜像是一个只读模板,它包含创建 Docker容器的说明。它和系统安装光盘有点像,使用系统安装光盘可以安装系统,同理,使用Docker镜像可以运行 Docker镜像中的程序。
  • Container(容器):容器是镜像的可运行实例。镜像和容器的关系有点类似于面向对象中,类和对象的关系。可通过 Docker API或者 CLI命令来启停、移动、删除容器。
  • Registry:Docker Registry是一个集中存储与分发镜像的服务。构建完 Docker镜像后,就可在当前宿主机上运行。但如果想要在其他机器上运行这个镜像,就需要手动复制。此时可借助Docker Registry来避免镜像的手动复制。

Docker 存储驱动

原理:

  • 定时复制

表示只是在需要写时才去复制,这个是针对已有文件的修改场景。

比如基于一个image启动多个Container,如果每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享一个image,所做的写操作都是对从image中复制到自己的文件系统的副本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个副本,每个容器修改的都是自己的副本,互相隔离,互不影响。使用CoW可以有效的提高磁盘的利用率。

  • 用时分配

用于在原本没有这个文件时的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会因为这个容器分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。

 

支持五种存储驱动

  • AUFS 早期使用

AUFS是一个能透明覆盖一或多个现有文件系统的层状文件系统。 支持将不同目录挂载到同一个虚拟文件系统下,可以把不同的目录联合在一起,组成一个单一的目录。它一种虚拟的文件系统,文件系统不用格式化,直接挂载即可

  • Btrfs
  • Devicemapper
  • OverlayFs 目前18.0版本以上默认存储驱动

从kernel3.18以后被整合到Linux内核中. 也叫叠加文件系统。目前集成是的overlay2

  • ZFS

 

Docker 数据共享与持久化

目前在Docker容器中管理数据有两种方式:

  • 数据卷 Data Volumes

由docker自身维护,用户需要在/etc/docker/daemon.json中指定启用docker自动启动容器时,关联宿主机上由docker默认自动创建一个目录,并与容器中指定目录关联的方式。

如:

docker run -v /home/test:/usr/test--name dataVol ubuntu64 /bin/bash

1.先创建一个普通的容器。用--name给他指定了一个名dataVol。

2.再创建一个新的容器,来使用这个数据卷。

docker run -it --volumes-from dataVol ubuntu64 /bin/bash

--volumes-from用来指定要从哪个数据卷来挂载数据。

这样在新创建的容器里/usr/Downloads目录会和宿主机目录/home/dock/Downloads同步

 

  • 挂载主机目录 Bind Mounts

用户自定义指定docker中的某目录挂载到宿主机的某个指定目录

配置方式:

如 docker run -it -v /root/data:/data -name xxxx

 

查看容器在宿主机上生成的挂载目录

docker inspect xxx

{
    ...
    "Image": "sha256:aba3d1ce80d11fa3edaa8e8c343049493711e43211289d99a6cf33f4c116571f",
    "ResolvConfPath": "/var/lib/docker/containers/5d4939ab640e2b37285f13d0bc81080c925daa5a5599ae07392940f5cabb267a/resolv.conf",
    "HostnamePath": "/var/lib/docker/containers/5d4939ab640e2b37285f13d0bc81080c925daa5a5599ae07392940f5cabb267a/hostname",
    "HostsPath": "/var/lib/docker/containers/5d4939ab640e2b37285f13d0bc81080c925daa5a5599ae07392940f5cabb267a/hosts",
    "LogPath": "/var/lib/docker/containers/5d4939ab640e2b37285f13d0bc81080c925daa5a5599ae07392940f5cabb267a/5d4939ab640e2b37285f13d0bc81080c925daa5a5599ae07392940f5cabb267a-json.log",
    "Name": "/cp3-gateway-server",
    "RestartCount": 0,
    "Driver": "overlay2",
    "Platform": "linux",
    "MountLabel": "",
    "ProcessLabel": "",
    "AppArmorProfile": "",
    "ExecIDs": null,
    "HostConfig": {
        "Binds": [
            "/cp3-cloud/docker/data/projects/:/data/projects"
        ],
        "ContainerIDFile": "",
        "LogConfig": {
            "Type": "json-file",
            "Config": {}
        },
        "NetworkMode": "default",
        "PortBindings": {
            "8760/tcp": [
                {
                    "HostIp": "",
                    "HostPort": "8760"
                }
            ]
        },
        "RestartPolicy": {
            "Name": "always",
            "MaximumRetryCount": 0
        },
        ...
    "GraphDriver": {
        "Data": {
            "LowerDir": "/var/lib/docker/overlay2/350bd02a5e915c86ee44bcf5091699f1d16ee6d12c185cd09360c951a8c0153e-init/diff:/var/lib/docker/overlay2/346a9cb30d74151c67ea7309c3b7e84122e93b6d8aa5e9b65c1742d9ef6dc3f6/diff:/var/lib/docker/overlay2/957f96db109dc5f6f2609c079372681c0092a54f47a3ab17f951aa4ff1d248d7/diff:/var/lib/docker/overlay2/dbcc4cbbcaf3737f321f51e615e85e66dcb58452a4e9cd4d8fc60569a851c766/diff:/var/lib/docker/overlay2/614dd0022b44b800db3e49856ea0100c29fa66a914f8d2a9a1831efddf928612/diff:/var/lib/docker/overlay2/e76565738bd64a1d16cd5436b3b170b349ee50c19190522e1f940908093353a1/diff:/var/lib/docker/overlay2/5b9a30a7fef2ddc3ea6193f9ca6b4bb6823106e7c04fefac8142c278d78f2e44/diff",
            "MergedDir": "/var/lib/docker/overlay2/350bd02a5e915c86ee44bcf5091699f1d16ee6d12c185cd09360c951a8c0153e/merged",
            "UpperDir": "/var/lib/docker/overlay2/350bd02a5e915c86ee44bcf5091699f1d16ee6d12c185cd09360c951a8c0153e/diff",
            "WorkDir": "/var/lib/docker/overlay2/350bd02a5e915c86ee44bcf5091699f1d16ee6d12c185cd09360c951a8c0153e/work"
        },
        "Name": "overlay2"
    },
    "Mounts": [
        {
            "Type": "bind",
            "Source": "/cp3-cloud/docker/data/projects",
            "Destination": "/data/projects",
            "Mode": "",
            "RW": true,
            "Propagation": "rprivate"
        }
    ]
    ....
}

Docker 网络模式

配置方式:docker run -itd --net=host -name xxx

  • Birdge模式 (默认)

当Docker进程启动时,会在主机上创建一个名为Docker0的虚拟网桥,此主机上启动的Docker容器默认会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机相似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器内部网卡),另一端在放在主机中,以vethxxx这样类似的名称命名,并将这个网络设备加入到docker0网桥中。

  • Host模式

容器将不会获取一个独立的Network Namespace,而是与宿主机共用一个Network NameSpace。也就是说容器的网卡和ip都使用宿主机的

  • Container模式

这个模式指定新创建的容器和已经存在的容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器也不会自己创建网卡,IP等。而是和一个指定的容器共享IP、端口范围等。

  • None模式

Docker容器拥有自己的Network Namespace,并不为Docker容器进行任何网络配置,没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等

Docker 状态转化

Docker原理分析及Dockfile实践_第2张图片

制作基础镜像

1.安装Docker

2.编写Dockerfile

#1.指定基础镜像
FROM centos:7

#2.指明该镜像的作者和其电子邮件
MAINTAINER huhua "[email protected]"

#3.在构建镜像时,指定镜像的工作目录,之后的命令都是基于此工作目录,如果不存在,则会创建目录
WORKDIR /usr/local/jdk

#4.一个复制命令,把jdk安装文件复制到镜像中,语法:ADD ... ,注意:jdk*.tar.gz使用的是相对路径
ADD jdk-8u11-linux-x64.tar.gz /usr/local/jdk/

#5.设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
RUN echo 'Asia/Shanghai' >/etc/timezone

#6.配置环境变量
ENV JAVA_HOME=/usr/local/jdk/jdk1.8.0_11
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
ENV PATH=$JAVA_HOME/bin:$PATH

#7.设置语言
ENV LANG en_US.UTF-8 
ENV LANGUAGE en_US.UTF-8
ENV LC_ALL en_US.UTF-8

3.执行buil命令

docker build -t='centos7-java8-base' .

DockerHub

https://hub.docker.com/

DockerHub是由docker公司运行和管理的基于云的存储库。用户可以注册后,发布和使用自己的镜像。

一个 Docker Registry可包含多个 Docker仓库,每个仓库可包含多个镜像标签,每个标签对应一个 Docker镜像。与Maven的仓库类似,Docker Registry可分为公有Docker Registry和私有Docker Registry。 最常用的DockerRegistry莫过于官网的Docker Hub, 这也是默认的Docker Registry。 Docker Hub上存放着大量优秀的镜像, 我们可使用Docker命令下载并使用。

 

常用docker命令

  • docker -v 查看版本
  • docker ps 查看正在运行的容器
  • docker attach 登录一个已经在执行的容器
  • docker build 建立一个新的image
  • docker commit 提交一个新的image
  • docker cp 将容器中的文件拷贝到主机上
  • docker daemon docker运行可指定项详解
  • docker diff 较一个容器不同版本提交的文件差异
  • docker events 获取sever中的实时事件
  • docker export 导出一个容器
  • docker history 显示一个image的历史
  • docker images 列出image
  • docker import 导入已有的image
  • docker info 展示docker的信息
  • docker inspect 显示更底层的容器或image信息
  • docker kill 杀死docker进程
  • docker load 加载image
  • docker login 登录docker注册服务器
  • docker logs 获取容器的日志
  • docker pause 暂停容器中的所有进程
  • docker port 端口转发
  • docker pull 从远端拉取一个image
  • docker push 推送image到注册服务器
  • docker restart 重启一个容器或多个容器
  • docker rm 删除一个或多个容器
  • docker rmi 删除image
  • docker run 运行一个新的容器
  • docker save 打包image
  • docker search 搜索images
  • docker start 启动一个容器
  • docker stop 停止一个容器
  • docker tag 为image打标签
  • docker top 显示容器中的进程
  • docker unpause 取消暂停所有的进程
  • docker wait 阻塞容器运行

 

Docker与虚拟机区别

  • docker 比 虚拟机的抽象层更少,不需要 Hypervisor 实现硬件资源虚拟化,直接使用宿主机的硬件资源,资源利用率更高
  • docker 利用的是宿主机的内核,而不需要 Guest OS,当新建一个容器时,docker不需要加载操作系统内核,节省了这一部分加载的耗时操作,构建过程是秒级的,当新建一个虚拟机时,虚拟机软件需要加载 Guest OS,构建过程是分钟级别的。
  • docker 属于进程级别隔离,虚拟机属于操作系统级隔离;

特性

容器

虚拟机

隔离级别

操作系统级

进程级

隔离策略

Hypervisor

CGroups

系统资源

5~15%

0~5%

启动时间

分钟级

秒级

镜像存储

gb

kb-mb

集群规模

至多上百

可上万

高可用策略

支持备份 容灾 迁移

支持动态 弹性 负载 

你可能感兴趣的:(容器虚拟化,docker,容器)