Huab-native messaging ntawm Red Hat OpenShift platform siv Quarkus thiab AMQ Online

Nyob zoo sawv daws! Ntawm no nws yog - peb qhov kawg tshaj tawm hauv Quarkus series! (Los ntawm txoj kev, saib peb lub vev xaib "Qhov no yog Quarkus - Kubernetes haiv neeg Java moj khaum". Peb mam li qhia koj yuav pib li cas los ntawm kos lossis hloov cov kev daws teeb meem npaj txhij)

Huab-native messaging ntawm Red Hat OpenShift platform siv Quarkus thiab AMQ Online

Π’ yav dhau los Hauv cov ntawv tshaj tawm no, peb tau saib cov cuab yeej cuam tshuam uas tuaj yeem siv los ntsuas qhov kev txhim kho tau los ntawm kev hloov kho Java daim ntawv thov.

Txij li version 0.17.0, quarkus txhawb kev siv Advanced Message Queuing Protocol (AMQP), uas yog tus qauv qhib rau kev xa cov lus lag luam ntawm cov ntawv thov lossis cov koom haum.

Red Hat AMQ Online yog ib qho kev pabcuam tsim los ntawm kev qhib qhov project EnMasse thiab siv lub platform-based messaging mechanism Red Hat OpenShift. Yog xav paub ntxiv txog nws ua haujlwm li cas, saib ntawm no (EN). Niaj hnub no peb yuav qhia koj yuav ua li cas muab AMQ Online thiab Quarkus los tsim kom muaj OpenShift-based messaging system siv ob txoj kev xa xov tshiab.

Nws yog xav tias koj twb tau siv AMQ Online ntawm OpenShift platform (yog tias tsis yog, saib kev qhia installation).

Txhawm rau pib, peb yuav tsim ib daim ntawv thov Quarkus uas yuav yog qhov kev txiav txim yooj yim uas siv cov lus xa rov qab. Daim ntawv thov no yuav suav nrog lub tshuab hluav taws xob txiav txim uas xa cov lus xaj mus rau cov kab lus ntawm lub sijhawm tas mus li, nrog rau cov txheej txheem kev txiav txim uas yuav ua cov lus los ntawm kab thiab tsim cov ntawv pom zoo hauv qhov browser.

Thaum peb tau tsim daim ntawv thov, peb yuav qhia koj yuav ua li cas rau embed qhov kev xa xov teeb tsa rau hauv daim ntawv thov thiab siv AMQ Online los muab cov peev txheej peb xav tau ntawm lub kaw lus.

Quarkus app

Peb daim ntawv thov Quarkus khiav ntawm OpenShift thiab yog qhov hloov kho ntawm qhov program amqp-qib pib. Ib qho piv txwv tiav ntawm cov neeg siv khoom sab tuaj yeem pom no.

Order generator

Lub tshuab hluav taws xob tsuas yog xa cov ntawv xaj ID loj hlob mus rau "kev txiav txim" chaw nyob txhua 5 vib nas this.

@ApplicationScoped
public class OrderGenerator {
 
    private int orderId = 1;
 
    @Outgoing("orders")
    public Flowable<Integer> generate() {
        return Flowable.interval(5, TimeUnit.SECONDS)
        .map(tick -> orderId++);
    }
}

Order Processor

Tus neeg tswj kev txiav txim yog qhov yooj yim dua, nws tsuas yog xa rov qab daim ID nkag mus rau qhov chaw nyob "confirmations".

@ApplicationScoped
public class OrderProcessor {
    @Incoming("orders")
    @Outgoing("confirmations")
    public Integer process(Integer order) {
        // Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ подтвСрТдСния Ρ€Π°Π²Π΅Π½ ΡƒΠ΄Π²ΠΎΠ΅Π½Π½ΠΎΠΌΡƒ ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€Ρƒ Π·Π°ΠΊΠ°Π·Π° <img draggable="false" class="emoji" alt=":-)" src="https://s.w.org/images/core/emoji/11.2.0/svg/1f642.svg">
        return order * 2;
    }
}

Cov ntaub ntawv pov thawj

Cov ntaub ntawv lees paub yog HTTP kawg rau sau cov ntawv lees paub tsim los ntawm peb daim ntawv thov.

@Path("/confirmations")
public class ConfirmationResource {
 
    @Inject
    @Stream("confirmations") Publisher<Integer> orders;
 
    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String hello() {
        return "hello";
    }
 
 
    @GET
    @Path("/stream")
    @Produces(MediaType.SERVER_SENT_EVENTS)
    public Publisher<Integer> stream() {
        return orders;
    }
}

hloov

