ããã«ã¡ã¯ãã¿ããªïŒ ããããQuarkus ã·ãªãŒãºã®æåŸã®æçš¿ã§ãã (ã¡ãªã¿ã«ããŠã§ãããŒãã芧ãã ãã
Ð
ããŒãžã§ã³0.17.0以éã
OpenShift ãã©ãããã©ãŒã ã« AMQ Online ããã§ã«ãããã€ãããŠããããšãåæãšããŠããŸã (ãŸã ãããã€ãããŠããªãå Žåã¯ãã
ãŸãããªã¢ã¯ãã£ã ã¡ãã»ãŒãžã³ã°ã䜿çšããåçŽãªæ³šæåŠçã·ã¹ãã ãšãªã Quarkus ã¢ããªã±ãŒã·ã§ã³ãäœæããŸãã ãã®ã¢ããªã±ãŒã·ã§ã³ã«ã¯ãäžå®ã®ééã§ã¡ãã»ãŒãž ãã¥ãŒã«æ³šæãéä¿¡ãã泚æãžã§ãã¬ãŒã¿ãšããã¥ãŒããã®ã¡ãã»ãŒãžãåŠçããŠãã©ãŠã¶ã§è¡šç€ºå¯èœãªç¢ºèªãçæãã泚æããã»ããµãå«ãŸããŸãã
ã¢ããªã±ãŒã·ã§ã³ãäœæããããã¡ãã»ãŒãžã³ã° ã·ã¹ãã æ§æãã¢ããªã±ãŒã·ã§ã³ã«åã蟌ã¿ãAMQ ãªã³ã©ã€ã³ã䜿çšããŠã·ã¹ãã äžã«å¿ èŠãªãªãœãŒã¹ãããããžã§ãã³ã°ããæ¹æ³ã瀺ããŸãã
ã¯ãªãŒã¯ã¹ã¢ããª
ç§ãã¡ã® Quarkus ã¢ããªã±ãŒã·ã§ã³ã¯ OpenShift äžã§å®è¡ãããããã°ã©ã ã®ä¿®æ£ããŒãžã§ã³ã§ãã
ãªãŒããŒãžã§ãã¬ãŒã¿
ãžã§ãã¬ãŒã¿ãŒã¯åçŽã«ãå¢å ãã泚æ ID ã 5 ç§ããšã«ã泚æãã¢ãã¬ã¹ã«å調ã«éä¿¡ããŸãã
@ApplicationScoped
public class OrderGenerator {
private int orderId = 1;
@Outgoing("orders")
public Flowable<Integer> generate() {
return Flowable.interval(5, TimeUnit.SECONDS)
.map(tick -> orderId++);
}
}
泚æåŠçè
泚æãã³ãã©ãŒã¯ããã«åçŽã§ãç¢ºèª ID ãã確èªãã¢ãã¬ã¹ã«è¿ãã ãã§ãã
@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;
}
}
確èªãªãœãŒã¹
確èªãªãœãŒã¹ã¯ãã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠçæããã確èªããªã¹ãããããã® HTTP ãšã³ããã€ã³ãã§ãã
@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;
}
}
調æŽ
AMQ Online ã«æ¥ç¶ããã«ã¯ãã¢ããªã±ãŒã·ã§ã³ã«ããã€ãã®æ§æããŒã¿ãã€ãŸã Quarkus ã³ãã¯ã¿æ§æãAMQP ãšã³ããã€ã³ãæ å ±ãã¯ã©ã€ã¢ã³ãè³æ Œæ å ±ãå¿ èŠã§ãã ãã¡ããããã¹ãŠã®èšå®ããŒã¿ã XNUMX ãæã«ä¿åããæ¹ãè¯ãã§ãããQuarkus ã¢ããªã±ãŒã·ã§ã³ãèšå®ããããã®å¯èœãªãªãã·ã§ã³ã瀺ãããã«ãããããæå³çã«åé¢ããŸãã
ã³ãã¯ã¿
ã³ãã¯ã¿æ§æã¯ãã¢ããªã±ãŒã·ã§ã³ ãããã㣠ãã¡ã€ã«ã䜿çšããŠã³ã³ãã€ã«æã«æäŸã§ããŸãã
mp.messaging.outgoing.orders.connector=smallrye-amqp
mp.messaging.incoming.orders.connector=smallrye-amqp
話ãç°¡åã«ããããã«ãã泚æãã¢ãã¬ã¹ã«ã¡ãã»ãŒãž ãã¥ãŒã®ã¿ã䜿çšããŸãã ãããŠãã¢ããªã±ãŒã·ã§ã³ã®ã確èªãã¢ãã¬ã¹ã¯ã¡ã¢ãªå ã®ãã¥ãŒã䜿çšããŸãã
AMQP ãšã³ããã€ã³ã
ã³ã³ãã€ã«æã«ã¯ AMQP ãšã³ããã€ã³ãã®ãã¹ãåãšããŒãçªå·ãäžæãªãããããããæ¿å ¥ããå¿ èŠããããŸãã ãšã³ããã€ã³ã㯠AMQ Online ã«ãã£ãŠäœæããã configmap ã§èšå®ã§ãããããã¢ããªã±ãŒã·ã§ã³ ãããã§ã¹ãã®ç°å¢å€æ°ãéããŠå®çŸ©ããŸãã
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
è³æ Œ
ãµãŒãã¹ ã¢ã«ãŠã³ã ããŒã¯ã³ã¯ãã¢ããªã±ãŒã·ã§ã³ã OpenShift ã«å¯ŸããŠèªèšŒããããã«äœ¿çšã§ããŸãã ãããè¡ãã«ã¯ããŸããããã®ãã¡ã€ã« ã·ã¹ãã ããèªèšŒããŒã¯ã³ãèªã¿åãã«ã¹ã¿ã ConfigSource ãäœæããå¿ èŠããããŸãã
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);
}
}
ã¢ããªã±ãŒã·ã§ã³ã®æ§ç¯ãšãããã€
ã¢ããªã±ãŒã·ã§ã³ã¯å®è¡å¯èœãã¡ã€ã«ã«ã³ã³ãã€ã«ããå¿
èŠããããããGraalVM ä»®æ³ãã·ã³ãå¿
èŠã§ãã ãã®ããã®ç°å¢ãã»ããã¢ããããæ¹æ³ã®è©³çŽ°ã«ã€ããŠã¯ã次ã®å¯Ÿå¿ããæé ãåç
§ããŠãã ããã
次ã«ãããã«ç€ºãããŠããæ瀺ã«åŸã£ãŠããœãŒã¹ãããŠã³ããŒãããã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããŠãããã€ããå¿ èŠããããŸãã
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
ãããã®ã³ãã³ãã®åŸãã¢ããªã±ãŒã·ã§ã³ããããã€ãããŸãããAMQ Online ã§å¿ èŠãªã¡ãã»ãŒãžã³ã° ãªãœãŒã¹ãæ§æãããŸã§ã¯èµ·åããŸããã
ã¡ãã»ãŒãžã³ã° ã·ã¹ãã ã®ã»ããã¢ãã
ããšã¯ãã¢ããªã±ãŒã·ã§ã³ãå¿ èŠãšãããªãœãŒã¹ãã¡ãã»ãŒãžã³ã° ã·ã¹ãã ã«èšå®ããã ãã§ãã ãããè¡ãã«ã¯ã以äžãäœæããå¿ èŠããããŸãã1) ã¡ãã»ãŒãžã³ã° ã·ã¹ãã ãšã³ããã€ã³ããåæåããããã®ã¢ãã¬ã¹ ã¹ããŒã¹ã 2) ã¢ããªã±ãŒã·ã§ã³ã§äœ¿çšããã¢ãã¬ã¹ãæ§æããããã®ã¢ãã¬ã¹ã 3) ãŠãŒã¶ãŒã«ã¯ã©ã€ã¢ã³ãè³æ Œæ å ±ãèšå®ããããã¡ãã»ãŒãžãéä¿¡ããŸãã
ã¢ãã¬ã¹ç©ºé
AMQ ãªã³ã©ã€ã³ã® AddressSpace ãªããžã§ã¯ãã¯ãæ¥ç¶ãšã³ããã€ã³ããšèªèšŒããã³èªå¯ããªã·ãŒãå ±æããã¢ãã¬ã¹ã®ã°ã«ãŒãã§ãã ã¢ãã¬ã¹ç©ºéãäœæãããšãã«ãã¡ãã»ãŒãžã³ã° ãšã³ããã€ã³ããå ¬éããæ¹æ³ãæå®ã§ããŸãã
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
ã¢ãã¬ã¹
ã¢ãã¬ã¹ã¯ã¡ãã»ãŒãžã®éåä¿¡ã«äœ¿çšãããŸãã åã¢ãã¬ã¹ã«ã¯ããã®ã»ãã³ãã£ã¯ã¹ã決å®ããã¿ã€ããšãäºçŽãããªãœãŒã¹ã®æ°ãæå®ãããã©ã³ããããŸãã ã¢ãã¬ã¹ã¯ãããšãã°æ¬¡ã®ããã«æ±ºå®ã§ããŸãã
apiVersion: enmasse.io/v1beta1
kind: Address
metadata:
name: quarkus-example.orders
spec:
address: orders
type: queue
plan: brokered-queue
ã¡ãã»ãŒãžã³ã°ãŠãŒã¶ãŒ
ä¿¡é Œã§ããã¢ããªã±ãŒã·ã§ã³ã ããèªåã®ã¢ãã¬ã¹ã«ã¡ãã»ãŒãžãéåä¿¡ã§ããããã«ããã«ã¯ãã¡ãã»ãŒãžã³ã° ã·ã¹ãã ã§ãŠãŒã¶ãŒãäœæããå¿ èŠããããŸãã ã¯ã©ã¹ã¿ãŒäžã§å®è¡ãããŠããã¢ããªã±ãŒã·ã§ã³ã®å Žåãã¯ã©ã€ã¢ã³ã㯠OpenShift ãµãŒãã¹ ã¢ã«ãŠã³ãã䜿çšããŠèªèšŒã§ããŸãã ãŠãŒã¶ãŒãserviceaccountãã¯ãããšãã°æ¬¡ã®ããã«å®çŸ©ã§ããŸãã
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"]
ã¢ããªã±ãŒã·ã§ã³ãæ§æããããã®æš©é
AMQ Online ã AMQP ãšã³ããã€ã³ãæ å ±ãåã蟌ãããã«äœ¿çšãã configmap ãäœæããã«ã¯ãRole ãš RoleBinding ãèšå®ããå¿ èŠããããŸãã
---
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
èšå®ãé©çšããæ¹æ³
次ã®ããã«ã¡ãã»ãŒãžã³ã° ã·ã¹ãã æ§æãé©çšã§ããŸãã
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
ã¢ããªã±ãŒã·ã§ã³ã®æ€èšŒ
ã¢ããªã±ãŒã·ã§ã³ãéå§ãããããšã確èªããã«ã¯ããŸãã察å¿ããã¢ãã¬ã¹ãäœæãããã¢ã¯ãã£ãã«ãªã£ãŠãããã©ããã確èªããŸãã
until [[ `oc get address quarkus-example.prices -o jsonpath='{.status.phase}'` == "Active" ]]; do echo "Not yet ready"; sleep 5; done
次ã«ãã¢ããªã±ãŒã·ã§ã³ ã«ãŒã URL ã確èªããŠã¿ãŸããã (ãã®ã¢ãã¬ã¹ããã©ãŠã¶ã§éãã ãã§ã)ã
echo "http://$(oc get route quarkus-example-client -o jsonpath='{.spec.host}')/prices.html"
AMQ Online ã«ãã£ãŠã¡ãã»ãŒãžãéåä¿¡ããããšããã±ãããå®æçã«æŽæ°ãããããšããã©ãŠã¶ãŒã«è¡šç€ºãããŸãã
èŠçŽ
ããã§ãã¡ãã»ãŒãžã³ã°ã« AMQP ã䜿çšãã Quarkus ã¢ããªã±ãŒã·ã§ã³ãäœæããRed Hat OpenShift ãã©ãããã©ãŒã äžã§å®è¡ããããã«ã¢ããªã±ãŒã·ã§ã³ãèšå®ããAMQ Online èšå®ã«åºã¥ããŠãã®èšå®ãå®è£ ããŸããã 次ã«ãã¢ããªã±ãŒã·ã§ã³ã®ã¡ãã»ãŒãžã³ã° ã·ã¹ãã ãåæåããããã«å¿ èŠãªãããã§ã¹ããäœæããŸããã
Quarkus ã«é¢ããã·ãªãŒãºã¯ããã§çµããã§ãããä»åŸãæ°ãããŠèå³æ·±ãããšããããããããŸãã®ã§ãã楜ãã¿ã«!
åºæïŒ habr.com