将 Spring Boot Java 应用部署到 Google Kubernetes Engine 上的 Kubernetes

1. 准备工作

Kubernetes 是一个开源项目,可在从笔记本电脑到高可用性多节点集群、从公有云到本地部署以及从虚拟机 (VM) 实例到裸金属等众多不同环境中运行。

在此 Codelab 中,您会将一个简单的 Spring Boot Java Web 应用部署到 GKE 上的 Kubernetes,目标是在 Kubernetes 上将 Web 应用作为复制应用运行。您需要将在机器上开发的代码转换为 Docker 容器映像,并在 GKE 上运行该映像。

您将使用 Google Cloud 上的全代管式 Kubernetes 服务 GKE,让您能够更专注于体验 Kubernetes,而不是设置底层基础架构。

如果您有兴趣在本地机器(如开发笔记本电脑)上运行 Kubernetes,不妨了解一下 Minikube,它为开发和测试目的提供了单节点 Kubernetes 集群的简单设置。如果需要,您可以使用 Minikube 完成此 Codelab。

此 Codelab 将使用使用 Spring Boot 构建应用指南中的示例代码。

前提条件

  • 熟悉 Java 编程语言和工具
  • 了解标准的 Linux 文本编辑器,例如 Vim、Emacs 和 nano

您将执行的操作

  • 将简单的 Java 应用打包为 Docker 容器。
  • 在 GKE 上创建 Kubernetes 集群。
  • 将 Java 应用部署到 GKE 上的 Kubernetes。
  • 扩大您的服务规模并发布升级。
  • 访问信息中心,这是基于网络的 Kubernetes 界面。

所需的条件

2. 设置和要求

自定进度的环境设置

  1. 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个

b35bf95b8bf3d5d8.png

a99b7ace416376c4.png

bd84a6d3004737c5.png

  • 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
  • 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用 PROJECT_ID 标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。
  • 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档
  1. 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。

激活 Cloud Shell

  1. 在 Cloud Console 中,点击激活 Cloud Shell853e55310c205094

55efc1aaa7a4d3ad.png

如果这是您第一次启动 Cloud Shell,系统会显示一个中间屏幕,说明它是什么。如果您看到中间屏幕,请点击继续

9c92662c6a846a5c

预配和连接到 Cloud Shell 只需花几分钟时间。

9f0e51b578fecce5

这个虚拟机装有所需的所有开发工具。它提供了一个持久的 5 GB 主目录,并在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的大部分(即使不是全部)工作都可以通过浏览器完成。

在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设为您的项目 ID。

  1. 在 Cloud Shell 中运行以下命令以确认您已通过身份验证:
gcloud auth list

命令输出

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目:
gcloud config list project

命令输出

[core]
project = <PROJECT_ID>

如果不是上述结果,您可以使用以下命令进行设置:

gcloud config set project <PROJECT_ID>

命令输出

Updated property [core/project].

3. 获取源代码

在 Cloud Shell 启动后,您可以使用命令行在主目录中克隆示例源代码。

$ git clone https://github.com/spring-guides/gs-spring-boot.git
$ cd gs-spring-boot/complete

4. 在本地运行应用

  1. 确保 JAVA_HOME 设置为正确的版本:
$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64
  1. 您可以使用 Spring Boot 插件正常启动 Spring Boot 应用。
$ ./mvnw -DskipTests spring-boot:run
  1. 在应用启动后,点击 Cloud Shell 工具栏中的网页预览1a94d5bd10bfc072,然后选择在端口 8080 上预览

6252b94905f3f7bd

您的浏览器会打开一个标签页,并连接到您刚启动的服务器。

9b6c29059957bd0.jpeg

5. 将 Java 应用打包为 Docker 容器

接下来,您需要准备好应用以便在 Kubernetes 上运行。第一步是定义容器及其内容。

  1. 为应用创建可部署的 JAR。
$ ./mvnw -DskipTests package
  1. 启用 Artifact Registry API 以存储您将创建的容器映像。
