写点什么

使用 Spring Boot 和 Docker 构建微服务架构(二)

用户头像
MaxHu
关注
发布于: 2020 年 05 月 25 日
使用Spring Boot和Docker构建微服务架构(二)

【编者的话】 这篇也是我多年前发表在 DockOne 社区的文章,对微服务架构以及容器化概念作一个概述,利用工具进行设置,深入探讨如何使用 Docker 工作,然后搭建我们的第一个容器,接着构建一个 Employee 微服务,并将添加一些额外的服务/容器,并且更新容器,采用 Docker Compose 以及使用 HAProxy 容器进行负载均衡。现在回顾这篇处于微服务及容器技术洪荒时代的文章,还是挺有意思的,现在从故纸堆里拿出来给大家作为参考吧,由于文章比较长,所以分为四篇来讲,本篇是第二篇。


第二篇 设置和开始


介绍和工具

在本篇中,我们将会构建第一篇中讨论的解决方案。我是在 Mac 上工作的,但是工具在 Mac 和 PC 上是相同的,所以在平台上的操作是 99%相同的,我将不会回顾如何安装这些工具,而是直接从如何使用它们开始,你所需要的准备工作如下:

  • Docker Toolbox:包含了 VirtualBox(作用为创建虚拟机用来运行容器)、Docker Machine(在虚拟机内运行 Docker 容器)、Docker Kitematic(一个管理在 Docker Machine 里运行的容器的 GUI)以及 Docker Compose(多容器编排工具)

  • Git:我在 Windows 上使用 Git Extensions,在 Mac 上使用 Source Tree,不过使用其他 Git 客户端包括命令行都是可以的。

  • Java 8 SDK:Java 8 在 JVM 永久代(PermGen)方面有了改进,另外对于 Streams API 和 Lambda 的支持也是非常赞的。

  • 构建工具的选择:让我们使用 Gradle 吧,我推荐使用SDKMan,正式名称为 GVM 来管理 Gradle 版本,如果你使用 Windows 工作,你可以使用 Cygwin 安装 SDKMan 或者 SDKMan 的 Powershell 命令行工具,或者Gravy也是可替代的选择。

  • IDE 的选择:我们使用Spring Tool Suite(STS)来工作,在本文写作时最新的 for Mac 版本为 3.7.0。

  • Rest 工具:对于任何 Web 服务项目使用都非常方便,我是 Chrome 扩展工具Postman的粉丝,如果你擅长 curl 命令行,这个工具也是不错的。

  • uMongo 或者 Mongo GUI:文档型数据库完美匹配自足性的模型——对象进行自动检索,并且参考对象可以在微服务架构中通过 ID 来引用,这些 ID 可以很好地映射到文档存储中,另外地,MongoDB 拥有运行很棒的“官方”Docker 镜像。


我们对于源代码管理的第一个意见——似乎也是绝大多数的在线观点,就是每个微服务都应该有自己的版本库。微服务的一个基本理念就是跨服务之间不能共享代码。就我个人而言,这对我架构师的小心脏是个小小的打击,因为任何实用工具的重复代码的数量可能会比较多,以及缺乏一个单一、统一的领域模型给我有点心痛的感觉。我理解这个原则——自足性意味着自力更生。为了这篇博文,我把所有的代码都放到了一个单独的代码库,然而,每个微服务在根目录下都有它一个自己的目录。这样做是为了让我可以随着时间的推移展示分支的进展。在一个真实的解决方案中,你应该让每一个微服务都有它自己的不同的版本库,也许会有统一的版本库引用其它的子模块。


总体思路

因为我们要处理隔离的、可重用的组件,我们将做以下的映射:

一个逻辑业务对象→一个微服务→一个 Git 版本库目录→一个 Mongo 集合

因为业务对象可能由多个对象组成,任何我们认为可以作为其自身业务对象的子对象都可以划分为其自身的组件栈。


更多有关 Docker 如何工作的信息,以及我们的第一个容器

为了理解如何构建一个完整的基于 Docker 容器的产品解决方案,我们将需要深入研究容器是如何在宿主机(或者是虚拟机,正如我们的例子)里运行的,使用 Docker 通常是有三个阶段:镜像构建、镜像分发和容器部署。


构建镜像——DockerFile 的世界

为了构建镜像,你要写一系列的指令用来获取已有的镜像,接着对该镜像做些改变和配置。官方的 Docker Hub Repository 包含了许多的“官方”镜像以及数以千计的用户定制的镜像。如果其中的镜像不太符合你的需求,你可以创建一个定制的 Dockerfile,用来在镜像上逐步添加一些内容,,比如安装系统软件包、复制文件或者公开一些网络端口,当我们构建微服务时,我们将会创建一个定制的 Dockerfile,不过现在,我们将会利用一个标准镜像来启动一个 MongoDB 实例。


容器联网

当容器启动时,有一个它私有的网络,容器宿主机端口将外部网络通信转发到单个的容器端口上,特定的容器端口可以通过 dockerfile 来决定公开,并且端口转发可以通过以下两种方式之一来进行:你可以显式地从宿主机映射端口到容器上,或者如果没有显式映射的话,Docker 将映射已声明的容器端口到宿主机一个可用的临时端口上(通常的范围是从 32768 到 61000)。当我们可以对整个解决方案显式地管理端口映射时,通常让 Docker 处理这一切是一个更加好的主意,并且可以通过 Link 机制公开端口信息到容器上,这方面将在我们构建我们的第一个微服务容器时有所涉及。


