Docker虚拟化

 一、虚拟化简介
1、虚拟化概述
       虚拟化是一种资源管理技术,能够把物理资源转变为逻辑上可以管理的资源,如服务器、网络、内存及存储资源,虚拟化可以打破物理结构内的壁垒,计算元件运行在虚拟的基础上而非真实的基础上,可以扩大硬件的容量,简化软件的重新配置过程,从而让用户可以用比原本的组太更好的方式来应用和管理这些资源。
       虚拟化技术允许一个平台同时运行多个操作系统,并且应用程序可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率,它是一个为了简化管理、优化资源的解决方案。
       目前企业主流的虚拟化技术包括:KVM、Xen、VMware Esxi、VirtualBox、Docker,虚拟化技术越来越广泛的应用到互联网企业。
2、虚拟化原理
       虚拟化解决方案的底部是要进行虚拟化的物理机器,该物理机器可以直接支持虚拟化,或间接支持虚拟化,那么就需要虚拟机管理程序的支持。虚拟机管理程序(virtual machine monitor,VMM),可以看作是平台硬件和操作系统之间的抽象化或者中间件。
       VMM为每个虚拟机分配一套数据结构来管理它们的状态,包括虚拟处理器的全套寄存器、物理内存的使用情况、网络设备状态、虚拟设备状态等。
       VMM可以对底层(HostOS)硬件资源(物理CPU、内存、磁盘、网卡、显卡等)进行封装、隔离,抽象为另一种形式的逻辑资源,再提供给上层(GuestOS)虚拟机使用,通过虚拟化技术实现的虚拟机被称为GuestOS,而作为GuestOS载体的物理主机称为HostOS(宿主)。
3、虚拟化技术实现的区别
 • 完全虚拟化技术,实际上是通过软件实现对操作系统的资源再分配,比较成熟,如KVM、VirtualBox等;
 • 半虚拟化技术,则是通过代码修改已有的系统,形成一种新的可虚拟化的系统,调用硬件资源去安装多个系统,整体速度上相对高一点。代表产品有Xen;
 • 轻量级虚拟化,介于完全虚拟化和半虚拟化之间,典型代表有Docker。
 
二、Docker 虚拟化简介
1、概述
       Docker 是一个开源的应用窗口引擎,开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux 机器上,进而实现虚拟化。容器是完全使用沙箱机制的,而且相互之间不会有任何接口,几乎没有性能开销,可以很容易地在机器和数据中心中运行,最重要的是,它们不依赖于任何语言、框架或包括系统。
       Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案,Docker 的基础是Linux 容器(Linux container,LXC)等技术,Docker 在LXC技术的基础上进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便,用户操作Dockeer 的容器就像操作一个快速轻量级的虚拟机一样简单。
       Docker 虚拟化和传统虚拟化(KVM、Xen等)方式的不同之处在于Docker 虚拟化可以在操作系统层面上直接实现App或者应用虚拟化,即直接在HostOS 上基于VMM启动各种App。直接复用本地主机的操作系统,而传统方式则在硬件的基础上,虚拟GuestOS操作系统,然后在GuestOS 操作系统,然后在GuestOS 操作系统上部署相关的App应用。
## Docker 虚拟化实施有以下三个概念:
 • Docker 镜像,Docker 镜像是一个静态模板,与常见的ISO镜像类似,是一个样板,不能直接修改,可以通过封装生成;
 • Docker 容器,基于Docker 镜像运行启动的应用或系统,称之为一个Docker 容器或者Docker 虚拟机;
 • Docker 仓库,Docker 仓库是存放Docker 镜像的地方,常见分为公开仓库(public)和私有仓库(private)两种形式。
2、Docker LXC 之 Cgroup 资源控制
       cgroups(control groups)是Linux内核提供的一种机制,这种机制可以根据特定的行为,把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源管理提供一个统一的框架。通俗的来说,cgroups可以限制、记录、隔离进程组所使用的物理资源(包括:CPU、memory、IO等),为容器实现虚拟化提供了基本保证,是构建Docker等一系列虚拟化管理工具的基石。
       实现cgroups的主要目的是为不同用户层面的资源管理,提供一个统一化的接口。从单个进程的资源控制到操作系统层面的虚拟化。
## Cgroups提供了以下四大功能:
 • 资源限制(Resource Limitation):cgroups可以对进程组使用的资源总额进行限制。如设定应用运行时使用内存的上限,一旦超过这个配额就发出OOM(Out of Memory)。
 • 优先级分配(Prioritization):通过分配的CPU时间片数量及硬盘IO带宽大小,实际上就相当于控制了进程运行的优先级。
 • 资源统计(Accounting): cgroups可以统计系统的资源使用量,如CPU使用时长、内存用量等等,这个功能非常适用于计费。
 • 进程控制(Control):cgroups可以对进程组执行挂起、恢复等操作。
3、Docker LXC 之 Namespace 访问隔离
       Namespace又称为命名空间,它主要做访问隔离。其原理是针对一类资源进行抽象,并将其封装在一起提供给一个容器使用,对于这类资源,因为每个容器都有自己的抽象,而他们彼此之间是不可见的,所以就可以做到访问隔离。
## Linux提供如下Namespace:
Namespace           Constant                          Isolates
 • Cgroup              CLONE_NEWCGROUP           Cgroup root directory
 • IPC                     CLONE_NEWIPC              System V IPC, POSIX message queues
 • Network             CLONE_NEWNET              Network devices, stacks, ports, etc.
 • Mount               CLONE_NEWNS               Mount points
 • PID                   CLONE_NEWPID              Process IDs
 • User                  CLONE_NEWUSER             User and group IDs
 • UTS                   CLONE_NEWUTS              Hostname and NIS domain name
以上Namespace分别对进程的 Cgroup root、进程间通信、网络、文件系统挂载点、进程ID、用户和组、主机名域名等进行隔离。
## 创建容器(进程)主要用到三个系统调用:
 • clone() – 实现线程的系统调用,用来创建一个新的进程,并可以通过上述参数达到隔离
 • unshare() – 使某进程脱离某个namespace
 • setns() – 把某进程加入到某个namespace
4、Docker LXC 之 Chroot 文件隔离
      Chroot 全称是change to root : 其中root 是根目录的意思,也就是改变(linux 根目录是/,也可以理解为设置)一个程序运行时参考的根目录的位置。
