容器是一个用于构建、分发、运行分布式应用的开源平台。容器化的应用可以在开发者的电脑上运行,并能够被部署到生产的云环境中,容器正以前所未有的方式在持续集成和持续部署中发挥着巨大作用。希云认为:在未来的工作中,容器这个平台是每个开发者都应该熟悉的。

开源 Java项目把容器带给 Java 开发者,后面会解释为什么容器对 Java 开发者那么重要,引导大家在容器中安装并部署 Java 应用,并让大家看到如何把容器集成到构建流程中。

容器快速指南

容器有它自己的术语,这些术语会在本文中反复用到,请先花一些时间去熟悉它们:容器引擎( Docker engine ):在服务器上的一个守护进程,它是你和容器应用与所依赖的操作系统的桥梁。

Dockerfile: 一个文本文件,内容是用于构建容器镜像的指令。

镜像: 构建一个 Dockerfile 的产物,构建过程中执行 Dockerfile 中的命令,会生成一个镜像。它首先会基于一个根系统(基础镜像)构建,然后安装应用,接着执行一系列命令来准备启动应用的环境。 Docker 镜像作为容器的基础,相当于容器的一个静态模块。

容器: 一个 Docker 镜像的运行时实例, Docker 镜像类似于模块的概念(从 Dockerfile 构建,这个 Dockerfile 包含了根系统,应用以及一系列构建镜像的命令),容器是那个镜像的一个实际能运行的实例。

宿主 : 一个物理机或者虚拟机,在此系统上运行着容器引擎,维持着容器所依赖的 Dockerhub 。

DockerHub : 官方的 Docker 镜像仓库,把 DockerHub 想象为 GitHub 仓库,对于 Git 来说是中央仓库, DockerHub 是官方保存及提供 Docker 镜像的中央仓库。

cSphereHub: 希云官方的 Docker 微镜像仓库, DockerHub 中有非常多的镜像,但 cSphereHub 中存放了精心挑选出来的,并精心制作的镜像。

Docker 简介

在二十多年前,软件应用曾经是非常庞大并且复杂的,会被部署在大型的计算机上。在 Java 的世界里边,我们开发的企业软件包( EAR )中,包含企业 JavaBean( EJB ) 和 web 组件( WAR ),然后会部署在大型应用服务器上。为了能尽量有效地利用这些大型计算机上的资源,我们会尽最大能力去设计这些应用。

在 21 世纪早期,随着云计算的出现,开发者们开始使用虚拟机以及服务器集群,去扩展应用以满足需求。要以虚拟化的方式部署应用,应用必须被设计得与传统方式有所不同,轻量级,面向对象的应用成为新标准。我们学会了把软件做成各种能互联的服务集合,将各组件尽可能地设计成无状态。可扩展架构的概念和实现都发生了变化,不再是依赖于单台大型计算机的垂直扩展,开发者和架构师开始思考以水平扩展方式实现:如何把单个应用部署到数个轻量级的计算机上。

容器的出现使虚拟化更向前迈进了一步,提供了一个轻量级的层,处于应用和所依赖的硬件中间,容器把应用当作是宿主系统的一个进程来运行。图一对比了传统虚拟机和容器。

图1 虚拟机与容器的比较

传统的虚拟机会在宿主系统运行着一个虚拟机监视器,并在虚拟机中运行着一个完整的客户系统( GuestOS ),应用依赖的所有包都在客户系统中。

相反地, 容器有个容器引擎,也是一个运行在宿主系统的守护进程。容器引擎把容器中的系统调用,翻译成宿主系统的原生调用。一个 Docker 镜像,作为容器的创建模板,只是包含了操作系统的最小层,以及仅仅是应用所需要的依赖库。

大家看起来感觉这些差异似乎不大,但实际上却是天壤之别。容器的优势很大一部分都是在这点体现出来的!

理解进程虚拟化

我们仔细分析一下虚拟机中的操作系统,我们会留意到虚拟机中的资源,例如 CPU 和内存。但当我们运行一个容器,我们会直接看到宿主机上的资源。我把容器看成是进程级的虚拟化平台,而不是系统级的虚拟化平台。基本上,应用是作为一个独立的自包含进程运行在宿主机上,容器通过借助着 Linux 上几个强大的组件,实现了隔离性,确保了每个进程都是操作系统上的独立进程。

