说在前面

公司这边这周轮到我做技术汇报,前段时间一直在折腾docker的相关操作,所以打算讲讲docker的相关知识。

Docker之前存在的问题

相信做过项目的大家都会遇到这样子的一种情况,软件开发的过程中,抛去刚开始的分析步骤以及开发流程,当软件开发完毕之后,这个时候需要将软件部署到对应的生产环境中,与之相对应的还有:开发环境、测试环境等,这些环境的配置部署都是完全一致的(仅仅只是配置不同)。 拿西瓜课表云端(此处仅指属于我开发的部分——Android客户端的检查更新以及数据统计部分)举例来说:每一次修改了代码,我需要在本地的IDE进行打包( ./gradlew clean build ),然后找到build目录下的 libs 目录中打包完成的jar包,然后将这个jar通过 scp 上传到对应的生产环境的服务器,再ssh到该服务器,执行 java -jar xxx.jar。而且当需要与Android端做联调的时候,整个的 build-package-upload-stop-run 的流程都会显得格外的繁琐。甚至还可能会出现其他问题:生产环境没安装jdk、某些依赖没有安装、环境变量没有配置等等。 因此需要一种能够将运行环境与软件一起打包带走的解决方案。

为什么不用虚拟机

虚拟机就是一种运行环境与软件打包带走的一种解决方案,我们只需要拿到镜像文件,然后将对应的虚拟机添加到 VMWare 或者 Vitual Box ,之后只需要简单的 开机 即可。当然,需要等那么一段时间。 玩过虚拟机的都清楚,虚拟机的运行需要先启动一个操作系统,然后才能启动里面的软件,而且虚拟机占用的资源甚至可能比我们运行的软件还大。此外,系统启动的必须步骤:登录无法绕过,而且启动虚拟机是真的~慢~~~~

Docker

由于虚拟机的缺点,所以Linux发展出了Linux容器。 Docker即是Linux容器的一种封装。将软件以及运行环境打包进一个镜像文件中,通过分发这个镜像文件,可以自动大量的机器时候进行快速的部署。

Docker的基本概念

Docker镜像(Image)

Docker镜像可以理解为Java的 类 ,镜像中包含了需要运行的软件以及这个软件需要的运行环境。Docker镜像可以用来创建容器,容器可以理解为镜像运行时的实例,也就是 对象 。 同编程语言一样,这个镜像是可以 继承 的,我们可以在一个镜像的基础进行简单的修改或者扩展,创建一个新的镜像。一般我们都是提供需要运行的软件,然后使用别人做好的镜像,创建一个新的运行镜像,这样我们能够剩下很多重复的环境配置步骤。

Docker容器(Container)

容器是通过镜像创建的运行时实例,它可以被启动、开始、停止、删除。容器之间是相互隔离的。容器本身也是一个文件,默认情况下,停止一个容器不会自动删除该文件,这样子可以在下一次直接启动该容器而不是创建一个新的容器。

Docker注册服务器(Registry)

正如其名,Docker仓库是用来存储多个Docker镜像的仓库,我们可以将这个仓库放到公共网络上,这样其他人可以通过公共网络拉去仓库中的Docker镜像。Docker Hub是Docker官方提供的注册服务器。

Docker仓库

和Docker Registry不同,Docker仓库指的是同一类型的镜像的仓库。 一个Registry可以有多个Docker仓库,一个Docker仓库有多个Docker镜像,但是一个Docker仓库中只能有同一类型的Docker镜像,同一类型指的是名字相同。比如: hello-world:1.0 和 hello-world:2.0 属于同一个Docker仓库,和 helloworld:1.0 不属于同一个仓库。而 : 后面的版本号称为标签(tag),默认标签是 latest。

Dockerfile

上面的概念了解了之后,我们就会想问,Docker镜像是如何制作出来的?这就需要编写Dockerfile。Dockerfile是一个文件,里面定义了镜像的配置。 Dockerfile示例:

#This is a Dockerfile
#Author:liming
#第一行必须指定基础镜像
FROM ubuntu
#维护者信息
MAINTAINER <[email protected]>
#镜像的操作指令
RUN echo "Hello World"
#容器启动时的指令
CMD /usr/sbin/nginx
  • FROM Dockerfile的第一条指令必须是FROM指令,用于指定基础镜像,也就是我们前面所提到的 父类。
  • MAINTAINER 指定维护者的信息。
  • RUN 自动shell终端执行的命令。
  • EXPOSE 暴露的端口号,启动时可以通过 -p-P 进行端口绑定。
  • ENV 指定一个环境变量,可以被后续的RUN命令使用。容器内部也可以使用环境变量。
  • ADD 复制指定的文件到容器中,可以是一个路径、一个tar文件或者url。
  • VOLUME 挂载目录到容器中,一般用于存储需要持久化存储的数据。
  • USER 指定运行容器时的用户名,后续的RUN也会使用该用户名。
  • WORKDIR 执行工作空间,可以理解为 cd
  • COPY 复制本地目录的文件到容器中。当ADD的文件是本地文件时,推荐使用COPY命令。
  • CMD 指定容器的启动命令,只能有一条CMD命令,用户启动容器时如果指定运行命令,那么会覆盖Dockerfile中的CMD命令。
  • ENTRYPOINT 指定容器启动后的命令,同CMD一样,只能有一条,多条时只会执行最后一条。

在Dockerfile所在目录,通过 docker build -t "${tag}" 命令即可构建属于自己的Docker镜像,Docker会根据Dockerfile指定的命令进行构建。 值得注意的一点是:Dockerfile会根据上一个命令的执行结果生成一个镜像,然后继续执行下一个命令。 这样就能将Docker镜像的构建过程缓存起来,方便下一次执行的时候重复使用。因此,为了有效的利用缓存,需要保持Dockerfile一致,并且尽量在末尾进行修改。 在Dockerfile中可以通过EXPOSE指定暴露的端口,也可以在此处进行端口的映射,但是不推荐这样指定。

关于Dockerfile的配置,推荐阅读一下两篇文章: Dockerfile最佳实践(一)

Dockerfile最佳实践(二)

安装

安装步骤应该都被各位写烂了,所以在这里就不重复写了,可以参考官方的文档进行安装(官方的才是最好的)。

参考链接

Docker 入门教程

跟我一起学docker(二)–核心概念和安装

跟我一起学docker(八)–Dockerfile