启动 MongoDB 容器

无论你是使用 Kitematic 还是 Docker 命令行,都可以非常简单的启动一个标准的容器。使用命令行的话,如果一切都安装正确,命令提示符将会包含以下三个关键的环境变量:

DOCKER_HOST=tcp://192.168.99.100:2376

DOCKER_MACHINE_NAME=default

DOCKER_TLS_VERIFY=1

DOCKER_CERT_PATH=/Users/[username]/.docker/machine/machines/default


这些是按照你的情况设置的(如果是在安装过程中打开的话,你可能需要重启终端或者命令提示符)。这些都是必要的,因为 Docker 不能直接运行在我的 Mac 笔记本上,而是跑在笔记本运行的虚拟机上。Docker 客户端非常有效地将 Docker 命令从我的笔记本“代理”到虚拟机上,在我们启动容器前,让我们重温一下一部分 Docker 命令是非常有益的,在使用任何图形用户界面之前,了解命令行的东西总是很好的。


Docker 级别的命令

docker ps

该命令将会列出所有运行的容器,显示的信息包括它们的 ID、名字、基础镜像名字和端口映射信息等。


docker build

该命令用来定义一个镜像——通过处理 Dockerfile 来创建一个新的镜像,我们将用这个命令来构建我们的微服务镜像。


docker pull[镜像名字]

该命令从远程 Repository 拉取镜像并且存储在本地。


docker run

该命令将基于一个本地或者远程 Repository(比如 Docker Hub)启动一个容器,我们将会相当多地探究这个命令。


docker push

该命令推送一个构建好的镜像到一个 Repository,通常是 Docker Hub。


容器特定的命令

这些命令使用容器 ID 或者名字作为一个参数:

docker status [容器名字/ID][容器名字/ID]

这个命令将显示指定的每一个容器的当前负载,比如 CPU 占用率、内存使用率以及网络流量等。


docker logs [-f][容器名字/ID]

该命令显示容器的最新的日志,-f 选项就好比 Shell 终端中的“tail -f”中的-f 选项。


docker inspect [容器名字/ID]

该命令将容器的所有配置信息以 JSON 的格式转储出来显示。


docker port [容器名字/ID]

该命令显示容器与宿主机之间的所有端口映射信息。


docker exec [-i][-t][容器名字/ID]

该命令将在目标容器上执行一条命令(-i 表明以交互方式运行,-t 表明以伪 TTY 终端运行),这个命令常用来获得一个容器终端 Shell:

docker exec -it [容器名字/ID]sh

一旦我们理解了这些参考材料,我们可以进入到下一步启动一个 Mongo 容器。

命令非常简单:docker run -P -d —name mongo mongo

解释如下:

  • P 选项告知 Docker 在临时端口范围里公开容器声明的任何端口

  • d 选项告知以 Daemon 方式运行容器(比如在后台)

  • name 选项给容器分配一个名字(名字必须在所有运行的容器实例中唯一,如果你不提供这个选项,将会获得一个随机的半友好的名字比如 modest_poitras)

  • 最后的 mongo 表明了使用哪一个镜像


Docker Hub 镜像的定义采用了[所有者]/[镜像名字][:标签]的命名格式,如果没有指定所有者,那么使用的就是“官方”的 Docker Hub 镜像——这是预留给 Docker 官方给软件供应商的礼物也就是成为官方镜像,如果最后的标签部分省略的话,那么就会认为你需要获得的是最新版本的镜像。


现在我们来尝试确认我们的 Mongo 实例已经启动并且运行了:

docker exec -it mongo sh

mongo

MongoDB shell version: 3.0.6

connecting to: test

Server has startup warnings:

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten]

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten]

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'

2015-09-02T00:57:30.761+0000 I CONTROL  [initandlisten]

> use microserviceblog

switched to db microserviceblog

> db.createCollection('testCollection')

{ "ok" : 1 }


在容器内部,Mongo 看起来正在运行,但是我们可以从外部获知吗?为了尝试这个,我们需要查看什么临时端口被映射到了 Mongo 的端口上,我们运行如下命令:

docker ps


从下面我们可以看到(为了可读性省略了一些列):

CONTAINER ID        IMAGE                PORTS                      NAMES

87192b65de95        mongo                0.0.0.0:32777->27017/tcp   mongodb


我们可以看到宿主机端口 32777 映射到了容器端口 27017 上,然而,记住我们的容器是运行在虚拟机上的,所以我们必须回到我们的环境变量:

$ echo $DOCKER_HOST

tcp://192.168.99.100:2376


我们应该可以通过如下的地址访问我们的 Mongo 容器的 27017 端口:

192.168.99.100:32777,启动 Mongo 然后点击那个位置显示数据库可以外部访问:


在这里结束第二篇吧,在本系列的第三篇中,我们将继续探讨,通过创建一个或两个微服务,管理它们的变化,然后运用持续集成以及产品部署技术进行工作。


发布于: 2020 年 05 月 25 日阅读数: 883
用户头像

MaxHu

关注

猫哥 2017.10.17 加入

通信行业出身的码农,互联网及区块链技术布道者,区块链技术及数字货币的坚定信仰者,产学研投四位一体践行者

评论 (1 条评论)

发布
用户头像
感谢分享原创文章,期待系列完成。
2020 年 05 月 25 日 13:57
回复
没有更多了
使用Spring Boot和Docker构建微服务架构(二)