$ gcloud services enable artifactregistry.googleapis.com
  1. 创建新的 Docker 代码库(如果不存在)。您必须先创建一个代码库,然后才能向其推送映像:
$ gcloud artifacts repositories create codelabrepo     --repository-format=docker --location=us-central1 
  1. 您的图片将采用以下格式:

{LOCATION}-docker.pkg.dev/{PROJECT-ID}/{REPOSITORY}/{IMAGE-NAME}

例如,如果您已在位置 us-central1 中创建了名为 codelabrepo 的仓库,并且您想将映像命名为 hello-java:v1,该映像将如下所示:

us-central1-docker.pkg.dev/{PROJECT-ID}/codelabrepo/hello-java:v1

  1. 使用 Jib 创建容器映像并将其推送到 Artifact Registry。
$ export GOOGLE_CLOUD_PROJECT=`gcloud config list --format="value(core.project)"`

$ ./mvnw -DskipTests com.google.cloud.tools:jib-maven-plugin:build -Dimage=us-central1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/codelabrepo/hello-java:v1
  1. 导航到 Cloud 控制台中的 Artifacts Registry 映像页面,应该能看到控制台中列出的容器映像。您现在拥有一个适用于整个项目的 Docker 映像,Kubernetes 可对其进行访问和编排(几分钟后您便会看到)。
  2. (可选)完成后(下载和提取所有内容需要一些时间),请使用以下命令测试映像,这会在端口 8080 上从您新创建的容器映像运行 Docker 容器作为守护程序。如果您遇到权限问题,请先运行 gcloud auth configure-docker us-central1-docker.pkg.dev
$ docker run -ti --rm -p 8080:8080 \
  us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1
  1. 再次充分利用 Cloud Shell 的网页预览功能。

6252b94905f3f7bd

  1. 您应该会在新标签页中看到默认页面。确认应用正在 Docker 容器中本地运行后,您可以按 Control+C 停止正在运行的容器。

6. 创建集群

您已准备好创建 GKE 集群。集群由 Google 管理的 Kubernetes API 服务器和一组工作器节点组成。工作器节点是 Compute Engine 虚拟机。

  1. 首先,请确保启用相关的 API 功能。
$ gcloud services enable compute.googleapis.com container.googleapis.com
  1. 创建一个包含两个 n1-standard-1 节点的集群(需要几分钟才能完成)。
$ gcloud container clusters create hello-java-cluster \
  --num-nodes 2 \
  --machine-type n1-standard-1 \
  --zone us-central1-c

最后,您应该会看到创建的集群。

