Azure 上的 Java:添加容器





5.00/5 (2投票s)
在本文中,我们将创建一个 Java 微服务来处理 Azure 表存储。
在上一篇文章中,我们准备了一个 Azure Kubernetes 集群来托管我们的容器化 Java 应用程序。在本系列最后一篇文章中,我们将创建一个 Java 微服务来处理Azure 表存储。然后,我们将对该微服务进行容器化,将其推送到容器注册表,并将容器化后的服务部署到我们的 Azure Kubernetes 集群。
创建 Java 微服务
我们将首先使用Quarkus框架来创建我们的微服务。请遵循这些说明开始。或者,一个更简单的替代方法是使用 Visual Studio Code。它有一个专用的 Quarkus 扩展,可以帮助您生成项目,其中还将包含 Dockerfile。安装 Quarkus 扩展后,使用 Visual Studio Code 命令面板开发 Quarkus 项目。
按如下方式配置您的 Quarkus 项目
- 构建工具:Maven
- 项目 groupId:com.temperatureservice
- 项目 artifactId:temperature-service
- 项目版本:1.0.0-SNAPSHOT
- 包名:com.temperatureservice
- 资源名:Temperature
生成的项目将在 docker 文件夹中包含四个 Dockerfile,以及 Temperature.java 文件(位于 java/com/temperatureservice 下),其中包含一个简单的 REST API,其中有一个 hello world
方法。我们将用一个从 SensorReadings
表中读取最近温度值的方法来替换此方法。为此,请在 pom.xml 文件的 dependencies
部分添加一个条目
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-storage</artifactId>
<version>4.2.0</version>
</dependency>
这会添加对 Java 的Azure 存储 SDK的引用。接下来,向项目中添加 SensorReadings
类
import com.microsoft.azure.storage.table.TableServiceEntity;
public class SensorReading extends TableServiceEntity{
private String PartitionKey;
private String RowKey;
private String Temperature;
// PartitionKey
public String getPartitionKey() { return this.PartitionKey; }
public void setPartitionKey(String key) { this.PartitionKey = key; }
// RowKey
public String getRowKey() { return this.RowKey; }
public void setRowKey(String key) { this.RowKey = key; }
// Temperature
public String getTemperature() { return this.Temperature; }
public void setTemperature(String temperature) { this.Temperature = temperature; }
}
上述类具有与我们在本系列第一篇文章中创建的类相同的结构。它派生自 TableServiceEntity
— Azure 存储 SDK 用于序列化和反序列化传输到或从 Azure 表存储传输的对象的基础类。
现在让我们按如下方式修改 Temperature.java
@Path("/temperature")
public class Temperature {
@GET
@Produces(MediaType.TEXT_PLAIN)
public String Get() {
try {
CloudTable cloudTable = GetCloudTable("SensorReadings");
// Filter items by the timestamp
String filter = GetTimeFilter();
TableQuery<SensorReading> tableQuery =
TableQuery.from(SensorReading.class)
.where(filter);
Iterable<SensorReading> sensorReadings = cloudTable.execute(tableQuery);
// Return recent temperature
if(sensorReadings.iterator().hasNext()){
SensorReading sensorReading = sensorReadings.iterator().next();
return sensorReading.getTemperature();
}
else
{
return "No recent sensor readings available";
}
}
catch (Exception e) {
return(e.toString());
}
}
// Other methods
}
上面的代码将连接到Azure 存储表实例,并检索过去一分钟的传感器读数。要连接到表,请添加以下辅助方法
private static CloudTable GetCloudTable(String tableName) {
// Connection string
final String connectionString =
"DefaultEndpointsProtocol=https;" +
"AccountName=<YOUR_ACCOUNT_NAME>;" +
"AccountKey=<YOUR_KEY>" +
"TableEndpoint=<YOUR_ENDPOINT>;";
try {
// Get storage account
CloudStorageAccount storageAccount = CloudStorageAccount.parse(connectionString);
// Create the table client
CloudTableClient tableClient = storageAccount.createCloudTableClient();
// Get table reference
return tableClient.getTableReference(tableName);
} catch (Exception e) {
return null;
}
}
该方法返回 CloudTable
实例,我们从中获取项目。要创建过滤器,请使用 GetTimeFilter
辅助方法
private static final String GetTimeFilter() {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"yyyy-MM-dd'T'HH:mm:ss.SS'Z'");
String dateTimeString = ZonedDateTime.now(ZoneId.of("UTC"))
.minusMinutes(1).format(formatter);
return String.format("Timestamp ge datetime'%s'", dateTimeString);
}
此辅助方法创建一个形状为 Timestamp ge datetime'2021-03-09T08:09:07.54Z'
的过滤器,其中 datetime
部分是动态创建的。
请记住,在实现 Azure Functions 时,我们在动态生成过滤器时遇到了问题。在此,我们通过以自己的集成代码以编程方式访问云表来解决此问题。
要测试微服务,请调用以下命令
mvn compile quarkus:dev
这将启动服务。
转到您的 Azure 表并添加一个项目。然后,向本地服务发送一个 GET 请求:https://:8080/temperature。它将返回温度,如下图所示。
使用 Azure 容器注册表
基本的 Docker 术语要求您在将 Docker 镜像部署到 Kubernetes 集群之前,先将其推送到注册表。在这里,我们将使用Azure 容器注册表 (ACR) 来创建我们自己的私有注册表。
让我们转到 Azure 门户并创建一个基本 SKU 的 ACR 注册表实例。我们将使用 ACR 实例 dbacr
。然后,我们需要将 ACR 附加到 AKS 集群。最简单的方法是通过 Azure CLI,调用以下命令(请参阅下面的屏幕截图)
az aks update -g aks-group -n akscluster --attach-acr dbacr
构建 Docker 镜像
要构建 Docker 镜像,我们可以使用与项目一起创建的四个 Dockerfile 之一。但是,这些仅在调用 mvn package 命令后在本地工作。为了克服这个问题,请修改 Dockerfile.jvm 以使用多阶段构建,其中首先构建应用程序,然后创建一个更轻的映像进行部署
FROM maven:3.6.3-jdk-11 AS MAVEN_BUILD # Copy the pom and src code to the container COPY ./ ./ # Package our application code RUN mvn clean package FROM registry.access.redhat.com/ubi8/ubi-minimal:8.3 ARG JAVA_PACKAGE=java-11-openjdk-headless ARG RUN_JAVA_VERSION=1.3.8 ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en' # Install java and the run-java script # Also set up permissions for user `1001` RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \ && microdnf update \ && microdnf clean all \ && mkdir /deployments \ && chown 1001 /deployments \ && chmod "g+rwX" /deployments \ && chown 1001:root /deployments \ && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \ && chown 1001 /deployments/run-java.sh \ && chmod 540 /deployments/run-java.sh \ && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security # Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size. ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager" # We make four distinct layers so if there are application changes the library layers can be reused COPY --from=MAVEN_BUILD --chown=1001 target/quarkus-app/lib/ /deployments/lib/ COPY --from=MAVEN_BUILD --chown=1001 target/quarkus-app/*.jar /deployments/ COPY --from=MAVEN_BUILD --chown=1001 target/quarkus-app/app/ /deployments/app/ COPY --from=MAVEN_BUILD --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ EXPOSE 8080 USER 1001 ENTRYPOINT [ "/deployments/run-java.sh" ]
您可以通过从应用程序文件夹调用以下命令来测试 Dockerfile(请注意,最后的 . 指向 docker 构建上下文 /current directory/)
docker build -f src/main/docker/Dockerfile.jvm -t quarkus/temperature-service-jvm . docker run -i --rm -p 8080:8080 quarkus/temperature-service-jvm
部署到 AKS
现在一切准备就绪,我们可以通过 Azure DevOps 管道将应用程序部署到 AKS 集群。最直接的方法是通过 Azure 门户中提供的部署中心。
部署中心使您可以快速创建 CI/CD 管道和必要的 Kubernetes 清单。要开始,请将您的代码推送到 Azure Repos。然后,在部署中心中单击“下一步”。在打开的页面中,选择您的项目和分支。
在下一步中,配置 Dockerfile 路径,将端口更改为“8080”,并在 Docker 构建上下文中键入“.”。
最后,创建新的 Kubernetes 命名空间并选择您的 Azure 容器注册表。
部署中心将配置 Azure DevOps 管道。您可以通过单击 Build 超链接来访问它们。
这将把您重定向到 Azure DevOps。以下是正在运行的 build
管道的一个示例
以下是 release
管道的一个示例
测试服务
在底层,部署中心创建了由以下部分组成的 Kubernetes 清单
- 使用推送到 Azure Kubernetes 服务的 Docker 镜像进行部署
- 通过 Azure 负载均衡器公开应用程序的服务
要访问 Quarkus 微服务,您需要获取服务的公共 IP。最简单的方法是通过 Azure Cloud Shell,调用以下命令
az aks get-credentials -n akscluster -g aks-group kubectl get svc --all-namespaces=true
您的服务的公共 IP 出现在 EXTERNAL-IP
列中。使用此 IP 地址向您的温度服务发送 GET 请求,如下所示
curl http://<YOUR_PUBLIC_IP>:8080/temperature
后续步骤
在本文中,我们创建了一个与 Azure 表存储协同工作的 Java 微服务。然后,我们对其进行了 Docker 化,并将其部署到了 Azure Kubernetes Service。Azure 表存储的连接字符串硬编码在服务中。实际上,您可以通过 Kubernetes 机密将其传递给 Docker 映像。
要了解有关在 Azure 上使用 Kubernetes 的更多信息,请浏览Kubernetes Bundle和Azure 上的 Kubernetes 入门实践。
在下一期 Java on Azure 系列中,我们将了解更多关于监控和扩展容器化应用程序、云原生身份验证以及利用云原生服务的信息。