使用Spring Boot和Kubernetes构建微服务架构

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

在本教程中,您将使用Kubernetes将Spring Boot微服务架构部署到Google Cloud,特别是Google Kubernetes Engine(GKE)。 您还将使用Istio创建服务网格层并创建公共网关。 整个事情将使用Okta OAuth JWT身份验证进行保护。

那是一堆烂话。 我们将不在这里深入解释微服务。 简而言之,微服务是一种设计模式,可将较大的单片服务拆分为较小的独立“微”服务。 这些服务通过网络松散耦合。 这种体系结构的好处是,每个服务都变得可测试,可维护且可独立部署。 在互联网规模上,在像Amazon和Netflix这样的大型公司中,这种架构都很棒,因为它允许公司将小型团队的职责分配给可管理的,离散的功能单元。 而不是拥有成千上万的人监督巨大的整体代码块。 不利之处是复杂性和基础架构的高昂初始成本,这对于无法规模化的较小项目可能没有意义。

Kubernetes是用于部署容器化服务的平台。 您可以将其视为Docker容器的容器协调器(这是一种简化,但是可以使用)。 这将使我们能够编写YAML脚本,以自动将微服务架构部署到我们选择的平台GKE。 这是一个庞大的项目,需要深入研究。 看看他们的文档以了解更多信息。

Istio在Kubernetes的基础上又增加了一层功能,增加了一些出色的监视,安全性,访问控制和负载平衡功能。 查看他们的网站以获取更多信息。

微服务架构的最后一部分是Google Cloud和GKE 。 这是您将用于部署微服务的平台。 本教程中未介绍的另一个选项是Minikube。 Minikube在您的计算机上本地运行,可能对某些人有用。 我发现Google Kubernetes Engine更易于使用且性能更高。

我们假设您熟悉Spring Boot和Java。 如果不是这样,请查看教程末尾的一些链接以帮助您入门。

Spring Boot和Kubernetes的要求

HTTPie :从他们的网站安装HTTPie,以便我们可以轻松地从终端运行HTTP请求。

Docker :如果尚未安装Docker Desktop,请从其网站下载并安装。

kubectl :这是Kubernetes的命令行界面。 有关安装说明,请参见其网站

Google Cloud :您需要一个启用了计费功能的Google Cloud帐户。 有一个免费试用版,其中应包括足够的学分和时间,以帮助您完成本教程。 转到Google Cloud网站并注册。

developer.okta.com :我们在开发人员网站上提供免费的开发人员帐户。 请立即注册一个。 您将在本教程结束时使用它。

gcloud :这是Google Cloud CLI。 按照其网站上的说明进行安装 。 完成此操作后,您需要通过运行以下命令来安装gcloud kubectl组件:

gcloud components install kubectl

我是否提到微服务的初始复杂性成本很高?

使用Istio创建一个Google Kubernetes Engine项目

您现在应该拥有一个启用了结算功能的Google Cloud帐户。 同样,您实际上不需要花任何钱,但是如果不付款,您将无法访问免费试用版。

创建一个新项目。 将其命名为spring-boot-gke (或任何您想使用的名称,但是您需要各种命令的项目ID)。 等待项目创建。

项目名称的结尾可能会带有一个ID号,例如spring-boot-gke-232934 。 您将需要几次该项目名称,因此请继续将其存储在shell变量中并记下它。

PROJECT_NAME=<your project name and ID>

项目准备就绪后,打开项目仪表板,打开导航菜单,然后单击Kubernetes Engine 。 单击启用帐单按钮(如果尚未启用帐单),然后选择一个帐单帐户。

单击创建集群

微服务架构

在左侧面板中,选择您的第一个集群

将集群命名为“ spring-boot-cluster”。

选择区域“ us-west1-a”。

单击集群配置面板底部的“ 高级选项”链接以显示高级选项。 向下滚动到底部,然后选中Enable Istio(beta)复选框。 这将自动在群集上安装Istio。

微服务架构

