Docker容器及Spring Boot微服务应用
1 什么是Docker
1.1 Docker的出现
- 问题一:项目实施环境复杂问题
传统项目实施过程中经常会出现“程序在我这跑得好好的,在你那怎么就不行呢?! ”
这是一个典型的应用场景,Docker image中包含了程序需要的所有的运行时依赖,比如java的程序,肯定要在image中包含jdk;比如Python的程序,肯定要在image中包含对应版本的Python解释器。Docker把整个运行时环境打包放到image中,所以搞定了环境依赖问题!
Docker解决了运行环境和配置问题,方便发布,也就方便做持续集成。
- 问题二:系统多用户的资源隔离问题
Linux本身就是个多租户的操作系统,可以多人共用,但是如果某个程序狂吃内存和CPU,占用了太多系统资源,这就会影响其他程序的运行。
所以虚拟机出现了,做了良好的资源隔离,不同用户之间不会相互影响。但是,虚拟机有缺点:创建速度慢,迁移起来麻烦,因为中间加了一层guest os,有了性能损耗,很牛的物理机也就创建几十个虚拟机,太浪费了……
相对虚拟机的重量级虚拟化方案, Docker出现了,让虚拟化变得轻量了起来,创建一个container瞬间完成,秒级!
Docker是更轻量的虚拟化,节省了虚拟机的性能损耗。
1.2 Docker概述
Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。Docker 的基础是 Linux 容器(LXC-Linux Container)等技术。
在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。
下面的图片比较了 Docker 和传统虚拟化方式的不同之处,可见容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。
(每个虚拟机都将拥有自己的操作系统以及应用程序必须的运行时环境)
(多个容器公用宿主机操作系统,每个容器拥有独立的应用程序运行时环境)
1.3 Docker的优势
Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
具体说来,Docker 在如下几个方面具有较大的优势。
- 更快速的交付和部署
对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。
- 更高效的虚拟化
Docker 容器的运行不需要额外的 hypervisor(虚拟化管理程序)支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。
- 更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。
特性 |
容器(Docker) |
虚拟机(VM) |
启动 |
秒级 |
分钟级 |
硬盘使用 |
MB级 |
GB级 |
性能 |
接近原生 |
弱于 |
系统支持量 |
单机支持上千个容器 |
单机支持几十个 |
1.4 Docker的局限
Docker并不是全能的,设计之初也不是KVM之类虚拟化手段的替代品,简单总结几点:
- Docker是基于Linux 64bit的,无法在windows/unix或32bit的linux环境下使用
- LXC是基于linux kernel的,因此container的guest系统只能是linux base的
- 隔离性比KVM虚拟化方案还是有些欠缺,所有container公用一部分的运行库
- 网络管理相对简单,主要是基于namespace隔离
- cgroup的cpu功能相比KVM的等虚拟化方案相比难以度量
- docker对disk的管理比较有限
- container随着用户进程的停止而销毁,container中的log等用户数据不便收集
1-2,有windows base应用的是不能使用Docker的
3-5主要是看用户的需求,到底是需要一个container还是一个VM, 同时也决定了docker作为 IaaS 不太可行
6-7虽然是docker本身不支持的功能,但是可以通过其他手段解决(disk quota, mount --bind)。总之,选用container还是vm, 就是在隔离性和资源复用性上做权衡
1.5 Docker VS VM
- 传统虚拟化中分为两个类型
Type-1型是指在服务器的硬件平台上先部署虚拟机管理层(Hypervisor),再在Hypervisor之上生成虚拟机,每个虚拟机再安装操作系统、运行库与相关的应用.Type-1虚拟化比较常见的是VMware的vSphere、微软的Hyper-V、Linux的KVM以及Xen.
Type-2型则在裸机之上先安装操作系统(比如Linux或Windows),再安装Hypervisor。Type-2的典型代表是VMware的Workstation以及Oracle的VirtualBOX。
由于Type-1型Hypervisor更接近硬件底层,所以可以降低更多的系统开销,但就Hypervisor本身来说,仍然要有一层基本的OS“垫底”,这也是其仍然会有系统开销的原因。
而对于容器技术来说,由于本身就源于操作系统的内核(Linux Kernel),所以也就基本不存在Hypervisor所带来的开销
- 容器虚拟化技术
与传统的服务器虚拟化相比,Docker的一重要特点就是在实现应用间隔离的同时,没有了对于传统虚拟化来说是必须的Hypervisor虚拟化管理层,因为从本质上来讲Docker的内核与Linux是一体的。Docker的根基——LXC就是一个将Linux运行时、库以及其他软件运行支撑环境与相关应用进行封闭的技术。从Linux的内核来看,LXC就相当于系统的一个本地进程,实质上与一个裸机(无虚拟化)应用没有什么区别,从而无需额外的虚拟化指令以及相应的系统虚拟化开销。因为在传统的虚拟化平台中,无论Hypervisor做得再轻薄,虚拟机都要先经过本地的OS再透过Hypervisor调用服务器的物理硬件资源,这与直接以系统进程出现的LXC相比,肯定会造成额外的性能影响。
1.6 Docker生命体系
从Docker的应用封装架构中,可以看出其最基础的运行内核与底层镜像就源于Linux的内核,用户可以将利用Dockerfile生成好的应用镜像,上传至远端的Docker Registry(比如Docker公司自己运营的云服务,或是私建的Docker Registry),也可以从Docker Registry里下拉一个别人已经建立好的镜像直接投入到容器中进行运行,相比之下Docker显然带给了LXC更灵活的部署与快速应变的能力
在Docker体系中,最关键的就是两个——Docker Registry(通过Docker Hub进行索引)以及Docker Engine,前者在远端(或称云端)负责收集与分发Docker的应用镜像(Images),后者则在客户端负责构建Docker应用容器,这明显就是一个云服务的AAS理念,当然用户也可以在自己的数据中心内部建立私有的Docker Registry,以方便在私有云内迅速生成自己的Docker集群,以应对灵活的、大规模的应用扩展需求。此时,也相当于在企业数据中心内部形成了一个云+端的Docker架构。
Docker在英语里的意思为“码头工人”,而其Logo就好似一艘酷似鲸鱼的大船运送一堆集装箱前往各地的码头。而从其理论上看,Docker就像是一个集装箱,利用LXC技术来整合不同规模、类型、层级的应用镜像,先通过集中汇总再有序的分发——每个码头就是一台服务器(或VM),大船就是Registry,码头的工人就是核心Engine,进行集装箱的装配,当然它还需要一系列的外围的支持(比如最重要的管理)。但从总体的 场景来说,Docker的名字还是非常贴切的。
1.7 Docker 关键字解析
Docker Image:
Docker image是一个只读模板,用于创建Docker容器。Image中可以包含linux操作系统、Apache或者Web应用程序等等,用户可以下载已经创建好的Docker image,也可以创建Docker image给其他用户使用。每个image是由很多层组成,Docker通过Union File Systems将这些层绑定在一个image中。每个image都以一个初级image做为基础,然后通过操作指令在这些初级image上添加新层,操作指令可以是运行的命令、添加文件或目录或者创建可用操作环境等。这些操作指令都被保存在“Dockerfile”文件中。
Docker Container:
Docker image的运行实例。Docker Containers可以运行、启动、停止或者被删除,每个container都是隔离的安全应用平台。
Docker registries:
Docker registries用于保存Docker image,也分公用和私用二种。公用的Docker registry就是Docker Hub,用户也可以创建私有的Docker registry,为其他用户提供Docker images下载。
Dockerfiles:
Dockerfile是对Docker Container创建过程的描述脚本。每个Dockerfile详细说明了开始的基础镜像,以及随后一系列在容器中运行的命令和添加到容器中的文件。Dockerfile也可以说明容器对外的端口,启动时的工作目录和缺省执行的命令。
LXC:(Linux Container)
Linux Container容器是一种内核虚拟化技术,可以提供轻量级的虚拟化,以便隔离进程和资源,而且不需要提供指令解释机制以及全虚拟化的其他复杂性。相当于C++中的NameSpace。容器有效地将由单个操作系统管理的资源划分到孤立的组中,以更好地在孤立的组之间平衡有冲突的资源使用需求。
VM:(Virtual Machines)
指通过软件模拟的具有完整硬件系统功能的、运行在一个完全隔离环境中的完整计算机系统。
Host OS:
指物理存在的计算机上运行的操作系统。宿主机操作系统。
Guest OS:
指运行在VM上的操作系统。例如在一台安装了Windows NT的计算机上安装了Vmware,那么,HOST指的是安装Windows NT的这台计算机,其Host′s OS为Windows NT。VM上运行的是Linux,那么Linux即为Guest OS。
Hypervisor:
Hypervisor是一种运行在物理服务器和操作系统之间的中间软件层,可允许多个操作系统和应用共享一套基础物理硬件,因此也可以看作是虚拟环境中的“元”操作系统,它可以协调访问服务器上的所有物理设备和虚拟机,也叫虚拟机监视器。当服务器启动并执行Hypervisor时,它会给每一台虚拟机分配适量的内存、CPU、网络和磁盘,并加载所有虚拟机的客户操作系统。
目前市场主要厂商及产品:VMware vSphere、微软Hyper-V、Citrix XenServer 、IBM PowerVM、Red Hat Enterprise Virtulization、Huawei FusionSphere、开源的KVM、Xen、VirtualBSD等。
Bootfs:(Boot File System)
主要包含 bootloader 和 kernel, bootloader主要是引导加载kernel, 当boot成功后 kernel 被加载到内存中后 bootfs就被卸载了.
Rootfx:(Root File System)
rootfs包含的就是典型 Linux 系统中的 /dev(外设访问接口信息),/proc(系统设备信息),/bin(系统工具集), /etc(APP配置信息) 等标准目录和文件。对于不同的linux发行版, bootfs基本是一致的, 但rootfs会有差别, 因此不同的发行版可以公用bootfs。
2 Docker及微服务架构
2.1 微服务概念
微服务架构风格是一种使用一套小服务来开发单个应用的方式途径,每个服务运行在自己的进程中,通过轻量的通讯机制联系,经常是基于HTTP资源API,这些服务基于业务能力构建,能够通过自动化部署方式独立部署,这些服务自己有一些小型集中化管理,可以是使用不同的编程语言编写,正如不同的数据存储技术一样。
2.2 基于Docker的微服务架构
Docker的细粒度松耦合能够让我们用一个Docker容器装载一个场景功能,也就是按照功能角色分类,每个Docker里面装一个服务或应用,一个服务器上可以运行多个Docker,或者多个Docker分散到多个服务器上运行。整个项目架构可以按照业务逻辑的规划以细粒度的方式分散在各个Docker容器中,并根据HTTP REST API的方式进行整合联动。
(Docker为基础的微服务架构)
本图由上到下分别由:Nginx负载均衡层,综合业务服务层,单业务服务层,数据库层等共同组成Docker为基础的微服务架构。图中每个服务节点均装载入单独的Docker Container中运行,并对外暴露基于Http协议的Port供外界访问(数据库容器仍然是基于JDBC的数据库连接池方式对其访问)。
- 负载均衡及反向代理层:可采用Nginx作为负载均衡及反向代理服务器,并且作为静态资源(HTML,图像文件,JS/CSS等静态资源)访问的服务器。Nginx的反向代理配置功能强大,可以根据用户访问路径或访问的服务资源进行路由转发,将用户的请求映射到其下的综合业务服务层对应的REST API接口中。
- 综合业务服务层:综合业务服务层是根据项目具体业务需求划分的多个单业务服务节点的整合。对访问者提供一组综合性业务逻辑REST API接口。其特点是只通过HTTP REST API方式调用其下的单业务服务层接口,而不与数据库通信。
- 单业务服务层:单业务服务层中每个服务节点都是对业务逻辑相对独立,功能相对集中一组REST API的封装。其特点是业务功能相对独立,与其他兄弟节点的功能耦合度低,并直接访问其下的数据库存储层。
- 数据库存储层:以Docker Contain为单位的数据存储层。
此框架实现重点为,在项目前期通过详细的功能需求分析并按业务逻辑的耦合度划分成多个服务节点,依靠Docker的独立且低耦合特性在物理层面上实现项目的细粒度分解。
其优点是:
- 1.可以根据用户的访问并发量在每个层次进行水平动态扩充,实现访问压力负载均衡。
- 2.对业务逻辑的多层次划分可很大程度上提高项目的复用性。
- 3.一旦将业务抽象成产品后,即可实现“用户按功能选购”的能力。
- 4.由于Docker的开发环境封装特性,可以简化项目部署成本,减少运维人员工作负担。
- 5.由于服务节点采用HTTP REST API的通讯方式,节点的实现可以采用不同运行时环境不同语言不同架构,比如可采用Spring,Play等多种架构方式。
缺点为,在项目设计前期,需要花费较多的时间进行详细的业务逻辑划分及系统分析。
接下来,我们将实现该架构图中的每个Docker节点的关键技术。
3 Docker 与 Spring Boot
3.1 Spring Boot 简介
Spring Boot充分利用了JavaConfig的配置模式以及“约定优于配置”的理念,能够极大的简化基于Spring MVC的Web应用和REST服务开发。
Spring 4倡导微服务的架构,微服务架构倡导将功能拆分到离散的服务中,独立地进行部署,Spring Boot能够很方便地将应用打包成独立可运行的JAR包,因此在开发模式上很契合这一理念。
特点:
• 创建独立Spring应用程序
• 嵌入式Tomcat,Jetty容器,无需部署WAR包
• 简化Maven及Gradle配置
• 尽可能的自动化配置Spring
• 直接植入产品环境下的实用功能,比如度量指标、健康检查及扩展配置等
• 无需代码生成及XML配置
3.2 Spring Boot在Docker中运行
在Eclipse中利用Maven的Spring boot+Docker模板搭建项目框架,实现步骤:
1.下载Eclipse的Maven插件。
2.在Eclipse中选择SpringBoot-Docker模板。
3.创建SpringBoot-Docker项目
基于该模板创建SpringBoot项目后,目录结构如上图,编译后会生成Dockerfile文件及<项目名>.jar文件。
4.在Docker环境下生成Docker Image镜像文件
由于已经有了Dockerfile文件及本项目的.jar文件,可以将其拷贝到虚拟机Docker环境中,并运行例如:docker build -t <example-service> . 指令,将Dockerfile描述编译成镜像文件,并进入本地Docker registries仓库中。
5.运行Docker Image文件,形成Container实例,与宿主机建立端口映射。
运行例如:docker run -p 48080:8080 -d <example-service> 指令,启动该项目的Container实例。
6.在浏览器上访问宿主机的48080端口,通过REST API访问业务接口。
至此,基于Docker Container的Spring boot项目启动完毕,并可在浏览器中访问。
4 Docker与Nginx
4.1 Nginx简介
Nginx ("engine x") 是一个高性能的 HTTP 和 反向代理 服务器,也是一个 IMAP/POP3/SMTP 代理服务器。
在高连接并发的情况下,Nginx能够支持高达 50,000 个并发连接数的响应。Nginx也可作为负载均衡服务器,Nginx 既可以在内部直接支持 Rails 和 PHP 程序对外进行服务,也可以支持作为 HTTP代理服务器对外进行服务。Nginx采用C进行编写,不论是系统资源开销还是CPU使用效率都比 Perlbal 要好很多。
Nginx 是一个安装非常的简单,配置文件非常简洁(还能够支持perl语法),Bugs非常少的服务器:Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够不间断服务的情况下进行软件版本的升级。
4.2 Nginx在Docker中运行
1.先访问hub.docker.com下载Nginx的Docker Image
可在虚机中的Docker环境中使用指令例如:docker pull nginx下载镜像文件。
2.查看该镜像文件
可使用docker images指令查看下载后的nginx镜像文件状态。
3.建立nginx反向代理映射及动静资源分离映射
4.启动Nginx服务
可使用如下指令例如:
docker run -d -p 8080:8080 -v /some-path/nginx.conf:/etc/nginx/nginx.conf:ro <nginx-container> 启动nginx代理服务。
至此,基于Docker的Nginx与Spring Boot反向代理架构搭建完毕。
5 Docker 与PostgreSQL
5.1 PostgreSQL在Docker中运行
1.在Docker hub中下载Postgre Image镜像文件
可以使用tag指令有针对性下载指定版本的镜像文件。例如:
docker pull postgres:9.4.4
2.运行Postgres Container实例
例如使用指令:
docker run -p 5432:5432 -e POSTGRES_PASSWORD=654321 -d <example-name>
3.确认Spring Boot项目中的数据库连接配置是否正确
至此,微服务架构图中所有层次节点均在Docker容器中部署完毕。
作者自述:
本人从事十六年WINDOWS应用/游戏/设备/WEB开发,目前从事Linux,Docker及CAAS云平台架构设计及开发。
基于全球开源共享理念,本人会分享更多原创及译文,让更多的IT人从中受益,与大家一起进步!
基因Cloud 原创,转发请注明出处
1738387@qq.com (工作繁忙,有事发邮件,QQ不加,非要事勿扰,多谢!)
2015年6月2日