Note: these instructions support the demonstration of an IBM MQ queue manager in a docker container and illustrate various capabilities as part of a demo. This is not intended as a reference guide or as production ready sample code. Please refer to the IBM MQ Documentation for more information on planning for and deploying IBM MQ in a container.
- Please follow this tutorial for full instructions on installing docker and running IBM MQ Developer Edition in a container.
- Run an MQ queue manager in a container
- Explore the default developer configuration with the IBM MQ Console
- Put some messages with a simple Golang application
- Secure a queue manager with TLS
- Containerize a Java application and connect to the MQ queue manager container secured with TLS
docker pull ibmcom/mq:latest
You can check the images has been successfully pulled with
docker images
and look for ibmcom/mq latest
in the listing
Now you have the MQ image, you're ready to run an IBM MQ queue manager as a container. However, by default container storage will be 'in memory' so messages will not persist on queues between container restarts. One approach is to crate a docker volume to attach persistent storage to the container.
docker volume create qm1data
In this example, the storage is named qm1data
.
Note: the docker run
command includes a default value for the app
user password, please modify this to something more suitable to your needs.
docker run --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --volume qm1data:/mnt/mqm --publish 1414:1414 --publish 9443:9443 --detach --env MQ_APP_PASSWORD=passw0rd --name QM1 ibmcom/mq:latest
The qm1data
volume is mounted into the container under /mnt/mqm
to provide a persistent store
In this example, the queue manager is named QM1
and two ports have been bound to the host so that messaging clients can connect to the queue manager and exchange messages on port 1414
. We can also access the IBM MQ Web Console via a browser on port 9443
. We have assigned the container instance a name of QM1
for convenience.
Check the docker process is running with
docker ps
The command should return a container id for the running queue manager container:
CONTAINER ID. IMAGE COMMAND CREATED STATUS PORTS NAMES NAMES
<your-container-id> ibmcom/mq:latest "runmqdevserver" 12 seconds ago Up 6 seconds 0.0.0.0:1414->1414/tcp, :::1414->1414/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp, 9157/tcp sad_leavitt QM1
Assuming the container is running, we can now check the queue manager is available. To do this, we exec into the container and start a bash shell.
docker exec -ti QM1 /bin/bash
We now have a command prompt inside the running container and can check the status of the queue manager using the dspmq
command.
dspmq
And we see the queue manager status
QMNAME(QM1) STATUS(Running)
The MQ container image includes the IBM MQ Console which we can connect to on port 9443. Open a web browser and naviagte to the console URL
https://localhost:9443/ibmmq/console
The console uses a self-signed TLS certificate in its default configuration. To proceed we need to accept the certificate and the console login page will load. Sign into the console with the user id admin
and the password passw0rd
(unless you set a different password in the docker run
command issued earlier).
Once inside the console, we can explore the default developer configuration.
The MQ dev patterns repo contains a standard set of samples spanning a range of languages and APIs. In this step we will clone the repo and put some messages with a Golang application.
First create / change to a suitable directory to work on the dev patterns repo clone, then clone the repo.
git clone https://github.com/ibm-messaging/mq-dev-patterns.git
under the mq-dev-patterns
top level directory, you'll see an env.json
file and the Go
directory that contians the Golang sample applications.
Open the env.json file in a suitable editor e.g., atom env.json
In the first MQ_ENDPOINTS entry remove the following lines as we have not configured TLS security at this stage
"CIPHER": "TLS_RSA_WITH_AES_128_CBC_SHA256",
"CIPHER_SUITE": "TLS_RSA_WITH_AES_128_CBC_SHA256",
"KEY_REPOSITORY": "../keys/clientkey"
Then modify the entry to include the correct credentials for the queue manager QM1
running in our container. The entry should look similar to:
{
"MQ_ENDPOINTS": [{
"HOST": "localhost",
"PORT": "1414",
"CHANNEL": "DEV.APP.SVRCONN",
"QMGR": "QM1",
"APP_USER": "app",
"APP_PASSWORD": "passw0rd",
"QUEUE_NAME": "DEV.QUEUE.1",
"MODEL_QUEUE_NAME": "DEV.APP.MODEL.QUEUE",
"DYNAMIC_QUEUE_PREFIX": "APP.REPLIES.*",
"TOPIC_NAME": "dev/"
}]
}
Save the env.json
file.
Change to the Golang source directory
cd Go/src
Run the basicput.go
application
go run basicput.go
You should see successful completion of the Golang application
MQ Put: 2021/08/16 18:27:29 Writing Message to Queue
MQ Put: 2021/08/16 18:27:29 Sending message {"greeting":"Hello from Go at ****-**-**T18:27:29+01:00","value":81}
MQ Put: 2021/08/16 18:27:29 Put message to DEV.QUEUE.1
MQ Put: 2021/08/16 18:27:29 MsgId:414d5120514d31202020202020202020fa9f1a6101290040
MQ Put: 2021/08/16 18:27:29 Application is Ending
You can use the console to check the messages were delieverd to DEV.QUEUE.1
This tutorial contains full step by step instructions.
Change into the directory that contains the mq-dev-patterns
directory, make and change into a directory called keys
mkdir keys
cd keys
openssl req -newkey rsa:2048 -nodes -keyout key.key -x509 -days 365 -out key.crt
Optionally, you can check the key with the following command
openssl x509 -text -noout -in key.crt
In this part of the demo we will use a Java client to Put and Get messages to a queue using TLS. The first step is to create a keystore and add the server certificate.
keytool -keystore clientkey.jks -storetype jks -importcert -file key.crt -alias server-certificate
Note you will need to stop your existing container with docker stop
as the ports have been allocated to it, or change the port you use locally (e.g. from 1414 to 1415) to avoid the conflict.
docker run --name mqtls --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --volume [!!path to directory with key and crt files!!]:/etc/mqm/pki/keys/mykey --publish 1414:1414 --publish 9443:9443 --detach --env MQ_APP_PASSWORD=passw0rd ibmcom/mq:latest
docker exec -ti mqtls /bin/bash
Once attached to the container with a bash shell
runmqsc QM1
Now show the Channel config
DISPLAY CHANNEL('DEV.APP.SVRCONN')
And validate that a cipher spec has been set under the SSLCIPH
attribute. You should see something like SSLCIPH(ANY_TLS12)
. Exit the shell.
exit
exit
Download the three prereq jars as linked here and copy them to the mq-dev-patterns/JMS
top level directory and then compile the put sample.
javac -cp ./com.ibm.mq.allclient-9.2.3.0.jar:./javax.jms-api-2.0.1.jar:./json-simple-1.1.1.jar:. com/ibm/mq/samples/jms/JmsPut.java
Add the following lines to the env.json
file.
"CIPHER": "TLS_RSA_WITH_AES_128_CBC_SHA256",
"CIPHER_SUITE": "TLS_RSA_WITH_AES_128_CBC_SHA256",
"KEY_REPOSITORY": "../keys/clientkey"
java -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=../../keys/clientkey.jks -Djavax.net.ssl.trustStorePassword=passw0rd -Dcom.ibm.mq.cfg.useIBMCipherMappings=false -cp ./com.ibm.mq.allclient-9.2.3.0.jar:./javax.jms-api-2.0.1.jar:./json-simple-1.1.1.jar:. com.ibm.mq.samples.jms.JmsPut
The sample app should complete successfully with the message:
INFO: Sent all messages!
You can use the console to check the messages were delieverd to DEV.QUEUE.1
.
The following section aims to illustrate the principle of containerizing an application, and not the best practices for doing so.
To simplify the configuration enabling the application container to talk to the queue manager server, we'll use a docker network
docker network create techcon21
docker run --name mqtls --env LICENSE=accept --env MQ_QMGR_NAME=QM1 --volume [!!path to directory with key and crt files!!]:/etc/mqm/pki/keys/mykey --publish 1414:1414 --publish 9443:9443 --detach --env MQ_APP_PASSWORD=passw0rd --network techcon21 ibmcom/mq:latest
Change localhost to be the name that we gave to our container instance so that it can be found on the docker network
"HOST": "mqtls",
atom Dockerfile
Add the following to your Dockerfile
FROM adoptopenjdk/openjdk8
RUN mkdir /mq-java-sample
RUN cd /mq-java-sample
COPY mq-dev-patterns/JMS JMS
COPY mq-dev-patterns/env.json .
COPY keys/clientkey.jks ./JMS
RUN cd JMS
WORKDIR JMS
RUN javac -cp ./com.ibm.mq.allclient-9.2.3.0.jar:./javax.jms-api-2.0.1.jar:./json-simple-1.1.1.jar:. com/ibm/mq/samples/jms/JmsPut.java
CMD java -Djavax.net.ssl.trustStoreType=jks -Djavax.net.ssl.trustStore=./clientkey.jks -Djavax.net.ssl.trustStorePassword=passw0rd -Dcom.ibm.mq.cfg.useIBMCipherMappings=false -cp ./com.ibm.mq.allclient-9.2.3.0.jar:./javax.jms-api-2.0.1.jar:./json-simple-1.1.1.jar:. com.ibm.mq.samples.jms.JmsPut
docker build . -t mq-app
docker run --rm --network techcon21 mq-app
The sample app should complete successfully with the message:
INFO: Sent all messages!
You can use the console to check the messages were delieverd to DEV.QUEUE.1
.