docker五分钟入门

docker作为golang社区的杀手级应用,已经拥有越来越多的关注,其在GitHub上已经拥有4万多个star。尤其在当前各种大规模分布式服务器的环境下,传统的环境部署方式和各种库依赖,已经和当下快速开发快速上线产生了很大的矛盾。所以不管是开发、运维和测试人员,都应该尝试去使用docker来维护pre、online和test环境。 <!--more-->

原理

Java总是宣称“Write once,run anywhere”。简单地说,docker允许你安装、部署你的应用程序,而不用担心底层的依赖环境。docker屏蔽了不同操作系统的差异,而对上层提供统一的访问接口。比如你可以在centOS上编译好程序,而在Ubuntu系统上运行,实现了“Build once,run anywhere”。

这其中的原理就是docker提供了“层”的概念:从Linux kernel,到OS,再到依赖的库和应用程序,每一层都是独立的。不同的上层可以共享相同的底层,比如centOS镜像和Ubuntu镜像共享相同的kernel层,Nginx和Apache共享相同的OS层。这样也使得镜像的体积大大减少。

既然上层共享下层,那么问题来了:如果有两个上层A和B,都需要下层中S的某个文件f,且A和B需要的文件内容是不同的。这时候不论将f的内容设置为A所需要的或是B所需要的,都不能满足另一方的需求。docker的解决办法是在A和B的上层再增加一个空白层,将该层所需要的特定文件拷贝到该层并修改,且S层中的这个文件在运行时会被覆盖。这样,从A或B的角度看,文件被修改了,而从S的角度看,还是原来的初始文件,这就在满足上层需要的同时保证了下层的原始性。

具体到操作方面,docker主要有镜像、容器和仓库三部分,分别写一下。

镜像

简单地说,镜像就是一个应用程序完整的运行环境,它包含了该程序需要的所有依赖,如库文件、配置文件、运行环境等,只要有docker,该镜像就能运行起来,具有很好的跨平台型。 你可以通过以下命令列出当前主机上所有的镜像:

1
$ docker images

可以看到,输出共有五列,分别为repository,tag,image ID,create和size。

  • repository代表该镜像所属的仓库,<none>表示不属于某个仓库,这很可能是在本机生成的镜像,没命名,也没有被提交。以docker.io/kurento/kurento-media-server为例,表示这是docker官方仓库里kurento用户的kurento-media-server镜像。
  • tag可以用来标记一个镜像的版本,启动镜像时如果不写,默认为latest,即最新版。
  • image ID是通过SHA256 hash算法产生的,用来唯一标记一个镜像。一般对某个镜像操作的时候,只需要输入image ID的前两位或三位即可。
  • created代表改镜像的创建时间。
  • size是该镜像的大小。

创建一个镜像

和Makefile一样,docker也有自己的构建文件,称为Dockerfile。通过编写该文件,可以使用docker build .一键生成我们所需要的镜像。以下是一个示例:

1
2
3
4
5
6
FROM centOS
MAINTAINER smart
RUN yum update
RUN yum -y install git nodejs
RUN npm install -g hexo-cl

其中,FROM指定一个基础镜像。docker中每个镜像都必须指定一个基础镜像,然后在其上进行操作。本例中是centOS。MAINTAINER指定这个镜像的维护者,RUN 指定在构建镜像时所进行的操作。每RUN一次,docker都会提交为一个新的镜像,并删除当前镜像。

镜像相关操作

  • docker rmi $id可删除某个镜像,其中$iddocker images中列出的ID;

容器

镜像和容器的概念很容易被混淆。它们之间的关系就和程序和进程的关系一样。镜像只是一个实体,运行起来的镜像称之为容器。可以看出,同一个镜像按照不同的参数运行,就形成了多个不同的容器。docker run $name可以生成一个容器并运行,其中$name是镜像名。一般来说,在运行容器的时候我们需要给定不同的参数,如-i表示保留容器的输入输出,通常和-t参数同时指定,表示保留容器输入输出的同时新打开一个命令行终端;--name $name为容器指定一个名字,$name是我们新指定的容器名;-p 8080:80表示将本机上的8080端口和容器中的80端口绑定,这样就可以通过访问主机的8080端口来访问到容器的80端口了;-d表示将容器在后台运行;-v $lpwd:$rpwd:[rw|ro]表示将本机的$lpwd路径指定的文件或目录映射到容器中$rpwd指定的文件或目录,以实现数据的交换,其中$lpwd$rpwd都是绝对路径。rwro是可选的,表示容器中该路径是可读写的或只读的,默认为rw

容器相关操作

类似于Linux对进程的操作一样,docker使用ps命令来列出所有当前正在运行的容器;

  • docker ps -l列出最近运行过的一个容器;
  • docker ps -a则列出本机上的所有容器,包括已经退出的;
  • docker rm $cid可删除$cid指定的容器,前提是该容器已经处于exit状态;docker rm $(docker ps -aq)删除本机上所有容器;
  • docker start $cname重新运行以前运行过的某个容器,$cname指定容器名称,同理,docker stop $cname停止某个正在运行的容器;
  • docker attach $cname附着到某个后台运行的容器上;

仓库

类似于GitHub,docker也有自己的官方仓库。其中存储了许多基础镜像和应用镜像,如centOS,Ubuntu,Nginx,WordPress等,也有民间人士自己制作的镜像。

每个免费账户可以创建一个private仓库和多个public仓库。可以利用docker push $iname将自己本地的镜像推送到远程仓库,也可以docker pull $iname去远端仓库拉取一个镜像。push的前提是需要先通过docker login登录,pull不用。

docker search $key可以搜索远端仓库,$key是关键字,包含该关键字的镜像都会被搜索出来,结果包含每个镜像的index,name,description,starts,official,automated,分别表示该镜像的索引,名称,描述,点赞数,是否为官方的,是否自动化构建的。