App Connect

 View Only

Creating a queue manager in OpenShift from the Command Line

By AMAR SHAH posted Thu December 09, 2021 01:32 AM

  

This blog is part of a series. For the whole series list see here


In the following scenarios, integration with IBM MQ is used. When we move IBM App Connect into containers, the recommendation is that wherever possible, we should move to working with MQ remotely. This is highly preferable to having a local MQ server residing alongside App Connect since it allows Kubernetes to fully take over administration of scaling and high availability of the components. This is part of a broader common practice around containerization, noting that each container should have only one job.

With this in mind, our integrations are going to need a remote queue manager to talk to when we migrate them into the container world. In this post we’re going to look at how to stand up an IBM MQ Queue Manager in a container on our Kubernetes environment. For consistency with our other scenarios we will choose the OpenShift container platform, although it is important to say that IBM MQ is supported on all major Kubernetes environments.  

Note that this is a simplistic deployment, purely to provide a remote queue manager for our App Connect scenarios, not an example of a proper production deployment. For example, we will not explore high availability and security, nor will we assign persistent storage to it.

We can create our containerized queue manager in one of two ways: via the command line, and via a web console. In this post we will describe the command line option.

The IBM MQ Operator   

As with App Connect, IBM have created an “operator” based on the Operator Framework to simplify deployment and running of IBM MQ Queue Managers in OpenShift.

The MQ Operator performs a number of functions. The most important in this scenario is to allow OpenShift to work with a new type of object called a QueueManager. The QueueManager object, unsurprisingly, looks after an IBM MQ Queue Manager running in a container.

In this scenario, we will provide Kubernetes with a definition file (known as a Custom Resource Definition, or CRD) that defines the QueueManager object we wish to create. The MQ Operator will automatically notice that new definition, and create a queue manager container with the queues and channels requested.

The IBM MQ Operator is installed in much the same way as the IBM App Connect operator, and only needs to be done once on a cluster. If you have already installed the Cloud Pak for Integration, then you should already have the operator in your catalog. If not, please refer to the instructions for installing an IBM MQ Operator in IBM documentation:

Installing and uninstalling the IBM MQ Operator on Red Hat OpenShift 

Configuring a queue manager with a ConfigMap

Queue managers can be declaratively configured using two key files

  • mqsc” files to define their queues and channels
  • ini” files to define properties about the queue manager itself

In our simple deployment the only thing we need to do is provide the definition for a queue and a channel, so we only need an mqsc file but the process for an ini file is largely identical.

The IBM MQ Operator is specifically designed to retrieve configuration information from OpenShift on startup via a ConfigMap or Secret. These are created in the namespace (project) where you will deploy the queue manager, and referenced in the queue manager definition.

 

ConfigMaps and Secrets in Kubernetes

When a container image is started up in Kubernetes, we often want to pass some key information to it such as some properties pertaining to how it should run, or some credentials it will need. The Kubernetes objects ConfigMap and Secret are designed specifically for this purpose.

The two are very similar, and the primary difference between them is that Secrets, as you might guess, are more suited to sensitive information. Secrets are base64 encoded and there are some differences in the way that they are handled.

It should be noted that the basic Secrets facility in Kubernetes is often not sufficiently secure on its own. However, it is a pluggable architecture that can be enhanced through third party “vault” software such as that provided by HashiCorp, or those provided natively by the major cloud providers.

A ConfigMap or Secret can be populated on the Kubernetes environment prior to a container being deployed, then on start up the values from it can be pulled into the container either as environment variables or mounted files. This technique provides a way to provide different values in each environment a container is deployed – e.g. different credentials in pre-production and production. It also enables us to use one standard container image for many different purposes, which is how we will be using it in this post.

In our scenario we will use a ConfigMap to supply the queue definitions to a standard queue manager container.   

 

Create a ConfigMap to define the queues and channels on the queue manager

In our case we would like to create a queue and also create a SVRCONN channel to enable App Connect to put and get messages from it and we are going to provide that via a Kubernetes ConfigMap.

Our mqsc definition looks like this:

    DEFINE QLOCAL('BACKEND') REPLACE
    DEFINE CHANNEL('ACECLIENT') CHLTYPE (SVRCONN) SSLCAUTH(OPTIONAL)
    ALTER QMGR CHLAUTH(DISABLED)
    REFRESH SECURITY

 

It says to create a queue named ‘BACKEND’, replacing any queue of that name currently present. It then defines a channel of type ‘SVRCONN’ (the type used by clients to talk to a queue manager) named ‘ACECLIENT’. For convenience the channel security is switched off. Clearly we would make different choices for a production queue manager, but this will do for our purposes.

First we need to create a definition file for the ConfigMap, then we’ll deploy it with the Kubernetes (OpenShift) command line.

Create a ConfigMap definition file looking like this with our mqsc instructions embedded within it:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mqsc-example
  namespace: mq