Creating cluster hello-java-cluster...done.
Created [https://container.googleapis.com/v1/projects/...].
kubeconfig entry generated for hello-dotnet-cluster.
NAME                  ZONE            MASTER_VERSION  
hello-java-cluster  us-central1-c  ...

现在,您应该拥有一个由 GKE 提供支持且功能齐全的 Kubernetes 集群。

758c7fca14f70623

现在是时候将容器化应用部署到 Kubernetes 集群了!从现在开始,您将使用 kubectl 命令行(已在 Cloud Shell 环境中设置)。此 Codelab 的其余部分要求 Kubernetes 客户端和服务器版本为 1.2 或更高版本。kubectl version 会显示该命令的当前版本。

7. 将您的应用部署到 Kubernetes

  1. Kubernetes Deployment 可以使用您创建的容器映像创建、管理和扩缩应用的多个实例。使用 kubectl run 命令将应用的一个实例部署到 Kubernetes。
$ kubectl create deployment hello-java --image=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1
  1. 要查看您创建的 Deployment,只需运行以下命令:
$ kubectl get deployments

NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   1         1         1            1           37s
  1. 如需查看该 Deployment 创建的应用实例,请运行以下命令:
$ kubectl get pods

NAME                         READY     STATUS    RESTARTS   AGE
hello-java-714049816-ztzrb   1/1       Running   0          57s

此时,您应该让容器在 Kubernetes 的控制下运行,但您仍须允许外部世界访问该容器。

8. 允许外部流量

默认情况下,Pod 只能通过其在集群内的内部 IP 访问。为了使 hello-java 容器可以从 Kubernetes 虚拟网络外部进行访问,您必须将 Pod 公开为 Kubernetes 服务。

  1. 在 Cloud Shell 中,您可以通过创建 Kubernetes LoadBalancer Service 将 Pod 公开给公共互联网。
$ kubectl create service loadbalancer hello-java --tcp=8080:8080

请注意,您直接公开了 Deployment,而不是 Pod。这会使生成的服务对 Deployment 管理的所有 Pod 的流量进行负载均衡(在本例中,只有一个 Pod,但稍后您将添加更多副本)。

Kubernetes 主实例会创建负载均衡器和相关的 Compute Engine 转发规则、目标池和防火墙规则,以使该服务完全可从 Google Cloud 外部进行访问。

  1. 如需查找服务的可公开访问的 IP 地址,只需请求 kubectl 即可列出所有集群服务。
$ kubectl get services

NAME         CLUSTER-IP     EXTERNAL-IP      PORT(S)    AGE
hello-java   10.3.253.62    aaa.bbb.ccc.ddd  8080/TCP    1m
kubernetes   10.3.240.1     <none>           443/TCP    5m
  1. 现在,通过将浏览器指向 http://<EXTERNAL_IP>:8080,您应该能够访问该服务。

9. 扩缩您的服务

Kubernetes 提供了许多强大的功能,其中一个就是可以轻松扩缩应用。假设您突然需要为您的应用增加容量。您只需指示副本控制器为您的应用实例管理新数量的副本即可。

$ kubectl scale deployment hello-java --replicas=3

deployment "hello-java" scaled

$ kubectl get deployment
NAME         DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
hello-java   3         3         3            3           22m

请注意声明式方法。您无需启动或停止新实例,而是声明应始终运行的实例数量。Kubernetes 协调循环只是确保实际情况与您的要求相符,然后根据需要采取措施。

10. 发布服务升级

在某些情况下,您部署到生产环境的应用将需要进行问题修复或需要其他功能。Kubernetes 可帮助您将新版本部署到生产环境,而不会影响您的用户。

  1. 点击 Cloud Shell 菜单中的打开编辑器 2109d75686c889a,打开代码编辑器。
  2. 导航到 src/main/java/com/example/springboot/HelloController.java 并更新响应的值。
package com.example.springboot;

import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;

@RestController
public class HelloController {

    @RequestMapping("/")
    public String index() {
        return "Greetings from Google Kubernetes Engine!";
    }
}
  1. 使用 Jib 构建并推送新版本的容器映像。充分利用缓存后,构建和推送更新的映像应该会快得多。
$ ./mvnw -DskipTests package com.google.cloud.tools:jib-maven-plugin:build -Dimage=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v2

您现在可以让 Kubernetes 顺利将您的副本控制器更新到新版应用了!

  1. 如需更改正在运行的容器的映像标签,您需要修改现有的 hello-java 部署并从 us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/hello-java:v1 更改映像

us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/hello-java:v2

  1. 您可以使用 kubectl set image 命令要求 Kubernetes 通过滚动更新在整个集群中部署新版应用(每次一个实例)。
$ kubectl set image deployment/hello-java hello-java=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v2

deployment "hello-java" image updated
  1. 再次检查 http://EXTERNAL_IP:8080,看看它是否返回了新响应。

11. 回滚

糟糕!您是否在使用新版应用时出错?可能是因为新版本包含错误,您需要快速回滚。借助 Kubernetes,您可以轻松地将其回滚到先前的状态。通过运行以下命令回滚应用:

$ kubectl rollout undo deployment/hello-java

再次检查 http://EXTERNAL_IP:8080 时,您应该会看到旧响应。

12. 恭喜

您已了解如何构建基于 Java 的新 Web 应用并将其部署到 GKE 上的 Kubernetes。

清理

$ gcloud container clusters delete hello-java-cluster --zone us-central1-c

$ gcloud container images delete us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1 us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v2

了解详情