你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

在 Azure Kubernetes 服务群集上使用 Quarkus 部署 Java 应用程序

本文介绍如何使用简单的 CRUD 应用程序在 Azure Kubernetes 服务 (AKS) 上快速部署 Red Hat Quarkus。 该应用程序是具有 JavaScript 前端和 REST 终结点的“待办事项列表”。 Azure Database for PostgreSQL 为应用提供持久性层。 本文介绍如何在本地测试应用并将其部署到 AKS。

先决条件

  • 如果没有 Azure 订阅,请在开始之前创建一个 Azure 免费帐户
  • Azure Cloud Shell 预先安装了所有的先决条件。 更多内容请参阅《Azure Cloud Shell 快速入门》。
  • 如果在本地运行本指南中的命令(而不是使用 Azure Cloud Shell),请完成以下步骤:
    • 准备一台安装了类似于 Unix 的操作系统(例如 Ubuntu、macOS 或适用于 Linux 的 Windows 子系统)的本地计算机。
    • 安装 Java SE 实现(例如, Microsoft Build of OpenJDK)。
    • 安装 Maven 3.5.0 或更高版本。
    • 安装适用于 OS 的 DockerPodman
    • 安装 jq
    • 安装 cURL
    • 安装 Quarkus CLI
  • 适用于 Unix 类环境的 Azure CLI。 本文仅需要 Azure CLI 的 Bash 环境。
    • 在代码中使用 DefaultAzureCredential 之前,开发人员应安装 Azure CLI 并使用 az login 命令以交互方式登录 Azure。
      az login
      
    • 本文需要的 Azure CLI 最低版本为 2.31.0。 如果使用 Azure Cloud Shell,则最新版本已安装。

创建应用项目

使用以下命令克隆本文的示例 Java 项目。 该示例位于 GitHub 上。

git clone https://github.com/Azure-Samples/quarkus-azure
cd quarkus-azure
git checkout 2023-07-17
cd aks-quarkus

如果看到有关处于拆离的 HEAD 状态的消息,可以放心忽略此消息。 由于本文不需要任何提交,因此拆离的 HEAD 状态是合适的。

在本地测试 Quarkus 应用

本部分的步骤介绍如何在本地运行应用。

Quarkus 支持在开发和测试模式下自动预配未配置的服务。 Quarkus 将此功能称为开发服务。 假设你有 Quarkus 功能,例如连接到数据库服务。 你想要测试应用,但尚未完全配置与真实数据库的连接。 Quarkus 会自动启动相关服务的存根版本,并将应用程序连接到该服务。 更多信息请参阅 Quarkus 文档中的《开发服务概述》 。

请确保容器环境(Docker 或 Podman)正在运行,并使用以下命令进入 Quarkus 开发模式:

quarkus dev

使用 mvn quarkus:dev 取代 quarkus dev 通过 Maven 完成相同的操作。

系统可能会询问是否要发送 Quarkus 开发模式使用情况的遥测数据。 如果询问,请根据需要回答。

Quarkus 开发模式支持实时重载和后台编译。 对应用源代码进行任何修改后,刷新浏览器就可以看到更改。 错误页会显示任何编译或部署问题。 Quarkus 开发模式在 5005 端口上侦听调试程序。 如果要在运行之前等待附加调试程序,请在命令行输入 -Dsuspend。 如果根本不需要调试程序,可以使用 -Ddebug=false

输出应如以下示例所示:

__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
INFO  [io.quarkus] (Quarkus Main Thread) quarkus-todo-demo-app-aks 1.0.0-SNAPSHOT on JVM (powered by Quarkus 3.2.0.Final) started in 3.377s. Listening on: http://localhost:8080

INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, resteasy-reactive, resteasy-reactive-jackson, smallrye-context-propagation, vertx]

--
Tests paused
Press [e] to edit command line args (currently ''), [r] to resume testing, [o] Toggle test output, [:] for the terminal, [h] for more options>