Txhawm rau txuas rau AMQ Online, peb daim ntawv thov yuav xav tau qee cov ntaub ntawv teeb tsa, xws li: Quarkus connector configuration, AMQP endpoint information thiab client credentials. Nws yog, ntawm chav kawm, zoo dua khaws tag nrho cov ntaub ntawv teeb tsa hauv ib qho chaw, tab sis peb yuav txhob txwm cais lawv los qhia cov kev xaiv tau rau kev teeb tsa Quarkus daim ntawv thov.

Cov khoom sib txuas

Connector configuration tuaj yeem muab tau ntawm lub sijhawm sib sau siv cov ntaub ntawv thov cov khoom:

mp.messaging.outgoing.orders.connector=smallrye-amqp
mp.messaging.incoming.orders.connector=smallrye-amqp

Txhawm rau khaws tej yam yooj yim, peb tsuas yog siv cov kab lus rau qhov chaw nyob "orders". Thiab qhov "confirmations" chaw nyob hauv peb daim ntawv thov yuav siv cov kab hauv nco.

AMQP qhov kawg

Thaum sib sau ua ke, lub npe hostname thiab tus lej chaw nres nkoj rau AMQP qhov kawg tsis paub, yog li lawv yuav tsum tau txhaj tshuaj. Qhov kawg tuaj yeem teeb tsa hauv configmap uas yog tsim los ntawm AMQ Online, yog li peb yuav txhais lawv los ntawm ib puag ncig hloov pauv hauv daim ntawv thov manifest:

spec:
  template:
    spec:
      containers:
      - env:
        - name: AMQP_HOST
          valueFrom:
            configMapKeyRef:
              name: quarkus-config
              key: service.host
        - name: AMQP_PORT
          valueFrom:
            configMapKeyRef:
              name: quarkus-config
              key: service.port.amqp

Cov ntaub ntawv pov thawj

Cov kev pabcuam tus lej token tuaj yeem siv los txheeb xyuas peb daim ntawv thov rau OpenShift. Txhawm rau ua qhov no, koj yuav tsum xub tsim ib qho kev cai ConfigSource uas yuav nyeem cov ntawv pov thawj token los ntawm cov ntaub ntawv pov thawj:

public class MessagingCredentialsConfigSource implements ConfigSource {
    private static final Set<String> propertyNames;
 
    static {
        propertyNames = new HashSet<>();
        propertyNames.add("amqp-username");
        propertyNames.add("amqp-password");
    }
 
    @Override
    public Set<String> getPropertyNames() {
        return propertyNames;
    }
 
    @Override
    public Map<String, String> getProperties() {
        try {
            Map<String, String> properties = new HashMap<>();
            properties.put("amqp-username", "@@serviceaccount@@");
            properties.put("amqp-password", readTokenFromFile());
            return properties;
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }
 
    @Override
    public String getValue(String key) {
        if ("amqp-username".equals(key)) {
            return "@@serviceaccount@@";
        }
        if ("amqp-password".equals(key)) {
            try {
                return readTokenFromFile();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }
        return null;
    }
 
    @Override
    public String getName() {
        return "messaging-credentials-config";
    }
 
    private static String readTokenFromFile() throws IOException {
        return new String(Files.readAllBytes(Paths.get("/var/run/secrets/kubernetes.io/serviceaccount/token")), StandardCharsets.UTF_8);
    }
}

Tsim thiab xa daim ntawv thov

Txij li thaum daim ntawv thov yuav tsum tau muab tso ua ke rau hauv cov ntaub ntawv executable, yuav tsum muaj GraalVM virtual tshuab. Yog xav paub ntxiv txog kev teeb tsa ib puag ncig rau qhov no, saib cov lus qhia sib xws hauv Quarkus Phau Ntawv Qhia.

Tom qab ntawd, ua raws li cov lus qhia tau muab rau ntawd, koj yuav tsum rub tawm qhov chaw, tsim thiab xa peb daim ntawv thov:

git clone https://github.com/EnMasseProject/enmasse-example-clients
cd enmasse-example-clients/quarkus-example-client
oc new-project myapp
mvn -Pnative -Dfabric8.mode=openshift -Dfabric8.build.strategy=docker package fabric8:build fabric8:resource fabric8:apply

Tom qab cov lus txib no, daim ntawv thov yuav raug xa mus, tab sis yuav tsis pib kom txog thaum peb teeb tsa cov kev xa xov peb xav tau hauv AMQ Online.

Kev teeb tsa lub tshuab xa xov

Tam sim no txhua yam uas tseem tshuav yog los teeb tsa cov peev txheej uas peb daim ntawv thov xav tau hauv kev xa xov. Txhawm rau ua qhov no, koj yuav tsum tsim: 1) qhov chaw nyob kom pib qhov kev xa xov kawg; 2) chaw nyob los teeb tsa qhov chaw nyob peb siv hauv daim ntawv thov; 3) Cov neeg siv xa xov los teeb tsa cov neeg siv khoom pov thawj.

