【2019 年 11 月版】 使用 Quarkus + Panache 探索将 CosmosDB 作为 MongoDB 的新方法

在Quarkus的Panache-Mongo中,简单入门CosmosDB。

这次我想使用 Azure 的分布式多模型数据库 CosmosDB 作为数据库,结合常用的 Quarkus + Panache 来构建一个简单的 REST API。

由于 CosmosDB 是”多模型”数据库,所以可以通过多种接口进行访问。(在创建实例时可以选择使用哪种模型,并且创建后访问只能在该模型下进行,因此不能同时从多个模型的API访问同一个实例)。

让我们尝试一下之前没有做过的 Panache 的 MongoDB 兼容功能。

创造 CosmosDB 实例

新規リソース - Microsoft Azure.png

请确保在创建 CosmosDB 资源时将 API 设置为“MongoDB”。

Azure Cosmos DB アカウントの作成 - Microsoft Azure.png
CosmosDB 接続文字列 - Microsoft Azure.png

2. 创建Quarkus项目

首先,请参考以下官方指南,创建MongoDB+Panache与Quarkus的项目。

    QUARKUS – SIMPLIFIED MONGODB WITH PANACHE

我将执行以下的Maven命令。

$ mvn io.quarkus:quarkus-maven-plugin:1.0.0.Final:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=mongodb-panache-quickstart \
    -DclassName="org.acme.mongodb.panache.FruitResource" \
    -Dpath="/fruits" \
    -Dextensions="resteasy-jsonb,mongodb-panache"
...
$ cd mongodb-panache-quickstart

就像往常一样…嗯!!! quarkus-maven-plugin:1.0.0.Final!终于发布了正式版本!!!(刚刚在GitHub仓库检查到1.0.1.Final已经发布了但是…)

接下来,将刚刚保存的 CosmosDB 连接字符串作为 MongoDB 的连接地址添加到 application.properties 文件中。

# configure the MongoDB client for a replica set of two nodes
quarkus.mongodb.connection-string = mongodb://.............
# mandatory if you don't specify the name of the database using @MongoEntity
quarkus.mongodb.database = person

3. 创建Entity类

按照平常的方式创建Person实体。这次我们将其基类设置为PanacheMongoEntity。
另外,在类的注解中指定了保存的目标集合名为”ThePerson”。

package org.acme.mongodb.panache.model;

import java.time.LocalDate;

import org.bson.codecs.pojo.annotations.BsonProperty;

import io.quarkus.mongodb.panache.MongoEntity;
import io.quarkus.mongodb.panache.PanacheMongoEntity;

@MongoEntity(collection="ThePerson")
public class Person extends PanacheMongoEntity {
    public enum Status {
        Alive, DECEASED
    }
    public String name;

    // will be persisted as a 'birth' field in MongoDB
    @BsonProperty("birth")
    public LocalDate birthDate;

    public Status status;
}

使用@BsonProperty注解将birthDate字段在BSON中的键设置为birth。接下来我们来实现REST API。

4. 实现 REST API

我将制作一个只有POST和GET的简单API。

package org.acme.mongodb.panache;

import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import org.acme.mongodb.panache.model.Person;
import org.bson.types.ObjectId;

@Path("/person")
@Produces(MediaType.APPLICATION_JSON)
public class PersonResource {

    @POST
    public Person create(Person person) {
        person.persist();
        return person;
    }

    @GET
    @Path("/{id}")
    public Person get(@PathParam("id") ObjectId id) {
        return Person.findById(id);
    }
}

几乎与使用Hibernate时的情况相同,只有一点需要注意。PanacheMongoEntity将ID设置为org.bson.types.ObjectId类型。因此,请将要传递给findById的对象也设置为ObjectId类型。剩下的由Rest Easy和Panache处理。顺便提一下,目前的mongodb-panache插件似乎不支持事务处理。

在开发服务器上进行确认