## 根目录的参考
linux 系统(原始的方案)  | 引入chroot 机制
/                                 /lxc
/usr                            /lxc/usr
/bin                            /lxc/bin
/sys                            /lxc/sys
如上我们一旦使用了chroot ,用户的中心就不是linux 系统的根目录,而是我们指定的/lxc (这个目录可以任意指定),所以chroot 确实可以修改根目录。
## chroot 机制的意义:
 • 增强系统的安全行
 • 指定程序访问的根目录,防止用攻击者可以通过程序的漏洞获取其他目录的读写权限;比如/etc/passwd 比如/ 下所有的权限
## chroot 机制在虚拟化中的作用:
chroot 机制因为安全问题才被引入的,但是在LXC 中却启动了举足轻重的作用,因为chroot 机制可以指定虚拟根目录,让不同的容器在不同的根目录下工作。
 • 不同的容器进程参考的根目录不同,相互直接不影响
 • 不同的容器因为共享linux 底层的文件系统,所以容器集成os的功能,实现轻量级!
 
三、Docker 虚拟化特点
## Docker 虚拟化跟传统虚拟化相比,有发下优点:
 • 操作启动快,运行时的性能可以获取极大提升,管理操作(启动、停止、开始、重启等)都是以秒或毫秒为单位的;
 • 轻量级虚拟化,用户会拥有足够的“操作系统”,仅需添加或减少镜像即可,单台服务器上可以部署100~1000个containers 容器,而传统虚拟化能虚拟10~20个虚拟机就非常不错了;
 • 开源免费,成本低,由现代Linux 内核支持并驱动;
 • 前景及云支持,正在越来越受欢迎,各大主流公司都在推动Docker 的快速发展,性能有很大的优势;
 • 更快速地交付和部署,Docker 在整个开发周期都可以完美的辅助用户实现快速交付;
 • 更快速地创建及迭代,Docker 能够快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的;
 • 高效的部署和扩容,Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等;
 • 更简单的管理,使用Docker,只需要小小的修改,就可以替代以往大量的更新工作,所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。
 
四、Docker 虚拟化原理
       Docker 虚拟化中啊核心的部分分为Docker 引擎,Docker 引擎是一个C/S(client/server)结构的应用。
       Docker server 是一个常驻进程,rest API实现了client 和server 间的交互协议,CLI 实现容器和镜像的管理,为用户提供统一的操作界面。Docker 使用C/S架构,client 通过接口与server 进程通信实现容器的构建、运行和发布,client和server可以运行在同一台集群,也可以通过跨主机实现远程通信。
       完整的Docker 镜像可以支撑一个Docker 容器的运行,在Dock er 容器运行过程中主要提供文件系统数据支撑。Docker 镜像作为Docker 中最基本的概念,有以下特性:
 • 镜像分层,每个镜像都由一个或多个镜像层组成;
 • 可通过在某个镜像上加上一定的镜像层得到新镜像(此过程可通过编写DockerFile或基于容器commit实现);
 • 每个镜像层拥有唯一镜像ID;
 • 镜像在存储和使用时共享相同的镜像层(根据ID),所以在pull镜像时,已有的镜像层会自动跳过下载;
 • 每个镜像层都是只读的,即使启动成容器,也无法对其真正的修改,修改只会作用于最上层的容器层。
       Docker 容器,可以理解为一个或多个运行进程,而这些运行进程将占有相应的内存、相应的CPU计算资源、相应的虚拟网络设备以及相应的文件系统资源。而Docker 容器所占用的文件系统资源,则通过Docker 镜像的镜像层文件来提供。
       基于每个镜像的json文件,Docker 可以通过解析Docker 镜像的json文件,获知应该在这这个镜像之上运行什么样的进程,应该为进程配置怎样的环境变量,Docker 守护进程实现了静态向动态的转变。
 
五、Docker 安装配置
     CentOS 6.X系统安装Docker 软件,首先要关闭SELinux,然后需要安装相应的epel源,安装代码如下:
# sed -i '/SELINUX/s/enforcing/disable/g' /etc/selinux/config
# setenfoce 0
# wget http://ftp.riken.jp/Linux/fedora/epel/6/x86_64/epel-release-6-8.noarch.rpm
# rpm -ivh epel-release-6-8.noarch.rpm
# yum install lxc libcgroup device-mapper-event-libs
# yum install docker -io
# yum install device-mapper* -y
Docker 安装完毕后,启动docker 进程/etc/init.d/docker start,并且查看docker 进程:# ps -ef|grep docker
     CentOS 7.X系统安装Docker 软件,首先要关闭SELinux,然后需要安装相应的epel源,安装代码如下:
# sed -i '/SELINUX/s/enforcing/disable/g' /etc/selinux/config
# setenfoce 0
 • 卸载旧版本
较旧版本的Docker被称为docker或docker-engine。如果已安装这些,请卸载它们以及相关的依赖项。
# yum remove docker docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-selinux \
                  docker-engine-selinux \
                  docker-engine
 • 设置官方存储库安装
# yum install -y yum-utils device-mapper-persistent-data lvm2
# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
 • 启用边缘和测试存储库(默认是禁用的)
# yum-config-manager --enable docker-ce-edge
# yum-config-manager --enable docker-ce-test
# yum-config-manager --disable docker-ce-edge     #使用disable禁用
 • 安装DOCKER CE 社区版(CE)
# yum install docker-ce
 • 列出仓库中可用的版本
# yum list docker-ce --showduplicates | sort -r
docker-ce.x86_64            18.03.1.ce-1.el7.centos             docker-ce-stable
docker-ce.x86_64            18.03.0.ce-1.el7.centos             docker-ce-stable
docker-ce.x86_64            17.12.1.ce-1.el7.centos             docker-ce-stable
docker-ce.x86_64            17.12.0.ce-1.el7.centos             docker-ce-stable
docker-ce.x86_64            17.09.1.ce-1.el7.centos             docker-ce-stable
docker-ce.x86_64            17.09.0.ce-1.el7.centos             docker-ce-stable
 • 安装特定的版本example: docker-ce-18.03.1.ce
# yum install docker-ce-<VERSION STRING>
 • 启动并测试
# systemctl start docker
# docker run hello-world
 • 升级DOCKER CE
要升级Docker CE,请按照仓库版本列表选择要安装的新版本。
 • 从包安装
