[OpenShift Container Platform][IBM Cloud Pak for Integration]

Example: Configuring a multi-instance queue manager

This example shows how you deploy a multi-instance queue manager into the Red Hat® OpenShift® Container Platform (OCP) using the IBM® MQ Operator. In this example, you also configure one way TLS communication between a sample client and the queue manager. The example demonstrates successful configuration by putting and getting messages before and after a simulated pod failure.

Before you begin

To complete this example, you must first have completed the following prerequisites:

  • Install the IBM MQ client, and add the installed samp/bin and bin directories to your PATH. The client provides the runmqakm, amqsputc and amqsgetc applications required by this example. Install the IBM MQ client as follows:
  • Install the OpenSSL tool for your operating system. You need this to generate a self-signed certificate for the queue manager, if you do not already have a private key and certificate.
  • Create a Red Hat OpenShift Container Platform (OCP) project/namespace for this example.
  • On the command line, log into the OCP cluster, and switch to the above namespace.
  • Ensure the IBM MQ Operator is installed and available in the above namespace.
  • Configure a default storage class in the OCP, to be used by your queue manager. If you want to complete this tutorial without setting a default storage class, see Note 2: Using a non-default storage class.

About this task

Multi-instance queue managers involve an active and a standby Kubernetes Pod. These run as part of a Kubernetes Stateful Set with exactly two replicas and a set of Kubernetes Persistent Volumes. For more information about multi-instance queue managers, see High availability for IBM MQ in containers.

The example provides a custom resource YAML defining a multi-instance queue manager with persistent storage, and configured with TLS. After deploying the queue manager into the OCP, you simulate failure of the active queue manager pod. You see automatic recovery occur, and prove that it has succeeded by putting and getting messages after the failure.

Example

Create a TLS private key and certificates for MQ server
This section documents how to create a self-signed certificate for the queue manager, and how to add the certificate to a key database to act as the truststore for the client. If you already have a private key and certificate, you can use those instead. Note that you should only use self-signed certificates for development purposes.
To create a self-signed private key and a public certificate in the current directory, run the following command:
openssl req -newkey rsa:2048 -nodes -keyout tls.key -subj "/CN=localhost" -x509 -days 3650 -out tls.crt
Add the queue manager public key to a client key database
A client key database is used as the truststore for the client application.
Create the client key database:
runmqakm -keydb -create -db clientkey.kdb -pw password -type cms -stash
Add the previously generated public key to the client key database:
runmqakm -cert -add -db clientkey.kdb -label mqservercert -file tls.crt -format ascii -stashed
Create a secret containing TLS certificates for queue manager deployment
So that your queue manager can reference and apply the key and certificate, create a Kubernetes TLS secret, referencing the files created above. When you do this, ensure you are in the namespace you created before you began this task.
oc create secret tls example-mi-secret --key="tls.key" --cert="tls.crt"
Create a config map containing MQSC commands
Create a Kubernetes config map containing the MQSC commands to create a new queue and a SVRCONN Channel, and to add a channel authentication record that allows access to the channel by blocking only those users called nobody.

Note that this approach should be used only for development purposes.

Ensure you are in the namespace you created earlier (see Before you begin), then enter the following YAML in the OCP UI, or using the command line:
apiVersion: v1
kind: ConfigMap
metadata:
  name: example-mi-configmap
data:
  tls.mqsc: |
    DEFINE QLOCAL('EXAMPLE.QUEUE') DEFPSIST(YES) REPLACE 
    DEFINE CHANNEL(MIQMCHL) CHLTYPE(SVRCONN) TRPTYPE(TCP) SSLCAUTH(OPTIONAL) SSLCIPH('ANY_TLS12_OR_HIGHER')
    SET CHLAUTH(MIQMCHL) TYPE(BLOCKUSER) USERLIST('nobody') ACTION(ADD)
Configure routing
If you are using an IBM MQ client or toolkit at IBM MQ 9.2.1 or later, you can configure routing to the queue manager by using a queue manager configuration file (an INI file). Within the file, you set the OutboundSNI variable to route based on hostname rather than channel name.
Create a file in the directory you are running commands in, called `mqclient.ini`, containing the following text:

#* Module Name: mqclient.ini                                     *#
#* Type       : IBM MQ MQI client configuration file             *#
#  Function   : Define the configuration of a client             *#
#*                                                               *#
#*****************************************************************#
#* Notes      :                                                  *#
#* 1) This file defines the configuration of a client            *#
#*                                                               *#
#*****************************************************************#
SSL:
   OutboundSNI=HOSTNAME
Note: Do not change any values in this page. For example the string HOSTNAME should be left as is.
For further details, see SSL stanza of the client configuration file.
If you are using an IBM MQ client or toolkit earlier than IBM MQ 9.2.1, you need to create an OCP route instead of the previous configuration file. Follow the steps in Note 1: Creating a route.
Deploy the queue manager
Important: In this example we use the MQSNOAUT variable to disable authorization on the queue manager, which allows us to focus on the steps required to connect a client using TLS. This is not recommended in a production deployment of IBM MQ, because it causes any applications connecting to have full administrative powers, with no mechanism to lower the permissions for individual applications.

Copy and update the following YAML.
Queue manager custom resource YAML:

apiVersion: mq.ibm.com/v1beta1
kind: QueueManager
metadata:
  name: miexample