Chaw nyob

Qhov Chaw Nyob Chaw Nyob hauv AMQ Online yog ib pab pawg ntawm cov chaw nyob uas qhia txog qhov kawg ntawm kev sib txuas thiab kev lees paub thiab kev tso cai txoj cai. Thaum koj tsim qhov chaw nyob, koj tuaj yeem qhia meej tias cov ntsiab lus xa xov yuav raug nthuav tawm li cas:

apiVersion: enmasse.io/v1beta1
kind: AddressSpace
metadata:
  name: quarkus-example
spec:
  type: brokered
  plan: brokered-single-broker
  endpoints:
  - name: messaging
    service: messaging
    exports:
    - name: quarkus-config
      kind: configmap

Chaw nyob

Chaw nyob yog siv los xa thiab txais cov lus. Txhua qhov chaw nyob muaj ib hom, uas txiav txim siab nws cov semantics, nrog rau cov phiaj xwm, uas qhia txog cov peev txheej uas yuav tsum tau khaws tseg. Qhov chaw nyob tuaj yeem txiav txim siab, piv txwv li, zoo li no:

apiVersion: enmasse.io/v1beta1
kind: Address
metadata:
  name: quarkus-example.orders
spec:
  address: orders
  type: queue
  plan: brokered-queue

Messaging neeg siv

Txhawm rau kom ntseeg tau tias tsuas yog cov ntawv thov kev ntseeg siab tuaj yeem xa thiab txais cov lus rau koj qhov chaw nyob, koj yuav tsum tsim tus neeg siv hauv kev xa xov. Rau cov ntawv thov ua haujlwm ntawm pawg, cov neeg siv khoom tuaj yeem lees paub siv tus account OpenShift kev pabcuam. Tus neeg siv "serviceaccount" tuaj yeem txhais tau, piv txwv li, zoo li no:

apiVersion: user.enmasse.io/v1beta1
kind: MessagingUser
metadata:
  name: quarkus-example.app
spec:
  username: system:serviceaccount:myapp:default
  authentication:
    type: serviceaccount
  authorization:
  - operations: ["send", "recv"]
    addresses: ["orders"]

Tso cai rau configure daim ntawv thov

Yuav kom AMQ Online los tsim cov configmap uas peb tau siv los embed AMQP cov ntaub ntawv kawg, Lub Luag Haujlwm thiab RoleBinding yuav tsum tau teeb tsa:

---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: quarkus-config
spec:
  rules:
  - apiGroups: [ "" ]
    resources: [ "configmaps" ]
    verbs: [ "create" ]
  - apiGroups: [ "" ]
    resources: [ "configmaps" ]
    resourceNames: [ "quarkus-config" ]
    verbs: [ "get", "update", "patch" ]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: quarkus-config
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: quarkus-config
subjects:
- kind: ServiceAccount
  name: address-space-controller
  namespace: amq-online-infra

Yuav ua li cas siv configurations

Koj tuaj yeem siv qhov kev teeb tsa kev xa xov zoo li no:

cd enmasse-example-clients/quarkus-example-client
oc project myapp
oc apply -f src/main/resources/k8s/addressspace
oc apply -f src/main/resources/k8s/address

Kev txheeb xyuas daim ntawv thov

Txhawm rau kom paub tseeb tias daim ntawv thov tau pib, ua ntej ntawm tag nrho, cia peb tshawb xyuas seb cov chaw nyob sib raug tau tsim thiab ua haujlwm:

until [[ `oc get address quarkus-example.prices -o jsonpath='{.status.phase}'` == "Active" ]]; do echo "Not yet ready"; sleep 5; done

Tom qab ntawd cia peb tshawb xyuas daim ntawv thov txoj kev URL (tsuas yog qhib qhov chaw nyob hauv qhov browser):

echo "http://$(oc get route quarkus-example-client -o jsonpath='{.spec.host}')/prices.html"

Tus browser yuav tsum qhia tias daim pib tau hloov kho ib ntus raws li cov lus xa thiab tau txais los ntawm AMQ Online.

Summing txog

Yog li peb tau sau ib daim ntawv thov Quarkus uas siv AMQP rau kev xa xov, teeb tsa daim ntawv thov kom khiav ntawm Red Hat OpenShift platform, thiab siv nws txoj kev teeb tsa raws li AMQ Online teeb tsa. Peb mam li tsim cov manifests xav tau los pib qhov kev xa xov rau peb daim ntawv thov.

Qhov no xaus cov koob txog Quarkus, tab sis muaj ntau yam tshiab thiab nthuav ua ntej, nyob twj ywm!

Tau qhov twg los: www.hab.com

Ntxiv ib saib