如果无法使用Docker的存储库来安装Docker,则可以下载.rpm适用于您的发行版的 文件并手动安装。每次要升级Docker时都需要下载新文件。
转到 https://download.docker.com/linux/centos/7/x86_64/stable/Packages/ 并下载.rpm要安装的Docker版本的文件。
注意:要安装边缘 包,stable请将上述URL中的单词更改 为edge。
# yum install docker-ce-18.03.1.ce-1.el7.centos.x86_64.rpm
 • 使用脚本安装
# curl -fsSL https://get.docker.com -o get-docker.sh
# /bin/sh get-docker.sh
 
六、Docker 必备命令
     对Docker 技术的深入学习,需要构建Docker 基础环境,熟练使用Docker 各种语法命令,要模拟Docker 虚拟化环境,需下载Docker 镜像,通过命令在宿主机服务器上直接下载Docker 公共仓库的镜像,具体步骤如下:
     公共仓库Nginx 和CentOS 镜像下载以及本地导入CentOS 镜像,执行如下命令:
# docker pull nginx                #Docker 下载Nginx镜像
# docker pull centos                #Docker 下载CentOS镜像
# cat centos68.tar |docker import - centos        #本地导入CentOS镜像
     对Docker 的管理除了可以下载镜像、导入镜像之外,还要掌握如下命令:
 • docker version                #查看Docker 版本
 • docker search CentOS                #搜索可用的Docker 镜像
 • docker images                #查看当前Docker 所有镜像
 • docker pull CentOS                #下载CentOS镜像
 • cat xxx|docker import - newname         #本地导入Docker 镜像
 • docker export container_id >cenos6.tar                #Docker 导出镜像
 • docker run CentOS echo "hello world"                #在Docker 容器中运行hello world
 • docker run CentOS yum install ntpdate                #在容器中安装ntpdate的程序
 • docker ps -l                        #获得最后一个容器的ID
 • docker ps -a                         #查看所有的容器
 • docker commit 87e2313132 CentOS:v1                #提交刚修改的容器
 • docker run -i -t -d CentOS /bin/bash                #启动Docker 镜像,-d 表示后台启动,-t 表示打开终端,-i 表示交互输入
 • docker stop id                 #关闭Docker 容器
 • docker start id                #启动Docker 容器
 • docker rm id                        #删除Docker 容器
 • docker rmi images                #删除Docker 镜像
 • docker run -d -p 80:80 -p 8022:22 CentOS:v2        #-p 表示指定Docker 容器端口映射,前面是宿主主机本地端口,后面是Docker 窗口中端口。
 • docker exec -it docker_id /bin/bash                #进入Docker 容器shell终端
 • docker exec docker_id df -h                        #查看Docker 容器内部磁盘分区
 
七、Docker 网络详解
1、基于Docker run 创建Docker 容器时,可以使用--net 选项指定容器的网络模式,Docker 默认有以下4种模式:
 • host 模式,使用--net=host 指定;
 • container 模式,使用--net=container:NAME_OR_ID 指定;
 • none 模式,使用--net=none 指定;
 • bridge 模式,使用--net=bridge 指定,默认设置
2、Docker 4 种网络模式详解如下:
 • host 模式详解:
基于host模式,容器将不会获得一个独立的network namespace,而是与宿主机共用一个network namespace,容器将不会虚拟出自己的网卡、配置自己的IP等,而是使用宿主机的IP和端口。
 • container 模式详解:
理解host 模式后,container 模式也非常好理解,container 模式指定新创建的容器和已经存在的一个容器共享一个network namespace,而不是和宿主机共享共享。即新创建的容器不会创建自己的网卡、配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。
 • none 模式详解:
Docker 容器拥有自己的network namespace,但是并不为Docker 容器进行任何网络配置。该Docker 容器没有网卡、IP、路由等信息,需要手工为Docker 容器添加网卡、配置IP等,典型pipework 工具为Docker 容器指定IP等信息。
 • bridge 桥接模式详解:
bridge 模式是Docker 默认的网络模式,该模式会为每一个容器分配network namespace、设置IP、路由等配置,默认会将Docker 容器连接到一个虚拟网桥交换机docker0上。
3、默认使用Docker 创建Docker 容器网络为bridge 模式,以下为创建Docker bridge创建过程:
 • 启动Docker 容器,首先会在Docker 宿主机上创建一对虚拟网卡 veth pair 设备,veth 设备总是成对出现的,组成了一条数据通道,数据从一端设备进入,就会从另一端设备出来,veth 设备常用来连接两个网络设备;
 • Docker 将veth pair 设备的一端放在新创建的容器中。并命名为eth0,然后将另一端放在宿主机中,以vethxxx 这样类似的名字命名,并将这个网络设备加入到docker0网桥中;
 • 从docker0 子网中分配一个IP给容器使用,并设置docker0 IP地址为窗口默认网关;
 • 此时,容器IP与宿主机能够通信,宿主机也可访问容器中的IP地址,在bridge 模式下,连在同一网桥上的容器之间可以相互通信,同时容器也可以访问外网,但是其他宿主机不能访问Docker 容器IP,需要通过NAT 将容器IP的port 映射为宿主机的IP和port,方可使用。
 
八、Docker 桥接模式
     Docker 容器默认使用docker0桥接网络,IP地址会自动分配,每个容器都是连接到docker0网桥上的。如果想让容器与宿主机同一网段的其他宿主机之间能访问,须在启动Docker 的时候将Docker 容器的某个端口映射到该宿主机的端口,其他宿主机连接Docker 宿主机的IP和port 即可。
     在生产环境中可以自定义Docker 桥接网卡,好处是可以设置Docker 容器的IP与宿主机同网段,无须NAT映射端口访问,更加方便、快捷,同时也可以基于pipework脚本为Docker 容器指定静态IP地址,以下为Docker 自定义桥接网络的配置方法,执行代码如下:
# yum install bridge-utils                        #安装bridge相关库支持
# /etc/init.d/docker stop                        #停止Docker 服务
# ifconfig docker0 down                        #关掉docker0
# brctl delbr docker0                        #删除docker0
# brctl addbr br0                        #创建br0网桥
# ip link set dev br0 up                        #开户br0网桥
# ip addr add 192.168.1.6/24 dev br0        #为br0分配物理网络中的IP地址
# ip addr del 192.168.1.6/24 /dev ens0        #将宿主机网卡的IP清空
# brctl addif br0 eht0                        #将宿主机eth0网卡挂到br0上
# ip route del default                        #删除原路由
# ip route add default via 192.168.1.6 dev br0        #为br0设置路由
如果Docker 宿主机操作系统为CentOS 6.X,Docker 启用br0设置如下:
# vim /etc/sysconfig/docker
other_args="-b=br0"
上述配置方法比较烦琐,生产环境建议直接通过创建网桥br0配置文件实现桥接,在/etc/sysconfig/network-scripts/下,修改原ifcfg-eth0网卡配置,同时增加ifcfg-eth0桥接网卡配置,操作步骤如下:
1、vim ifcfg-eth0 内容修改如下:
DEVICE=eth0
BOOTPROTO=none
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
BRIDGE="br0"
IPADDR=192.168.1.6
NETMASK=255.255.255.0
GATEWAY=192.168.1.254
USERCTL=no
2、vim ifcfg-br0 内容修改如下:
DEVICE="br0"
BOOTPROTO=none
IPV6INIT=no
NM_CONTROLLED=no
ONBOOT=yes
TYPE="Bridge"
IPADDR=192.168.1.6
NETMASK=255.255.255.0
GATEWAY=192.168.1.254
USERCTL=no
3、Docker 桥接网卡配置完毕,直接重启network 服务即可。
# /etc/init.d/network restart
4、修改Docker 桥接网卡为br0。如果Docker 宿主机操作系统为CentOS 7.X,Docker 启用br0 设置如下,然后重启Docker 服务即可。
# vim /etc/sysconfig/docker-network
DOCKER_NETWORK_OPTIONS="-b=br0"
启动新的Docker 容器,使用命令docker attach容器ID或docker exec -it 容器ID /bin/bash 进入容器,会自动分配 192.168.1.x 网段的IP地址。
     通过配置br0桥接网卡,快速实现Docker 容器快速获取动态IP地址,生产环境服务器的IP均为静态IP,基于pipework工具为Docker 容器指定静态IP地址,以下为pipework工具配置Docker 容器静态IP地址的方法,通过pipework指定的静态IP,当容器重启之后,静态IP会丢失,所以启动容器之前需重新绑定该IP,也可以通过shell脚本自动配置IP,代码如下:
#安装pipework工具
git clone https://github.com/jpetazzo/pipework
cp ~/pipework/pipework /usr/local/bin/
docker run -itd --net=none --name=lamp2 CentOS 7 /bin/bash
#基于pipework 设置Docker 容器IP为192.168.1.11,网关为192.168.1.6,Docker 容器IP子网掩码为255.255.255.0
pipework br0 lamp2 192.168.1.11/24@192.168.1.6
查看Docker 容器IP地址,执行如下代码:
# docker exec lamp2 ifconfig
 
九、Docker 桥接模式
     DockFile 是一种能被Docker 程序解释的脚本,DockerFile 由多条指令组成,每条指令对应Linux 系统中不同的命令,基于DockerFile 可以自定义创建生产环境所需的Docker 镜像,通过镜像可以启动所需的Docker 容器。
     Docker 程序将这些DockerFile 指令翻译为真正的Linux 命令,DockerFile 有特定的书写格式和支持的命令,Docker 程序解决这些命令间的依赖关系,类似于Linux系统中编译软件所使用的MakeFile 文件。
     Docker 程序可以读取DockerFile 文件,根据指令生成定制的image,需要定制自己额外的需求时,只需在DockerFile 上添加或修改指令,重新生成image即可,省去了敲命令的麻烦,以下为DockerFile 镜像制作常用的命令详解:
FROM<image>:<tag>                FROM指令表示指定一个基本的镜像源,或从公共库拉取一个镜像源,DockerFile文件第一行必须指定FROM基础镜像源
MAINTAINER                        设置DockerFile 编写人或维护者的信息
LABEL<key>=<value>                设置标签、采用键值对的形式
RUN<command>                核心命令,表示运行的Linux 指令,每条RUN指令在当前基础镜像上执行,并且提交成为新的镜像
EXPOSE<port>[<port>]                用来指定Docker 容器中监听的端口,用于外界宿主机互联访问,启动Docker 时,可以通过-P,主机会自动分配一个端口号转发到指定的端口
ENV<key>=<value>                设置环境变量,执行RUN指令及Docker 启动时被引用
WORKDIR /path/to/workdir        设置工作目录,执行RUN、ADD、COPY、ENV指令时的基础路径
COPY<src><dest>和ADD<src><dest>        Linux 系统增加及复制文件,ADD在和COPY相同的基础上,ADD允许<src>是一个URL,同时ADD的<src>是一个压缩格式文档,<src>将会解压缩复制
CMD和ENTRYPOINT                配置Docker 容器启动后执行的命令,每个DockerFile 至少指定一个CMD命令或ENTRYPOINT,两者都可以指定shell或exec函数调用的方式执行命令,默认DockerFile run启动镜像之后便会退出容器,需要一个长时间运行的命令,使得容器一直执行
 • CMD和ENTRYPOINT的详解如下:
CMD ["executable","param1","param2"]                运行一个可执行的文件并提供参数
CMD ["param1","param2"]                        为ENTRYPOINT指定参数
CMD command param1 param2                        以/bin/sh -c 的方法执行的命令
ENTRYPOINT ["executable","param1","param2"]        首选执行形式
ENTRYPOINT command param1 param2                以/bin/sh -c 的方法执行的命令
 • CMD和ENTRYPOINT的区别如下:
每个 DockerFile 只能有一个CMD/ENTRYPOINT指令,超过一个CMD只有最后一个生效;
CMD在运行时会被Docker run command 指定命令覆盖,而ENTRYPOINT 不会被运行时Docker run command 覆盖;
DockeFile 中同时设置CMD和EINTRYPOINT,Docker 在build 过程中会将CMD中指定的内容作为ENTRYPOINT 的参数;
     如果Docker 启动需运行多个启动命令,彼此之间可以使用&&分开,最后一个命令必须为无限运行的命令,否则启动的容器将会被退出。
VOLUME [DIR]                设置本地挂载目录,用于存放数据库和需要保持的数据
USER daemon                指定Docker 运行时的用户名或UID,后续的RUN也会使用指定用户
ONBUILD [INSTRUCTION]        配置当前所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令
 
十、DockerFile 企事业案例
     (一)基于DockerFile 相关指令,可以在Docker 宿主机上编写DockerFile 文件,本案例为实现Docker 容器运行,并对外开启22端口,DockerFile 代码如下:
#设置基本的镜像,后续命令都以这个镜像为基础
FROM CentOS_lamp:v1
#作者信息
MAINTAINER TANG.COM
#RUN 命令会在上面指定的镜像里执行任何命令
RUN yum install passwd openssl openssh-server -y
RUN echo '123456'|passwd --stdin root
RUN sed -i '/^session\s\+required\s\+pam_loginuid.so/s/^/#/' /etc/pam.d/sshd
RUN mkdir -p /root/.ssh&&chown root.root /root&&chmod 700 /root/.ssh
RUN mkdir /var/run/sshd
#暴露ssh端口22
EXPOSE 22
#设定运行镜像时的默认命令并且打印Docker IP地址,以daemon 方式启动sshd
CMD ip addr ls eth0 |awk '{print $2}' |egrep -o '([0-9]+\.){3}[0-9]+';/usr/sbin/sshd -D
     (二)基于DockerFile 相关指令,可以在Docker 宿主机上编写DockerFile 文件,本案例为实现Docker 容器运行,并对外开启80端口,DockerFile 代码如下:
#设置基本的镜像,后续命令都以这个镜像为基础
FROM CentOS_lamp:v1
#作者信息
MAINTAINER TANG.COM
#RUN 命令会在上面指定的镜像里执行任何命令
RUN yum install pcre-devel -y
RUN yum install httpd httpd-devel -y
RUN echo "<h1>The Test Page TANG</h1>" >>/var/www/html/index.html
#暴露ssh端口22
EXPOSE 22
#启动httpd
CMD ["/usr/sbin/apachectl","-D","FOREGROUND"]
     (三)基于DockerFile 相关指令,可以在Docker 宿主机上编写DockerFile 文件,本案例为实现Docker 容器运行,并对外开户3306端口,DockerFile 代码如下:
FROM CentOS:v1
RUN groupadd -r mysql && useradd -r -g msyql mysql
RUN install -y gcc zlib-devel gd-devel
ENV MSYQL_MAJOR 5.6
ENV MSYQL_VERSION 5.6.20
RUN
        && curl -SL "http://dev.mysql.com/get/Downloads/MySQL-$MYSQL_MAJOR/mysql-$MYSQL_VERSION-linux-glibc2.5-x86_64.tar.gz" -o msyql.tar.gz\
        && curl -SL "http://mysql.he.net/Downloads/MySQL-$MYSQL_MAJOR/mysql-$MYSQL_VERSION-linux-glibc2.5-x86_64.tar.gz.asc" -o msyql.tar.gz.asc\
        && mkdir /usr/local/mysql \
        && tar -xzf msyql.tar.gz -C /usr/local/msyql \
        && rm mysql.tar.gz* \
ENV PATH $PATH:/usr/local/mysql/bin:/usr/local/mysql/scripts
WORKDIR /usr/local/mysql
VOLUME /var/lib/mysql
EXPOSE 3306
CMD ["mysqld","--datadir=/var/lib/mysql","--user=mysql"]
     (五)基于DockerFile 相关指令,可以在Docker 宿主机上编写DockerFile 文件,本案例为实现Docker 容器运行,并对外开启8080端口,DockerFile 代码如下:
FROM CentOS:v1
#设置DockerFile 运行工作目录
WORKDIR /tmp
#安装JAVA JDK
RUN wget --no-cookies --no-check-certificate --header "Cookie:gpw_e24=http%3a%2f%2fwww.oracle.com%2ftechnetwork%2fjava%2fjavase%2fdownloads%2fjdk7-downloads-1880260.html;oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u79-b15/jdk-7u79-linux-x64.tar.gz
RUN tar -zxf jdk-7u70-linux-x64.tar.gz
RUN mkdir -p /usr/java/
RUN mv jdk1.7.0_79 /usr/java/
#配置环境变量
ENV JAVA_HOME /usr/java/jdk1.7.0_79/
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH.:$JAVA_HOME/lib:$JRE_HOME/lib
ENV PATH $PATH:$JAVA_HOME/bin
#安装配置tomcat服务
RUN wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-7/v7.0.62/bin/apache-tomcat-7.0.62.tar.gz
RUN tar xvf apache-tomcat-7.0.62.tar.gz
RUN mv apache-tomcat-7.0.62 /usr/local/tomcat/
#配置tomcat 环境变量
ENV CATALINA_HOME /usr/local/tomcat/
EXPOSE 8080
#设置tomcat 自启动
CMD ["/usr/local/tomcat/bin/catalina.sh","run"]
 
十一、Docker 磁盘扩容
     device mapper是Linux2.6内核中提供的一种从逻辑设备到物理设备的映射框架机制,device mapper driver默认会创建一个100GB的存储文件,主要用于存储镜像和容器,每一个容器都被限制在10GB大小的卷内,也可以基于loopback 自动创建稀疏文件,具体为用/var/lib/docker/devicemapper/devicemapper下的data和metadata实现动态磁盘扩容,默认创建的100GB存储总空间和Docker 容器10GB是无法满足生产环境应用的,需要扩大Docker 总容量和Docker 容器的rootfs 根系统大小。
     Docker 服务在启动的时候可以配置device mapper 的启动参数,docker -d --storage-opt dm.foo=bar,常见参数如下:
dm.basesize                默认为10GB,限制容器和镜像的大小
dm.loopdatasize                存储池大小。默认为100GB
dm.datadev                存储池设备,/var/lib/docker/devicemapper/devicemapper/data
dm.loopmetadatasize        元数据大小,默认为2GB
dm.metadatasize        无数据设备,/var/lib/docker/devicemapper/devicemapper/metadata
dm.fs                        文件系统,置认为ext4
dm.blocksize blocksize        默认为64KB
dm.blkdiscard                默认为true
     将Docker 置信存储池从100GB扩大到2TB,存储池元数据从2GB扩大到10GB,执行命令如下:
rm -rf /var/lib/docker/devicemapper/devicemapper
mkdir -p /var/lib/docker/devicemapper/devicemapper
dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/data bs=1G count=0 seek=2000
dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/metadata bs=1G count=0 seek=10
     还可以通过配置文件直接添加以下代码实现将Docker 默认存储池从100GB扩大到2TB,存储池元数据从2GB扩大到10GB,修改配置文件/etc/sysconfig/docker-storage,加入如下代码:
DOCKER_STORAGE_OPTIONS="--storage-opt dm.loopdatasize=2000G --storage -opt dm.loopmetadatasize=10G --storage-opt dm.fs=ext4"
     上述配置完毕后,重启Docker 服务即可,新生成的Docker 容器磁盘大小即可生效,如果不在配置文件中指定,还可以基于以下命令直接启动,生产环境推荐修改配置文件,而不推荐命令行方式直接启动,执行命令如下:
docker -d --storage-opt dm.loopdatasize=2000G --storage-opt dm.loopmetadatasize=10G --storage-opt dm.fs=ext4
     以上方法只适用于新容器生成,并且修改后需要重启Docker ,无法做到动态地给正运行的容器指定大小,基于现有容器在线扩容,宿主机文件系统类型支持ext2、ext3、ext4,不支持XFS。
Docker 在线扩容方法:
 • 查看原容器的磁盘空间大小
# df -h
 • 查看Docker 存储device mapper 设备名称
# ls -l /dav/mapper/docker-*
 • 查看Docker mapper 卷信息表查看该设备所占用的多少扇区
# dmsetup table docker-******************************
 • 计算扩容大小
扩容大小是以扇区为单位的,例如10GB有扇区近 20971520个左右,装空间扩容为15GB,计算15GB的空间所需扇区的大小:
echo $((15*1024*1024*1024/512))
31457280
然后修改Dokcer 容器卷信息表、激活并且验证,使用echo 命令将新的扇区大小写入,
注意只是改变20971520 的数字为31457280 ,其他数字不变,通过命令dmsetup resume 将修改后的容器文件激活,通过命令dmsetup table 查看最新Docker 扇区信息。
# echo 0 31457280 thin 253:0 30 |dmsetup load docker-*****************************
# dmsetup resume docker-******************************
# dmsetup table docker-*******************************
 • 修改文件系统大小,命令为resize2fs
# resize2fs /dev/mapper/docker-******************************
 • 验证Docker rootfs 磁盘大小
# df -h
     通过上述步骤成功地将Docker 容器的10GB空间扩容为15GB,还可以将上述步骤写成shell脚本,基于脚本参数快速扩容。给Docker 磁盘扩容除了采用上述方法外,还可以使用挂载目录方法,基于-v参数,在启动Docker 容器时指定。
 
十二、Docker 构建私有仓库
     Docker 镜像默认存放在仓库中,Docker 仓库分为公共仓库和私有仓库,随着公司业务的发展,Docker 镜像的种类也非常繁多,为了统一管理,可以基于registry 搭建本地私有仓库。
1、使用Docker 私有仓库有以下优点:
 • 节省网络带宽,针对每个镜像不用去Docker 官网仓库下载;
 • Docker 镜像从本地私有仓库中下载;
 • 构建公司内部私有仓库,方便各部门使用,服务器管理更加统一;
 • 可以基于GIT或SVN、Jenkins更新本地Docker 私有仓库镜像版本。
2、使用Docker registry 构建本地私有仓库的方法及步骤:
 • 下载Docker registry 镜像
# docker pull registry
 • 启动私有仓库容器
# mkdir -p /data/registry/
# docker run -itd -p 5000:5000 -v /data/registry:/tmp/registry docker.io/registry
默认情况下,会将仓库存放于容器内的/tmp/registry目录下。这样如果容器被删除,则存放于容器中的镜像也会丢失,所以一般情况下会指定本地/data/registry 目录挂载到容器内的/tmp/registry下。
 • 上传镜像至本地私有仓库。客户端上传镜像至本地私有仓库,以busybox 镜像为例,将busybox上传至私有仓库服务器,命名如下:
# docker pull busybox
# docker tag busybox 192.168.1.123:5000/busybox
# docker push 192.168.1.123:5000/busybox
 • 检测本地私有仓库:
# curl -XGET http://192.168.1.123:5000/v2/_catalog
# curl -XGET http://192.168.1.123:5000/v2/busybox/tags/list
 • 客户端本地私有仓库。在客户端Docker 配置文件/etc/sysconfig/docker 中添加以下代码,同时重启Docker 服务,获取本地私有仓库。
OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false --insecure-registry 192.168.1.123:5000'
ADD_REGISTRY='--add-registry 192.168.1.123:5000'
     至此,Dokcer 本地私有仓库部署完毕,可以向仓库中添加、更新Docker 镜像,或查看、删除Docker 仓库相关的镜像,操作命令如下:
# curl -XGET http://192.168.1.123:5000/v2/_catalog
# curl -XGET http://192.168.1.123:5000/v2/image_name/tags/list
# curl -X DELETE http://192.168.1.123:5000/v1/repositories/镜像名称
#v2 版本,官网不建议删除私有仓库中的镜像,可以基于delete-docker-registry-image工具
#删除Dokcer 镜像
# curl https://raw.githubusercontent.com/burnettk/delete-docker-registry-image/master/delete_docker_registry_image.py|sudo tee /usr/local/bin/delete_docker_registry_image >/dev/null
# chmod a+x /usr/local/bin/delete_docker_registry_image
# export REGISTRY_DATA_DIR=/data/registry/v2
# delete_docker_registry_image --image centos:v1
 
十三、Docker 自动化部署(一)
     想批量应用于生产环境,需要编写能够实现自动安装并配置Docker 虚拟化及桥接网络的脚本,同时使用pipework 这个软件来配置容器IP,能够实现容器简单的管理,以下为CentOS 6.X Linux 系统一键安装、配置、管理Docker 的shell 脚本,脚本代码如下:
#!/bin/bash
#auto install docker and create VM
#By tang.com 2018
#Define PATH Varablies
IPADDR=`ifconfig|grep "Bcast"|awk '{print $2}'|cut -d: -f2|grep "192.168"|head -1`
GATEWAY=`route -n|grep "UG"|awk '{print $2}'|grep "192.168"|head -1`
DOCKER_IPADDR=$1
IPADDR_NET=`ifconfig|grep "Bcast"|awk '{print $2}'|cut -d: -f2|grep "192.168"|head -1|awk -F. '{print $1"."$2"."$3".""xxx"}'`
NETWORK=(
        HWADDR=`ifconfig eht0 |egrep "HWaddr|Bcast"|tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $1}'`
        IPADDR=`ifconfig eht0 |egrep "HWaddr|Bcast"|tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $2}'`
        NETMASK=`ifconfig eht0 |egrep "HWaddr|Bcast"|tr "\n" " "|awk '{print $5,$7,$NF}'|sed -e 's/addr://g' -e 's/Mask://g'|awk '{print $3}'`
        GATEWAY=`route -n|grep "UG"|awk '{print #2}'`
)
if [ -z "$1" -o -z "$2" -o -z "$3" -o -z "$4" ];then
        echo -e "\033[32m------------------------------------\033[0m"
        echo -e "\033[32mPlease exec $0 IPADDR CPU(C) MEM(G) DISK(G),example $0 $IPADDR_NET 16 32 50\033[0m"
        exit 0
