前言前一阵的工作,大多数是与部署相关的,通过将项目打包,然后利用docker,部署在AWS上去。就在这一段时间里面我便对docker产生了浓厚的兴趣,这也就激发我去深入研究的一个动力。那么下面开始我们的docker之旅。
什么是docker我们可以首先通过以下网址对docker有一个认识:docker的讲解。简单来说docker可以让我们的部署变得更加简洁。(这里我就不做那么更详细的解释了,因为我觉得它总结的要比我总结好的多。)
为什么用docker在没出现docker的时候,我们完成的java web项目需要打成一个war。然后得在服务器中配置各种各样的参数,例如说jdk,tomcat,数据库等。配置的周期相当的冗杂并且繁琐。但是现在有了docker,我们不但可以使用一个空的镜像,从头开始构建,还可以使用之前各种大牛已经build好的镜像,直接使用。而且在项目需要迁移的时候,我们只需要在需要部署的地方,直接使用之前项目使用的docker放置好自己的项目即可,方便快捷。
docker的基本概念docker最重要的三个概念是:镜像(image),容器(container),仓库(repository),在这三个概念中,镜像是最重要的概念。
* 镜像
我们可以把镜像理解为一个文件系统,并且是一个只读的文件系统。镜像是由一层层的只读层构造起来的,但是从使用者的角度来看我们只有一个镜像而已。那么问题就来了,镜像是只读的,那么我们在使用它的过程中,如果需要对它进行修改,该怎么办呢,别着急,这个就得看我们的容器了。
* 容器
容器是镜像的一个运行实例,可以不准确的把镜像当作类,容器当作对象。容器其实他的结构是与镜像相类似的,底部也是一层层的只读层,只不过在最上层会存在一个存储层,我们可以在这一层定制化我们的这个容器,还可以通过build命令,把容器打包成我们自己需要的镜像。另外镜像启动后会形成一个容器,容器在计算机中是一个进程,但这个进程对其他进程并不可见。
容器的启动过程:
检查镜像是否在本地存在,如果不存在去远程仓库下载
==>利用镜像创建一个容器
==>启动刚刚创建的容器
==>分配一个文件系统给容器,并且在镜像层外挂载一个可读可写层
==>从宿主主机的网桥接口中桥接一个给容器
==>从网桥中分一个ip地址给容器
==>执行用户指定的应用程序
==>执行完毕后容器自动终止
* 仓库
这个理解起来就很简单了,大家应该有使用过git,他是有一个远程的仓库,这个仓库记录着我们的代码,和每一次我们提交的记录。但是在这里,把docker的仓库比做maven仓库更加恰当,就相当于我们可以去maven远程仓库取我们需要的依赖,多个依赖构成了我们的整个项目,这个思想同样适用于docker。默认情况下,我们都是从docker hub中取得的镜像(http://registry.hub.docker.com/)
使用docker实践是检验真理最好的方式,我会在不断的实践中给大家讲解docker命令。
本人使用mac,所以所有操作都会在mac进行。如果使用docker的话,强烈不推荐搭建使用windows系统,因为docker对于windows很不友好,用起来十分不方便,那怎么办呢,win的同学,可以在电脑上安装虚拟机,然后安装一个linux系统(centos,red hat,ubantu)。
下面给出安装的链接:
Mac:mac安装docker的方法
Linux:centos安装docker的方法
在使用docker之前,如果是不熟悉linux命令的,推荐强烈去学一下,因为我自己感觉这对于docker的学习是很有帮助的。
安装好docker,那就开始我们的表演。
1.docker search <镜像名称>当我们在对docker的镜像一无所知的时候,我们可以通过查询镜像,看看自己想要的镜像存不存在。例如说我们这里可以docker search tomcat。
2.docker pull <镜像名称>:<镜像版本>其实我们的版本都可以不用填写,默认情况下是latest,也就是去取最新的版本。
3.docker run -d -p <外部端口>:<内部端口> <镜像名称>:<镜像的tag>打开terminal终端,在终端中输入:docker run -d -p 8080:8080 tomcat 这里启动一个tomcat镜像作为演示。熟悉tomcat的应该知道,默认的端口号为8080,所以我这里使用了默认端口。这里解释一下外部/内部端口,这个很容易理解,docker在运行的时候,会启动一个tomcat,这个tomcat的端口为8080。外部端口指的就是宿主电脑的端口。就是我们可以通过我们的电脑访问的端口。
* -d <指的是后台运行容器>
* -p <指的是指定端口>
* –link <连接的容器名称>:<连接的别名>
可以使容器和容器之间相互连接
* -v <挂载到容器的目录>
* –volumes-from <可以挂载的数据卷容器名称> (通过启动一个新容器,使用 -v 命令挂载一个目录,然后通过这个命令把容器挂载到数据卷容器上,可以多个容器挂载同一个数据卷容器上,而且数据卷容器本身可以不是启动的状态。)
* -v <本地已有的目录>(这个路径必须是绝对路径):<容器的目录>。如下,我自己创建了一个宿主机与容器中的文件夹映射,然后创建了一个文件,宿主机相应的也产生了文件。
(Tips:其实我们本可以不使用pull进行下载镜像,因为docker镜像在启动的时候,如果放下这个镜像不存在,那么自己会去下载镜像。)如果想的话,可以添加上 – name 作为这个启动容器的名称,如果我们不定义名称,可以通过容器的id操纵这个容器。并且docker run 是一个组合命令,实际上组合的是 create+start
4.docker create –name <容器名称> <镜像名称>:<镜像tag>5.docker start <容器的id>这里把create 以及start一起讲一下,create命令就是在镜像的只读层的最上面加上一个存储的可读可写层。上面的 -d 与 -p 的option 都是create命令的,创建一个容器可配的option相当的多,这里就不详细说明了。create命令后,容器是处于stop状态的,得需要start命令启动。start命令则是给容器分配一个进程,然后启动起来。
6.docker images查看本地已经有的docker镜像。
通过 docker images - -format [.ID]:[.Repository]指定显示镜像id以及名称
7.docker rmi <容器名称>:<容器tag>移除已经存在的指定的容器。
8.docker ps -a查看所有的容器。
当把-a换成-qa的时候就是查看所有容器的id。
9.docker exec -it <容器Id> /bin/bash进入docker 容器 docker exec -it(后面可以接上容器id或者容器名称) /bin/bash
* -it 是 -i以及-t。
* -i是保持标准输入打开
* -t是表示分配一个伪终端。
10.docker tag <已有镜像名>:<已有镜像版本> <新镜像名>:<新镜像版本>我们可以使用docker tag tomcat:latest mytomcat:latest。这样就会新生成一个镜像名字叫做mytomcat,版本为latest,只有别名不同而已,但是同样指向了同一个镜像。
11.docker inspect <镜像名称>:<镜像版本>显示镜像的详细信息,包括制作者,适应框架,各层的数字摘要。
12.docker history <镜像名称>:<镜像版本>前面已经说过,既然镜像是一层一层构成的,那么我们肯定可以看到,各层的记录,使用此命令,可以看出镜像发生的变化。过长的信息会被自动拦截我们可以使用 –no-trunc显示信息完整的信息。
13.docker commit <进程号>/<容器名称> <镜像名称>:<版本号>基于现有镜像,形成自己的镜像 。原理就是在原有的镜像基础上增加自己修改过的存储层,叠加为一个新的镜像,保存下来。成功后,会返回一个 sha256的码作为镜像的唯一标实。
形成新的自己的镜像,一共有三个方法:
* 通过 commit 命令
* 通过模版进行构建
我们可以通过openVZ为我们提供的模板进行创建,也可以通过自己导出的模板进行创建,openvz网址 openvz模板下载地址。
我们以ubantu的模板为例。命令为cat ubuntu-x86_64-minimal.tar.gz | docker import ubuntu:14.04。执行完以上命令,就可以通过docker images 看到我们的镜像了。
* 通过Dockerfile文件进行构建。
但是docker commit 需要慎用,因为具体做了什么修改任何人都是看到的,完全就是一个黑盒操作。而且进行的删除操作,并不是真正意义上的删除,每一次的修改都是在上一次的基础上,这使得 镜像越来越臃肿。如果我们想要定制我们的docker镜像可以使用dockerfile
13.docker save -o 导出的镜像名称(后缀为.tar) <镜像名称>:<镜像的版本>14.docker load –input 导出的镜像名称(后缀为.tar)15.docker export -o 导出的镜像名称(后缀为.tar) <容器Id>16.docker import 导出的镜像名称(后缀为.tar) <镜像名称>:<镜像的版本>前两个命令是搭配在一起的,我们通过save命令,把镜像打包成tar文件的形式,这就可以分享给别人进行使用,然后其他人可以通过 load 命令将 导出的文件,保存到本地。
后两个命令也是搭配起来的将正在运行的容器,打包成一个tar文件。然后把tar文件import进来,形成一个镜像。
我们可以看出load和import命令十分相似,那他们的区别在哪呢?
* load 命令导入镜像存储文件到本地镜像库
* import 导入一个容器快照到本地镜像库
容器快照文件将丢弃所有的历史记录以及元数据信息,仅保留快照时的状态
镜像存储文件保持完整记录,相对的体积也会更大。
在我动手实践的时候也明显感觉到了,使用export要比save的速度快的多。
这里的 load的时候犯了一个错误,在后面跟上了镜像的名称与版本,其实是并不需要的,切记下次不会再加了。
17.docker stop <容器的ID>停止正在运行的容器实例。
18.docker rm <容器的ID>在删除一个容器实例之前,应该先要将容器停止。
主要支持的选项:
* -f , –force = false 强制删除一个正在运行的容器
* -l , –link=false 删除容器的连接,但是保存容器
* -v , –volumes=false 删除容器挂载的数据卷
19.docker restart <容器的ID>重新启动容器,将容器先停止,后启动。
20.docker build -t <生成镜像的名称>:<镜像的版本>后续在下一篇文章,我会继续整理有关Dockerfile的编写,以及其他相关的内容。我希望这样的总结,可以给大家带来帮助,也对自己梳理知识体系有所帮助,谢谢大家
本文参考书籍:《Docker技术入门与实战》