spec:
  license:
    accept: false
    license: L-RJON-C7QG3S
    use: NonProduction
  queueManager:
    name: MIEXAMPLE
    availability:
      type: MultiInstance
    mqsc:
    - configMap:
        name: example-mi-configmap
        items:
        - tls.mqsc
  template:
    pod:
      containers:
        - env:
            - name: MQSNOAUT
              value: 'yes'
          name: qmgr
  version: 9.2.5.0-r3
  web:
    enabled: true
  pki:
    keys:
      - name: example
        secret:
          secretName: example-mi-secret
          items: 
          - tls.key
          - tls.crt

Ensuring you are in the namespace you created earlier, deploy the updated YAML in the OCP UI, using the command line, or using the IBM Cloud Pak® for Integration Platform Navigator.

Validation

After a brief delay, the multi instance queue manager should be configured and available for use. In this section we validate that the queue manager behaves as expected.

Confirm that the queue manager is running
The queue manager is now being deployed. Confirm it is in Running state before proceeding. For example:
oc get qmgr miexample
Test the connection to the queue manager
To confirm the queue manager is configured for one-way TLS communication, use the amqsputc and amqsgetc sample applications:
Find the queue manager hostname
To find the queue manager hostname for route miexample-ibm-mq-qm, run the following command. The hostname is returned in the HOST field.
oc get routes miexample-ibm-mq-qm
Specify the queue manager details
Create a file CCDT.JSON that specifies the queue manager details. Replace the host value with the hostname returned by the previous step.
{
    "channel":
    [
        {
            "name": "MIQMCHL",
            "clientConnection":
            {
                "connection":
                [
                    {
                        "host": "<host from previous step>",
                        "port": 443
                    }
                ],
                "queueManager": "MIEXAMPLE"
            },
            "transmissionSecurity":
            {
              "cipherSpecification": "ECDHE_RSA_AES_128_CBC_SHA256"
            },
            "type": "clientConnection"
        }
   ]
}
Export environment variables
Export the following environment variables, in the manner appropriate for your operating system. These variables will be read by amqsputc and amqsgetc.
Update the path to the files on your system:
export MQCCDTURL='<full_path_to_file>/CCDT.JSON'
export MQSSLKEYR='<full_path_to_file>/clientkey'
Put messages to the queue
Run the following command:
amqsputc EXAMPLE.QUEUE MIEXAMPLE
If connection to the queue manager is successful, the following response is output:
target queue is EXAMPLE.QUEUE
Put several messages to the queue, by entering some text then pressing Enter each time.
To finish, press Enter twice.
Retrieve the messages from the queue
Run the following command:
amqsgetc EXAMPLE.QUEUE MIEXAMPLE
The messages you added in the previous step have been consumed, and are output.
After a few seconds, the command exits.
Force the active pod to fail
To validate the automatic recovery of the multi-instance queue manager, simulate a pod failure:
View the active and standby pods
Run the following command:
oc get pods
Note that, in the READY field, the active pod returns the value 1/1, whereas the standby pod returns the value 0/1.
Delete the active pod
Run the following command, specifying the full name of the active pod:
oc delete pod miexample-ibm-mq-<value>
View the pod status again
Run the following command:
oc get pods
View the standby pod log
Run the following command, specifying the full name of the standby pod:
oc logs miexample-ibm-mq-<value>
You should see the following message:
IBM MQ queue manager 'MIEXAMPLE' becoming the active instance.
Put and get messages again
After the standby pod becomes the active pod (that is, after the READY field value becomes 1/1), use the following commands again, as previously described, to put messages to the queue manager then retrieve messages from the queue manager:
amqsputc EXAMPLE.QUEUE MIEXAMPLE
amqsgetc EXAMPLE.QUEUE MIEXAMPLE

Congratulations, you have successfully deployed a multi-instance queue manager, and shown that it can automatically recover from a pod failure.

Additional information

Note 1: Creating a route
If you are using an IBM MQ client or toolkit earlier than IBM MQ 9.2.1, you need to create an OCP route.
To create the route, ensure you are in the namespace you created earlier (see Before you begin), then enter the following YAML in the OCP UI, or using the command line:

apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: example-mi-route
spec:
  host: miqmchl.chl.mq.ibm.com
  to:
    kind: Service
    name: miexample-ibm-mq
  port:
    targetPort: 1414
  tls:
    termination: passthrough
Note that the Red Hat OpenShift Container Platform Router uses SNI for routing requests to the IBM MQ queue manager. If you change the channel name specified in the config map containing MQSC commands, you must also change the host field here, and in the CCDT.JSON file that specifies the queue manager details. For more information, see Configuring a Route to connect to a queue manager from outside a Red Hat OpenShift cluster.
Note 2: Using a non-default storage class
This example expects a default storage class to have been configured in OCP, therefore no storage information is required in the queue manager custom resource YAML. If you do not have a storage class configured as default, or you want to use a different storage class, add defaultClass: <storage_class_name> under spec.queueManager.storage.
The storage class name must exactly match the name of a storage class that exists on your OCP system. That is, it must match the name returned by the command oc get storageclass. It must also support ReadWriteMany. For more information, see Storage considerations for IBM MQ Operator.
Note 3: Using IBM Cloud File Storage
In some situations, for example when using IBM Cloud File Storage, you also need to specify the securityGroups field in the queue manager custom resource YAML. For example, by adding the following child field directly under spec:

  securityContext:
    supplementalGroups: [99]
For more information, see Storage considerations for IBM MQ Operator.