因为容器化的应用与宿主机上的进程运行方式类似,所以设计上也和虚拟机中的应用不同。举个例子说,我们通常会在一个虚拟机上运行 Tomcat 和 MySQL 数据库,但容器的实践中,我们会把 app 服务器与数据库分别部署,各自运行在不同的容器中。这样让容器更好地管理宿主系统上的独立单元,这意味着要更有效率地使用容器,我们需要以适当的粒度设计应用,例如微服务的方式。

Docker 中的微服务

简单来说,微服务是一种可以促进系统模块化的架构方式。在微服务架构中,复杂的应用以更小的独立进程组成,各个进程有一个或多个特定的功能,应用与语言无关的API和其他进程通信。

微服务是通过粒度非常小,高度解耦的服务集合,来提供单一或多个相关联的功能。例如,如果你正在管理着一个用户中心和购物车,那你很可能是选择把它们设计成独立的服务,如用户中心服务和购物车服务;而不是把两个模块打成一个包作为一个服务运行。更具体来说,使用微服务意味着构建 web services,而且是最常见的 RESTful web service ,并把它们按功能分组。在 Java 中,我们会把这些服务打成 WAR 包,并部署到一个容器中,例如 Tomcat,然后运行 Tomcat 和容器中的服务。

安装容器

在我们深入研究容器之前,先让我们把本地环境搭建起来。如果你正在使用 Linux 系统,那非常好,你可以直接安装并运行容器。对于那些使用 Windows 或者 Mac 的用户来说,容器可以通过一个叫 Docker Toolbox 的工具来使用,这个工具会安装一个虚拟机(使用 Oracle 的 Virtual Box ),这个虚拟机中会运行着包含容器守护进程的 Linux 系统。我们可以使用容器客户端把指令发送给守护进程处理,注意,你不需要管理这个虚拟机,只要安装这个工具并执行容器命令行工具即可。

开始从 Mac, Windows,或 Linux 相应的文档里下载 Docker。

我的电脑是 Mac,所以我下载并运行了 Mac 版的 Docker Toolbox 安装包,之后我运行了 Docker Quickstart 终端,这样会启动一个 Virtual Box 镜像和一个命令行终端。这个安装过程与 Windows 下的基本相同,更多请参考 Windows 版的文档。

DockerHub: Docker的镜像仓库

我们开始使用容器之前,先花几分钟去访问一下 cSphereHub ,这个镜像仓库。浏览一下 cSphereHub ,你会发现上边有数个镜像,精挑细选的微镜像。如果使用 cSphere 管理平台,添加微镜像仓库后,仓库里面包含了 docker 官方的一些镜像。镜像仓库中有基础系统,如 Alpine、 Ubuntu,或者 Java 相关的如 Tomcat、 jdk、 jre 等等。你还可以发现几乎所有流行的应用上边都会有,包括 MySQL、 MongoDB、 Neo4j、 Redis、 Memcached、 Postgres、 Nginx、 Node.js、 WordPress、 PHP、 Perl、 Ruby 等等。在你打算自行构建一个新镜像之前,请确认 cSphereHub 或者 DockerHub 上有没有。

作为一个练习,我们运行一个简单的 CentOS 镜像,在 Docker Toolbox 的命令行中输入:

sh $ docker run -it centos

这个容器命令是你与Docker守护进程的主要接口。run 指令告诉容器去下载并运行指定的镜像(假设在本地还没有这个镜像)。又或者,你可以用 pull 命令直接下载一个镜像但不运行它。有两个参数:i 会让Docker用交互模式运行,t 会让它创建一个TTY终端。注意非官方的镜像使用既定的格式"用户名/镜像名",而官方的镜像会省略用户名,所以我们只需要指定"centos"来运行镜像即可。另外,也可以在镜像名后加“:版本号”指定版本号,例如,centos:7。每个镜像默认使用的都是最新版本,当前CentOS最新版本号是7.

在运行$ docker run -it centos 之后,你会见到Docker开始下载这个镜像,完成后会见到类似以下的输出:

sh $ docker run -it centos

[root@dcd69de89aad /]#

因为我们用了交互模式去运行,它显示了一个 root 用户的 shell 命令提示符。查看一下这个系统,然后使用exit退出。

可以用docker images命令来查看系统中已下载好的镜像:

sh $ docker images

REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE

java 8 5282faca75e8 4 weeks ago 817.6 MB

tomcat latest 71093fb71661 8 weeks ago 347.7 MB

centos latest 7322fbe74aa5 11 weeks ago 172.2 MB

你可以看到我已经有了最新版的CentOS、Tomcat 和 Java 8。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