DEV Community

Thirumurthi S
Thirumurthi S

Posted on

Deploying Apache Artemis as container

Steps

  • Building Apache Artemis Image from Github
    • Clone source code from apache-artemis github project.
    • Build distribution locally using maven for version 2.17.0.
    • Build Docker image using locally generated artifact.
  • Push Image to ACR
    • Tag the Docker images and push to Azure Container Registry (ACR)
  • Running image in Kubernetes Cluster
    • Create a AKS cluster and namespace
    • Use deployment manifest file to run the image
    • Expose service of type load-balancer for deployment
  • Build client to connect to Broker

    • Spring-boot client (producer/consumer) to connect to MQ Broker
  • Development requires below software to be installed

    • Docker - 20.10+
    • Kubectl - 1.20.4+ (client)
Building Docker Image
# Clone the project to specific directory
$ git clone https://github.com/apache/activemq-artemis

# fetch all tags 
$ git fetch --all --tags 

# checkout the tag to local branch
$ git checkout tags/2.17.0 –b localversion-2.17.0

# navigate and build 2.17.0 distrubiton
$ cd artemis-distribution
$ mvn  -Dskip.test=true install

// check the target directory for created file 
$ ls –lrht artemis-distribution/target/apache-artemis-2.17.0-bin/apache-artemis-2.17.0

// build the docker related files
$ ./prepare-docker.sh --from-local-dist --local-dist-path ../artemis-distribution/target/apache-artemis-2.17.0-bin/apache-artemis-2.17.0

// check docker/Dockerfile-centos file in ./activemq-artemis/artemis-distribution/target/apache-artemis-2.17.0-bin/apache-artemis-2.17.0 and use below
$ docker build -f ./docker/Dockerfile-centos -t artemis-centos . 

// Run container locally to see if the image is starting up correctly
$ docker run --rm –it –p 61616:61616 –p 8161:8161 artemis-centos 
Enter fullscreen mode Exit fullscreen mode
Pushing image to ACR (Azure Container Registry)
# Login to Azure 
$ az login
$ az account set -s <aks-subscription-name>
$ az acr login --name <acr-name>

# verify the image locally
$ docker pull <acr-name>.azurecr.io/<project>/artemis/v1:latest
$ docker run --rm -it -p 61616:61616 -p 8161:8161 <acr-name>.azurecr.io/<project>/artemis/v1
Enter fullscreen mode Exit fullscreen mode
Create namespace, Deployment manifest file for Artemis
# Command to create  namespace
$ kubectl create namespace artemis-demo

# Add label to the namespace created
$ kubectl label namespace artemis-demo name=artemis-demo

# command used to change the default namespace is artemis-demo
$ kubectl config --current-context --namespace=artemis-demo

# navigate to the file location of artemis-deploy.yaml, issue below command
# the --namespace is not required if the first command was executed.
$ kubectl apply –f artemis-deploy.yaml --namepsace=artemis-demo
 
# the deployment and service status can be viewed with below command
$ kubectl get deployment,service -o wide

# to get the pod status and pod name
$ kubectl get pod

# the logs on the pods
$ kubectl logs pod/<pod-name-from-above-command>
Enter fullscreen mode Exit fullscreen mode
Validate the service endpoint to access the Artemis console
# After deployment – use below command
$ kubectl get endpoint

# Display the service status, check if the external IP is created
$ kubect get service/artemis-server-lb

# Describe the service and fetch the LoadBalancer Ingress IP
$ kubectl describe service/artemis-server-lb | grep Load
Enter fullscreen mode Exit fullscreen mode
apiVersion: apps/v1 
kind: Deployment
metadata:
  name: artemis-broker-deployment
  labels:
     app: artemis-broker
     type: artemis
     environment: dev-poc
spec:
  template:
     metadata:
        name: artemis-broker
        labels:
           app: artemis-broker
           type: artemis
     spec:
        containers:
        - name: artemis-server
          image: <azureacrname>.azurecr.io/<project>/artemis/v1   #will use the latest version.
  replicas: 1
  selector:    # This specifies which pods to be replicated 
      matchLabels:
         type: artemis
---
apiVersion: v1
kind: Service
metadata:
  name: artemis-server-lb
  labels:
    app: artemis-server-lb
  annotations:
    service.beta.kubernetes.io/azure-load-balancer-internal: "true"
spec:
  type: LoadBalancer
  ports:
    - name: tcp-acceptor
      port: 61616
      targetPort: 61616
      nodePort: 30616
      protocol: TCP
    - name: amqp-acceptor
      port: 5672
      targetPort: 5672
      nodePort: 30567
      protocol: TCP
    - name: web-console
      port: 8161
      targetPort: 8161
      nodePort: 30816
      protocol: TCP
  selector:
    app: artemis-broker
    type: artemis
Enter fullscreen mode Exit fullscreen mode

Spring client code to access the containerized Artemis Queue

  • application.properties
brokerUrl = amqp://<external-ip-fromservice>:5672
artemisUser = artemis
artemisPassword = artemis

connectionCount=3

server.port=8085

spring.h2.console.enabled=true
spring.datasource.platform=h2
spring.datasource.url=jdbc:h2:mem:test
Enter fullscreen mode Exit fullscreen mode
  • Rest controller, to send message
package camel.amqp.Producer;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@Component
public class ArtemisProducer {

    @Autowired
    JmsTemplate jmsTemplate;

    @PostMapping(value = "/artemis/sendMessage")
    public void sendMessage(
        @RequestParam(name = "message", required = true) final String[] message){
            jmsTemplate.convertAndSend("test.queue", message);
    }   
}
Enter fullscreen mode Exit fullscreen mode
  • configuration class
package camel.amqp;

import org.apache.camel.component.jms.JmsConfiguration;
import org.apache.qpid.jms.JmsConnectionFactory;
import org.messaginghub.pooled.jms.JmsPoolConnectionFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Component;

@Component
public class AmqpJmsPoolConectionFactoryConfig {


    @Value("${artemisUser}")
    private String userName;

    @Value("${artemisPassword}")
    private String password;

    @Value("${brokerUrl}")
    private String brokerUrl;

    @Value("${connectionCount}")
    private int connectionCount;

    @Bean
    public JmsConnectionFactory jmsConnectionFactory() {
        JmsConnectionFactory jmsConnectionFactory = new JmsConnectionFactory(userName, password, brokerUrl);
        return jmsConnectionFactory;
    }

    @Bean(initMethod="start",destroyMethod="stop")
    public JmsPoolConnectionFactory jmsPoolConnectionFactory() {
        JmsPoolConnectionFactory jmsPoolConnectionFactory = new JmsPoolConnectionFactory();
        jmsPoolConnectionFactory.setMaxConnections(connectionCount);
jmsPoolConnectionFactory.setConnectionFactory(jmsConnectionFactory());
            return jmsPoolConnectionFactory;
        }

    @Bean
    public JmsConfiguration jmsConfiguration(@Value("${connectionCount}") int connectionCount){
        JmsConfiguration jmsConfiguration = new JmsConfiguration();
        jmsConfiguration.setConcurrentConsumers(connectionCount);       jmsConfiguration.setConnectionFactory(jmsPoolConnectionFactory());
        return jmsConfiguration;
    }

    @Bean
    public JmsTemplate jmsTemplate() {
        return new JmsTemplate(jmsConnectionFactory());
    }
}
Enter fullscreen mode Exit fullscreen mode
  • Entry point to Spring Boot Application
package bootcamelamqp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CamelAmqpApplication {

    public static void main(String[] args) {
        SpringApplication.run(CamelAmqpApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

Discussion (0)