Docker原理03

最后,咱们聊一下,Docker是如何实现虚拟化的。

1、先说一下Docker镜像
Docker多层文件系统
从图上可以看出,每一个镜像由一系列的层(layers)组成(Debian,Add Emacs,Add Apache,writable,但不包括内核,内核是与宿主机公用的)。

可如下复现:下载Debian镜像(200m),添加Emacs(20m)后,生成一个新的镜像,然后添加Apache(80m)后,生成了下一个新的镜像,然后运行时,挂在了一个可读写曾,供应用软件写数据。
如果不用分层式架构,那Debian镜像为200m,Emacs镜像为220m,Apache镜像为300m,你的硬盘一共需要720m。而分层后,各层只需要存储与原来不同的文件,所以结果为Debian镜像为200m,Emacs镜像为20m,Apache镜像为80m,你的硬盘一共需要300m。
分层的另外一个好处是,如果你希望新建一个Jetty(60m)镜像,同样可以从Debian镜像进行,这样相互之间就可以很好的复用已有镜像了。同样的,镜像升级的时候,也只需要更新自己所在的层,重新打包一个镜像,就可以升级完毕了。

那分层镜像架构,在运行时,是如何挂载到一起的呢?
答案是联合文件系统(UnionFS)。Union文件系统允许独立文件系统中的文件和文件夹(称之为分支)被透明覆盖,形成一个单独连贯的文件系统,所以可以方便的将这些层联合到一个镜像中。

2、再说一下容器是实现隔离的呢?
容器主要作用是隔离工作空间,虚拟机之间相互隔离,虚拟机与宿主机之间也相互隔离。当容器运行的时候,Docker就需要为该容器创建一个命名空间集合,每一个应用在它们自己的命名空间中运行而且不会访问到命名空间之外。
现在常用的容器有:Linux的LXC,BSD的Jails,Solaris的Zone等。

Docker使用到的命名空间有:
pid命名空间: 使用在进程隔离(PID: Process ID)。
net命名空间: 使用在管理网络接口(NET: Networking)。
ipc命名空间: 使用在管理进程间通信资源 (IPC: InterProcess Communication)。
mnt命名空间: 使用在管理挂载点 (MNT: Mount)。
uts命名空间: 使用在隔离内核和版本标识 (UTS: Unix Timesharing System)。

3、容器是如何管理硬件资源的呢?
答案是群组控制。
群组控制允许Docker分享或者限制容器使用硬件资源。
Docker使用了cgroups技术来管理群组。

Docker原理02

然后,咱们聊一下,Docker是如何运行的。

Docker整体架构如下(假设你比较熟悉VMWare或VirtualBox):
Docker Architecture
Docker Client:与Docker Deamon交互,告诉Docker Deamon要做什么,可以理解为一个远程执行Docker相关各种指令的工具
Docker Host:Docker Deamon的运行环境,就是宿主机
Docker Deamon:Docker服务,管理容器的创建,运行,停止等,是核心服务
Docker Images:Docker镜像,可以先理解为存放GuestOS所需二进制文件的只读光盘(这个不准确的,其实有分层结构),比如你可以把Ubuntu的可运行环境,经过定制后,做成一个镜像(不需要内核,不需要自己重头开始建立)
Docker Containers:Docker容器,通过某个镜像来创建,可以理解为一个虚拟机的实例
Docker Registry:Docker仓库,用来存放大家做好的镜像文件,可以方便的查询和下载

那当你运行下面指令时,究竟发生了什么呢?

# 利用基础镜像为ubuntu创建一个容器,采用交互模式运行(-it),并在容器中执行命令/bin/bash,
docker run -it ubuntu /bin/bash

1、查找并获取镜像文件:Docker检查本地是否有ubuntu镜像,如果本地没有该镜像,Docker会从Docker Hub下载。
2、创建容器:如果镜像已经存在或镜像下载后,Docker会使用它来创建新的容器。
3、分配文件系统并且挂载一个可读写的层。
4、分配网络/桥接接口: 创建一个允许容器与本地主机通信的网络接口。
5、设置一个IP地址: 从池中寻找一个可用的IP地址并且服加到容器上。
6、运行你指定的程序:按上面的命令,应该为/bin/bash
7、捕获并且提供应用输出: 连接并且记录标准输出、输入和错误让你可以看到你的程序是如何运行的。