fi
CPU=`expr $2 -1`
if [ ! -e /usr/bin/bc ];then
        yum install bc -y >>/dev/null 2>&1
fi
MEM_F=`echo $3 \*1024|bc`
MEM=`printf "%.0f\n" $MEM_F`
DISK=$4
USER=$5
REMARK=$6
ping $DOCKER_IPADDR -c 1 >>/dev/null 2>&1
if [ $? -eq 0 ];then
        echo -e "\033[32m-------------------\033[0m"
        echo -e "\033[32mThe IP address to be used,Please change other IP,exit.\033[0m"
        exit 0
fi
if [ ! -e /etc/init.d/docker ];then
        rmp -ivh http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
        yum install docker-io -y
        yum install device-mapper* -y
        /etc/init.d/docker start
        if [ $? -ne 0 ];then
                echo "Docker install error,please check."
                exit
        fi
fi
cd /etc/sysconfig/network-scripts/
mkdir -p /data/backup/`data +%Y%m%d-%H%M`
yes|cp ifcfg-eth* /data/backup/`data +%Y%m%d-%H%M`/
if [ -e /etc/sysconfig/network-scripts/ifcfg-br0 ];then
        echo
else
        cat>ifcfg-eth0<<EOF
        DEVICE=eth0
        BOOTPROTO=none
        ${NETWORK[0]}
        NM_CONTROLLED=no
        ONBOOT=yes
        TYPE=Ethernet
        BRIDGE="br0"
        ${NETWORK[1]}
        ${NETWORK[2]}
        ${NETWORK[3]}
        URERCTL=no
EOF
        cat>ifcfg-br0<<EOF
        DEVICE="br0"
        BOOTPROTO=none
        ${NETWORK[0]}
        IPV6INIT=no
        ONBOOT=yes
        TYPE="Bridge"
        ${NETWORK[1]}
        ${NETWORK[2]}
        ${NETWORK[3]}
        USERCTL=no
EOF
        /etc/init.d/network restart
fi
echo "Your can restart Ethernet Service:/etc/init.d/network restart !"
echo '---------------------------------------------------------------'
cd -
#######create docker container
service docker status >>/dev/null
if [ $? -ne 0 ];then
        /etc/init.d/docker restart
fi
NAME="Docker_`echo $DOCKER_IPADDR|awk -F"." '{print $(NF-1)"_"$NF}'`"
IMAGES=`docker images|grep -v "REPOSITORY"|grep -v "none"|head -1|awk '{print $1}'`
CID=$(docker run -itd --cpuset-cpus=0-$CPU -m ${MEM}m --net=none --name=$NAME $IMAGES /bin/bash)
if [ -z $IMAGES ];then
        echo "Please Download Docker CentOS Images,you can to be use docker search CentOS,and docker pull CentOS6.5-ssh,exit 0"
        exit 0
fi
if [ ! -f /usr/local/bin/pipework ];then
        you install wget unzip zip -y
        wget https://github.com/jpetazzo/pipework/archive/master.zip
        unzip master
        cp pipework-master/pipework /usr/local/bin/
        chmod +x /usr/local/bin/pipework
        rm -rf master
fi
ip netns >> /dev/null
if [ $? -ne 0 ];then
        rpm -e iproute --nodeps
        rpm -ivh https://repos.fedorapeople.org/openstack/EOL/openstack-grizzly/epel-6/iproute-2.6.32-120.el6ost.netns.2.x86_64.rpm
fi
pipework br0 $NAME $DOCKER_IPADDR/24@ $IPADDR
docker ps -a |grep "$NAME"
DEV=$(basename $(echo /dev/mapper/docker-*-$CID))
dmsetup table $DEV |sed "s/0 [0-9]* thin/0 $((${DISK}*1024*1024*1024/512)) thin/"|dmsetup load $DEV
dmsetup resume $DEV
resize2fs /dev/mapper/$DEV
docker start $CID
docker logs $CID
LIST="docker_vmlist.csv"
if [ ! -e $LIST ];then
        echo "编号,容器ID,容器名称,CPU,内存,硬盘,容器IP,宿主机IP,使用人中,备注">$LIST
fi
######################################
NUM=`cat docker_vmlist.csv|grep -v CPU|tail -1|awk -F, '{print $1}'`
if [[ $NUM -eq "" ]];then
        NUM="1"
else
        NUM=`expr $NUM + 1`
fi
######################################
echo -e "\033[32mCreate virtual client Successfully.\n$NUM `echo $CID|cut -b 1-12` $NAME $2C ${MEM}M ${DISK}G $DOCKER_IPADDR $IPADDR $USER $REMARK\033[0m"
if [ -z $USER ];then
        USER="NULL"
        REMARK="NULL"
fi
echo $NUM,`echo $CID|cut -b 1-12`,$NAME,${2}C,${MEM}M,${DISK}G,$DOCKER_IPADDR,$IPADDR,$USER,$REMARK>>$LIST
rm -rf docker_vmlist_*
iconv -c -f utf-8 -t gb2312 docker_vmlist.csv -o docker_vmlist_`date +%H%M`.csv
 
十四、Docker 自动化部署(二)
     目前越来越多的企业开始使用CentOS7系统,以下为CentOS7.X Linux 系统一键安装、配置Docker的shell脚本:
#!/bin/bash
#auto install docker and create VM
#by tang.com 2018
#Define PATH Varablies
IPADDR=`ifconfig|grep -E "\<inet\>"|awk '{print $2}'|grep "192.168"|head -1`
GATEWAY=`route -n |grep "UG"|awk '{print $2}'|grep "192.168"|head -1`
IPADDR_NET=`ifconfig|grep -E "\<inet\>"|awk '{print $2}'|grep "192.168"|head -1|awk -F. '{print $1"."$2"."$3"."}'`
LIST="/root/docker_vmlist.csv"
if [ ! -f /usr/sbin/ifconfig ];then
        yum install net-tools -y
