Docker 作为一种轻量级的虚拟机技术,目前已经得到了广泛的应用。Docker 能够把你从繁琐的项目配置中拯救出来,并且提高项目的统一性,开发人员在开发好了项目之后,完全可以把项目打包成为一个 Docker 镜像,然后把其交给运维即可。

1. 安装 Docker

如果你是在 Ubuntu 上(需要 64 位操作系统),只需要一行命令就可以搞定

sudo apt-get install docker.io

此时可以运行以下命令来查看 Docker 的相关信息

docker info

在其它的操作系统上安装 Docker 可以参考官方文档

2. 理解容器

容器就是我们在 Docker 中运行服务的地方,一个宿主机上可以运行着多个容器,他们可以分别包含着不同的服务。

例如,我们现在运行着三个容器,分别运行了 MySQL、Tomcat 和 Nginx(不同的服务其实是可以运行在同一个容器中的,但是我们一般还是建议不同的服务应该运行在不同的容器中)这三个服务,那么我们就好像拥有了三台不同的物理机一样,这三台机器是相互独立的,你可以把其想象成三台运行着服务的真正的机器。Docker 提供了三台机器间互相通信的方式,但在这里我们不会做过多的涉及,因为这一次我们只会构建一个容器。

想要查看当前主机上运行着的容器,可以使用命令

docker ps

想要查看当前主机上所有(包括已停止)的容器,使用命令

docker ps -a

目前我们还启动任何容器,所以列表为空。

3. 理解镜像

上面已经讲到了容器的概念,镜像其实就是由容器生成的一种只读的文件。

打个比方,小 A 自己花了三个小时,手动构建了一个容器,小 A 感到很高兴。此时小 A 的同事小 B 也想要用小 A 的这个容器,该怎么办呢?此时小 A 可以通过以下命令把他自己构建的容器打包成为一个镜像

docker commit -m "Build a image" <容器ID> <镜像名称>

-m 就是构建镜像的时候提交的相关信息,这里的-m是可选项。容器 ID 就是容器的唯一的标识,在显示容器列表的时候可以查看到,而镜像名称就是你想给自己镜像所取的名字,这里镜像名字也是有一套规则的,但是本着简单起见,本文不做涉及,读者有兴趣可自行查阅。

Docker 提供了以下几种方式来获得/创建一个镜像:

  1. 直接从外部仓库中 pull 别人已经做好的镜像;
  2. 自己手动的构建好一个容器,然后然后把其 commit 为一个镜像(就是上面提到的那种方式);
  3. 通过 Dockerfile 来以文本的方式记录下你创建一个容器的过程,别人可以直接用这个文件来生成对应的镜像;
  4. 关于 docker-compose.yml,其作用就是对多个 Dockerfile 进行处理,即处理包含有多个镜像的过程;

其中方式 1 和方式 3 使用的较多,如果想要获取一个别人已经制作好的镜像,可选择方式 1,如果想要自定义一个镜像,一般选择方式 3。

4. 从外部仓库获取一个镜像

上面介绍了一点容器和镜像的基础知识,想必你已经能够大概的明白容器和镜像的概念了,下面我就来获取我们的第一个镜像,这里我们就以 Tomcat 镜像为例。执行以下命令

docker pull hub.c.163.com/public/tomcat:7.0.28
  • 关于中央仓库: Docker 中的中央仓库就是存放了大量的 Docker 镜像的地方,如果你用过 Maven 或者 Python 的 pip 命令,那么你对这种概念一定不会陌生,全球最大的中央仓库是 Docker 官方的docker hub。不过在这里我使用的是网易蜂巢的 Docker 镜像服务,其服务器在国内,速度也会更快一点。

上面的命令会执行一系列的下载操作,执行完毕之后,如果不出错,那么你已经获取到了一个 Tomcat 的镜像。此时执行命令

sudo docker images

将会列出所有的镜像列表,我的镜像列表如下所示

可以看到,这是一个从 163 仓库下载下来的镜像,并且他的名字是十分有规律的。至此,我们已经成功得从远程仓库获取了一个 Tomcat 镜像,下面我会讲如何启动这个镜像使其成为一个容器并运行。

关于 Dockerfile

Dockerfile 也是一种创建镜像的及其常用并且也是非常重要的方式,有些时候可能会是唯一的方式(比如在使用 Daocloud 服务的时候)。

