读书笔记《cloud-native-applications-in-java》云-本机应用程序部署
云原生应用程序最独特的事情之一就是它们的部署。在传统的应用程序部署中,团队通过登录到服务器并安装应用程序来部署他们的应用程序。但是在云中通常有很多服务器,登录到每台服务器并手动安装应用程序是不可行的,而且很容易出错。为了解决这些问题,我们使用云配置工具来自动部署云原生应用程序。
在本章中,我们将深入探讨微服务的部署模型——包括如何将应用程序打包为 Docker 容器、如何设置 CI/CD 管道以及如何 保护您的服务免受安全攻击,例如 分布式拒绝服务 (DDoS)。我们将介绍以下内容:
- Deployment models, packaging, and containerization (using Docker)
- Deployment patterns (blue-green, canary release, and dark release)
- DDoS
- CI/CD
我们将介绍用于在云环境中部署我们的应用程序的 deployment 模型。
云的基本构建块是虚拟机(以下简称VM),相当于用户可以登录并安装或维护应用程序的物理服务器(或主机)。不同之处在于可以在单个主机上托管多个 VM,从而提高资源利用率。这是通过使用虚拟化实现的,其中在主机上安装了管理程序,然后可以分配物理服务器上的可用资源,例如与托管在其上的不同 VM 的计算、内存、存储和网络连接。可以使用以下策略将云原生应用程序部署在此类 VM 上:
- Several applications per VM
- One application per VM
当每个 VM 运行多个应用程序时,一个应用程序可能会占用 VM 上的所有可用资源并饿死其他应用程序。另一方面,每个 VM 运行单个应用程序可确保应用程序是隔离的,因此它们不会相互影响,但这种部署的缺点是浪费资源,因为每个应用程序可能并不总是消耗所有的它可用的资源。
PaaS 或平台即服务是部署云原生应用程序的另一个 流行选项。 PaaS 提供额外的服务来补充云原生应用程序的开发、扩展和维护。通过 buildpack 进行自动化构建和部署等服务极大地减少了设置额外基础架构以支持这些活动所花费的时间。 PaaS 还提供了一些基本的基础设施服务,例如开箱即用的监控、日志聚合、秘密管理和负载平衡。 Cloud Foundry、Google App Engine、Heroku 和 OpenShift 是一些例子 即服务。
做出的努力提供了独立操作所需的隔离级别,同时还保护 资源利用,导致了容器技术的发展。通过利用 Linux 内核的特性,容器在进程级别提供 CPU、内存、存储和网络隔离。下图展示了虚拟化之间的区别:
容器消除了对来宾操作系统的需求,从而大大增加了可以运行的容器数量,而不是同一主机上的虚拟机数量。容器的占用空间也更小,大约为 MB,而 VM 可以轻松超过几 GB。
容器在所需的 CPU 和内存量方面也非常节省资源,因为它们不必支持在运行成熟的操作系统时必须支持的许多外围系统:
上图显示了云原生应用程序部署策略的演变,旨在提高应用程序的资源利用率和隔离性。堆栈的顶部是在主机上运行的 VM 中运行的容器。这允许应用程序扩展两度:
- Increasing the number of containers within a VM
- Increasing the number of VMs running containers
Docker 是一个容器runtime,它已广受欢迎,并已证明自己是部署云原生应用程序的强大平台。 Docker 在所有主要平台上都可用,例如 Windows、Mac 和 Linux。由于容器需要 Linux 内核,因此在 Linux 环境中运行 Docker 引擎更容易。但是,有多种资源可用于在 Windows 和 Mac 环境中舒适地运行 Docker 容器。我们将演示如何将我们一直在开发的服务部署为 Docker 容器,包括连接到在其自己的容器中运行的外部数据库。
在我们的示例中,我们将使用 Docker Toolbox 并使用 Docker Machine 创建一个 VM,Docker 引擎将在其中运行。我们将使用 Docker 命令行客户端连接到该引擎并使用提供的各种命令。
我们将开始containerize我们当前的项目作为一组Docker 容器。我们将完成每个项目的步骤。
- Add a Dockerfile with the following contents in
$WORKSPACE/eureka-server/Dockerfile
:
- Build the runnable JAR, which will be available in the target folder:
- Build the Docker container:
上述命令的输出如以下屏幕截图所示:
- Before running the container, we need to create a network on which the different containers can communicate freely with each other. This can be created by running the following command:
上述命令的输出如以下屏幕截图所示:
- Run the container with the name
eureka
and attach it to the network created earlier:
上述命令的输出如以下屏幕截图所示:
接下来我们在产品 API 项目上工作:
- Build the Spring Boot JAR to reflect changes to
application.yml
:
- Add a
.dockerignore
file with the following contents:
- Add a Dockerfile with the following contents:
- Build the Docker container:
上述命令的输出如以下屏幕截图所示:
- Start several Docker containers:
上述命令的输出如以下屏幕截图所示:
产品 API 将在以下 URL 提供:
http://<docker-host>:8011/product/1
http://<docker-host>:8012/product/1
要将 product
API 连接到外部数据库而不是内存数据库,首先创建一个容器镜像,其中已经填充了数据:
- Create a
Dockerfile.postgres
with the following contents:
- Now build the Postgres container image which will have the database initialized with the contents of
import-postgres.sql
:
上述命令的输出如以下屏幕截图所示:
- Add a new Spring profile,
postgres
to theapplication.yml
by appending the following contents to the existing file:
确保将 <docker-host>
替换为适合您环境的值。
- Build the Spring Boot JAR to reflect changes to
application.yml
:
- Build the Docker container:
上述命令的输出如以下屏幕截图所示:
- If you already have containers running off the old image you can stop and remove them:
- Start the database container:
上述命令的输出如以下屏幕截图所示:
- Start several Docker containers for the product API:
产品 API 将在以下 URL 提供:
http://<docker-host>:8011/product/1
http://<docker-host>:8012/product/1
在介绍了云原生应用程序的打包和部署模型之后,我们现在将介绍用于部署云原生应用程序的模式.传统上,应用程序部署在多个环境中,例如开发、测试、暂存、预生产等,并且这些环境中的每一个都可能是最终生产环境的缩小版本。应用程序通过一系列预生产环境并最终部署到生产环境。但是,一个显着的区别是,虽然在所有其他环境中都可以容忍停机,但生产部署中的停机可能会导致严重的业务后果。
使用云原生应用程序,可以发布零停机时间的软件。这是实现的,通过将自动化严格应用到应用程序的开发、测试和部署的各个方面来实现。我们将介绍 持续集成 (CI) / 持续部署 (CD) 在后面的部分,但我们将在这里介绍一些能够快速部署应用程序的模式。所有这些模式都依赖于路由器组件的存在,与负载均衡器不同,它可以将请求路由到某个集合应用程序实例。在某些情况下,应用程序本身是使用隐藏在功能标志后面的功能构建的,可以通过更改应用程序配置来启用这些功能。
蓝绿部署是一个发生在三个阶段的模式。 initial 部署状态在以下 图。应用程序的所有流量都被路由到现有实例,这些实例被视为蓝色实例。蓝绿部署的表示如下:
在蓝绿部署的第一阶段,一组带有新版本应用程序的新实例被配置并可用。在此阶段,最终用户无法使用新的绿色应用程序实例,并在内部验证部署。这显示在这里:
在部署的下一阶段,在路由器上抛出一个比喻开关,它现在开始将所有请求路由到绿色实例而不是旧的蓝色实例。旧的蓝色实例会保留一段时间,如果检测到任何严重问题,我们可以根据需要快速将部署回滚到应用程序的旧实例:
在部署的最后阶段,应用程序的旧蓝色实例被停用,绿色实例成为下一个稳定的生产版本:
Canary deployment 也是蓝绿部署的一种变体。 Canary 部署解决了同时运行两个生产实例时配置的资源浪费问题,尽管时间很短。在金丝雀部署中,绿色环境是蓝色环境的缩小版本,它依赖于路由器的能力,将一小部分请求始终路由到新的绿色环境,而将大部分请求路由到蓝色的环境。 以下 图描述了这一点:
这在发布需要由少数 beta 测试用户测试的应用程序的新功能,然后根据该用户组的反馈向所有用户推出时特别有用。一旦确定绿色环境已准备好全面推出,绿色环境中的实例将逐渐增加,同时蓝色环境中的实例将逐渐减少。下面的图表序列最好地说明了这一点:
这样就避免了必须运行两个生产级环境的问题,并且可以从一个版本平滑过渡到另一个版本,同时还可以轻松回退到旧版本。
另一种用于部署云原生应用程序的流行部署 pattern 是暗发布模式。在这里,新功能隐藏在功能标志后面并为选定的用户组启用,或者在某些情况下,用户完全不知道该功能,而应用程序会模仿用户的行为并练习应用程序的隐藏功能。一旦该功能被认为已准备好并稳定地向所有用户推出,然后通过切换功能标志来启用它。
云原生应用程序部署的核心方面之一依赖于能力 来有效地自动化和构建软件交付管道。这主要是通过使用 CI/CD 工具来完成的,这些工具可以从源存储库中获取源代码、运行测试、构建可部署的工件并将它们部署到目标环境。大多数现代 CI/CD 工具(例如 Jenkins)都支持配置构建管道,这些构建管道可用于基于脚本形式的配置文件构建多个工件。
我们将以 Jenkins 流水线脚本为例来演示如何配置简单的构建流水线。在我们的示例中,我们将简单地构建两个工件,即 eureka-server
和 product-api
可运行 JAR。添加一个名为 Jenkinsfile
的新文件,其内容如下:
管道脚本执行以下操作:
- Checks out the source code from GitHub
- Configures the Maven tool
- Builds two artifacts by running the Maven build within two directories of the checked-out source repository
- Stores the test results and the resultant JARs from the build
在 Jenkins 中创建一个新的流水线作业:
在管道配置中,指定 GitHub 存储库以及该 Git 存储库中 Jenkinsfile
的路径:
在运行构建时,应该会构建两个工件:
可以扩展管道脚本来构建我们在本章前面使用 Jenkins 的 Docker 插件手动构建的 Docker 容器。