Spring 小技巧:使用 Spring Cloud Cloud Foundry Java Client 自動配置操作平台

工程 | Josh Long | 2020 年 4 月 1 日 | ...

嗨,Spring 的粉絲們!歡迎來到另一期的 Spring 小技巧!在本期中,我們將介紹我內心深處的東西(以及我的 @author 標籤!) - Cloud Foundry Java Client 自動配置。

什麼是 Cloud Foundry?

Cloud Foundry 是一個開放原始碼的 PaaS。它具有很大的靈活性。 如果我誠實地說,我愛它。 它很簡單。我喜歡像這樣在不需要在 YAML 神的祭壇上做出太多犧牲的情況下,給我靈活性的東西。 它是一個有主見的平台即服務。 您將應用程式提供給平台,然後平台將其部署。 您上傳一個 Spring Boot 應用程式,它會發現該應用程式是一個獨立、自包含的所謂「胖」.jar,然後它會下載所需的 JDK,配置必要的記憶體量,然後建立一個包含您的應用程式、JDK 和正確配置的檔案系統,然後將所有這些轉換為容器。

嗯,更具體地說,構建包 (buildpack) 是獲取上傳的工件並為其派生運行時和運行應用程式的環境的東西。 然後,構建包會分層疊加在平台上各種經過認可的作業系統版本之上。 結果是一致性。 您透過一致性獲得速度。 您透過了解每個應用程式看起來基本上都相同來獲得速度。 該平台以類似的配置運行所有應用程式,但允許對 RAM、硬碟空間等內容進行一些變更。

這種方法的另一個好處是,平台負責建構容器。 整個容器建立生命週期都透過平台進行路由。 如果平台需要,它可以再次建立環境,例如當基礎平台中存在安全性修復時。 平台可以透明地重建這些東西,以利用新的平台修復。 您也可以這樣做。

在 Cloud Foundry 中,重新暫存應用程式的行為會強制其重建該環境。 平台也可以自動為您執行此操作。 如果您願意,可以執行滾動重新暫存。 您可能這樣做是因為您想要指定一些新的環境變數。 有一個新的訊息佇列或資料庫要綁定到應用程式嗎? 重新暫存它。 如果您想升級 JDK 之類的內容,或構建包中描述的其他任何內容,您可以這樣做。 Java 14 出來了嗎? 太好了,讓我們使用它。

Cloud Foundry 使這種工作變得容易,因為所有這些都可以透過 HTTP REST API 控制。 您可以詢問平台,您有哪些應用程式正在使用(比如說)基於 Python 的構建包? 哪個在使用 Java? 然後您可以告訴它只暫存那些。

Cloud Foundry Java Client

先前的影片中,我們介紹了 Cloud Foundry Java Client。 該客戶端讓您可以程式設計方式(且反應式)地與平台對話並指示它執行操作。 在本影片中,我們將介紹相對較新的 Cloud Foundry Java Client 自動配置,它現在是 Spring Cloud Cloud Foundry Discovery Client 實作的一部分。 我們不會使用 Discovery Client。(也許這必須等到另一個影片了!)

由於現在有一個 Spring Boot 自動配置可以完成連接到平台的大部分工作,因此 Java Client 非常容易設置。 讓我們在 Spring Initalizr 上建立一個新專案。 選擇 Cloud Foundry Discovery ClientLombokReactive Web。 按一下 Generate

我們的範例應用程式

為了示範這一點,我們將部署兩個範例應用程式,一個使用 JVM,另一個使用 Python。 為了簡單起見,我們將使用 Spring CLI 使用 Spring Boot 和 Groovy 建立一個簡單的 HTTP 應用程式。 然後,我們將建立一個 Python 應用程式。

要部署這些應用程式,您需要在 Cloud Foundry 執行個體上建立一個帳戶。 我正在使用 Pivotal Web Services。 註冊很便宜。 如果您已經有一個執行個體,請登入它。

Python 應用程式

這是 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)

HerokuCloud Foundry 使用 Procfile 檔案來告訴平台,Python 應用程式應該是一個 Web 應用程式。 它向平台描述如何運行該程式。

web: Python application.py

當平台看到傳入的應用程式時,它必須下載所有工件才能運行該應用程式。 您可以使用 Pipfile 檔案執行此操作,它有點像 Maven 常用的 pom.xml

[[source]]
name = "pypi"
url = "https://pypi.org/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 應用程式

這是 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 自動配置重新暫存

好吧,我想示範能夠只是將一些字串插入屬性檔案中,然後 - 登登! - 現在您可以使用出色的 Cloud Foundry Java Client 來操作您的平台是多麼酷。 但沒有什麼可看的! 您只需將 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
  • 確定該應用程式是否使用我們正在尋找的構建包(在本例中為 Python 構建包)
  • 確定它們的構建包
  • 然後重新暫存它們。

非常酷,是吧? 可程式設計的平台在運作! 現在,與程式設計平台相關的開銷。

注意:我借用了並大大簡化了來自 Cloud Foundry Livelessons 訓練影片的重新暫存器程式碼,該影片是 Josh McKenty 和我在 2017 年製作的。

取得 Spring 電子報

隨時掌握 Spring 電子報的最新消息

訂閱

領先一步

VMware 提供培訓和認證,加速您的進度。

了解更多

取得支援

Tanzu Spring 在單一訂閱中提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位檔案。

了解更多

即將舉行的活動

查看 Spring 社群中所有即將舉行的活動。

查看全部