领先一步
VMware 提供培训和认证,助您加速进步。
了解更多大家好,Spring 粉丝!欢迎收看另一期 Spring Tip!在本期中,我们将探讨一个我非常喜爱的主题(也是我 @author 标签所代表的!)—— Cloud Foundry Java 客户端自动配置。
Cloud Foundry 是一个开源的 PaaS。它具有很高的灵活性。说实话,我很喜欢它。它很简单。我喜欢这种类型的东西,它们能在不要求我在 YAML 神祇祭坛上做出太多牺牲的情况下,赋予我灵活性。它是一个有明确定义的平台即服务。你把应用程序交给平台,它就会部署它们。你上传一个 Spring Boot 应用,它就会识别出该应用是一个独立的、自包含的,所谓的“胖”.jar 文件,然后下载所需的 JDK,配置足够的内存,创建一个包含你的应用、JDK、正确配置的文件系统,最后将所有内容打包成一个容器。
好吧,具体来说,buildpacks 负责接收上传的工件并为其派生出运行应用程序的运行时和环境。然后,buildpacks 会在平台各种受支持的操作系统版本之上添加层。结果就是一致性。通过一致性获得速度。通过知道每个应用都看起来基本相同来获得速度。平台以相似的配置运行所有这些应用,允许一些变化,例如内存、硬盘空间等。
这种方法的另一个好处是平台负责构建容器。整个容器创建生命周期都通过平台进行。如果需要,平台可以重新创建环境,例如当基础平台有安全修复时。平台可以透明地重新构建这些东西以利用新的平台修复。你也可以这样做。
在 Cloud Foundry 中,重新分阶段应用程序会强制它重建该环境。平台也可以为你自动执行此操作。如果你愿意,可以执行滚动重新分阶段。你这样做可能是因为你想指定一些新的环境变量。是否有新的消息队列或数据库需要绑定到应用程序?重新分阶段它。如果你想升级像 JDK 或 buildpack 描述的任何其他东西,你也可以这样做。Java 14 出来了?太好了,我们来用它。
Cloud Foundry 使这类工作变得容易,因为所有内容都可以通过 HTTP REST API 进行控制。你可以询问平台,你有哪些应用程序在使用——比如说——基于 Python 的 buildpack?哪些在使用 Java?然后你可以告诉它只分阶段那些。
在之前的视频中,我们讨论了 Cloud Foundry Java 客户端。该客户端允许你以编程方式(和响应式地)与平台进行通信并指示其执行操作。在本视频中,我们将介绍 Spring Cloud Cloud Foundry Discovery Client 实现中相对较新的 Cloud Foundry Java 客户端自动配置。我们不会使用 Discovery Client。(这可能要留待另一个视频了!)
Java 客户端的设置非常简单,因为现在有一个 Spring Boot 自动配置,它完成了连接到平台的大部分工作。让我们通过Spring Initializr创建一个新项目。选择 `Cloud Foundry Discovery Client`、`Lombok` 和 `Reactive Web`。点击 `Generate`。
为了演示这一点,我们将部署两个示例应用程序,一个使用 JVM,另一个使用 Python。为了简单起见,我们将使用 Spring CLI 创建一个使用 Spring Boot 和 Groovy 的简单 HTTP 应用程序。然后我们将创建一个 Python 应用程序。
要部署它们,你需要有一个 Cloud Foundry 实例的账户。我正在使用Pivotal Web Services。注册价格便宜。如果你已经有了一个实例,请登录。
这是Python 应用程序。
Python 应用程序(application.py)是使用 Python Flask 框架的一个类似的简单 HTTP 应用程序。
#!/usr/bin/env python
from flask import Flask
import os
app = Flask(__name__)
cf_port = os.getenv("PORT")
if cf_port is None:
cf_port = '5000'
@app.route('/')
def hello():
return {'message': 'Hello, world'}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(cf_port), debug=True)
Heroku 和 Cloud Foundry 使用 Procfile 文件来告知平台 Python 应用程序应该作为一个 Web 应用程序运行。它向平台描述了如何运行程序。
web: Python application.py
当平台看到传入的应用程序时,它必须下载运行该应用程序所需的所有工件。你通过一个 Pipfile 文件来完成此操作,它有点像 Maven 中熟悉的 pom.xml。
[[source]]
name = "pypi"
url = "https://pypi.ac.cn/simple"
verify_ssl = true
[dev-packages]
[packages]
flask = "*"
[requires]
python_version = "3.7"
这是我用于部署应用程序的部署脚本 deploy.sh。
#!/bin/bash
APP_NAME=sample-python-app-${RANDOM}
cf push -p . ${APP_NAME}
这是Java 应用程序。
以下是一个工作的 Spring Boot CLI 应用程序——所有的一切。
@RestController
class GreetingsRestController {
@GetMapping("/hello")
String get (){
return "Hello, world"
}
}
为了部署它,我写了一个小小的 deploy.sh,包含了以下的咒语。这个脚本只有两行:一行是将 .groovy 脚本变成一个可工作的 Spring Boot(一个自包含的“胖” .jar 文件,所有依赖项都包含在内)应用程序,另一行是部署它。
#!/bin/bash
APP_NAME=hello-world-${RANDOM}
JAR_NAME=app.jar
spring jar ${JAR_NAME} hello.groovy
cf push -p ${JAR_NAME} APP_NAME
好了,我想演示一下,只需要在属性文件中插入一些字符串,然后——瞧!——你就可以通过出色的 Cloud Foundry Java 客户端来操作你的平台,这有多么酷。但是没有什么可看的!你只需将 Spring Boot 依赖项添加到类路径并插入一些属性。所以,我将向你展示代码和配置来构建选择性的重新分阶段。我已经向你展示了无数关于构建响应式应用程序的视频;我不会回顾那些基础知识。我们来看看一些代码。
首先,这是配置属性。我将把值留给你自己指定。在上面的视频中,我将它们定义为环境变量(export SPRING_CLOUD_CLOUNDFOUNDRY_USERNAME=...)。
spring.cloud.cloudfoundry.space=joshlong
spring.cloud.cloudfoundry.org=my-org
spring.cloud.cloudfoundry.password=wouldnt-u-like-to-know
spring.cloud.cloudfoundry.username=my-user-email
spring.cloud.cloudfoundry.url=api.run.pivotal.io
现在是实际的 Java 代码。
package com.example.cfac;
import lombok.SneakyThrows;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j2;
import org.cloudfoundry.client.CloudFoundryClient;
import org.cloudfoundry.client.v2.applications.SummaryApplicationRequest;
import org.cloudfoundry.operations.CloudFoundryOperations;
import org.cloudfoundry.operations.applications.RestageApplicationRequest;
import org.cloudfoundry.operations.applications.StopApplicationRequest;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@SpringBootApplication
public class CfacApplication {
@SneakyThrows
public static void main(String[] args) {
SpringApplication.run(CfacApplication.class, args);
System.in.read();
}
}
@Component
@Log4j2
class Restager {
private final String buildpack = "python";
private boolean isValidBuildpack(String one, String two) {
return (StringUtils.hasText(one) ? one : StringUtils.hasText(two) ? two : "").contains(this.buildpack);
}
Restager(CloudFoundryOperations ops, CloudFoundryClient client) {
ops
.applications()
.list()
.filter(as -> as.getRunningInstances() > 0)
.flatMap(as -> client.applicationsV2().summary(SummaryApplicationRequest.builder().applicationId(as.getId()).build()))
.filter(as -> isValidBuildpack(as.getBuildpack(), as.getDetectedBuildpack()))
.doOnNext(as -> log.info("restaging " + as.getName() + '.'))
.flatMap(as -> ops.applications().restage(RestageApplicationRequest.builder().name(as.getName()).build()))
.subscribe();
}
}
该应用程序相对直接。它使用 CloudFoundryOperations 来
SummaryApplicationRequest很酷,不是吗?可编程平台在工作!现在,编程平台没有任何开销。
注意:我从 2017 年 Josh McKenty 和我一起完成的 Cloud Foundry Livelessons 培训视频中借用了重新分阶段器的代码,并大大简化了它。