在底部,单击创建以创建集群。 喝咖啡或休息一下; 创建集群将需要几分钟。

同时,如果尚未安装,请继续运行以下命令来初始化gcloud CLI:

gcloud init

在初始化过程中,可以将新项目设置为默认项目,并将项目区域设置为默认区域。

部署集群后,您需要使用以下命令将本地gcloudkubectl CLI连接到该集群:

gcloud container clusters get-credentials {yourClusterName} --zone us-west1-a --project {yourProjectId}

如果您使用了其他项目名称,则需要更改命令以反映该名称。

注意:如果单击Google Cloud Platform仪表板右侧的“ 连接”按钮,您将看到正确的命令,可输入:

微服务架构

结果,您应该看到类似以下的内容:

Fetching cluster endpoint and auth data.
kubeconfig entry generated for spring-boot-cluster.

您还需要为自己赋予集群管理员权限:

kubectl create clusterrolebinding cluster-admin-binding --clusterrole=cluster-admin --user=$(gcloud config get-value core/account)

现在,您需要检查并确保Istio服务已安装并正在运行。 有两种检查方法。 首先,在您的Google Cloud Platform Kubernetes Engine仪表板中,单击“ 服务”按钮。 您应该在spring-boot-cluster看到Istio服务的列表。 它们的状态列下都应有绿色的“确定”。

在此期间,请注意类型为LoadBalancer名为istio-ingressgateway的服务。 这是群集的公共负载平衡器,该条目显示公共IP和开放端口。

微服务架构

另一种检查方法是使用kubectl CLI。

要检查服务,请使用以下命令: kubectl get services --all-namespaces 。 必须使用--all-namespaces才能显示istio-system命名空间中的Istio服务。

$ kubectl get services --all-namespaces
NAMESPACE      NAME                     TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)                                                                                                                   AGE
default        kubernetes               ClusterIP      10.31.240.1     <none>           443/TCP                                                                                                                   5m
istio-system   istio-citadel            ClusterIP      10.31.252.214   <none>           8060/TCP,9093/TCP                                                                                                         3m
istio-system   istio-egressgateway      ClusterIP      10.31.247.186   <none>           80/TCP,443/TCP                                                                                                            3m
istio-system   istio-galley             ClusterIP      10.31.249.131   <none>           443/TCP,9093/TCP                                                                                                          3m
istio-system   istio-ingressgateway     LoadBalancer   10.31.244.186   35.185.213.229   80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30675/TCP,8060:31581/TCP,853:32460/TCP,15030:30998/TCP,15031:31606/TCP   3m
istio-system   istio-pilot              ClusterIP      10.31.251.44    <none>           15010/TCP,15011/TCP,8080/TCP,9093/TCP                                                                                     3m
istio-system   istio-policy             ClusterIP      10.31.246.176   <none>           9091/TCP,15004/TCP,9093/TCP                                                                                               3m
istio-system   istio-sidecar-injector   ClusterIP      10.31.240.214   <none>           443/TCP                                                                                                                   3m
istio-system   istio-telemetry          ClusterIP      10.31.247.23    <none>           9091/TCP,15004/TCP,9093/TCP,42422/TCP                                                                                     3m
istio-system   promsd                   ClusterIP      10.31.246.88    <none>           9090/TCP                                                                                                                  3m
kube-system    default-http-backend     NodePort       10.31.250.134   <none>           80:31955/TCP                                                                                                              4m
kube-system    heapster                 ClusterIP      10.31.250.242   <none>           80/TCP                                                                                                                    4m
kube-system    kube-dns                 ClusterIP      10.31.240.10    <none>           53/UDP,53/TCP                                                                                                             4m
kube-system    metrics-server           ClusterIP      10.31.245.127   <none>           443/TCP

要检查Kubernetes Pod,请使用: kubectl get pods --all-namespaces