那大家看下来,步骤1、6、7没有什么难理解的,但2、3、4、5究竟在做什么呢?

Docker原理01

首先聊一下虚拟化技术。

虚拟化离我们很近,平时我们接触的虚拟化技术种类很多,比如硬件虚拟化(超线程技术),虚拟设备(虚拟光驱、虚拟软件、WinMount)、虚拟网络(VPN),桌面虚拟化(虚拟桌面、远程桌面),虚拟内存(利用交换文件或交换分区扩展系统可用内存),存储虚拟化(硬盘分区,网络硬盘映射),各类游戏机模拟器等。有些技术用的是如此普遍,你并不一定觉得它应该归类到虚拟化技术之中。但是,一旦提到虚拟化技术,你一定会想到其中一个,那就是虚拟机。

虚拟机技术按实现方式,分为纯硬件虚拟化、纯软件虚拟化及基于硬件辅助的软件虚拟化。其中纯硬件虚拟化,一般在大型机上实现的比较多,操作系统比较单一(其实支持该硬件架构的操作系统就可以,但多数情况下同一型号大型机操作系统的确比较单一),硬件架构复杂。纯软件虚拟化,其实现技术比较复杂,一般通过hypervisor提供硬件虚拟层,支持多种操作系统。时至今日,很多设备都提供了硬件辅助虚拟化的功能,这大大降低了虚拟机管理软件的实现难度,并增强了虚拟机的执行效率,所以现在一般的虚拟化软件都支持基于硬件辅助的软件虚拟化。

虚拟机技术按虚拟化程度分为三种,第一种是完全虚拟化,第二种准虚拟化,第三种是操作系统级层虚拟化。其中,
完全虚拟化,直接用软件/硬件辅助方式,不修改Guest,模拟虚拟机的全部硬件的技术,一般支持多种操作系统,但效率一般不高;
准虚拟化,直接用软件/硬件辅助方式,并同时通过修改Guest,对其进行一定程度的“欺骗”,实现与hypervisor相配合,实现虚拟化的技术,一般支持多种操作系统,运行效率比较高;
操作系统层虚拟化,是利用操作系统特性,利用一个操作系统内核,模拟多台虚拟设备的方式,由于一般需要共享操作系统内核,一般只支持一类操作系统;

还有一类特殊的虚拟机软件,叫跨平台虚拟化,允许针对特定CPU或者操作系统的软件,不做修改就能运行在其他平台上。如Wine(在Linux上模拟Windows应用),还有我们用的各类游戏模拟器(在Windows/Linux上模拟红白机FC、Projetc64、PSP)等。

那我们回过头来看下Docker的虚拟化方式与普通虚拟化方式的区别:
A、Dcoker虚拟化
Dcoker虚拟化
B、VMware VirtualBox虚拟化
VMware VirtualBox虚拟化

比较下来就很清楚了:

项目 Docker VMware VirtualBox
虚拟化技术 纯软件虚拟化 纯软件虚拟化+基于硬件辅助的软件虚拟化
虚拟化程度 操作系统级层虚拟化 完全虚拟化+准虚拟化
硬件抽象层 不需要 hypervisor
运行效率 安装插件前,效率较低;安装插件后,效率较高
支持系统 Linxu各发行版 硬件架构支持即可安装
需要安装Guest系统 共享内核,应用软件需要安装 完全安装

Docker建立自己的image

1、首先到dockerhub注册自己的账号
dockerhub

2、新建一个repository名字为justatest

3、取回debian6的镜像

docker pull debian:6

4、新建~/Docker/justatest/Dockerfile

From debian:6
RUN apt-get -y update && apt-get install -y fortunes
CMD /usr/games/fortune -a

5、创建并上传你的image

#创建image
docker build -t justatest .
#运行image
docker run justatest
#查看你的image id
docker images
#进行标记
docker tag image-id neohope/justatest:latest
#登录
docker login
#上传
docker push neohope/justatest
#下载
docker pull neohope/justatest
#运行
docker run neohope/justatest

安装Docker

按官方说法,Docker客户端现在可以安装到Linxu、Windows和MacOS上。但其实,在Windows和MacOS上,都需要安装一个工具叫做Docker Toolbox。该工具的作用是,帮你安装VirtualBox,创建虚拟机,并用Boot2Docker进行启动。