我们可以手动书写一个 Dockerfile 文件,然后

  • 通过 EXPOSE 来开放镜像端口;
  • 通过 COPY 来复制宿主机文件到镜像中的指定位置;
  • 其他的一些命令;
  • 最后,根据 Dockerfile 文件创建一个名为image-name的镜像:docker build -t image-name .

关于 Dockerfile 的内容也非常多,在这里我们不会更多的涉及,有兴趣的读者可自行查阅相关资料学习。

5. 通过镜像来启动一个容器

通过上面的步骤,我们已经成功的拥有了一个 Tomcat 的镜像,接下来,是时候把他启动起来了。执行命令

docker run --name tomcat -d -p 80:8080 8e17306cf050
  • run 表示要通过一个镜像启动一个容器;
  • --name tomcat 是给这个启动的容器起了个名字,名字是 tomcat。如果不加此项,Docker 会自动给这个容器起一个名字;
  • -d 表示此容器会以守护进程(daemon)的方式来执行。如果想要以命令行的方式来执行,可以使用 -it 选项,并且需要在最后加上bash命令,即:
    docker run --name tomcat -it -p 80:8080 8e17306cf050 bash
    
    事实上,更加一般的做法是先以守护进程的方式启动容器,之后通过命令
    docker exec -it 8e17306cf050 bash
    
    来进入容器的bash,我比较推荐使用第二种做法
  • -p 80:8080 表示把当前宿主机的 80 端口映射到容器的 8080 端口;
  • 8e17306cf050 就是上面的 Tomcat 镜像的 ID,通过 docker images 可以查看到,表示我们想要启动的容器是对应于这个镜像的。

启动完毕后,在浏览器中打开http://127.0.0.1/,应该能够看到如下内容,表示容器已成功启动,并且对应的 Tomcat 服务已经在正常运行。

之后,执行以下命令显示所有正在运行的容器

docker ps

我们可以查看到正在运行的名称叫做 tomcat 的容器,并且可以查看到它的容器 ID。

为了后面的操作能够顺利进行,我们需要先执行 docker stop <容器ID>docker rm <容器ID> 来停止并删除这个容器。

如上图所示,在这里我们只能显示 Tomcat 的初始网页,怎么样才能让容器运行我们自己所写的代码呢?观察之前在浏览器中所所打开的页面,其中有一行

This is the default Tomcat home page. It can be found on the local filesystem at: /var/lib/tomcat7/webapps/ROOT/index.html

也就是说 /var/lib/tomcat7/webapps/ROOT/ 就是项目的根目录,我们只需要把自己的 Java 项目放到这个文件夹下就能执行我们自己的代码了。那么要怎么做?执行命令

docker run --name tomcat -d -p 80:8080 -v /home/derobukal/Desktop/html:/var/lib/tomcat7/webapps/ROOT/ 8e17306cf050 

这条启动容器的命令和上面的相比多了个 -v /home/derobukal/Desktop/html:/var/lib/tomcat7/webapps/ROOT/,表示把当前文件夹的 /home/derobukal/Desktop/html 目录(必须是绝对路径)挂载到 /var/lib/tomcat7/webapps/ROOT/ 上,此时对文件夹 html 的操作就相当于在操作容器中 tomcat 下的 ROOT 文件夹。我们在 html 文件夹下新建一个文件,命名为index.html,在之中输入hello, world,然后刷新浏览器页面,显示结果如下

至此我们已经可以成功的部署 Tomcat 应用了。

如果你需要重启 Tomcat,可以执行命令

docker restart <容器ID>

可以通过以下命令来删除一个 Docker 镜像

docker rmi <镜像ID>

总结:

在 Docker 中需要清晰的区分镜像和容器的概念,并且要明白他们所对应的操作有什么不同。如果能理解了他们之中的差异,那么也就能够快速的理解 Docker 的相关操作了。

本文只是对 Docker 进行了一个简单的介绍,想要了解更多关于 Docker 的内容,读者可以参阅 Docker 技术入门与实战 一书,这里介绍了关于 Docker 的大量细节,如果你想要更加深入的了解 Docker,那么你一定不能错过这本书籍。

参考:

  1. Docker简明教程
  2. 如何在docker中部署tomcat,并且部署java应用程序