$ kubectl get pods --all-namespaces
NAMESPACE      NAME                                                      READY     STATUS      RESTARTS   AGE
istio-system   istio-citadel-7c4864c9d5-7xq9x                            1/1       Running     0          10m
istio-system   istio-cleanup-secrets-ghqbl                               0/1       Completed   0          10m
istio-system   istio-egressgateway-c7f44ff8-tz7br                        1/1       Running     0          10m
istio-system   istio-galley-698f5c74d6-hmntq                             1/1       Running     0          10m
istio-system   istio-ingressgateway-774d77cb7c-qvhkb                     1/1       Running     0          10m
istio-system   istio-pilot-6bd6f7cdb-gb2gd                               2/2       Running     0          10m
istio-system   istio-policy-678bd4cf9-r8p6z                              2/2       Running     0          10m
istio-system   istio-sidecar-injector-6555557c7b-99c6k                   1/1       Running     0          10m
istio-system   istio-telemetry-5f4cfc5b6-vj8cf                           2/2       Running     0          10m
istio-system   promsd-ff878d44b-hlkpg                                    2/2       Running     1          10m
kube-system    heapster-v1.6.0-beta.1-8c76f98c7-2b4dm                    2/2       Running     0          9m
kube-system    kube-dns-7549f99fcc-z5trl                                 4/4       Running     0          10m
kube-system    kube-dns-autoscaler-67c97c87fb-m52vb                      1/1       Running     0          10m
kube-system    kube-proxy-gke-spring-boot-cluster-pool-1-b6988227-p09h   1/1       Running     0          10m
kube-system    l7-default-backend-7ff48cffd7-ppvnn                       1/1       Running     0          10m
kube-system    metrics-server-v0.2.1-fd596d746-njws2                     2/2       Running     0          10m

各个Pod的状态都必须为CompletedRunning 。 我遇到了几次问题,其中自动配置不起作用,并且某些吊舱从未达到Running状态,并停留在ContainerCreating 。 我必须删除群集并重新安装它才能正常工作。

如果发生这种情况,您可以使用describe pods命令查看发生了什么: kubectl describe pods -n istio-system 。 这将为您提供有关istio-system名称空间中所有Pod的istio-system ,这些信息是使用-n选项指定的。

如果到此为止没有问题,那么现在您已经在安装了Istio的GKE上部署了Kubernetes集群! 很甜

如果您遇到问题,Google和Istio都会提供一些非常有用的文档。 查看Google GKE文档Istio GKE文档以获得进一步的支持。

为您的微服务创建Spring Boot项目

现在转到Spring Initializer并创建您的启动项目。

  • 将构建工具从Maven更改为Gradle
  • 使用Java和Spring Boot版本2.1.3
  • 更新为: com.okta.spring
  • 使用工件springbootkbe
  • 添加三个依赖项Reactive WebReactive MongoDBLombok
微服务架构

单击生成项目并下载项目。 将项目解压缩到本地计算机上的某个位置,然后在您喜欢的IDE或编辑器中将其打开。

Spring Initializer已创建了带有MongoDB支持的准系统响应式Webflux项目,供您扩展。

与我的其他一些教程一样,并且由于我喜欢皮划艇,因此您将构建一个简单的反应式REST服务,该服务维护皮划艇条目的数据库。 它实际上只是为了演示基本的CRUD功能(创建,读取,更新和删除),并且可以推广到任何类型的资源。

src/main/java下的com.okta.spring.springbootkbe包中,创建一个名为Kayak.java的文档类,并将以下内容粘贴到其中。 这是您的反应性数据模型文档。

package com.okta.spring.springbootkbe;
  
import lombok.AllArgsConstructor;  
import lombok.Data;  
import lombok.NoArgsConstructor;  
import org.springframework.data.mongodb.core.mapping.Document;  
  
@Document  
@Data  
@AllArgsConstructor  
@NoArgsConstructor  
public class Kayak {  
  
    private String name;  
    private String owner;  
    private Number value;  
    private String makeModel;  
}

现在,在相同的包KayakRepository.java创建另一个文件。

package com.okta.spring.springbootkbe;  
  
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;  
  