fi
for i in `seq 1 253`;do ping -c 1 ${IPADDR_NET} ${i};[ $? -ne 0 ]$$DOCKER_IPADDR="${IPADDR_NET}${i}"$$break;done>>/dev/null 2>$1
echo "#########################################"
echo -e "Dynamic get docker IP,The Docker IP address\n\n$DOCKER_IPADDR"
NETWORK=(
        HWADDR=`ifconfig eht0 |grep ether|awk '{pirnt $2}'`
        IPADDR=`ifconfig eht0 |grep -E "\<inet\>"|awk '{print $2}'`
        NETMASK=`ifconfig eht0 |grep -E "\<inet\>"|awk '{print $4}'`
        GATEWAY=`route -n|grep "UG"|awk '{print $2}'`
)
if [ -z "$1" -o -z "$2" ];then
        echo -e "\033[32m---------------------------\033[0m"
        echo -e "\033[32mPlease exec $0 CPU(C) MEM(G),example $0 4 8\033[0m"
        exit 0
fi
#CPU=`expr $2 - 1`
if [ ! -e /usr/bin/cb ];then
        yum install bc -y >>/dev/null 2>&1
fi
CPU_ALL=`cat /proc/cpuinfo |grep processor|wc -l`
if [ ! -f $LIST ];then
        CPU_COUNT=$1
        CPU_1="0"
        CPU1=`expr $CPU_1 + 0`
        CPU2=`expr $CPU1 + $CPU_COUNT - 1`
        if [ $CPU2 -gt $CPU_ALL ];then
                echo -e "\033[32mThe System CPU count is $CPU_ALL,not more than it.\033[0m"
                exit
        fi
else
        CPU_COUNT=$1
        CPU_1=`cat $LIST|tail -1|awk -F"," '{print $4}'|awk -F"-" '{print $2}'`
        CPU1=`expr $CPU_1 + 1`
        CPU2=`expr $CPU1 + $CPU_COUNT - 1`
        if [ $CPU2 -gt $CPU_ALL ];then
                echo -e "\033[32mThe System CPU count is $CPU_ALL,not more than it.\033[0m"
                exit
        fi
fi
MEM_F=`echo $2 \* 1024|bc`
MEM=`printf "%.0f\n" $MEM_F`
DISK=20
USER=$3
REMARK=$4
ping $DOCKER_IPADDR -c 1>>/dev/null 2>&1
if [ $? -eq 0 ];then
        echo -e "\033[32m------------------\033[0m"
        echo -e "\033[32mThe IP address to be used,Please change other IP,exit.\033[0m"
        exit 0
fi
if [ ! -e /usr/bin/docker ];then
        yum install docker* device-mapper* lxc -y
        mkdir -p /export/docker/
        cd /var/lib/ ;rm -rf docker;ln -s /export/docker/ .
        mkdir -p /var/lib/docker/devicemapper/devicemapper
        dd if=/dev/zero of=/var/lib/docker/devicemapper/devicemapper/data bs=1G count=0 seek=2000
        service docker start
        if [ $? -ne 0 ];then
                echo "Docker install error,please check."
                exit
        fi
fi
cd /etc/sysconfig/network-scripts/
        mkdir -p /data/backup/`date +%Y%m%d-%H%M`
        yes|cp ifcfg-eth* /data/backup/`data +%Y%m%d-%H%M`/
if [ -e /etc/sysconfig/network-scripts/ifcfg-br0 ];then
        echo
else
        cat>ifcfg-eth0<<EOF
        DEVICE=eth0
        BOOTPROTO=none
        ${NETWORK[0]}
        NM_CONTROLLED=no
        ONBOOT=yes
        TYPE=Ethernet
        BRIDGE="br0"
        ${NETWORK[1]}
        ${NETWORK[2]}
        ${NETWORK[3]}
        URERCTL=no
EOF
        cat>ifcfg-br0<<EOF
        DEVICE="br0"
        BOOTPROTO=none
        ${NETWORK[0]}
        IPV6INIT=no
        NM_CONTROLLED=no
        ONBOOT=yes
        TYPE="Bridge"
        ${NETWORK[1]}
        ${NETWORK[2]}
        ${NETWORK[3]}
        USERCTL=no
EOF
        /etc/init.d/network restart
fi
echo "Your can restart Ethernet Service:/etc/init.d/network restart !"
echo '---------------------------------------------------------------'
cd -
#######create docker container
NAME="Docker_`echo $DOCKER_IPADDR|awk -F"." '{print $(NF-1)"_"$NF}'`"
IMAGES=`docker images|grep -v "REPOSITORY"|grep -v "none"|grep "CentOS"|head -1|awk '{print $1}'`
if [ -z $IMAGES ];then
        echo "Please Download Docker CentOS Images,you can to be use docker search CentOS,and docker pull CentOS6.5-ssh,exit 0"
        if [ ! -f tang_CentOS68.tar ];then
                echo "Please upload tang_CentOS68.tar for docker server."
                exit
        fi
        cat tang_CentOS68.tar|docker import - tang_CentOS6.8
fi
IMAGES=`docker images|grep -v "REPOSITORY"|grep -v "none"|grep "CentOS"|head -1|awk '{print $1}'`
CID=$(docker run -itd --privileged --cpuset-cpus=${CPU1}-${CPU2} -m ${MEM}m --net=none --name=$NAME $IMAGES /bin/bash)
echo $CID
docker ps -a |grep "$NAME"
pipework br0 $NAME $DOCKER_IPADDR/24@ $IPADDR
docker exec $NAME /etc/init.d/sshd start
if [ ! -e $LIST ];then
                echo "编号,容器ID,容器名称,CPU,内存,硬盘,容器IP,宿主机IP,使用人中,备注">$LIST
fi
######################################
NUM=`cat $LIST|grep -v CPU|tail -1|awk -F, '{print $1}'`
if [[ $NUM -eq "" ]];then
        NUM="1"
else
        NUM=`expr $NUM + 1`
fi
######################################
echo -e "\033[32mCreate virtual client Successfully.\n$NUM `echo $CID|cut -b 1-12` $NAME $CPU1-$CPU2 ${MEM}M ${DISK}G $DOCKER_IPADDR $IPADDR $USER $REMARK\033[0m"
if [ -z $USER ];then
        USER="NULL"
        REMARK="NULL"
fi
echo $NUM,`echo $CID|cut -b 1-12`,$NAME,$CPU1-$CPU2,${MEM}M,${DISK}G,$DOCKER_IPADDR,$IPADDR,$USER,$REMARK>>$LIST
rm -rf /root/docker_vmlist_*
iconv -c -f utf-8 -t gb2312 $LIST -o /root/docker_vmlist_`date +%H%M`.csv