data:
  example1.mqsc: |
    DEFINE QLOCAL('BACKEND') REPLACE
    DEFINE CHANNEL('ACECLIENT') CHLTYPE (SVRCONN) SSLCAUTH(OPTIONAL)
    ALTER QMGR CHLAUTH(DISABLED)
    REFRESH SECURITY

 

Save this YAML in a file ConfigMap-mqsc-example.yaml

Now create the ConfigMap using the following command:

# oc apply -f ConfigMap-mqsc-example.yaml

That’s now done. The mqsc information is stored in the mq namespace of the Kubernetes cluster, ready for the container to use it when it starts up.

Should you want to list the configMaps in your environment, run the following command:

# oc get ConfigMap

 NAME           DATA     AGE
mqsc-example     1       5m

 

To view the contents of ConfigMap, run the following command:

 # oc describe ConfigMap mqsc-example  

Deploying a queue manager using OCP CLI

We now need to create a definition file for our MQ Operator describing what we want it to deploy.

The following will instruct the operator to deploy an IBM MQ container using the mqsc definitions in the ConfigMap we just created.

apiVersion: mq.ibm.com/v1beta1
kind: QueueManager
metadata:
namespace: mq
  name: quickstart-cp4i
spec:
  license:
    accept: true
    license: L-APIG-BMJJBM
    use: Production
  web:
    enabled: true
  version: 9.2.1.0-r1
  template:
    pod:
      containers:
        - env:
            - name: MQSNOAUT
              value: 'yes'
          name: qmgr
  queueManager:
    name: QUICKSTART
    mqsc:
      - configMap:
          name: mqsc-example
          items:
          - example1.mqsc
    storage:
      queueManager:
        type: ephemeral

 

The container will have a queue manager called “QUICKSTART” and will use the IBM MQ container image that has version 9.2.1.0-r1 of the product binaries. For simplicity, it will have ephemeral (non-persistent) storage, and security will be turned off. It will then draw in and create the queue and channels we defined in the ConfigMap we created earlier.

Save the above yaml in a file mq-quickstart.yaml

Now, create the queue manager using the command:

# oc apply -f mq-quickstart.yaml

You may recall from Scenario 3 that Kubernetes always deploys containers within a “pod”. The operator has taken care of this detail for you, and you can now check the status of pod using following standard Kubernetes command. You can see that the Operator has auto-generated a name for the pod (quickstart-cp4i-ibm-mq-0)based on the metadata.name field in our definition file above.

# oc get pods

NAME                       READY   STATUS    RESTARTS   AGE
quickstart-cp4i-ibm-mq-0   1/1     Running   0          4m22s

 

The IBM MQ container knows how to report not just the status of the container, but also the queue manager running inside it. As such, when the above command reports a status of ‘Running’, this in fact indicates that the queue manager has been successfully deployed and started.

 The mq-quickstart.yaml definition we just deployed instructed the MQ Operator to create an object of kind: QueueManager which represents the underlying container. We can talk to this object directly from the Kubernetes command line to query the running queue manager’s status and configuration.  For example:

 

# oc get QueueManager

NAME              PHASE
quickstart-cp4i   Running

 Once again, the status field (‘Running’) indicates that the queue manager has been successfully deployed.

 For more information see: Operating IBM MQ using the IBM MQ Operator

 

Communicating with the Queue Manager via a Kubernetes “Service”

 

We’ve seen that the queue manager is running, but how would you connect to it to GET and PUT messages?

For the moment we’ll just consider the situation where we would like to connect to MQ from another container in the same Kubernetes cluster, such as an App Connect container for example. This will suffice for the next few scenarios in our series, but it is of course also possible to expose MQ beyond the cluster, and that explored in the MQ documentation center.  

When the Operator instantiated our MQ container in a pod, it also created a Kubernetes object called a “Service”. Put simply, a Service is a logical hostname that can be used to talk to containers in a pod within the same Kubernetes cluster.  The Service provides a level of indirection such that pods can be restarted, moved between Kubernetes worker nodes. Calls to the Service will be routed to wherever the running pod is located. This is a great example of the benefit that Kubernetes brings as it performs all the routing on your behalf, dynamically adjusting it as necessary.  

We can obtain the service names (and port numbers) with in the mq-demo namespace using following command:

# oc get services -n mq

 NAME                          TYPE        CLUSTER-IP        PORT(S)           
quickstart-cp4i-mq-ibm-mq    ClusterIP   172.30.189.143   9443/TCP,1414/TCP  

 

From this we can note that  

Service name : quickstart-cp4i-mq-ibm-mq
Port Number : 1414

 

Now, we have all the information on queue manager side that we needed to use with ACE flows, or indeed any other MQ Client within the cluster.

  • Queue manager name : QUICKSTART
  • Queues for applications to PUT and GET messages: BACKEND
  • Channel for communication with the application: ACECLIENT
  • MQ hostname and listener port: quickstart-cp4i-mq-ibm-mq/1414