public interface KayakRepository extends ReactiveMongoRepository<Kayak, Long> {  
}

在本教程中,我不会对这里发生的事情进行过多的详细介绍。 Spring Boot在这两个文件之间进行了大量自动匹配,以创建功能齐全的反应式Mongo文档。

接下来,您需要添加一个控制器以允许访问Kayak文档数据模型。 在com.okta.spring.springbootkbe包中创建一个名为KayakController的文件。

package com.okta.spring.springbootkbe;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Controller
@RequestMapping(path = "/kayaks")
public class KayakController {

    private final KayakRepository kayakRepository;

    public KayakController(KayakRepository kayakRepository) {
        this.kayakRepository = kayakRepository;
    }

    @PostMapping()
    public @ResponseBody
    Mono<Kayak> addKayak(@RequestBody Kayak kayak) {
        return kayakRepository.save(kayak);
    }
  
    @GetMapping()
    public @ResponseBody
    Flux<Kayak> getAllKayaks() {
        Flux<Kayak> result = kayakRepository.findAll();
        return result;
    }}

该控制器向/kayaks端点添加了两种方法,即POST和GET端点,它们分别添加了新的皮划艇并列出所有皮划艇。

最后,添加一个简单的根控制器RootController

package com.okta.spring.springbootkbe;  
  
import org.springframework.stereotype.Controller;  
import org.springframework.web.bind.annotation.*;  
import reactor.core.publisher.Flux;  
  
@Controller  
public class RootController {  
  
    @GetMapping("/")  
    @ResponseBody  
    public Flux<String> getRoot() {  
      return Flux.just("Alive");  
    }
}

此控制器是必需的,因为Kuberenetes在我们服务的根端点上执行运行状况检查,并且需要返回响应,否则群集将认为您的服务已关闭。 实际的端点是可配置的,但您现在可以将其留在根目录下。

要将一些示例数据引导到我们的数据库中,请更新SpringbootkbeApplication类定义以匹配以下内容。

package com.okta.spring.springbootkbe;  
  
import org.springframework.boot.ApplicationRunner;  
import org.springframework.boot.SpringApplication;  
import org.springframework.boot.autoconfigure.SpringBootApplication;  
import org.springframework.context.annotation.Bean;  
import reactor.core.publisher.Flux;  
  
@SpringBootApplication  
public class SpringbootkbeApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootkbeApplication.class, args);
    }

    @Bean
    ApplicationRunner init(KayakRepository repository) {

        Object[][] data = {
            {"sea", "Andrew", 300.12, "NDK"},
            {"creek", "Andrew", 100.75, "Piranha"},
            {"loaner", "Andrew", 75, "Necky"}
        };

        return args -> {
            repository
                .deleteAll()
                .thenMany(
                    Flux
                        .just(data)
                        .map(array -> {
                            return new Kayak((String) array[0], (String) array[1], (Number) array[2], (String) array[3]);
                        })
                        .flatMap(repository::save)
                )
                .thenMany(repository.findAll())
                .subscribe(kayak -> System.out.println("saving " + kayak.toString()));

        };
    }
}

至此,您将拥有一个功能全面的Spring Boot应用程序(减去MongoDB服务器)。 要测试您的应用,请将以下依赖项添加到build.gradle文件中。

compile 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'

这会将嵌入式MongoDB数据库添加到您的项目。 在部署到集群之前,您需要删除此依赖项,但是它将允许您在本地运行Spring Boot应用程序。

使用以下gradle bootRun运行Spring Boot应用程序: gradle bootRun

您应该看到一堆以结尾的输出:

2019-02-14 19:29:34.941  INFO 35982 --- [ntLoopGroup-2-4] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:5, serverValue:5}] to localhost:61858
2019-02-14 19:29:34.946  INFO 35982 --- [ntLoopGroup-2-3] org.mongodb.driver.connection            : Opened connection [connectionId{localValue:4, serverValue:4}] to localhost:61858
saving Kayak(name=sea, owner=Andrew, value=300.12, makeModel=NDK)
saving Kayak(name=loaner, owner=Andrew, value=75, makeModel=Necky)
saving Kayak(name=creek, owner=Andrew, value=100.75, makeModel=Piranha)