说实话,该工具做的还不是很完善,而且做了太多的假设,我并不喜欢。比如虚拟机路径必须在~/.docker/machine下面。比如会强制帮你安装网卡。比如docker-machine获取虚拟机的IP时,默认虚拟机第二块网卡设置为Host-Only,并通过VBoxManage获取虚拟机第二块网卡IP地址(源码中写死的)。不推荐大家使用。如果一定要用的话,大家还是不要用docker-machine,只需要docker和Git就够了。

说这么多,就是不想大家花费太多时间,用不完善的工具,来体验Docker的强大 。所以建议大家还是直接使用Linux,或者在虚拟机里自己安装Linux会好一些。我喜欢Debian,但如果你不太熟,建议用Ubuntu。

1、安装Linux,并保证可以联网

2、安装Docker

#从网址取回文件,输出到标准输出,并传递给sh执行
wget -qO- https://get.docker.com/ | sh

3、测试安装是否成功

#docker从repository取回hello-world:latest的镜像,并运行
docker run hello-world

#docker从repository取回debian:latest的镜像,并运行bash命令
docker run -it debian bash

4、docker常用命令

#查看本地有哪些镜像
docker images

#查找debian镜像
docker search debian

#取回debian6的镜像
docker pull debian:6

#按image-id删除镜像
docker rmi image-id

#查看当前运行的容器
docker ps

#kill一个容器
docker kill contianer-id

#删掉一个容器 
docker rm contianer-id

#杀掉所有容器
docker kill $(docker ps -a -q)

#删除所有容器
docker rm $(docker ps -a -q)

PS:
boot2docker的默认用户为docker,密码为tcuser

Docker开启Remote API

远程执行Docker命令,基本有两种方式,一种是SSH到宿主机上,相当于在宿主机本地执行。一种是利用Docker的Remote API,打开2375端口,直接远程执行。本文说的是第二种方式,发行版Debian8。

1、临时方案:在宿主机上直接执行

#旧版本
docker -H 0.0.0.0:2375 -d &
#新版本
docker daemon -H 0.0.0.0:2375 &

2、永久方式
2.1编辑/etc/systemd/system/docker-tcp.socket

[Unit]
Description=Docker Socket for the API

[Socket]
ListenStream=2375
BindIPv6Only=both
Service=docker.service

[Install]
WantedBy=sockets.target

2.2执行

systemctl enable docker-tcp.socket
systemctl stop docker
systemctl start docker-tcp.socket
systemctl start docker

3、测试

#本地
docker -H tcp://127.0.0.1:2375 ps
#远程
docker -H tcp://HOST_IP:2375 ps

Docker常用命令

1、镜像相关的命令

#从docker hub查询镜像
sudo docker search xxx

#从docker hub拉取镜像
sudo docker pull xxx

#列出本地镜像
sudo docker images

#删除本地镜像
sudo docker rmi xxx

#登陆登出registry
sudo docker login
sudo docker logout

#从docker file创建镜像
sudo docker build

#从contianer创建镜像
sudo docker commit

#标记镜像
sudo docker tag

#镜像发送到registry
sudo docker push

2、contianer相关命令

#创建但不运行contianer
sudo docker create xxx

#创建并运行contianer
sudo docker run xxx

#运行contianer
sudo docker start xxx

#停止contianer
sudo docker stop xxx

#杀死contianer
sudo docker kill xxx

#查看正在运行的本地contianer列表
sudo docker ps

#查看全部本地contianer列表
sudo docker ps -a

#查看contianer详情
sudo docker inspect xxx

#查看contianer日志
sudo docker logs xxx

#查看contianer端口
sudo docker port xxx

#查看contianer进程
sudo docker top xxx

#删除contianer
sudo docker rm xxx

3、宿主机操与虚拟机互操作

#附加到contianer,没有反应,可以按向上键
sudo docker attach xxx
#退出
#Ctrl+D
#detach
#Ctrl+P Ctrl+Q

#容器与宿主机之间拷贝文件
sudo docker cp xxx:/yyy /zzz

#在宿主机执行容器中的命令
sudo docker exec xxx yyy

#查看docker信息
sudo docker info

4、网络

#查看网络
sudo docker network ls

#创建网络
sudo docker network create xxx