在运行 Quarkus 开发模式的终端上按 w 键。 w 键将打开默认 Web 浏览器并显示 Todo 应用程序。 还可以直接在 http://localhost:8080 访问应用程序 GUI。

待办事项示例应用程序的屏幕截图。

请尝试在待办事项列表中选择待办事项。 UI 用删除线文本样式提示选择。 还可以通过键入“验证待办事项应用”并按 ENTER 键将新的待办事项添加到待办事项列表,如以下屏幕截图所示:

待办事项示例应用程序添加新事项的屏幕截图。

访问 RESTful API (/api) 以获取存储在本地 PostgreSQL 数据库中的所有待办事项:

curl --verbose http://localhost:8080/api | jq .

输出应如以下示例所示:

* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /api HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-length: 664
< Content-Type: application/json;charset=UTF-8
<
{ [664 bytes data]
100   664  100   664    0     0  13278      0 --:--:-- --:--:-- --:--:-- 15441
* Connection #0 to host localhost left intact
[
  {
    "id": 1,
    "title": "Introduction to Quarkus Todo App",
    "completed": false,
    "order": 0,
    "url": null
  },
  {
    "id": 2,
    "title": "Quarkus on Azure App Service",
    "completed": false,
    "order": 1,
    "url": "https://learn.microsoft.com/en-us/azure/developer/java/eclipse-microprofile/deploy-microprofile-quarkus-java-app-with-maven-plugin"
  },
  {
    "id": 3,
    "title": "Quarkus on Azure Container Apps",
    "completed": false,
    "order": 2,
    "url": "https://learn.microsoft.com/en-us/training/modules/deploy-java-quarkus-azure-container-app-postgres/"
  },
  {
    "id": 4,
    "title": "Quarkus on Azure Functions",
    "completed": false,
    "order": 3,
    "url": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-first-quarkus"
  },
  {
    "id": 5,
    "title": "Verify Todo apps",
    "completed": false,
    "order": 5,
    "url": null
  }
]

q 键退出 Quarkus 开发模式。

创建 Azure 资源以运行 Quarkus 应用

本部分的步骤介绍如何创建以下 Azure 资源来运行 Quarkus 示例应用:

  • Azure Database for PostgreSQL
  • Azure 容器注册表 (ACR)
  • Azure Kubernetes 服务 (AKS)

其中一些资源必须在 Azure 订阅范围内具有唯一的名称。 若要确保这种唯一性,可以使用首字母缩写、序列、日期、后缀模式。 若要应用此模式,请通过首字母缩写、序列号、当日日期和特定资源后缀来命名资源,例如,rg 表示“资源组”。 使用以下命令定义环境变量,以便稍后使用:

export UNIQUE_VALUE=<your unique value, such as ejb010717>
export RESOURCE_GROUP_NAME=${UNIQUE_VALUE}rg
export LOCATION=<your desired Azure region for deploying your resources. For example, eastus>
export REGISTRY_NAME=${UNIQUE_VALUE}reg
export DB_SERVER_NAME=${UNIQUE_VALUE}db
export CLUSTER_NAME=${UNIQUE_VALUE}aks
export AKS_NS=${UNIQUE_VALUE}ns

创建用于 PostgreSQL 的 Azure 数据库

Azure Database for PostgreSQL 是一种托管服务,可在 Azure 云中运行、管理和缩放具有高可用性的 PostgreSQL 数据库。 本部分导向单独的快速入门,介绍如何创建单个 Azure Database for PostgreSQL 服务器并与其连接。 但是,按照快速入门中的步骤操作时,需要使用下表中的设置来自定义示例 Quarkus 应用的数据库部署。 填写 Azure 门户中的字段时,请将环境变量替换为实际值。

设置 说明
资源组 ${RESOURCE_GROUP_NAME} 选择“新建”。 部署会创建该新资源组。
服务器名称 ${DB_SERVER_NAME} 此值构成数据库服务器主机名的一部分。
位置 ${LOCATION} 从下拉列表中选择一个位置。 请记下位置。 其他创建的 Azure 资源必须使用此相同位置。
管理员用户名 quarkus 示例代码假定使用此值。
Password Secret123456 示例代码假定使用此值。

脑中记得替换这些数据,同时请按照《快速入门:使用Azure 门户创建 Azure Database for PostgreSQL 服务器》中的步骤操作,直到“配置防火墙规则”部分。 然后,在“配置防火墙规则”部分中,确保为“允许访问 Azure 服务”选择“是”,然后选择“保存”。 如果忽略此操作,Quarkus 应用则无法访问数据库,并且根本无法启动。

完成“配置防火墙规则”部分的所有快速入门步骤(包括允许访问 Azure 服务的步骤)后,请返回到本文。

在 PostgreSQL 中创建待办事项数据库

你在前面创建的 PostgreSQL 服务器为空。 没有任何可以与 Quarkus 应用程序配合使用的数据库。 使用以下命令创建名为 todo 的新数据库:

az postgres db create \
    --resource-group ${RESOURCE_GROUP_NAME} \
    --name todo \
    --server-name ${DB_SERVER_NAME}

必须使用 todo 作为数据库的名称,因为示例代码假定使用此数据库名称。

如果命令成功,输出将类似于以下示例:

{
  "charset": "UTF8",
  "collation": "English_United States.1252",
  "id": "/subscriptions/REDACTED/resourceGroups/ejb010718rg/providers/Microsoft.DBforPostgreSQL/servers/ejb010718db/databases/todo",
  "name": "todo",
  "resourceGroup": "ejb010718rg",
  "type": "Microsoft.DBforPostgreSQL/servers/databases"
}

创建 Microsoft Azure 容器注册表实例

由于 Quarkus 是一种云原生技术,因此它本身就支持创建在 Kubernetes 中运行的容器。 Kubernetes 完全依赖于容器注册表,它从中查找要运行的容器映像。 AKS 内置对 Azure 容器注册表 (ACR) 的支持。

使用 az acr create 命令创建 ACR 实例。 以下示例创建了以环境变量 ${REGISTRY_NAME} 的值为名的 ACR 实例:

az acr create \
    --resource-group $RESOURCE_GROUP_NAME \
    --location ${LOCATION} \
    --name $REGISTRY_NAME \
    --sku Basic \
    --admin-enabled

很快,你应该会在 JSON 输出中看到以下行:

  "provisioningState": "Succeeded",
  "publicNetworkAccess": "Enabled",
  "resourceGroup": "<YOUR_RESOURCE_GROUP>",

连接 Docker 和 ACR 实例

登录 ACR 实例。 登录后可以推送映像。 运行以下命令验证连接:

export LOGIN_SERVER=$(az acr show \
    --name $REGISTRY_NAME \
    --query 'loginServer' \
    --output tsv)
echo $LOGIN_SERVER
export USER_NAME=$(az acr credential show \
    --name $REGISTRY_NAME \
    --query 'username' \
    --output tsv)
echo $USER_NAME
export PASSWORD=$(az acr credential show \
    --name $REGISTRY_NAME \
    --query 'passwords[0].value' \
    --output tsv)
echo $PASSWORD
docker login $LOGIN_SERVER -u $USER_NAME -p $PASSWORD

如果使用 Podman 而不是 Docker,请对命令进行必要的更改。

成功登录到 ACR 实例后,应该会在命令输出的末尾看到 Login Succeeded

创建 AKS 群集

使用 az aks create 命令创建 AKS 群集。 以下示例用一个节点创建了以环境变量 ${CLUSTER_NAME} 的值为名的群集。 群集连接到在上述步骤中创建的 ACR 实例。 此命令需要几分钟才能完成。

az aks create \
    --resource-group $RESOURCE_GROUP_NAME \
    --location ${LOCATION} \
    --name $CLUSTER_NAME \
    --attach-acr $REGISTRY_NAME \
    --node-count 1 \
    --generate-ssh-keys \
    --enable-managed-identity

数分钟后,命令完成并返回有关群集的 JSON 格式信息,包括以下内容:

  "nodeResourceGroup": "MC_<your resource_group_name>_<your cluster name>_<your region>",
  "privateFqdn": null,
  "provisioningState": "Succeeded",
  "resourceGroup": "<your resource group name>",

连接到 AKS 群集

若要管理 Kubernetes 群集,可以使用 Kubernetes 命令行客户端 kubectl。 如果使用的是 Azure Cloud Shell,则 kubectl 已安装。 若要在本地安装 kubectl ,请使用 az aks install-cli 命令,如以下示例所示:

az aks install-cli

更多 kubectl 相关信息请参阅 Kubernetes 文档中的《命令行工具 (kubectl) 》。

若要将 kubectl 配置为连接到 Kubernetes 群集,请使用 az aks get-credentials 命令,如以下示例所示。 此命令将下载凭据,并将 Kubernetes CLI 配置为使用这些凭据。

az aks get-credentials \
    --resource-group $RESOURCE_GROUP_NAME \
    --name $CLUSTER_NAME \
    --overwrite-existing \
    --admin

成功的输出文本与下列内容相似:

Merged "ejb010718aks-admin" as current context in /Users/edburns/.kube/config

k 的别名设置为 kubectl 是个实用技巧。 如果出现此情况,请使用以下命令:

alias k=kubectl

若要验证群集的连接,请使用 kubectl get 命令返回群集节点列表,如以下示例所示:

kubectl get nodes

以下示例输出显示在上一步创建的单个节点。 请确保节点的状态为 Ready

NAME                                STATUS   ROLES   AGE     VERSION
aks-nodepool1-xxxxxxxx-yyyyyyyyyy   Ready    agent   76s     v1.23.8

在 AKS 创建新的命名空间

使用以下命令在 Kubernetes 服务中为 Quarkus 应用创建新的命名空间:

kubectl create namespace ${AKS_NS}

输出应如以下示例所示:

namespace/<your namespace> created

自定义云原生配置

作为一项云原生技术,Quarkus 可以为标准 Kubernetes、Red Hat OpenShift 和 Knative 自动配置资源。 更多信息请参阅《Quarkus Kubernetes 指南》、《Quarkus OpenShift 指南》和《Quarkus Knative 指南》。 开发人员可以通过应用生成的清单将应用程序部署到目标 Kubernetes 群集。

若要生成适宜的 Kubernetes 资源,请使用以下命令在本地终端中添加 quarkus-kubernetescontainer-image-jib 扩展:

quarkus ext add kubernetes container-image-jib

Quarkus 修改 POM 以确保将这些扩展列为 <dependencies>。 如果系统要求安装名为 JBang 的内容,请点击“是”允许安装。

输出应如以下示例所示:

[SUCCESS] ✅  Extension io.quarkus:quarkus-kubernetes has been installed
[SUCCESS] ✅  Extension io.quarkus:quarkus-container-image-jib has been installed

若要验证是否已添加扩展,可以运行 git diff 检查输出。

作为一项云原生技术,Quarkus 支持配置文件概念。 Quarkus 拥有以下三个内置的配置文件:

  • dev - 处于开发模式时激活
  • test - 在运行测试时激活
  • prod - 未在开发或测试模式下运行时的默认配置文件

Quarkus 根据需要支持任意数量的命名配置文件。

本部分中的剩余步骤指导取消注释和自定义 src/main/resources/application.properties 文件中的值。 通过删除前导 # %prod.,确保取消所有以 # 开头行的注释。

prod. 前缀表明在 prod 配置文件中运行时这些属性处于活动状态。 有关配置文件的详细信息,请参阅Quarkus 文档

数据库配置

添加以下数据库配置变量。 将 <DB_SERVER_NAME_VALUE> 的值替换为环境变量 ${DB_SERVER_NAME} 的实际值。

# Database configurations
%prod.quarkus.datasource.db-kind=postgresql
%prod.quarkus.datasource.jdbc.url=jdbc:postgresql://<DB_SERVER_NAME_VALUE>.postgres.database.azure.com:5432/todo
%prod.quarkus.datasource.jdbc.driver=org.postgresql.Driver
%prod.quarkus.datasource.username=quarkus@<DB_SERVER_NAME_VALUE>
%prod.quarkus.datasource.password=Secret123456
%prod.quarkus.hibernate-orm.database.generation=drop-and-create

Kubernetes 配置

添加以下 Kubernetes 配置变量。 请确保将 service-type 设置为 load-balancer 以便在外部访问应用。

# AKS configurations
%prod.quarkus.kubernetes.deployment-target=kubernetes
%prod.quarkus.kubernetes.service-type=load-balancer

容器映像配置

作为一项云原生技术,Quarkus 支持生成与 Docker 和 Podman 兼容的 OCI 容器映像。 添加以下容器映像变量。 分别将 <LOGIN_SERVER_VALUE><USER_NAME_VALUE> 的值替换为 ${LOGIN_SERVER}${USER_NAME} 环境变量的实际值。

# Container Image Build
%prod.quarkus.container-image.build=true
%prod.quarkus.container-image.registry=<LOGIN_SERVER_VALUE>
%prod.quarkus.container-image.group=<USER_NAME_VALUE>
%prod.quarkus.container-image.name=todo-quarkus-aks
%prod.quarkus.container-image.tag=1.0

生成容器映像并推送到 ACR

现在,运行以下命令以生成应用程序。 此命令使用 Kubernetes 和 Jib 扩展来生成容器映像。

quarkus build --no-tests

输出应 BUILD SUCCESS 结尾。 Kubernetes 清单文件在 target/kubernetes 中生成,如以下示例所示:

tree target/kubernetes
target/kubernetes
├── kubernetes.json
└── kubernetes.yml

0 directories, 2 files

可以使用 dockerpodman 命令行 (CLI) 验证是否生成了容器映像。 输出与以下示例类似:

docker images | grep todo
<LOGIN_SERVER_VALUE>/<USER_NAME_VALUE>/todo-quarkus-aks   1.0       b13c389896b7   18 minutes ago   420MB

使用以下命令将容器映像推送到 ACR:

export TODO_QUARKUS_TAG=$(docker images | grep todo-quarkus-aks | head -n1 | cut -d " " -f1)
echo ${TODO_QUARKUS_TAG}
docker push ${TODO_QUARKUS_TAG}:1.0

输出应类似于以下示例:

The push refers to repository [<LOGIN_SERVER_VALUE>/<USER_NAME_VALUE>/todo-quarkus-aks]
dfd615499b3a: Pushed
56f5cf1aa271: Pushed
4218d39b228e: Pushed
b0538737ed64: Pushed
d13845d85ee5: Pushed
60609ec85f86: Pushed
1.0: digest: sha256:0ffd70d6d5bb3a4621c030df0d22cf1aa13990ca1880664d08967bd5bab1f2b6 size: 1995

将应用推送到 ACR 后,可以通知 AKS 运行应用。

将 Quarkus 应用部署到 AKS

本部分的步骤介绍如何在创建的 Azure 资源上运行 Quarkus 示例应用。

使用 kubectl apply 将 Quarkus 应用部署到 AKS

在命令行上输入 kubectl 以部署 Kubernetes 资源,如以下示例所示:

kubectl apply -f target/kubernetes/kubernetes.yml -n ${AKS_NS}

输出应如以下示例所示:

deployment.apps/quarkus-todo-demo-app-aks created

使用以下命令验证应用是否运行:

kubectl -n $AKS_NS get pods

如果 STATUS 字段的值显示除 Running 以外的任何内容,请在继续操作之前排查并解决问题。 使用以下命令可以帮助检查 Pod 日志:

kubectl -n $AKS_NS logs $(kubectl -n $AKS_NS get pods | grep quarkus-todo-demo-app-aks | cut -d " " -f1)

使用以下命令获取 EXTERNAL-IP 以访问待办事项应用程序:

kubectl get svc -n ${AKS_NS}

输出应如以下示例所示:

NAME                        TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)        AGE
quarkus-todo-demo-app-aks   LoadBalancer   10.0.236.101   20.12.126.200   80:30963/TCP   37s