使用HTTPie测试应用程序: http :8080 (这会在默认的Spring Boot端口上运行get请求)。

HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
transfer-encoding: chunked

Alive

并使用以下命令获取/kayaks端点: http :8080/kayaks

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
transfer-encoding: chunked
[
  {
    "makeModel": "NDK",
    "name": "sea",
    "owner": "Andrew",
    "value": 300.12
  },
  {
    "makeModel": "Necky",
    "name": "loaner",
    "owner": "Andrew",
    "value": 75
  },
  {
    "makeModel": "Piranha",
    "name": "creek",
    "owner": "Andrew",
    "value": 100.75
  }
]

假设一切正常,请删除嵌入的Mongo依赖项 。 您将使用Mongo Kubernetes Pod,这种依赖性将导致集群部署出现问题。

compile 'de.flapdoodle.embed:de.flapdoodle.embed.mongo'

为您的Spring Boot App部署MongoDB Kubernetes Pod

Kubernetes通过使用YAML部署脚本部署Docker容器来工作(大致概括和简化)。

在项目的根目录中创建一个名为deployment-mongo.yml的文件。

apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: mongodb  
  labels:  
    appdb: mongodb  
spec:  
  replicas: 1  
  selector:  
    matchLabels:  
      appdb: mongodb  
  template:  
    metadata:  
      labels:  
        appdb: mongodb  
    spec:  
      containers:  
        - name: mongodb  
          image: mongo:3.6.6  
          ports:  
            - containerPort: 27017  
---  
apiVersion: v1  
kind: Service  
metadata:  
  name: mongodb  
  labels:  
    app: mongodb  
spec:  
  ports:  
    - port: 27017  
      protocol: TCP  
  selector:  
    appdb: mongodb

这定义了在集群上创建Mongo数据库所需的MongoDB Kubernetes DeploymentService 。 我不会尝试完全解释这些对象在这里,但是您可以阅读Kubernetes 部署文档服务文档 。 粗略地说,部署定义了在已部署的Pod中运行的微应用程序,而服务则提供了总体抽象,该抽象定义了Pod中对应用程序的访问点。 这种抽象提供了必要的连续性,因为Pod可能会被杀死并重新启动,并且可能有多个Pod运行一项服务。

现在有些激动! 您将把Mongo数据库部署和服务部署到GKE集群。

使用以下命令:

kubectl apply -f deployment-mongo.yml

您应该看到:

deployment.apps "mongodb" created
service "mongodb" created

通过运行以下命令来检查Pod:

$ kubectl get pods

您应该看到:

NAME                      READY     STATUS    RESTARTS   AGE
mongodb-c5b8bf947-rkw5f   1/1       Running   0          21s

如果状态列为ContainerCreating ,请稍等片刻,然后再次运行命令。 如果它在ContainerCreating停留超过几分钟,则可能出现了问题。 您可以使用kubectl describe podskubectl get events命令来了解正在发生的事情。

这使用标准docker映像mongo:3.6.6配置了在端口27017上运行的Mongo数据库。

太好了吧? 下一站,火箭科学!

将Spring Boot App部署到集群

在根目录中添加一个名为Dockerfile的文件:

FROM openjdk:8-jdk-alpine  
ENV APP_FILE springbootkbe-0.1.0-SNAPSHOT.jar  
ENV APP_HOME /usr/app  
EXPOSE 8000  
COPY build/libs/*.jar $APP_HOME/  
WORKDIR $APP_HOME  
ENTRYPOINT ["sh", "-c"]  
CMD ["exec java -jar $APP_FILE"]

更新src/main/resources/application.properties

server.port=8000
spring.data.mongodb.host=mongodb
spring.data.mongodb.port=27017

Dockerfile您的Spring Boot端口配置为要在Dockerfile公开的端口,并配置MongoDB主机和端口。 默认情况下,主机将是群集中服务的名称。

再次构建您的应用程序(您确实删除了flapdoodle依赖项,对吗?):

gradle clean build

在根项目目录中创建另一个名为deployment.yml Kubernetes部署脚本:

apiVersion: v1  
kind: Service  
metadata:  
  name: kayak-service  
  labels:  
    app: kayak-service  
spec:  
  ports:  
    - name: http  
      port: 8000  
  selector:  
    app: kayak-service  
---  
apiVersion: extensions/v1beta1  
kind: Deployment  
metadata:  
  name: kayak-service  
spec:  
  replicas: 1  
  template:  
    metadata:  
      labels:  
        app: kayak-service  
        version: v1  
    spec:  
      containers:  
        - name: kayak-app  
          image: gcr.io/spring-boot-gke-/kayak-app:1.0  
          imagePullPolicy: IfNotPresent  
          env:  
            - name: MONGODB_HOST  
              value: mongodb  
          ports:  
            - containerPort: 8000  
          livenessProbe:  
            httpGet:  
              path: /  
              port: 8000  
            initialDelaySeconds: 5  
            periodSeconds: 5

注意:请仔细查看gcr.io/spring-boot-gke/kayak-app:1.0的行。 中间部分是Google Cloud项目名称。 这需要与您使用的项目名称以及分配的ID号(例如spring-boot-gke-43234spring-boot-gke-43234

gcr.io为美国的gcr.io指定了Google Cloud主机。 可以指定其他位置。 有关更多信息,请参见Google Container Registry文档

即将发生的事情的简要摘要,因为其中有很多活动的部分。 Spring Boot应用程序将进行docker化:内置于docker映像中。 在群集上运行部署脚本时,它将尝试从Google Container注册表中提取此映像。 因此,您需要将映像推送到容器注册表并对其进行标记,以便Kubernetes可以找到正确的映像。

如果您使用的是本地Docker桌面,请继续启动并等待其启动。

在做任何事情之前,您需要配置Google Cloud和docker以便一起玩:

gcloud auth configure-docker

构建docker映像:

docker build -t kayak-app:1.0 .

标记图像并将其推送到Google容器注册表(再次注意Google Cloud项目名称):

docker tag kayak-app:1.0 gcr.io/$PROJECT_NAME/kayak-app:1.0;  
docker push gcr.io/$PROJECT_NAME/kayak-app:1.0

现在应用deployment.yml文件复制到GKE集群:

kubectl apply -f deployment.yml

检查以确保Pod正确部署:

kubectl get pods
NAME                             READY     STATUS    RESTARTS   AGE
kayak-service-7df4fb9c88-srqkr   1/1       Running   0          56s
mongodb-c5b8bf947-dmghb          1/1       Running   0          16m

但是,此时您的集群还没有准备好。 它不是公开可用的。

创建一个名为istio-gateway.yml的文件

apiVersion: networking.istio.io/v1alpha3  
kind: Gateway  
metadata:  
  name: kayak-gateway  
spec:  
  selector:  
    istio: ingressgateway # use Istio default gateway implementation  
  servers:  
  - port:  
      name: http  
      number: 80  
      protocol: HTTP  
    hosts:  
    - '*'  
---  
apiVersion: networking.istio.io/v1alpha3  
kind: VirtualService  
metadata:  
  name: kayak-service  
spec:  
  hosts:  
  - "*"  
  gateways:  
  - kayak-gateway  
  http:  
  - match:  
    - uri:  
        prefix: /  
    route:  
    - destination:  
        port:  
          number: 8000  
        host: kayak-service

并应用:

kubectl apply -f istio-gateway.yml

您应该得到:

gateway.networking.istio.io "kayak-gateway" created
virtualservice.networking.istio.io "kayak-service" created

测试已部署的Google Kubernetes Engine + Spring Boot App

既然您已成功将Spring Boot应用程序部署到Google Kubernetes集群并创建了将服务链接到外部世界的网关,您将需要测试端点。

Istio网站上有一些关于入口流量的优秀文档,这些文档具有很多很好的信息。 下面是从该页面复制的一些命令,这些命令将确定面向公众的主机/ ip地址和端口并将其保存到shell变量中

export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}');
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}');

在您的配置中, INGRESS_PORT可能只是HTTP的默认80(无SSL)。

运行以下命令以查看主机和端口:

echo "$INGRESS_HOST, HTTP PORT=$INGRESS_PORT";

也可以通过在Cloud Platform仪表板-> Kubernetes Engine->服务中查看负载均衡器IP地址来找到公共IP地址。 寻找类型LoadBalancer的 istio-ingressgateway服务。

测试应用程序!

http $INGRESS_HOST:$INGRESS_PORT/

您应该看到:

HTTP/1.1 200 OK
content-type: text/plain;charset=UTF-8
...

Alive

并点击/kayaks端点:

http $INGRESS_HOST:$INGRESS_PORT/kayaks

您应该看到:

HTTP/1.1 200 OK
content-type: application/json;charset=UTF-8
...
[
  {
    "makeModel": "NDK",
    "name": "sea",
    "owner": "Andrew",
    "value": 300.12
  },
  {
    "makeModel": "Piranha",
    "name": "creek",
    "owner": "Andrew",
    "value": 100.75
  },
  {
    "makeModel": "Necky",
    "name": "loaner",
    "owner": "Andrew",
    "value": 75
  }
]

欢迎来到微服务的世界!

显然,GKE和Istio可以完成更多工作。 在实践中,微服务通常管理大型服务网格和已部署的Pod,可以根据需要进行扩展和缩小,并且可以在不同部分之间以及与外部世界一起管理复杂的安全体系结构。 本教程将不涉及更多内容,但是还需要再走一步:使用Okta添加JSON Web令牌身份验证。

在Okta上创建OpenID Connect应用程序

登录到您的developer.okta.com帐户(您确实注册了他们的免费开发者帐户之一,对吗?如果不是,请前往developer.okta.com )。

单击应用程序顶部菜单,然后单击添加应用程序按钮。

选择应用程序类型Web

微服务架构

单击下一步

为应用命名。 我将其命名为“ Spring Boot GKE”。

登录重定向URI下,添加https://oidcdebugger.com/debug

在底部,在允许的授予类型下 ,选中隐式(混合)框。

微服务架构

单击完成

让页面保持打开状态,并记下Client IDClient Secret 。 使用OIDC调试器生成JSON Web令牌时,一分钟之内将需要它们。

更新OAuth 2.0的Spring Boot微服务

将以下依赖项添加到您的build.gradle

compile 'org.springframework.security:spring-security-oauth2-client'
compile 'org.springframework.security:spring-security-oauth2-resource-server'

您还需要将以下内容添加到src/main/resources/application.properties文件中(填写您自己的Oktadeveloper URL,类似于dev-123456.okta.com):

spring.security.oauth2.resourceserver.jwt.issuer-uri=https://{yourOktaDomain}/oauth2/default

这告诉Spring需要在什么地方对即将生成的JSON Web令牌(JWT)进行身份验证。

最后,您需要添加一个名为SecurityConfiguration.java的新Java类:

package com.okta.spring.springbootkbe;  
  
import org.springframework.context.annotation.Bean;  
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;  
import org.springframework.security.config.web.server.ServerHttpSecurity;  
import org.springframework.security.web.server.SecurityWebFilterChain;  
  
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
            .authorizeExchange()
            .pathMatchers("/").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt();
        return http.build();
    }
}

此文件将项目配置为允许根端点上的所有事务,但授权所有其他事务。

构建一个新的Docker映像并推送到GKE集群

现在您有了一个新的,启用了身份验证的Spring Boot应用程序,您需要对其进行构建,将其打包在Docker容器中,将其推送到Google Cloud Docker注册表中,然后将新的部署应用于Kubernetes集群。

从您的外壳转到项目根目录。

使用身份验证更新构建Spring Boot应用程序:

gradle clean build

构建新的Docker映像。 注意新的映像名称(包括-auth )。 另外:确保您的Docker桌面正在运行。

docker build -t kayak-app-auth:1.0 .

标记您的Docker映像并将其推送到Google Cloud容器注册表。 如有必要,请在回购路径中更改项目名称。

docker tag kayak-app-auth:1.0 gcr.io/$PROJECT_NAME/kayak-app-auth:1.0;  
docker push gcr.io/$PROJECT_NAME/kayak-app-auth:1.0;

删除集群上已部署的Pod:

kubectl delete -f deployment.yml

更新deployment.yml文件以反映新的映像名称(文件中的第28行):

spec:  
  containers:  
    - name: kayak-app  
      image: gcr.io/spring-boot-gke/kayak-app-auth:1.0

重新部署更新的Kubernetes部署:

kubectl apply -f deployment.yml

使用kubectl get pods检查pod的状态。 完全更新将需要几秒钟。 准备就绪后,测试/端点。

http $INGRESS_HOST:$INGRESS_PORT/
HTTP/1.1 200 OK
...

Alive

/kayaks端点,应该对其进行保护:

$ http $INGRESS_HOST:$INGRESS_PORT/kayaks
HTTP/1.1 401 Unauthorized
...

很近! 您需要做的最后一件事是使用OIDC调试器工具生成令牌并测试JWT身份验证。

生成一个JWT并测试OAuth 2.0

转到OIDC调试器 。 您需要从Okta OIDC应用程序中获取客户ID

  • 填写授权URI: https://{yourOktaDomain} /oauth2/default/v1/authorize
  • 填写客户ID
  • abcdefstate
  • 点击底部的发送请求

复制生成的令牌,并将其存储在shell变量中以方便使用:

TOKEN=eyJraWQiOiI4UlE5REJGVUJOTnJER0VGaEExekd6bWJqREp...

再次在/kayaks端点上运行GET,这次使用令牌:

http $INGRESS_HOST:$INGRESS_PORT/kayaks Authorization:"Bearer $TOKEN"

注意双引号! 单引号不起作用,因为该变量不会在字符串中扩展。

您应该得到:

HTTP/1.1 200 OK
cache-control: no-cache, no-store, max-age=0, must-revalidate
content-type: application/json;charset=UTF-8
...
[
  {
    "makeModel": "NDK",
    "name": "sea",
    "owner": "Andrew",
    "value": 300.12
  },
  {
    "makeModel": "Piranha",
    "name": "creek",
    "owner": "Andrew",
    "value": 100.75
  },
  {
    "makeModel": "Necky",
    "name": "loaner",
    "owner": "Andrew",
    "value": 75
  }
]

使用Spring Boot微服务和Kubernetes向前发展

而已! 您已经在这里盖了一吨土地。 您使用Istio在Google Cloud上使用Google Kubernetes创建了Kubernetes集群。 您已将本地系统配置为使用gcloudkubectl与集群进行kubectl 。 您创建了一个使用MongoDB后端的Spring Boot应用,对其进行了docker化处理,并将其推送到Google Cloud注册表中,然后将其部署到您的集群中。 您还向应用程序添加了OIDC身份验证。

您可以在oktadeveloper / okta-spring-boot-microservice-kubernetes的 GitHub上找到此示例的源代码。

如果您喜欢微服务和Spring Boot,那么您可能也喜欢这些帖子:

如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 在Twitter上关注@oktadev在Facebook上关注我们,或订阅我们的YouTube频道

使用Spring Boot和Kubernetes构建微服务架构 ”最初于2019年4月1日发布在Okta开发者博客上。

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

翻译自: https://www.javacodegeeks.com/2019/04/build-microservice-architecture-spring-boot-kubernetes.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值