Should you use runmqsc against a queue manager in a container?

Whilst we would encourage you to administer queue managers running in containers using the Operator as described above, viewing  queue manager properties via the QueueManager object, and making changes by re-applying the definition file.

However, it is still possible to connect to them the way you may be used to today, using the runmqsc shell and running commands from within that.

We would strongly discourage making changes to running containers via runmqsc as this would result in the live configuration of the queue manager no longer matching the definition files stored in your source code repository – this causes “configuration drift” and risks operational instability and unpredictability. Any changes you make live would be overwritten the next time you applied the definition files. It is fundamental to a good cloud native approach that the definitions in source code repository are considered the master configuration.

Runmqsc could potentially be used to view the queue manager configuration directly. To do this you would have the MQ CLI installed on your local machine, and potentially set up TLS etc. You would then point the CLI at the same Kubernetes “Service” used for PUT and GET, and this will route your request through to the queue manager container.

Another alternative is to open a remote shell session with the container. The advantage here is that you do not have to have MQ installed and configured locally as you are using the runmqsc installed in the container. However, to do this you will need to find out the specific name of the pod, rather than allowing the Kubernetes Service to do the routing for you.

As an example, to confirm if the Queue manager has picked up the ConfigMap you can login to the queue manager pod and check that the queues and channels are created as defined in the ConfigMap

  

# oc rsh quickstart-cp4i-ibm-mq-0

 
sh-4.4$ runmqsc
5724-H72 (C) Copyright IBM Corp. 1994, 2020.
Starting MQSC for queue manager QUICKSTART.

     1 : dis qmgr
AMQ8408I: Display Queue Manager details.

   QMNAME(QUICKSTART)                      ACCTCONO(DISABLED)
   CHLAUTH(DISABLED)                       CLWLDATA( )


dis ql(BACKEND)
     2 : dis ql(BACKEND)
AMQ8409I: Display Queue details.
   QUEUE(BACKEND)                          TYPE(QLOCAL)
 
dis channel(ACECLIENT)
    3 : dis channel(ACECLIENT)
AMQ8414I: Display Channel details.
  CHANNEL(ACECLIENT)                    CHLTYPE(SVRCONN)


Whilst it’s nice to know the above is possible, and it might just be useful in some edge cases around diagnostics, let’s reinforce the message that this should not be your primary approach.

You should aim to work through Kubernetes command line using the Operator. This will enable you to view your queue managers configurations using the new Kubernetes QueueManager object without having to concern yourself with which Kubernetes Service, or indeed Pod they are located.

Furthermore, you should maintain your queue managers by applying updates to the Operator using their definition files, enabling you to have a single audit trail and source of truth regarding the queue manager configuration.

Automating queue manager creation and maintenance.

We’ve taken some trouble to explain quite a lot of concepts along the way, but the actual actions we took to create the queue manager, were really just the following two commands.

 # oc apply -f ConfigMap-mqsc-example.yaml

# oc apply -f mq-quickstart.yaml

We just needed to know what information to put into the ConfigMap (the mqsc definition) and QueueManager files. It’s then easy to see how queue manager creation could be  automated via a simple pipeline, and for example hooked up to definition files stored in a source code repository.

This “GitOps” approach has many benefits. For example, to change to a new version of the underlying MQ runtime would be performed by simply changing the version field in the mq-quickstart.yaml definition file. Once that change was committed in source control, this would kick off the pipeline, which would pass that new definition file to the IBM MQ Operator. The Operator would then take on the job of using standard Kubernetes mechanisms to introduce updated containers for the existing queue managers with minimal downtime. 




Acknowledgement and thanks to Kim Clark for providing valuable technical input to this article.



#IntegrationBus(IIB)#AppConnectEnterprise(ACE)#Docker#containers #mq

​​​​

Permalink

Comments

Thu March 10, 2022 05:00 AM

@Ron Peereboom

The MQ operator will apply MQSC at start-up of the container. If a queue manager already exists (e.g the container is restarting, instead of starting for the first time) then the MQSC will be applied to the existing MQ configuration. At the moment there is no dynamic loading of MQSC while the queue manager is started, if changes are needed then standard MQ tools would be used (MQ Console, MQ Explorer, REST API, runmqsc, PCF, etc).

Fri January 14, 2022 05:47 AM

Using "Configuration as code" for MQ is easy to do if your queue manager configuration (queues etc) does not change.

What I would like to understand is how the operator handles changes in the mqsc configuration. Does it just recreate the whole queue manager and how does that affect availability? Or does it apply the mqsc to the running queue manager? Or even more sophisticated, does it actually compare the old and new configurations and then add, change and remove queues as necessary?

In other words, how much of the operator maturity model has been implemented in the operator and how does it work internally?