我们通常所说的docker是什么?在这里英文本意为“搬运工”这里指的的docker搬运点的是集装箱,集装箱装的是够任意类型的APP,开发者通过Docker可以将app变成一种标准化,可移植的、自管
我们通常所说的docker是什么?
在这里英文本意为“搬运工”这里指的的docker搬运点的是集装箱,集装箱装的是够任意类型的APP,开发者通过Docker可以将app变成一种标准化,可移植的、自管理的组件、可以在任意主流的系统开发,调试和运行
简单的来说,docker是一种用了新颖的方式实现的轻量级的虚拟化,类似于VM,但是在原理和应用上和VM还是有很大的区别,其专业的名称是应用容器;
所谓应用容器,就比如将Nginx,Mysql等软件程序将其封装成一组特定的虚拟机一样,如果我们想用Nginx这些应用的话,我们直接运行这个容器就好了,这就相当于运行起来的虚拟机一样,只要能运行,这些配置都省下来了,如果说系统层面的宿主机出现了异常需要迁移,那么我们将这个容器转移平台就可以的
Docker基于Go语言开发的,代码托管在Github上,docker容器可以封装任何有效负载,计划可以在任何服务器之间进行一致性运行,也就是说,开发者构建的应用,只需要一次构建即可多平台运行,运营人员只需要配置服务,即可运行所有应用,
若是利用容器的话,那么开发直接在容器里开发,测试的时候整个同期给测试,测好了把测试后容器再上线就好了,通过容器,整个开发,测试和生产环境保持高度一致;
此外容器也有和VM一样具有一定的隔离性,各个容器之间的数据和内存之间相互隔离,可以保证一定的安全性
Hyper-V、KVM和XEN等虚拟机管理程序都是“”基于虚拟化硬件仿真机制”,这就意味着,它们对系统硬件要求很高,然而,容器确实使用共享的操纵系统,它们在使用系统资源方面比虚拟机管理程序要高效很多,容器不是对硬件要求进行的虚拟化的处理,而是驻留在一个linux实例上,Docker可以解决虚拟机能够解决的问题,同时也能解决虚拟机由于资源要求过高而无法解决的问题
为什么使用Docke?或者是docker有哪方面的优势
1)快速的交付应用程序
开发者使用一个标准image来构建开发容器,开发完成之后,系统管理员就可以使用这个容器来部署代码
docker可以快速的创建容器,快速的迭代应用程序,并让整个过程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的
docker容器轻量级,启动很快,启动的时候是次秒级的,节约开发,测试,部署时间
2)更容易部署和扩展
docker容器可以在几乎所有环境中运行,物理机,虚拟机,公有云,私有云,服务器等等
docker容器兼容很多平台,这样就可以把一个应用程序从一个平台上迁移到到另一个
3)效率高
Docker容器不需要hypervisor,他是内核级虚拟化
4)快速的部署也以为这更简单的管理
通常是需要小小的改变就可以替代以往巨型和大量更新工作
【Docker常用的案列】
自动打包和部署应用
创建轻量,私有的Paas环境
自动化测试和持续集成/部署
部署并扩展WEB应用/数据库和后端服务器
【VM的选用】
docker容器相对于VM还是有很多优点的,
1)启动速度快,容器通常在一秒内可以启动,而VM要很久
2)资源利用率小,一台普通服务器可以跑上个容器
3)性能开销小,VM需要额外的CPU和内存来完成OS的功能,这一部分占据了额外的资源
下图所示:对比了docker和传统虚拟化(KVM,XEN等)方式的不同之处,Docker容器是在操作系统层面上实现了虚拟化,直接复用本地主机操作系统,而传统方式则是在硬件基础上,虚拟出自己的系统,再在系统上部署相关的APP应用
传统虚拟化方案:Nginx(图一)
Docker虚拟化解决方案:Nginx镜像-nginx容器-对外访问
Docker虚拟化三个概念解析:镜像,容器,仓库
镜像:Docker的镜像其实就是模板,跟我们常见的ISO镜像类似,是一个样板
容器:使用镜像常见的应用或者系统,称之为一个容器
仓库:仓库是存放镜像的地方,分为公开仓库(Public)和私有仓库(Private)两种形式
Docker最早为LXC+AUFS组合,Docker0.9.0版本开始引入libcontainer,可以视作LXC的替代品,其中LXC负责资源管理,AUFS负责镜像管理;而LXC包括Cgroup,namespace,chroot等组件,并通过cgroup进行资源管理
从资产管理来看,Docker,LXC,Cgroup三者的关系是:cgroup在最底层落实资源管理,LXC在cgroup上封装了一层,Docker又在LXC封装了一层
Cgroup是linux内核提供的一种可以限制,记录,隔离进程组所使用的物理资源(如CPU,Memory,IO等)的机制,Cgroups也是LXC为实现虚拟化所使用的资源管理手段,可以说没有Cgroups也就没有LXC,也就没有Docker
Cgroup最初的目的地为资源管理提供一个统一的框架,即整合现有的Cgroup等子系统,也为未来开发新的子系统提供接口,现在的Cgroup使用与多种应用场景,从单个进程的资源控制,到实现操作系统层次的虚拟化
LXC容器可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性,容器有效的将单个系统管理的资源划分到独立的组中,以便更好的在独立的组之间平衡有冲突的资源使用需求
【对比传统的虚拟机总结】
【Docker的体系结构】
docker使用C/S架构,docker daemon作为server端接受clinet的请求,并处理(创建,运行,分发容器)他们可以运行在一个机器上,也通过socket或者去RESTful API通信
Docker daemon一般在宿主机后台运行,docker clinet以系统命令形式存在,用户用docker命令与docker daemon交互;
docker守护进程(docker daemon)
如图上所示,docker守护进程运行在一台主机上,用户并不直接和守护进行交互,而通过docker客户端间接和其通信
Docker客户端(Docker client)
Docker客户端实际上是docker的二进制程序,是用户与docker交互方式,它接受用户指令并且与背后的docker守护进程通信;
Docker 内部:
要理解 Docker 内部构建,需要理解以下三种部件:
Docker 镜像 - Docker images
docker镜像是docker容器运行时的只读模板,镜像可以用来创建docker容器。每个镜像由一系列层的(layers)组成,Docker使用的UFS(联合文件系统)来讲这些层联合到单独的镜像中,
UFS允许独立文件系统中的文件和文件夹被透明覆盖,形成一个单独连贯的文件系统,正因为有了这些镜像层的存在,docker是如此的轻量,当你改变一个docker镜像,比如说升级到某个程序最新版本,这样一个新的层会被创建,不需要替换或者是说重新创建,只需要升级,层使得分发docker镜像变得简单和快速;
每个docker都有很多层次构成,docker使用 union file systems 将这些不同的层结合到一个image 中去。
例如:centos镜像中安装nginx,就成了nginx镜像”,其实在此时Docker镜像的层级概念就体现出来了。底层一个centos操作系统镜像,上面叠加一个ngnx层,就完成了一个nginx镜像的构建。层级概念就不难理解,此时我们一般centos操作系统镜像称为nginx镜像层的父镜像。
Docker 仓库 - Docker registeries
docker仓库用来保存镜像,可以理解为代码控制中的代码仓库,同样的,docker仓库也有共公有和私有的概念,公有Docker仓库名字是docker hub,docker hub提供了庞大的镜像集合供使用,这些镜像可以是自己创建的,或者在比人的镜像基础上创建
仓库是集中存放镜像文件的场所,有时候会把仓库 和仓库注册服务器(Regitry)混为一谈,
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括 Docker Pool等,可以提供大陆用户更稳定快速的访问。
当然,用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后就可以使用push命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上pull下来就可以了。
*注:Docker 仓库的概念跟Git类似,注册服务器可以理解为 GitHub 这样的托管服务。
Docker 容器 - Docker containers
Docker 利用容器来运行应用,一个Docker容器包含了所有的某个应用运行所需要的环境。每一个 Docker 容器都是从 Docker 镜像创建的。Docker 容器可以运行、开始、停止、移动和删除。每一个 Docker 容器都是独立和安全的应用平台。
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。
可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
*注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层
[Docker 底层技术]
docker底层的 2 个核心技术分别是 Namespaces 和 Control groups
Namespaces用来隔离各个容器
1)pid namespace
不同用户的进程就是通过pid namespace 隔离开的,且不同 namespace 中可以有相同pid。所有的LXC进程在docker中的父进程为docker进程,每个lxc进程具有不同的 namespace 。
2) net namespace
有了pid namespace, 每个 namespace 中的pid能够相互隔离,但是网络端口还是共享 host 的端口。网络隔离是通过 net namespace 实现的,每个 net namespace 有独立的 network devices, IP addresses, IP routing tables, /proc/net 目录。这样每个 container 的网络就能隔离开来。docker默认采用veth的方式将 container 中的虚拟网卡同 host 上的一个docker bridge: docker0 连接在一起。
3) ipc namespace
container 中进程交互还是采用linux常见的进程间交互方法 (interprocess communication - IPC),包括常见的信号量、消息队列和共享内存。container 的进程间交互实际上还是host 上具有相同pid namespace 中的进程间交互。
4) mnt namespace
类似chroot,将一个进程放到一个特定的目录执行。mnt namespace 允许不同 namespace 的进程看到的文件结构不同,这样每个 namespace 中的进程所看到的文件目录就被隔离开了。在container里头,看到的文件系统,就是一个完整的linux系统,有/etc、/lib 等,通过chroot实现。
5) uts namespace
UTS("UNIX Time-sharing System") namespace 允许每个 container 拥有独立的 hostname 和 domain name, 使其在网络上可以被视作一个独立的节点而非 Host 上的一个进程。
6) user namespace
每个 container 可以有不同的 user 和 group id, 也就是说可以在 container 内部用 container 内部的用户执行程序而非 Host 上的用户。
有了以上 6 种 namespace 从进程、网络、IPC、文件系统、UTS和用户角度的隔离,一个 container 就可以对外展现出一个独立计算机的能力,并且不同 container 从 OS 层面实现了隔离。然而不同 namespace 之间资源还是相互竞争的,仍然需要类似ulimit来管理每个 container 所能使用的资源 - -cgroup。
cgroups(Control groups)实现了对资源的配额和度量。
【创建自己的镜像】
一:使用docker commit 来扩展一个 image
1.1:先下载一个容器
docker pull training/sinatra
1.2用容器启动这个镜像
docker run -t -i training/sinatra /bin/bash
1.3:接下来给使用中的容器,添加自己需要的工具,组装自己的运行环境
1.4:结束后,我们使用exit来退出,现在我们的容器已经改变了,我们使用docker commint命令来提交相应的副本
docker commit -m “Added json gem” -a “xiaoyu” 0b2616b0e5a8 ouruser/sinatra:v2
其中, -m 来指定提交的说明信息,跟我们使用的版本控制工具一样; -a 可以指定更新的用户信息;之后是用来创建镜像的容器的 ID;最后指定目标镜像的仓库名和 tag 信息。创建成功后会返回这个镜像的 ID信息。
二:从dockerfile来创建image
使用docker commit 来扩展一个 image 比较简单,但它不容易在一个团队中分享它。我们使用docker build 来创建一个新的 image 。为此,我们需要创建一个dockerfile,包含一些如何创建我们的image 的指令。现在,我们来创建一个目录和一个dockerfile
Dockerfile基本的语法是
使用#来注释
FROM指令告诉 Docker 使用哪个镜像作为基础(docker使用哪个 image 源)
MAINTAINER是维护者的信息
RUN开头的指令会在创建中运行,比如安装一个软件包,在这里使用 yum来安装了一些软件
编写完成Dockerfile后可以使用docker build 来生成镜像。
2.1、创建镜像所在的文件夹和Dockerfile文件
命令:
1、mkdir sinatra
2、cd sinatra
3、touch Dockerfile
2.2、在Dockerfile文件中写入指令,没一条指令都会更新镜像的信息例如:
# This is a comment
FROM ubuntu:14.04
MAINTAINER Kate Smith ksmith@example.com
RUN apt-get update && apt-get install -y ruby ruby-dev
RUN gem install sinatra
格式说明:
每行命令都是以 INSTRUCTION statement 形式,就是命令+ 清单的模式。命令要大写,“#”是注解。
FROM 命令是告诉docker 我们的镜像什么。
MAINTAINER 是描述 镜像的创建人。
RUN 命令是在镜像内部执行。就是说他后面的命令应该是针对镜像可以运行的命令。
2.3、创建镜像
命令:docker build -t ouruser/sinatra:v2 .
docker build 是docker创建镜像的命令
-t 是标识新建的镜像属于 ouruser的
sinatra是仓库的名称
:v2 是tag
“.”是用来指明 我们的使用的Dockerfile文件当前目录的
2.4、创建完成后,从镜像创建容器
docker run -t -i ouruser/sinatra:v2 /bin/bash
其中 -t 标记来添加 tag,指定新的镜像的用户信息。“.”是Dockerfile所在的路径(当前目录),也可以替换为一个具体的Dockerfile的路径。
可以看到 build 进程在执行操作。它要做的第一件事情就是上传这个Dockerfile内容,因为所有的操作都要依据Dockerfile来进行。然后,Dockfile中的指令被一条一条的执行。每一步都创建了一个新的容器,在容器中执行指令并提交修改(就跟之前介绍过的docker commit 一样)。当所有的指令都执行完毕之后,返回了最终的镜像 id。所有的中间步骤所产生的容器都被删除和清理了。
*注意一个镜像不能超过 127 层
拓展:
进入容器
在使用 -d 参数时,容器启动后会进入后台。某些时候需要进入容器进行操作,有很多种方法,包括使用docker attach 命令或nsenter命令。
使用docker attach进入容器
1.docker attach 允许我们进入后台进程.
2.--sig-proxy=false 不使用容器转发信号,允许我们使用 ctrl -c 来退出,执行dockerps查看在后台运行
但是使用 attach 命令有时候并不方便。当多个窗口同时 attach 到同一个容器的时候,所有窗口都会同步显示。当某个窗口因命令阻塞时,其他窗口也无法执行操作了。
也可以执行docker exec进入运行的容器
docker exec -it 容器ID/名称 /bin/bash
以上命令返回一个命令界面,exec代表直接在容器中运行命令
容器导入和导出
导出容器
docker export [容器 id] > [导出文件]
如果要导出本地某个容器,可以使用docker export 命令。
导入容器
可以使用docker import 从容器快照文件中再导入为镜像
# cat centos6.tar | docker import – centos6:test
#docker images