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 界面。
所需的条件
- Google Cloud 项目
- 浏览器,例如 Google Chrome
2. 设置和要求
自定进度的环境设置
- 登录 Google Cloud 控制台,然后创建一个新项目或重复使用现有项目。如果您还没有 Gmail 或 Google Workspace 账号,则必须创建一个。
- 项目名称是此项目参与者的显示名称。它是 Google API 尚未使用的字符串。您可以随时对其进行更新。
- 项目 ID 在所有 Google Cloud 项目中是唯一的,并且是不可变的(一经设置便无法更改)。Cloud 控制台会自动生成一个唯一字符串;通常情况下,您无需关注该字符串。在大多数 Codelab 中,您都需要引用项目 ID(通常用
PROJECT_ID
标识)。如果您不喜欢生成的 ID,可以再随机生成一个 ID。或者,您也可以尝试自己的项目 ID,看看是否可用。完成此步骤后便无法更改该 ID,并且此 ID 在项目期间会一直保留。 - 此外,还有第三个值,即部分 API 使用的项目编号,供您参考。如需详细了解所有这三个值,请参阅文档。
- 接下来,您需要在 Cloud 控制台中启用结算功能,以便使用 Cloud 资源/API。运行此 Codelab 应该不会产生太多的费用(如果有的话)。若要关闭资源以避免产生超出本教程范围的结算费用,您可以删除自己创建的资源或删除项目。Google Cloud 新用户符合参与 300 美元免费试用计划的条件。
激活 Cloud Shell
- 在 Cloud Console 中,点击激活 Cloud Shell。
如果这是您第一次启动 Cloud Shell,系统会显示一个中间屏幕,说明它是什么。如果您看到中间屏幕,请点击继续。
预配和连接到 Cloud Shell 只需花几分钟时间。
这个虚拟机装有所需的所有开发工具。它提供了一个持久的 5 GB 主目录,并在 Google Cloud 中运行,大大增强了网络性能和身份验证功能。您在此 Codelab 中的大部分(即使不是全部)工作都可以通过浏览器完成。
在连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设为您的项目 ID。
- 在 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`
- 在 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. 在本地运行应用
- 确保 JAVA_HOME 设置为正确的版本:
$ export JAVA_HOME=/usr/lib/jvm/java-1.17.0-openjdk-amd64
- 您可以使用 Spring Boot 插件正常启动 Spring Boot 应用。
$ ./mvnw -DskipTests spring-boot:run
- 在应用启动后,点击 Cloud Shell 工具栏中的网页预览,然后选择在端口 8080 上预览。
您的浏览器会打开一个标签页,并连接到您刚启动的服务器。
5. 将 Java 应用打包为 Docker 容器
接下来,您需要准备好应用以便在 Kubernetes 上运行。第一步是定义容器及其内容。
- 为应用创建可部署的 JAR。
$ ./mvnw -DskipTests package
- 启用 Artifact Registry API 以存储您将创建的容器映像。
$ gcloud services enable artifactregistry.googleapis.com
- 创建新的 Docker 代码库(如果不存在)。您必须先创建一个代码库,然后才能向其推送映像:
$ gcloud artifacts repositories create codelabrepo --repository-format=docker --location=us-central1
- 您的图片将采用以下格式:
{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
- 使用 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
- 导航到 Cloud 控制台中的 Artifacts Registry 映像页面,应该能看到控制台中列出的容器映像。您现在拥有一个适用于整个项目的 Docker 映像,Kubernetes 可对其进行访问和编排(几分钟后您便会看到)。
- (可选)完成后(下载和提取所有内容需要一些时间),请使用以下命令测试映像,这会在端口 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
- 再次充分利用 Cloud Shell 的网页预览功能。
- 您应该会在新标签页中看到默认页面。确认应用正在 Docker 容器中本地运行后,您可以按
Control+C
停止正在运行的容器。
6. 创建集群
您已准备好创建 GKE 集群。集群由 Google 管理的 Kubernetes API 服务器和一组工作器节点组成。工作器节点是 Compute Engine 虚拟机。
- 首先,请确保启用相关的 API 功能。
$ gcloud services enable compute.googleapis.com container.googleapis.com
- 创建一个包含两个
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 集群。
现在是时候将容器化应用部署到 Kubernetes 集群了!从现在开始,您将使用 kubectl
命令行(已在 Cloud Shell 环境中设置)。此 Codelab 的其余部分要求 Kubernetes 客户端和服务器版本为 1.2 或更高版本。kubectl
version
会显示该命令的当前版本。
7. 将您的应用部署到 Kubernetes
- Kubernetes Deployment 可以使用您创建的容器映像创建、管理和扩缩应用的多个实例。使用
kubectl run
命令将应用的一个实例部署到 Kubernetes。
$ kubectl create deployment hello-java --image=us-central1-docker.pkg.dev/$GOOGLE_CLOUD_PROJECT/codelabrepo/hello-java:v1
- 要查看您创建的 Deployment,只需运行以下命令:
$ kubectl get deployments NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE hello-java 1 1 1 1 37s
- 如需查看该 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 服务。
- 在 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 外部进行访问。
- 如需查找服务的可公开访问的 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
- 现在,通过将浏览器指向
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 可帮助您将新版本部署到生产环境,而不会影响您的用户。
- 点击 Cloud Shell 菜单中的打开编辑器 ,打开代码编辑器。
- 导航到
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!";
}
}
- 使用 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 顺利将您的副本控制器更新到新版应用了!
- 如需更改正在运行的容器的映像标签,您需要修改现有的
hello-java
部署并从us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/hello-java:v1
更改映像
到us-central1-docker.pkg.dev/PROJECT_ID/codelabrepo/hello-java:v2
- 您可以使用
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
- 再次检查
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