目录
概况
用途
架构
原理
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是轻量级的虚拟化技术。
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等主要应用于以下三个系统调用:
Docker 容器运行起来是一个直接运行在宿主机上面的进程,那么如果限定每个容器最多消耗多少CPU资源呢?如果一个容器疯狂的消耗资源岂不是会影响同一宿主机上面其他的容器?所以Docker就需要一个限制容器能够使用资源上限的机制,那就是Linux Cgroup技术。Linux Cgroup 全称是Linux Control Group。它最主要的作用是限制一个进程组能够使用的资源上限,包括CPU,MEM,DISK,NET等等。当容器的内存使用量超过了Cgroup限定值会被系统OOM。
每个容器运行起来后都有一个独立的文件系统,例如Ubuntu镜像的容器能够看到Ubuntu的文件系统,Centos能够看到Centos的文件系统, 不是说容器是运行在宿主机上面的进程吗,为什么能够看到和宿主机不一样的文件系统呢?那就要归功于Union FS,全称是Union File System,联合文件系统。将多个不同位置的目录联合挂载到同一个目录,将相同的部分合并。Docker利用这种联合挂载能力,将容器镜像里面的多层内容呈现为统一的rootfs(根文件系统),即root用户能够看到的根目录底下所有的目录文件。rootfs打包了整个操作系统的文件和目录,是应用运行时所需要的最完整的“依赖库”,也就是我们说的“镜像”。
镜像分为基础镜像只读层,和Init层,和读写层。
Docker使用了C/S体系架构,Docker客户端与Docker守护进程通信,Docker守护进程负责构建,运行和分发Docker容器。Docker客户端和守护进程可以在同一个系统上运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程使用REST API通过UNIX套接字或网络接口进行通信。
原理:
表示只是在需要写时才去复制,这个是针对已有文件的修改场景。
比如基于一个image启动多个Container,如果每个Container都去分配一个image一样的文件系统,那么将会占用大量的磁盘空间。而CoW技术可以让所有的容器共享image的文件系统,所有数据都从image中读取,只有当要对文件进行写操作时,才从image里把要写的文件复制到自己的文件系统进行修改。所以无论有多少个容器共享一个image,所做的写操作都是对从image中复制到自己的文件系统的副本上进行,并不会修改image的源文件,且多个容器操作同一个文件,会在每个容器的文件系统里生成一个副本,每个容器修改的都是自己的副本,互相隔离,互不影响。使用CoW可以有效的提高磁盘的利用率。
用于在原本没有这个文件时的场景,只有在要新写入一个文件时才分配空间,这样可以提高存储资源的利用率。比如启动一个容器,并不会因为这个容器分配一些磁盘空间,而是当有新文件写入时,才按需分配新空间。
支持五种存储驱动
AUFS是一个能透明覆盖一或多个现有文件系统的层状文件系统。 支持将不同目录挂载到同一个虚拟文件系统下,可以把不同的目录联合在一起,组成一个单一的目录。它一种虚拟的文件系统,文件系统不用格式化,直接挂载即可
从kernel3.18以后被整合到Linux内核中. 也叫叠加文件系统。目前集成是的overlay2
目前在Docker容器中管理数据有两种方式:
由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同步
用户自定义指定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 run -itd --net=host -name xxx
当Docker进程启动时,会在主机上创建一个名为Docker0的虚拟网桥,此主机上启动的Docker容器默认会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机相似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器内部网卡),另一端在放在主机中,以vethxxx这样类似的名称命名,并将这个网络设备加入到docker0网桥中。
容器将不会获取一个独立的Network Namespace,而是与宿主机共用一个Network NameSpace。也就是说容器的网卡和ip都使用宿主机的
这个模式指定新创建的容器和已经存在的容器共享一个Network Namespace,而不是和宿主机共享。新创建的容器也不会自己创建网卡,IP等。而是和一个指定的容器共享IP、端口范围等。
Docker容器拥有自己的Network Namespace,并不为Docker容器进行任何网络配置,没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等
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' .
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命令下载并使用。
特性 |
容器 |
虚拟机 |
隔离级别 |
操作系统级 |
进程级 |
隔离策略 |
Hypervisor |
CGroups |
系统资源 |
5~15% |
0~5% |
启动时间 |
分钟级 |
秒级 |
镜像存储 |
gb |
kb-mb |
集群规模 |
至多上百 |
可上万 |
高可用策略 |
支持备份 容灾 迁移 |
支持动态 弹性 负载 |