可以使用以下命令将 EXTERNAL-IP 的值作为完全限定的 URL 保存到环境变量:

export QUARKUS_URL=http://$(kubectl get svc -n ${AKS_NS} | grep quarkus-todo-demo-app-aks | cut -d " " -f10)
echo $QUARKUS_URL

${QUARKUS_URL} 打开新的 Web 浏览器。 然后,添加一个文本内容为 Deployed the Todo app to AKS 的新待办事项。 此外,将 Introduction to Quarkus Todo App 事项选为完成。

AKS 上运行的待办事项示例应用程序的屏幕截图。

访问 RESTful API (/api) 以获取存储在 Azure PostgreSQL 数据库中的所有待办事项,如以下示例所示:

curl --verbose ${QUARKUS_URL}/api | jq .

输出应如以下示例所示:

* Connected to 20.237.68.225 (20.237.68.225) port 80 (#0)
> GET /api HTTP/1.1
> Host: 20.237.68.225
> User-Agent: curl/7.88.1
> Accept: */*
>
< HTTP/1.1 200 OK
< content-length: 828
< Content-Type: application/json;charset=UTF-8
<
[
  {
    "id": 2,
    "title": "Quarkus on Azure App Service",
    "completed": false,
    "order": 1,
    "url": "https://learn.microsoft.com/en-us/azure/developer/java/eclipse-microprofile/deploy-microprofile-quarkus-java-app-with-maven-plugin"
  },
  {
    "id": 3,
    "title": "Quarkus on Azure Container Apps",
    "completed": false,
    "order": 2,
    "url": "https://learn.microsoft.com/en-us/training/modules/deploy-java-quarkus-azure-container-app-postgres/"
  },
  {
    "id": 4,
    "title": "Quarkus on Azure Functions",
    "completed": false,
    "order": 3,
    "url": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-first-quarkus"
  },
  {
    "id": 5,
    "title": "Deployed the Todo app to AKS",
    "completed": false,
    "order": 5,
    "url": null
  },
  {
    "id": 1,
    "title": "Introduction to Quarkus Todo App",
    "completed": true,
    "order": 0,
    "url": null
  }
]

使用 Azure Cloud Shell 验证数据库是否已更新

选择“Cloud Shell”图标,在 Azure 门户中打开 Azure Cloud Shell,如以下屏幕截图所示:

Azure 门户的屏幕截图,其中突出显示了“Cloud Shell”按键。

在本地运行以下命令,并将结果粘贴到 Azure Cloud Shell:

echo psql --host=${DB_SERVER_NAME}.postgres.database.azure.com --port=5432 --username=quarkus@${DB_SERVER_NAME} --dbname=todo

当系统询问密码时,请使用创建数据库时使用的值。

使用以下查询获取所有待办事项:

select * from todo;

输出应类似于以下示例,并且应包含和以上所示待办事项应用 GUI 中相同的项:

查询输出 ASCII 表的屏幕截图。

如果在输出中看到 MORE,请键入 q 退出寻呼机。

输入 \q 退出 psql 程序并返回到 Cloud Shell。

清理资源

若要避免 Azure 费用,应清除不需要的资源。 如果不再需要群集,请使用 az group delete 命令来删除资源组、容器服务、容器注册表和所有的相关资源。

git reset --hard
docker rmi ${TODO_QUARKUS_TAG}:1.0
docker rmi postgres
az group delete --name $RESOURCE_GROUP_NAME --yes --no-wait

还可以使用 docker rmi 删除由 Quarkus 开发模式生成的容器映像 postgrestestcontainers

后续步骤