让我们在开发服务器上完成实施后,暂时进行操作确认。
使用以下命令启动开发服务器。

$ mvn quarkus:dev

首先,在启动完成后,我们先试着通过终端使用curl命令进行POST JSON数据。

$ curl -H 'Content-Type:application/json' -d '{"name":"Alice","birth":"2010-10-11","status":"Alive"}' http://localhost:8080/person
{"id":"5ddfb90c682fc42ef21e666f","name":"Alice","status":"Alive"}
CosmosDB - データ エクスプローラー.png

我们从浏览器也可以尝试访问 http://localhost:8080/person/5ddfb90c682fc42ef21e666f!

localhost 8080 person 5ddfb90c682fc42ef21e666f.png

是的,虽然这是JSON格式的,没有任何花哨的装饰,但5ddfb90c682fc42ef21e666f已经获取到了!

6. 本地化

我試著挑戰成為母語使用者!

在连接到 CosmosDB 时,由于 SSL 是必需的,因此请参考以下页面进行 SSL 支持的本地构建。

    QUARKUS – USING SSL WITH NATIVE EXECUTABLES # Working with containers

只需将Dockerfile 设置如下即可。

## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/centos-quarkus-maven:19.2.1 AS build
RUN mkdir -p /tmp/ssl-libs/lib \
  && cp /opt/graalvm/jre/lib/security/cacerts /tmp/ssl-libs \
  && cp /opt/graalvm/jre/lib/amd64/libsunec.so /tmp/ssl-libs/lib/
COPY mongodb-panache-quickstart/src /usr/src/app/src
COPY mongodb-panache-quickstart/pom.xml /usr/src/app
USER root
RUN chown -R quarkus /usr/src/app
USER quarkus
RUN mvn -f /usr/src/app/pom.xml -Pnative -Dmaven.test.skip=true clean package

## Stage 2 : create the docker final image
FROM registry.access.redhat.com/ubi8/ubi-minimal
WORKDIR /work/
COPY --from=build /usr/src/app/target/*-runner /work/application
COPY --from=build /tmp/ssl-libs/ /work/
RUN chmod 775 /work
EXPOSE 8080
CMD ["./application", "-Dquarkus.http.host=0.0.0.0", "-Djava.library.path=/work/lib", "-Djavax.net.ssl.trustStore=/work/cacerts"]

直接在/tmp/ssl-libs目录下复制了GraalVM中的cacerts和sunec静态库,并将其添加到可执行镜像中以便引用。

接下来,我们将创建一个参考此文件的 docker-compose.yml。

version : "3"
services:
  quarkus:
    build:
      context: .
    ports:
      - 8080:8080

所以,进行构建工作。

$ docker-compose build

7. 确认母语者的行为

我们尽快启动吧。

$ docker-compose up -d

所以,照常使用curl进行POST请求。

$ $ curl -H 'Content-Type:application/json' -d '{"name":"Alice","birth":"2010-10-11","status":"Alive"}' http://localhost:8080/person
{"id":"5ddfc8c96b679d01d9bc40c0","name":"Alice","status":"Alive"}

刚才以不同的ID正常返回了!

我在浏览器中尝试访问 http://localhost:8080/person/5ddfc8c96b679d01d9bc40c0 。

localhost 8080 person 5ddfc8c96b679d01d9bc40c0.png

我們也可以從 CosmosDB 的資料探索器中進行確認。

Cosmos- データ エクスプローラー2.png

好耶,我们确认生成了第二份文件!辛苦啦!

总结

虽然有点仓促,但我们通过Panache经MongoDB客户端成功地实现了数据在CosmosDB的读写操作。同时,我们也确认了即使是通过本地构建的二进制文件,也可以正常地通过SSL连接到CosmosDB!虽然我们非常迫不及待地想要尝试在Azure容器上部署,但今天就到这里吧。

我已将本次的成果物上传至以下存储库,请参考。

    quarkus-examples branch panache-mongo-cosmos