小编去了解一项技术时,总是喜欢朝着四个方面去做研究:这个技术为什么会出现?这个技术是什么?这个技术如何运用?有没有类似功能的技术,区别在哪?
其次就是了解这个技术是什么,要真正的掌握一门技术,最主要的还是掌握这项技术的核心原理,甚至能从底层代码角度给出分析并展开。
再者,就是实战的运用,技术本身不是孤立的,在了解了原理之后,就是需要动手操练,实践是检验真理的唯一标准,在多门技术的融合使用中,加深对当前技术的深入了解。小编在面试中接触过四类人:第一种是理解深入并且实战经验也很丰富;第二种是实战经验丰富,但理解不够深入,表现比如表达不出来关键点,对一些核心名词理解较差;第三种是理解有了,但是没有过实战,表现是能侃侃而谈,但一问实际使用,比如需要引入什么jar包、如何处理异常、怎么部署等等就是一问三不知;第四种就是两者都没有掌握的。我们在选择的时候一般也只会选择前两种。
最后,就是了解类似的技术,在一个领域,如果只是掌握一门技术,在运用上当然没有问题,但是现在技术日新月异,需要不断学习新的技术,拓宽我们的知识面,并且有比较才知道区别,了解同一个领域不同的技术,也能从侧面加深我们对当前技术的理解,这也是相辅相成的。
今天,我们就从这四个角度来谈谈Docker这么技术。
作为程序员来说。软件开发部署最让人头痛的事情是需要重复在不同的操作系统或者不同的环境下搭建同样的环境。环境搭建需要添加各种依赖,可能还需要配置各种环境变量,有时候在一台机器上正常运行,却不能保证在另外一台机器也能正常运行,费时费力,还容易出错。有没有一种办法,能不能从根本上解决问题,软件可以带环境安装?也就是说,安装的时候,把原始环境一模一样地复制过来。
1、虚拟机
虚拟机(virtual machine)就是带环境安装的一种解决方案。它可以在一种操作系统里面运行另一种操作系统,比如在Windows系统里面运行Linux系统。应用程序对此毫无感知,因为虚拟机看上去跟真实系统一模一样,而对于底层系统来说,虚拟机就是一个普通文件,不需要了就删掉,对其他部分毫无影响。虽然用户可以通过虚拟机还原软件的原始环境。但是,这个方案有几个缺点。
资源占用多:虚拟机会独占一部分内存和硬盘空间。它运行的时候,其他程序就不能使用这些资源了。哪怕虚拟机里面的应用程序,真正使用的内存只有1MB,虚拟机依然需要几百MB的内存才能运行。
冗余步骤多:虚拟机是完整的操作系统,一些系统级别的操作步骤,往往无法跳过,比如用户登录。
启动慢:启动操作系统需要多久,启动虚拟机就需要多久。可能要等几分钟,应用程序才能真正运行。
2、Linux容器
由于虚拟机存在诸多缺点,Linux发展出了另一种虚拟化技术:Linux容器(Linux Containers,缩写为LXC)。Linux容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
由于容器是进程级别的,相比虚拟机有很多优势。
启动快:容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
资源占用少:容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
体积小:容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。
这个时候Docker出现了,Docker属于Linux容器的一种封装。先来看一下Docker的发展历史。
2010年,几个搞IT的大胡子年轻人在旧金山成立了一家做PaaS平台(平台即服务)的公司,公司起名为“dotCloud”。
这家公司主要提供基于PaaS的云计算技术服务。什么是PaaS?PaaS的全称是Platform as a Service,也就是平台即服务,它是描述作为集成租用或交付的计算平台的概念解决方案,解决方案堆栈可以是一组组件或软件用于开发功能齐全的产品或服务的子系统,例如使用OS,Web服务器,数据库和编程语言的Web应用程序等。
dotCloud不仅支持诸如PHP、MySql等传统技术框架,还包括Node.js、MongoDB等新兴技术。基于dotCloud提供的开发工具和技术框架,你可以直接使用dotCloud的SDK编写代码和构建业务服务,并在联网的时候把这些代码推送到云端,实现自动部署和测试。
Docker技术诞生之后,并没有引起行业的关注。而dotCloud公司,当时两面夹击。前有IBM的蓝云,微软的Azure,Amazon的EC2,Google的GAE,VMware的Cloud Foundry等等大牌企业搅局,后方大本营资金短缺,难以为继。在他们快要坚持不下去的时候,提出了“开源”Docker。开源,也就是意味着开放源代码,将原来内部保密的程序源代码开放给所有人,然后让大家一起参与进来,贡献代码和意见。Docker开源之后,受到广大程序员的青睐,越来越多的人加入了Docker开源社区,也将Docker这门技术不断向前推进,不久之后的2013年发行面世。
二、Docker是什么
Docker是一种Linux容器技术,容器有效的将由单个操作系统挂管理的资源划分到孤立的组中,以便更好的在组之间平衡有冲突的资源使用需求。可简单理解为一种沙盒。每个容器内运行一个应用,不同的容器之间相互隔离,容器之间也可以建立通信机制。容器的创建和停止都十分快速,资源需求远远低于虚拟机。
Docker属于Linux容器(Linux容器在上一小节提到)的一种封装,提供简单易用的容器使用接口,它是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。Docker可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。有了Docker,就不用担心环境问题。
Docker技术使用Linux内核和内核功能来分隔进程,以便各进程相互独立运行。这种独立性正是采用容器的目的所在;它可以独立运行多种进程、多个应用程序,更加充分地发挥基础设施的作用,同时保持各个独立系统的安全性。
此外,由于这些工具基于Linux容器构建,使得Docker既易于使用,又别具一格 , 它可为用户提供前所未有的高度应用程访问权限、快速部署以及版本控制和分发能力。
总体来说,Docker的接口相当简单,用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
接下来介绍Docker的三大核心概念:镜像、容器、仓库,以及他们的关系。
镜像是创建Docker容器的基础,Docker镜像类似于虚拟机镜像,可以把Docker镜像理解成一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变(只读)。
Docker提供了一套十分简单的机制来创建和更新现有的镜像。用户可以从网上下载一个已经做好的应用镜像,并通过命令直接使用。总之,应用运行是需要环境的,而镜像就是来提供这种环境。
例如:一个镜像可以完全包含了Ubuntu操作系统环境,可以把它称作一个Ubuntu镜像。镜像也可以安装了Apache应用程序(或其他软件),可以把它称为一个Apache镜像。
(2)Docker容器(Container)
镜像(Image)和容器(Container)的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。并且这些容器都是相互隔离、互不可见的。
Docker容器(Container)类似于一个轻量级的沙箱子(因为Docker是基于Linux内核的虚拟技术,所以消耗资源十分少),可以把每个容器看作一个简易版的Linux系统环境(包括了root用户权限、进程空间、用户空间和网络空间),以及与运行在其中的应用程序打包而成的应用盒子。Docker利用容器来运行和隔离应用。容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。
镜像自身是只读的。容器从镜像启动的时候,Docker会在镜像的最上层创建一个可写层,镜像本身将保持不变。就像用ISO装系统之后,ISO并没有什么变化一样。
(3)Docker仓库(Repository)
Docker仓库(Repository)类似于代码仓库,是Docker集中存放镜像文件的场所。每个仓库集中存放某一类镜像,往往包括多个镜像文件,通过不同的标签(tag)来进行区分。例如存放Ubuntu操作系统镜像的仓库,称为Ubuntu仓库,其中可能包括14.04,12.04等不同版本的镜像。但是,如果需要在其它服务器上使用这个镜像,我们就需要一个集中的存储、分发镜像的服务,Docker Registry就是这样的服务。理解这个关系就是:一个Docker Registry中可以包含多个仓库(Repository);每个仓库可以包含多个标签(Tag);每个标签对应一个镜像。
根据存储的镜像公开分享与否,Docker仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
目前,最大的公开仓库是Docker Hub,存放了数量庞大的镜像供用户下载。国内的公开仓库包括Docker Pool等,可以提供稳定的国内访问。如果用户不希望公开分享自己的镜像文件,Docker也支持用户在本地网络内创建一个只能自己访问的私有仓库。
当用户创建了自己的镜像之后就可以使用push将它上传到指定的公有或则私有仓库。这样用户下次在另一台机器上使用该镜像时,只需将其从仓库pull下来就可以了。
三、Docker如何使用
在没有用docker之前,我们需要在本地、测试、演示、线上部署相同的环境,相同的软件每个环境都要安装一次,并且每来一个新同事,相同的环境有要重新安装一遍,很麻烦且过于重复。docker可以完美的解决这个问题。
用docker之后我们只需要在本地、测试、演示、线上分别安装相同的docker,然后在本地搭建环境,将搭建好的环境容器生成docker镜像,只要将这个docker镜像提供给测试、演示和线上即可构建出相同的环境,在代码部署上我们可以利用docker数据卷将本地项目目录文件直接挂载到测试环境中。
Docker是一个开源的商业产品,有两个版本:社区版(Community Edition,缩写为CE)和企业版(Enterprise Edition,缩写为EE)。企业版包含了一些收费服务,个人开发者一般用不到。
目前网络上有很多的安装教程,大家可以自行搜索一下。特别注意的是:如果你在windows操作系统上安装Docker,注意在任务管理中查看本机虚拟化是否已启用,如果虚拟化是已禁用,那么你需要重启电脑进入bios开启虚拟化。
2、使用docker搭建服务
使用docker搭建服务,一般分为几个步骤:
(1)搜索镜像:docker search +镜像名字+标签名字(镜像名字和标签名字之间没有空格,不加标签默认最新的镜像,也就是 latest 标签的镜像),从Docker Hub中搜索符合条件的镜像
#docker search myql
#docker search myql5.7
注意:如果不是root用户,并且当前用户没有添加到docker用户组(可以用whoami && id查看当前用户id和组id),会提示连接拒绝:
(2)下载镜像命令 docker pull [IMAGE_NAME]:[TAG],默认从Docker Hub官方的仓库中下载需要搭建服务的镜像文件,如果没有指定版本(即没有输入标签TAG),默认会获取仓库中最新版本的镜像(latest 标签的镜像)。(注意是Docker Hub官方仓库中最新的镜像,而不是软件本身最新的镜像);
使用示例:
#docker pull mysql # 拉取最新版mysql镜像
#docker pull mysql:5.7 # 拉取 指定标签版本mysql 5.7
(3)查看下载的镜像命令,docker images 或者docker image ls 查看有没有刚刚下载的镜像;
表头REPOSITORY、TAG、IMAGE ID、CREATED、SIZE 名词解释:
REPOSITORY: 来自于哪个仓库;
TAG: 镜像的标签信息,比如 5.7、latest 表示不同的版本信息;
IMAGE ID: 镜像的 ID, 如果您看到两个 ID 完全相同,那么实际上,它们指向的是同一个镜像,只是标签名称不同罢了;
CREATED: 镜像最后的更新时间;
SIZE: 镜像的大小,优秀的镜像一般体积都比较小,这也是我更倾向于使用轻量级的 alpine 版本的原因;
(4)创建一个新的容器并运行一个命令: docker run [options] 镜像名 [向启动容器中传入的命令]
OPTIONS参数说明:
示例1:使用镜像nginx:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。(/bin/bash的作用是因为docker后台必须运行一个进程,否则容器就会退出,在这里表示启动容器后启动bash)
#docker run -it nginx:latest /bin/bash
示例2:使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx。
#docker run --name mynginx -d nginx:latest
示例3:使用nginx镜像运行容器
#docker run --name nginx-test -p 8080:80 -d nginx
--name nginx-test:容器名称。
-p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口。
-d nginx: 设置容器在在后台一直运行。
示例4:使用镜像mysql运行容器
#docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql
-p 3306:3306 :映射容器服务的3306端口到宿主机的3306端口,外部主机可以直接通过 宿主机ip:3306访问到MySQL的服务。
MYSQL_ROOT_PASSWORD=123456:设置MySQL服务root用户的密码。
示例5:使用 tomcat 镜像运行容器
#docker run --name tomcat -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/test -d tomcat
-p 8080:8080:将主机的 8080 端口映射到容器的 8080 端口。
-v $PWD/test:/usr/local/tomcat/webapps/test:将主机中当前目录下的test挂载到容器的/test。
示例6:使用redis镜像运行容器
#docker run -itd --name redis-test -p 6379:6379 redis
-p 6379:6379:映射容器服务的6379端口到宿主机的6379端口。外部可以直接通过宿主机ip:6379访问到Redis的服务。
(5)查看是否安装成功,docker ps [options] 命令查看是否安装成功。
表头字段分析:
CONTAINER ID(container id ) :容器ID,可以通过这id找到唯一的对应容器
IMAGE (image):该容器所使用的镜像
COMMAND (command):启动容器时运行的命令
CREATED (created):容器的创建时间
STATUS (status):容器现在的状态,状态有7种:created(已创建)|restarting(重启中)|running(运行中)|removing(迁移中)|paused(暂停)|exited(停止)|dead,up表示运行中
PORTS (ports):容器的端口信息和使用的连接类型(tcp\udp)
NAMES (names):镜像自动为容器创建的名字,也唯一代表一个容器
(6)查看容器详细信息
#docker inspect 容器id
(7)进入容器,使用docker exec进入Docker容器
#docker exec -it 容器ID /bin/bash
四、与Docker类似功能的技术有哪些,他们有何区别?
自从Docker在2013年发行以来,一直是容器市场青睐的对象,不过最近几年,也有不少容器开始崭露头角,并且开始占据容器市场。比如CoreOS rkt、Mesos容器引擎、LXC容器、Containerd等。
(1)CoreOS rkt:支持两种不同的镜像类型:Docker和appc。rkt最大的优势就是可以直接兼容kubernets。另外rkt还支持 TPM(可信平台模块),提供了非常好的安全性支持。它对应用容器也做了很多优化处理。同Docker相比rkt还是缺少一些可整合的第三方接口。
(2)Mesos 容器引擎:它是Apache 的开源项目,Mesos提供了非常好的性能参数。同 rkt 类似,它也支持Docker和appc 两种镜像。而且参考Docker对OCI的兼容方式。不过Mesos容器引擎必须通过Mesos框架来运行这些容器,而不能像其它容器那样可以单独运行。
(3)LXC容器:它仿真了一个类似虚拟机的操作体验,并避免了虚拟机额外的系统负载。而且Windows 跟MacOS用户都可以访问lxd进程。不过LXC容器目前还不能同kubernetes进行整合,也没有实现对OCI标准的支持。
(4)Containerd:它是一个符合工业标准的容器运行时,注重简洁、健壮性以及可移植性。它目前是CNCF(云原生计算基金会)的孵化项目。Containerd可以以守护进程的方式在Linux和Windows上运行。Containerd支持OCI镜像文件,与gRPC天然嵌合,而且具有完善的容器生命周期管理功能。